/* * 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. Load more
/* * 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]); void setupAESstate(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. */ void setupAESXCBCstate(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. */ void aesCBCencrypt(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++; } } void aesCBCdecrypt(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 void incrementCTR(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); } void aesCTRencrypt(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); } } void aesCTRdecrypt(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 void encode(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 int aes_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,