|
@@ -30,6 +30,7 @@
|
|
|
*/
|
|
|
#include <u.h>
|
|
|
#include <libc.h>
|
|
|
+#include <mp.h>
|
|
|
#include <libsec.h>
|
|
|
|
|
|
typedef uchar u8;
|
|
@@ -43,12 +44,30 @@ 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,
|
|
|
+ },
|
|
|
+};
|
|
|
+
|
|
|
+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);
|
|
|
|
|
|
-static int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits);
|
|
|
-static int rijndaelKeySetupDec(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits);
|
|
|
-static int rijndaelKeySetup(u32 erk[/*4*(Nr + 1)*/], u32 drk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits);
|
|
|
-static void rijndaelEncrypt(const u32 rk[], int Nr, const uchar pt[16], uchar ct[16]);
|
|
|
-static void rijndaelDecrypt(const u32 rk[], int Nr, const uchar ct[16], uchar pt[16]);
|
|
|
+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)
|
|
@@ -58,12 +77,89 @@ setupAESstate(AESstate *s, uchar key[], int keybytes, uchar *ivec)
|
|
|
keybytes = AESmaxkey;
|
|
|
memmove(s->key, key, keybytes);
|
|
|
s->keybytes = keybytes;
|
|
|
- s->rounds = rijndaelKeySetup(s->ekey, s->dkey, s->key, keybytes * 8);
|
|
|
+ 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 rijndaelKeySetup was invalid */
|
|
|
+ /* 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 */
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -82,7 +178,7 @@ aesCBCencrypt(uchar *p, int len, AESstate *s)
|
|
|
ip = s->ivec;
|
|
|
for(eip = ip+AESbsize; ip < eip; )
|
|
|
*p2++ ^= *ip++;
|
|
|
- rijndaelEncrypt(s->ekey, s->rounds, p, q);
|
|
|
+ aes_encrypt(s->ekey, s->rounds, p, q);
|
|
|
memmove(s->ivec, q, AESbsize);
|
|
|
memmove(p, q, AESbsize);
|
|
|
p += AESbsize;
|
|
@@ -90,7 +186,7 @@ aesCBCencrypt(uchar *p, int len, AESstate *s)
|
|
|
|
|
|
if(len > 0){
|
|
|
ip = s->ivec;
|
|
|
- rijndaelEncrypt(s->ekey, s->rounds, ip, q);
|
|
|
+ aes_encrypt(s->ekey, s->rounds, ip, q);
|
|
|
memmove(s->ivec, q, AESbsize);
|
|
|
for(eip = ip+len; ip < eip; )
|
|
|
*p++ ^= *ip++;
|
|
@@ -105,7 +201,7 @@ aesCBCdecrypt(uchar *p, int len, AESstate *s)
|
|
|
|
|
|
for(; len >= AESbsize; len -= AESbsize){
|
|
|
memmove(tmp, p, AESbsize);
|
|
|
- rijndaelDecrypt(s->dkey, s->rounds, p, q);
|
|
|
+ aes_decrypt(s->dkey, s->rounds, p, q);
|
|
|
memmove(p, q, AESbsize);
|
|
|
tp = tmp;
|
|
|
ip = s->ivec;
|
|
@@ -117,18 +213,191 @@ aesCBCdecrypt(uchar *p, int len, AESstate *s)
|
|
|
|
|
|
if(len > 0){
|
|
|
ip = s->ivec;
|
|
|
- rijndaelEncrypt(s->ekey, s->rounds, ip, q);
|
|
|
+ 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)
|
|
|
{
|
|
|
- USED(p, len, digest, s);
|
|
|
- return nil; /* TODO: compute aes hash for ipsec */
|
|
|
+ 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*
|
|
@@ -147,13 +416,13 @@ hmac_aes(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest,
|
|
|
* @return the number of rounds for the given cipher key size.
|
|
|
*/
|
|
|
static int
|
|
|
-rijndaelKeySetup(u32 erk[/* 4*(Nr + 1) */], u32 drk[/* 4*(Nr + 1) */],
|
|
|
- const u8 cipherKey[], int keyBits)
|
|
|
+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 = rijndaelKeySetupEnc(erk, cipherKey, keyBits);
|
|
|
+ Nr = aes_setupEnc(erk, cipherKey, keyBits);
|
|
|
|
|
|
/*
|
|
|
* invert the order of the round keys and apply the inverse MixColumn
|
|
@@ -889,8 +1158,8 @@ static const u32 rcon[] = {
|
|
|
*
|
|
|
* @return the number of rounds for the given cipher key size.
|
|
|
*/
|
|
|
-static int
|
|
|
-rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits)
|
|
|
+int
|
|
|
+aes_setupEnc(ulong rk[/*4*(Nr + 1)*/], const uchar cipherKey[], int keyBits)
|
|
|
{
|
|
|
int i = 0;
|
|
|
u32 temp;
|
|
@@ -977,13 +1246,13 @@ rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits)
|
|
|
* @return the number of rounds for the given cipher key size.
|
|
|
*/
|
|
|
static int
|
|
|
-rijndaelKeySetupDec(u32 rk[/* 4*(Nr + 1) */], const u8 cipherKey[], int keyBits)
|
|
|
+aes_setupDec(ulong rk[/* 4*(Nr + 1) */], const uchar cipherKey[], int keyBits)
|
|
|
{
|
|
|
int Nr, i, j;
|
|
|
- u32 temp;
|
|
|
+ ulong temp;
|
|
|
|
|
|
/* expand the cipher key: */
|
|
|
- Nr = rijndaelKeySetupEnc(rk, cipherKey, keyBits);
|
|
|
+ Nr = aes_setupEnc(rk, cipherKey, keyBits);
|
|
|
/* invert the order of the round keys: */
|
|
|
for (i = 0, j = 4*Nr; i < j; i += 4, j -= 4) {
|
|
|
temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp;
|
|
@@ -1021,11 +1290,12 @@ rijndaelKeySetupDec(u32 rk[/* 4*(Nr + 1) */], const u8 cipherKey[], int keyBits)
|
|
|
return Nr;
|
|
|
}
|
|
|
|
|
|
-static void
|
|
|
-rijndaelEncrypt(const u32 rk[/* 4*(Nr + 1) */], int Nr, const u8 pt[16],
|
|
|
- u8 ct[16])
|
|
|
+/* using round keys in rk, perform Nr rounds of encrypting pt into ct */
|
|
|
+void
|
|
|
+aes_encrypt(const ulong rk[/* 4*(Nr + 1) */], int Nr, const uchar pt[16],
|
|
|
+ uchar ct[16])
|
|
|
{
|
|
|
- u32 s0, s1, s2, s3, t0, t1, t2, t3;
|
|
|
+ ulong s0, s1, s2, s3, t0, t1, t2, t3;
|
|
|
#ifndef FULL_UNROLL
|
|
|
int r;
|
|
|
#endif /* ?FULL_UNROLL */
|
|
@@ -1204,11 +1474,11 @@ rijndaelEncrypt(const u32 rk[/* 4*(Nr + 1) */], int Nr, const u8 pt[16],
|
|
|
PUTU32(ct + 12, s3);
|
|
|
}
|
|
|
|
|
|
-static void
|
|
|
-rijndaelDecrypt(const u32 rk[/* 4*(Nr + 1) */], int Nr, const u8 ct[16],
|
|
|
- u8 pt[16])
|
|
|
+void
|
|
|
+aes_decrypt(const ulong rk[/* 4*(Nr + 1) */], int Nr, const uchar ct[16],
|
|
|
+ uchar pt[16])
|
|
|
{
|
|
|
- u32 s0, s1, s2, s3, t0, t1, t2, t3;
|
|
|
+ ulong s0, s1, s2, s3, t0, t1, t2, t3;
|
|
|
#ifndef FULL_UNROLL
|
|
|
int r;
|
|
|
#endif /* ?FULL_UNROLL */
|
|
@@ -1390,7 +1660,7 @@ rijndaelDecrypt(const u32 rk[/* 4*(Nr + 1) */], int Nr, const u8 ct[16],
|
|
|
#ifdef INTERMEDIATE_VALUE_KAT
|
|
|
|
|
|
static void
|
|
|
-rijndaelEncryptRound(const u32 rk[/* 4*(Nr + 1) */], int Nr, u8 block[16],
|
|
|
+aes_encryptRound(const u32 rk[/* 4*(Nr + 1) */], int Nr, u8 block[16],
|
|
|
int rounds)
|
|
|
{
|
|
|
int r;
|
|
@@ -1483,7 +1753,7 @@ rijndaelEncryptRound(const u32 rk[/* 4*(Nr + 1) */], int Nr, u8 block[16],
|
|
|
}
|
|
|
|
|
|
static void
|
|
|
-rijndaelDecryptRound(const u32 rk[/* 4*(Nr + 1) */], int Nr, u8 block[16],
|
|
|
+aes_decryptRound(const u32 rk[/* 4*(Nr + 1) */], int Nr, u8 block[16],
|
|
|
int rounds)
|
|
|
{
|
|
|
int r;
|