1855 lines · 68.5 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * this code is derived from the following source, * and modified to fit into the plan 9 libsec interface. * most of the changes are confined to the top section, * with the exception of converting Te4 and Td4 into u8 rather than u32 arrays. * * rijndael-alg-fst.c * * @version 3.0 (December 2000) * * Optimised ANSI C code for the Rijndael cipher (now AES) * * @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be> * @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be> * @author Paulo Barreto <paulo.barreto@terra.com.br> * * This code is hereby placed in the public domain. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */#include <u.h>#include <libc.h>#include <mp.h>#include <libsec.h> typedef uchar	u8;typedef ulong	u32; #define FULL_UNROLL#define const static const u32 Td0[256];static const u32 Td1[256];static const u32 Td2[256];static const u32 Td3[256];static const u8  Te4[256];static uchar basekey[3][16] = {	{	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,	},	{	0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,	0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,	},	{	0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,	0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,	},}; static int aes_setupEnc(ulong rk[/*4*(Nr + 1)*/], const uchar cipherKey[],		int keyBits);static int aes_setupDec(ulong rk[/*4*(Nr + 1)*/], const uchar cipherKey[],		int keyBits);static int aes_setup(ulong erk[/*4*(Nr + 1)*/], ulong drk[/*4*(Nr + 1)*/],		const uchar cipherKey[], int keyBits); void	aes_encrypt(const ulong rk[], int Nr, const uchar pt[16], uchar ct[16]);void	aes_decrypt(const ulong rk[], int Nr, const uchar ct[16], uchar pt[16]); voidsetupAESstate(AESstate *s, uchar key[], int keybytes, uchar *ivec){	memset(s, 0, sizeof(*s));	if(keybytes > AESmaxkey)		keybytes = AESmaxkey;	memmove(s->key, key, keybytes);	s->keybytes = keybytes;	s->rounds = aes_setup(s->ekey, s->dkey, s->key, keybytes * 8);	if(ivec != nil)		memmove(s->ivec, ivec, AESbsize);	if(keybytes==16 || keybytes==24 || keybytes==32)		s->setup = 0xcafebabe;	/* else aes_setup was invalid */} /* * AES-XCBC-MAC-96 message authentication, per rfc3566. */ voidsetupAESXCBCstate(AESstate *s)		/* was setupmac96 */{	int i, j;	uint q[16 / sizeof(uint)];	uchar *p; 	assert(s->keybytes == 16);	for(i = 0; i < 3; i++)		aes_encrypt(s->ekey, s->rounds, basekey[i],			s->mackey + AESbsize*i); 	p = s->mackey;	memset(q, 0, AESbsize); 	/*	 * put the in the right endian.  once figured, probably better	 * to use some fcall macros.	 * keys for encryption in local endianness for the algorithm...	 * only key1 is used for encryption;	 * BUG!!: I think this is what I got wrong.	 */	for(i = 0; i < 16 / sizeof(uint); i ++){		for(j = 0; j < sizeof(uint); j++)			q[i] |= p[sizeof(uint)-j-1] << 8*j;		p += sizeof(uint);	}	memmove(s->mackey, q, 16);} /* * Not dealing with > 128-bit keys, not dealing with strange corner cases like * empty message.  Should be fine for AES-XCBC-MAC-96. */uchar*aesXCBCmac(uchar *p, int len, AESstate *s){	uchar *p2, *ip, *eip, *mackey;	uchar q[AESbsize]; 	assert(s->keybytes == 16);	/* more complicated for bigger */	memset(s->ivec, 0, AESbsize);	/* E[0] is 0+ */ 	for(; len > AESbsize; len -= AESbsize){		memmove(q, p, AESbsize);		p2 = q;		ip = s->ivec;		for(eip = ip + AESbsize; ip < eip; )			*p2++ ^= *ip++;		aes_encrypt((ulong *)s->mackey, s->rounds, q, s->ivec);		p += AESbsize;	}	/* the last one */ 	memmove(q, p, len);	p2 = q+len;	if(len == AESbsize)		mackey = s->mackey + AESbsize;	/* k2 */	else{		mackey = s->mackey+2*AESbsize;	/* k3 */		*p2++ = 1 << 7;			/* padding */		len = AESbsize - len - 1;		memset(p2, 0, len);	} 	ip = s->ivec;	p2 = q;	for(eip = ip + AESbsize; ip < eip; )		*p2++ ^= *ip++ ^ *mackey++;	aes_encrypt((ulong *)s->mackey, s->rounds, q, s->ivec);	return s->ivec;			/* only the 12 bytes leftmost */} /* * Define by analogy with desCBCencrypt;  AES modes are not standardized yet. * Because of the way that non-multiple-of-16 buffers are handled, * the decryptor must be fed buffers of the same size as the encryptor. */voidaesCBCencrypt(uchar *p, int len, AESstate *s){	uchar *p2, *ip, *eip;	uchar q[AESbsize]; 	for(; len >= AESbsize; len -= AESbsize){		p2 = p;		ip = s->ivec;		for(eip = ip+AESbsize; ip < eip; )			*p2++ ^= *ip++;		aes_encrypt(s->ekey, s->rounds, p, q);		memmove(s->ivec, q, AESbsize);		memmove(p, q, AESbsize);		p += AESbsize;	} 	if(len > 0){		ip = s->ivec;		aes_encrypt(s->ekey, s->rounds, ip, q);		memmove(s->ivec, q, AESbsize);		for(eip = ip+len; ip < eip; )			*p++ ^= *ip++;	}} voidaesCBCdecrypt(uchar *p, int len, AESstate *s){	uchar *ip, *eip, *tp;	uchar tmp[AESbsize], q[AESbsize]; 	for(; len >= AESbsize; len -= AESbsize){		memmove(tmp, p, AESbsize);		aes_decrypt(s->dkey, s->rounds, p, q);		memmove(p, q, AESbsize);		tp = tmp;		ip = s->ivec;		for(eip = ip+AESbsize; ip < eip; ){			*p++ ^= *ip;			*ip++ = *tp++;		}	} 	if(len > 0){		ip = s->ivec;		aes_encrypt(s->ekey, s->rounds, ip, q);		memmove(s->ivec, q, AESbsize);		for(eip = ip+len; ip < eip; )			*p++ ^= *ip++;	}} /* * AES-CTR mode, per rfc3686. * CTRs could be precalculated for efficiency * and there would also be less back and forth mp */ static voidincrementCTR(uchar *p, uint ctrsz){	int len;	uchar *ctr;	mpint *mpctr, *mpctrsz; 	ctr = p + AESbsize - ctrsz;	mpctr = betomp(ctr, ctrsz, nil);	mpctrsz = itomp(1 << (ctrsz*8), nil);	mpadd(mpctr, mpone, mpctr);	mpmod(mpctr, mpctrsz, mpctr);	len = mptobe(mpctr, ctr, ctrsz, nil);	assert(len == ctrsz);	mpfree(mpctrsz);	mpfree(mpctr);} voidaesCTRencrypt(uchar *p, int len, AESstate *s){	uchar q[AESbsize];	uchar *ip, *eip, *ctr; 	ctr = s->ivec;	for(; len >= AESbsize; len -= AESbsize){		ip = q;		aes_encrypt(s->ekey, s->rounds, ctr, q);		for(eip = p + AESbsize; p < eip; )			*p++ ^= *ip++;		incrementCTR(ctr, s->ctrsz);	} 	if(len > 0){		ip = q;		aes_encrypt(s->ekey, s->rounds, ctr, q);		for(eip = p + len; p < eip; )			*p++ ^= *ip++;		incrementCTR(ctr, s->ctrsz);	}} voidaesCTRdecrypt(uchar *p, int len, AESstate *s){	aesCTRencrypt(p, len, s);}  /* taken from sha1; TODO: verify suitability (esp. byte order) for aes *//* *	encodes input (ulong) into output (uchar). Assumes len is *	a multiple of 4. */static voidencode(uchar *output, ulong *input, ulong len){	ulong x;	uchar *e; 	for(e = output + len; output < e;) {		x = *input++;		*output++ = x >> 24;		*output++ = x >> 16;		*output++ = x >> 8;		*output++ = x;	}} /* TODO: verify use of aes_encrypt here */AEShstate*aes(uchar *p, ulong len, uchar *digest, AEShstate *s){	uchar buf[128];	ulong x[16];	int i;	uchar *e; 	if(s == nil){		s = malloc(sizeof(*s));		if(s == nil)			return nil;		memset(s, 0, sizeof(*s));		s->malloced = 1;	} 	if(s->seeded == 0){		/* seed the state, these constants would look nicer big-endian */		s->state[0] = 0x67452301;		s->state[1] = 0xefcdab89;		s->state[2] = 0x98badcfe;		s->state[3] = 0x10325476;		/* in sha1 (20-byte digest), but not md5 (16 bytes)*/		s->state[4] = 0xc3d2e1f0;		s->seeded = 1;	} 	/* fill out the partial 64 byte block from previous calls */	if(s->blen){		i = 64 - s->blen;		if(len < i)			i = len;		memmove(s->buf + s->blen, p, i);		len -= i;		s->blen += i;		p += i;		if(s->blen == 64){			/* encrypt s->buf into s->state */			// _sha1block(s->buf, s->blen, s->state);			aes_encrypt((ulong *)s->buf, 1, s->buf, (uchar *)s->state);			s->len += s->blen;			s->blen = 0;		}	} 	/* do 64 byte blocks */	i = len & ~0x3f;	if(i){		/* encrypt p into s->state */		// _sha1block(p, i, s->state);		aes_encrypt((ulong *)s->buf, 1, p, (uchar *)s->state);		s->len += i;		len -= i;		p += i;	} 	/* save the left overs if not last call */	if(digest == 0){		if(len){			memmove(s->buf, p, len);			s->blen += len;		}		return s;	} 	/*	 *  this is the last time through, pad what's left with 0x80,	 *  0's, and the input count to create a multiple of 64 bytes	 */	if(s->blen){		p = s->buf;		len = s->blen;	} else {		memmove(buf, p, len);		p = buf;	}	s->len += len;	e = p + len;	if(len < 56)		i = 56 - len;	else		i = 120 - len;	memset(e, 0, i);	*e = 0x80;	len += i; 	/* append the count */	x[0] = s->len>>29;		/* byte-order dependent */	x[1] = s->len<<3;	encode(p+len, x, 8); 	/* digest the last part */	/* encrypt p into s->state */	// _sha1block(p, len+8, s->state);	aes_encrypt((ulong *)s->buf, 1, p, (uchar *)s->state);	s->len += len+8;		/* sha1: +8 */ 	/* return result and free state */	encode((uchar *)digest, (ulong *)s->state, AESdlen);	if(s->malloced == 1)		free(s);	return nil;} DigestState*hmac_aes(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest,	DigestState *s){	return hmac_x(p, len, key, klen, digest, s, aes, AESdlen);}   /* * this function has been changed for plan 9. * Expand the cipher key into the encryption and decryption key schedules. * * @return	the number of rounds for the given cipher key size. */static intaes_setup(ulong erk[/* 4*(Nr + 1) */], ulong drk[/* 4*(Nr + 1) */],	const uchar cipherKey[], int keyBits){	int Nr, i; 	/* expand the cipher key: */	Nr = aes_setupEnc(erk, cipherKey, keyBits); 	/*	 * invert the order of the round keys and apply the inverse MixColumn	 * transform to all round keys but the first and the last	 */	drk[0       ] = erk[4*Nr    ];	drk[1       ] = erk[4*Nr + 1];	drk[2       ] = erk[4*Nr + 2];	drk[3       ] = erk[4*Nr + 3];	drk[4*Nr    ] = erk[0       ];	drk[4*Nr + 1] = erk[1       ];	drk[4*Nr + 2] = erk[2       ];	drk[4*Nr + 3] = erk[3       ];	erk += 4 * Nr;	for (i = 1; i < Nr; i++) {		drk += 4;		erk -= 4;		drk[0] =		    Td0[Te4[(erk[0] >> 24)       ]] ^		    Td1[Te4[(erk[0] >> 16) & 0xff]] ^		    Td2[Te4[(erk[0] >>  8) & 0xff]] ^		    Td3[Te4[(erk[0]      ) & 0xff]];		drk[1] =		    Td0[Te4[(erk[1] >> 24)       ]] ^		    Td1[Te4[(erk[1] >> 16) & 0xff]] ^		    Td2[Te4[(erk[1] >>  8) & 0xff]] ^		    Td3[Te4[(erk[1]      ) & 0xff]];		drk[2] =		    Td0[Te4[(erk[2] >> 24)       ]] ^		    Td1[Te4[(erk[2] >> 16) & 0xff]] ^		    Td2[Te4[(erk[2] >>  8) & 0xff]] ^		    Td3[Te4[(erk[2]      ) & 0xff]];		drk[3] =		    Td0[Te4[(erk[3] >> 24)       ]] ^		    Td1[Te4[(erk[3] >> 16) & 0xff]] ^		    Td2[Te4[(erk[3] >>  8) & 0xff]] ^		    Td3[Te4[(erk[3]      ) & 0xff]];	}	return Nr;}  /*Te0[x] = S [x].[02, 01, 01, 03];Te1[x] = S [x].[03, 02, 01, 01];Te2[x] = S [x].[01, 03, 02, 01];Te3[x] = S [x].[01, 01, 03, 02];Te4[x] = S [x] Td0[x] = Si[x].[0e, 09, 0d, 0b];Td1[x] = Si[x].[0b, 0e, 09, 0d];Td2[x] = Si[x].[0d, 0b, 0e, 09];Td3[x] = Si[x].[09, 0d, 0b, 0e];Td4[x] = Si[x]*/ static const u32 Te0[256] = {    0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU,    0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U,    0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU,    0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU,    0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U,    0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU,    0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU,    0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU,    0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU,

Lines 1–500 of 1855.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t