diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2016-03-23 02:45:35 +0100 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2016-03-23 02:45:35 +0100 |
commit | aa6673fcfbe3bc41078487f4ef5d5aea459cd953 (patch) | |
tree | 691a08eb0191904f7f8ba8a7f9ad4939aafa9907 /sys/src | |
parent | 7ff779ff52b3da9c3b4cfee38cd90088ac65d6c3 (diff) |
add portable AES-GCM (Galois/Counter Mode) implementation to libsec and devtls
Diffstat (limited to 'sys/src')
-rw-r--r-- | sys/src/9/port/devtls.c | 97 | ||||
-rw-r--r-- | sys/src/libsec/port/aes_gcm.c | 200 | ||||
-rw-r--r-- | sys/src/libsec/port/aesgcmtest.c | 314 | ||||
-rw-r--r-- | sys/src/libsec/port/mkfile | 5 | ||||
-rw-r--r-- | sys/src/libsec/port/tlshand.c | 26 |
5 files changed, 623 insertions, 19 deletions
diff --git a/sys/src/9/port/devtls.c b/sys/src/9/port/devtls.c index 93bd8225e..a30a60b35 100644 --- a/sys/src/9/port/devtls.c +++ b/sys/src/9/port/devtls.c @@ -88,11 +88,12 @@ struct Secret int (*unpad)(uchar*, int, int); DigestState *(*mac)(uchar*, ulong, uchar*, ulong, uchar*, DigestState*); - int (*aead_enc)(Secret*, uchar*, int, uchar*, int); - int (*aead_dec)(Secret*, uchar*, int, uchar*, int); + int (*aead_enc)(Secret*, uchar*, int, uchar*, uchar*, int); + int (*aead_dec)(Secret*, uchar*, int, uchar*, uchar*, int); int block; /* encryption block len, 0 if none */ int maclen; + int recivlen; void *enckey; uchar mackey[MaxMacLen]; }; @@ -246,8 +247,10 @@ static int des3enc(Secret *sec, uchar *buf, int n); static int des3dec(Secret *sec, uchar *buf, int n); static int aesenc(Secret *sec, uchar *buf, int n); static int aesdec(Secret *sec, uchar *buf, int n); -static int ccpoly_aead_enc(Secret *sec, uchar *aad, int aadlen, uchar *data, int len); -static int ccpoly_aead_dec(Secret *sec, uchar *aad, int aadlen, uchar *data, int len); +static int ccpoly_aead_enc(Secret *sec, uchar *aad, int aadlen, uchar *reciv, uchar *data, int len); +static int ccpoly_aead_dec(Secret *sec, uchar *aad, int aadlen, uchar *reciv, uchar *data, int len); +static int aesgcm_aead_enc(Secret *sec, uchar *aad, int aadlen, uchar *reciv, uchar *data, int len); +static int aesgcm_aead_dec(Secret *sec, uchar *aad, int aadlen, uchar *reciv, uchar *data, int len); static int noenc(Secret *sec, uchar *buf, int n); static int sslunpad(uchar *buf, int n, int block); static int tlsunpad(uchar *buf, int n, int block); @@ -821,14 +824,16 @@ if(tr->debug) pprint("decrypted %d\n", unpad_len); if(tr->debug) pdump(unpad_len, p, "decrypted:"); } + ivlen = sec->recivlen; if(tr->version >= TLS11Version){ - ivlen = sec->block; - len -= ivlen; - if(len < 0) - rcvError(tr, EDecodeError, "runt record message"); - unpad_len -= ivlen; - p += ivlen; + if(ivlen == 0) + ivlen = sec->block; } + len -= ivlen; + if(len < 0) + rcvError(tr, EDecodeError, "runt record message"); + unpad_len -= ivlen; + p += ivlen; if(unpad_len >= sec->maclen) len = unpad_len - sec->maclen; @@ -837,7 +842,7 @@ if(tr->debug) pdump(unpad_len, p, "decrypted:"); put16(header+3, len); aadlen = (*tr->packAAD)(in->seq++, header, aad); if(sec->aead_dec != nil) { - len = (*sec->aead_dec)(sec, aad, aadlen, p, unpad_len); + len = (*sec->aead_dec)(sec, aad, aadlen, p - ivlen, p, unpad_len); if(len < 0) rcvError(tr, EBadRecordMac, "record mac mismatch"); } else { @@ -1299,8 +1304,11 @@ if(tr->debug)pdump(BLEN(b), b->rp, "sent:"); if(sec != nil){ maclen = sec->maclen; pad = maclen + sec->block; - if(tr->version >= TLS11Version) - ivlen = sec->block; + ivlen = sec->recivlen; + if(tr->version >= TLS11Version){ + if(ivlen == 0) + ivlen = sec->block; + } } n = BLEN(bb); if(n > MaxRecLen){ @@ -1326,12 +1334,12 @@ if(tr->debug)pdump(BLEN(b), b->rp, "sent:"); put16(p+3, n); if(sec != nil){ - if(ivlen > 0) - randfill(p + RecHdrLen, ivlen); aadlen = (*tr->packAAD)(out->seq++, p, aad); if(sec->aead_enc != nil) - n = (*sec->aead_enc)(sec, aad, aadlen, p + RecHdrLen + ivlen, n) + ivlen; + n = (*sec->aead_enc)(sec, aad, aadlen, p + RecHdrLen, p + RecHdrLen + ivlen, n) + ivlen; else { + if(ivlen > 0) + randfill(p + RecHdrLen, ivlen); packMac(sec, aad, aadlen, p + RecHdrLen + ivlen, n, p + RecHdrLen + ivlen + n); n = (*sec->enc)(sec, p + RecHdrLen, ivlen + n + maclen); } @@ -1527,6 +1535,23 @@ initccpolykey(Encalg *ea, Secret *s, uchar *p, uchar *iv) } static void +initaesgcmkey(Encalg *ea, Secret *s, uchar *p, uchar *iv) +{ + s->enckey = smalloc(sizeof(AESGCMstate)); + s->enc = noenc; + s->dec = noenc; + s->mac = nomac; + s->aead_enc = aesgcm_aead_enc; + s->aead_dec = aesgcm_aead_dec; + s->block = 0; + s->maclen = 16; + s->recivlen = 8; + memmove(s->mackey, iv, ea->ivlen); + randfill(s->mackey + ea->ivlen, s->recivlen); + setupAESGCMstate(s->enckey, p, ea->keylen, nil, 0); +} + +static void initclearenc(Encalg *, Secret *s, uchar *, uchar *) { s->enc = noenc; @@ -1543,6 +1568,8 @@ static Encalg encrypttab[] = { "aes_256_cbc", 256/8, 16, initAESkey }, { "ccpoly64_aead", 256/8, 0, initccpolykey }, { "ccpoly96_aead", 256/8, 96/8, initccpolykey }, + { "aes_128_gcm_aead", 128/8, 4, initaesgcmkey }, + { "aes_256_gcm_aead", 256/8, 4, initaesgcmkey }, { 0 } }; @@ -1697,6 +1724,7 @@ tlswrite(Chan *c, void *a, long n, vlong off) if(!tos->mac || !tos->enc || !tos->dec || !toc->mac || !toc->enc || !toc->dec) error("missing algorithm implementations"); + if(strtol(cb->f[3], nil, 0) == 0){ tr->in.new = tos; tr->out.new = toc; @@ -2155,16 +2183,18 @@ ccpoly_aead_setiv(Secret *sec, uchar seq[8]) } static int -ccpoly_aead_enc(Secret *sec, uchar *aad, int aadlen, uchar *data, int len) +ccpoly_aead_enc(Secret *sec, uchar *aad, int aadlen, uchar *reciv, uchar *data, int len) { + USED(reciv); ccpoly_aead_setiv(sec, aad); ccpoly_encrypt(data, len, aad, aadlen, data+len, sec->enckey); return len + sec->maclen; } static int -ccpoly_aead_dec(Secret *sec, uchar *aad, int aadlen, uchar *data, int len) +ccpoly_aead_dec(Secret *sec, uchar *aad, int aadlen, uchar *reciv, uchar *data, int len) { + USED(reciv); len -= sec->maclen; if(len < 0) return -1; @@ -2174,6 +2204,37 @@ ccpoly_aead_dec(Secret *sec, uchar *aad, int aadlen, uchar *data, int len) return len; } +static int +aesgcm_aead_enc(Secret *sec, uchar *aad, int aadlen, uchar *reciv, uchar *data, int len) +{ + uchar iv[12]; + int i; + + memmove(iv, sec->mackey, 4+8); + for(i=0; i<8; i++) iv[4+i] ^= aad[i]; + memmove(reciv, iv+4, 8); + aesgcm_setiv(sec->enckey, iv, 12); + aesgcm_encrypt(data, len, aad, aadlen, data+len, sec->enckey); + return len + sec->maclen; +} + +static int +aesgcm_aead_dec(Secret *sec, uchar *aad, int aadlen, uchar *reciv, uchar *data, int len) +{ + uchar iv[12]; + + len -= sec->maclen; + if(len < 0) + return -1; + memmove(iv, sec->mackey, 4); + memmove(iv+4, reciv, 8); + aesgcm_setiv(sec->enckey, iv, 12); + if(aesgcm_decrypt(data, len, aad, aadlen, data+len, sec->enckey) != 0) + return -1; + return len; +} + + static DigestState* nomac(uchar *, ulong, uchar *, ulong, uchar *, DigestState *) { diff --git a/sys/src/libsec/port/aes_gcm.c b/sys/src/libsec/port/aes_gcm.c new file mode 100644 index 000000000..18ea5e1cc --- /dev/null +++ b/sys/src/libsec/port/aes_gcm.c @@ -0,0 +1,200 @@ +#include <u.h> +#include <libc.h> +#include <mp.h> +#include <libsec.h> + +static void +load128(uchar b[16], ulong W[4]) +{ + W[0] = (ulong)b[15] | (ulong)b[14]<<8 | (ulong)b[13]<<16 | (ulong)b[12]<<24; + W[1] = (ulong)b[11] | (ulong)b[10]<<8 | (ulong)b[ 9]<<16 | (ulong)b[ 8]<<24; + W[2] = (ulong)b[ 7] | (ulong)b[ 6]<<8 | (ulong)b[ 5]<<16 | (ulong)b[ 4]<<24; + W[3] = (ulong)b[ 3] | (ulong)b[ 2]<<8 | (ulong)b[ 1]<<16 | (ulong)b[ 0]<<24; +} + +static void +store128(ulong W[4], uchar b[16]) +{ + b[15] = W[0], b[14] = W[0]>>8, b[13] = W[0]>>16, b[12] = W[0]>>24; + b[11] = W[1], b[10] = W[1]>>8, b[ 9] = W[1]>>16, b[ 8] = W[1]>>24; + b[ 7] = W[2], b[ 6] = W[2]>>8, b[ 5] = W[2]>>16, b[ 4] = W[2]>>24; + b[ 3] = W[3], b[ 2] = W[3]>>8, b[ 1] = W[3]>>16, b[ 0] = W[3]>>24; +} + +static void +gfmul(ulong X[4], ulong Y[4], ulong Z[4]) +{ + long m, i; + + Z[0] = Z[1] = Z[2] = Z[3] = 0; + for(i=127; i>=0; i--){ + m = ((long)Y[i>>5] << 31-(i&31)) >> 31; + Z[0] ^= X[0] & m; + Z[1] ^= X[1] & m; + Z[2] ^= X[2] & m; + Z[3] ^= X[3] & m; + m = ((long)X[0]<<31) >> 31; + X[0] = X[0]>>1 | X[1]<<31; + X[1] = X[1]>>1 | X[2]<<31; + X[2] = X[2]>>1 | X[3]<<31; + X[3] = X[3]>>1 ^ (0xE1000000 & m); + } +} + +static void +prepareM(ulong H[4], ulong M[16][256][4]) +{ + ulong X[4], i, j; + + for(i=0; i<16; i++){ + for(j=0; j<256; j++){ + X[0] = X[1] = X[2] = X[3] = 0; + X[i>>2] = j<<((i&3)<<3); + gfmul(X, H, M[i][j]); + } + } +} + +static void +ghash1(AESGCMstate *s, ulong X[4], ulong Y[4]) +{ + ulong *Xi, i; + + X[0] ^= Y[0], X[1] ^= Y[1], X[2] ^= Y[2], X[3] ^= Y[3]; + if(0){ + gfmul(X, s->H, Y); + return; + } + + Y[0] = Y[1] = Y[2] = Y[3] = 0; + for(i=0; i<16; i++){ + Xi = s->M[i][(X[i>>2]>>((i&3)<<3))&0xFF]; + Y[0] ^= Xi[0]; + Y[1] ^= Xi[1]; + Y[2] ^= Xi[2]; + Y[3] ^= Xi[3]; + } +} + +static void +ghashn(AESGCMstate *s, uchar *dat, ulong len, ulong Y[4]) +{ + uchar tmp[16]; + ulong X[4]; + + while(len >= 16){ + load128(dat, X); + ghash1(s, X, Y); + dat += 16, len -= 16; + } + if(len > 0){ + memmove(tmp, dat, len); + memset(tmp+len, 0, 16-len); + load128(tmp, X); + ghash1(s, X, Y); + } +} + +static ulong +aesxctr1(AESstate *s, uchar ctr[AESbsize], uchar *dat, ulong len) +{ + uchar tmp[AESbsize]; + ulong i; + + aes_encrypt(s->ekey, s->rounds, ctr, tmp); + if(len > AESbsize) + len = AESbsize; + for(i=0; i<len; i++) + dat[i] ^= tmp[i]; + return len; +} + +static void +aesxctrn(AESstate *s, uchar *dat, ulong len) +{ + uchar ctr[AESbsize]; + ulong i; + + memmove(ctr, s->ivec, AESbsize); + while(len > 0){ + for(i=AESbsize-1; i>=AESbsize-4; i--) + if(++ctr[i] != 0) + break; + + if(aesxctr1(s, ctr, dat, len) < AESbsize) + break; + dat += AESbsize; + len -= AESbsize; + } +} + +void +aesgcm_setiv(AESGCMstate *s, uchar *iv, int ivlen) +{ + if(ivlen == 96/8){ + memmove(s->ivec, iv, ivlen); + memset(s->ivec+ivlen, 0, AESbsize-ivlen); + s->ivec[AESbsize-1] = 1; + } else { + ulong L[4], Y[4] = {0}; + + ghashn(s, iv, ivlen, Y); + L[0] = ivlen << 3; + L[1] = ivlen >> 29; + L[2] = L[3] = 0; + ghash1(s, L, Y); + store128(Y, s->ivec); + } +} + +void +setupAESGCMstate(AESGCMstate *s, uchar *key, int keylen, uchar *iv, int ivlen) +{ + setupAESstate(s, key, keylen, nil); + + memset(s->mackey, 0, AESbsize); + aes_encrypt(s->ekey, s->rounds, s->mackey, s->mackey); + load128(s->mackey, s->H); + prepareM(s->H, s->M); + + if(iv != nil && ivlen > 0) + aesgcm_setiv(s, iv, ivlen); +} + +void +aesgcm_encrypt(uchar *dat, ulong ndat, uchar *aad, ulong naad, uchar tag[16], AESGCMstate *s) +{ + ulong L[4], Y[4] = {0}; + + ghashn(s, aad, naad, Y); + aesxctrn(s, dat, ndat); + ghashn(s, dat, ndat, Y); + L[0] = ndat << 3; + L[1] = ndat >> 29; + L[2] = naad << 3; + L[3] = naad >> 29; + ghash1(s, L, Y); + store128(Y, tag); + aesxctr1(s, s->ivec, tag, 16); +} + +int +aesgcm_decrypt(uchar *dat, ulong ndat, uchar *aad, ulong naad, uchar tag[16], AESGCMstate *s) +{ + ulong L[4], Y[4] = {0}; + uchar tmp[16]; + + ghashn(s, aad, naad, Y); + ghashn(s, dat, ndat, Y); + L[0] = ndat << 3; + L[1] = ndat >> 29; + L[2] = naad << 3; + L[3] = naad >> 29; + ghash1(s, L, Y); + store128(Y, tmp); + aesxctr1(s, s->ivec, tmp, 16); + if(tsmemcmp(tag, tmp, 16) != 0) + return -1; + aesxctrn(s, dat, ndat); + return 0; +} diff --git a/sys/src/libsec/port/aesgcmtest.c b/sys/src/libsec/port/aesgcmtest.c new file mode 100644 index 000000000..8e8afc656 --- /dev/null +++ b/sys/src/libsec/port/aesgcmtest.c @@ -0,0 +1,314 @@ +#include <u.h> +#include <libc.h> +#include <libsec.h> +#include <mp.h> + +typedef struct Test Test; +struct Test +{ + char *K; + char *P; + char *A; + char *IV; + char *T; +}; + +Test tests[] = { + { /* Test Case 1 */ + "00000000000000000000000000000000", + "", + "", + "000000000000000000000000", + + "58E2FCCEFA7E3061367F1D57A4E7455A" + }, + { /* Test Case 2 */ + "00000000000000000000000000000000", + "00000000000000000000000000000000", + "", + "000000000000000000000000", + + "AB6E47D42CEC13BDF53A67B21257BDDF", + }, + { /* Test Case 3 */ + "feffe9928665731c6d6a8f9467308308", + "d9313225f88406e5a55909c5aff5269a" + "86a7a9531534f7da2e4c303d8a318a72" + "1c3c0c95956809532fcf0e2449a6b525" + "b16aedf5aa0de657ba637b391aafd255", + "", + "cafebabefacedbaddecaf888", + + "4D5C2AF327CD64A62CF35ABD2BA6FAB4" + }, + { /* Test Case 4 */ + "feffe9928665731c6d6a8f9467308308", + "d9313225f88406e5a55909c5aff5269a" + "86a7a9531534f7da2e4c303d8a318a72" + "1c3c0c95956809532fcf0e2449a6b525" + "b16aedf5aa0de657ba637b39", + "feedfacedeadbeeffeedfacedeadbeef" + "abaddad2", + "cafebabefacedbaddecaf888", + + "5BC94FBC3221A5DB94FAE95AE7121A47" + }, + { /* Test Case 5 */ + "feffe9928665731c6d6a8f9467308308", + "d9313225f88406e5a55909c5aff5269a" + "86a7a9531534f7da2e4c303d8a318a72" + "1c3c0c95956809532fcf0e2449a6b525" + "b16aedf5aa0de657ba637b39", + "feedfacedeadbeeffeedfacedeadbeef" + "abaddad2", + "cafebabefacedbad", + + "3612D2E79E3B0785561BE14AACA2FCCB" + }, + { /* Test Case 6 */ + "feffe9928665731c6d6a8f9467308308", + "d9313225f88406e5a55909c5aff5269a" + "86a7a9531534f7da2e4c303d8a318a72" + "1c3c0c95956809532fcf0e2449a6b525" + "b16aedf5aa0de657ba637b39", + "feedfacedeadbeeffeedfacedeadbeef" + "abaddad2", + "9313225df88406e555909c5aff5269aa" + "6a7a9538534f7da1e4c303d2a318a728" + "c3c0c95156809539fcf0e2429a6b5254" + "16aedbf5a0de6a57a637b39b", + + "619CC5AEFFFE0BFA462AF43C1699D050" + }, + { /* Test Case 7 */ + "00000000000000000000000000000000" + "0000000000000000", + "", + "", + "000000000000000000000000", + + "CD33B28AC773F74BA00ED1F312572435" + }, + { /* Test Case 8 */ + "00000000000000000000000000000000" + "0000000000000000", + "00000000000000000000000000000000", + "", + "000000000000000000000000", + + "2FF58D80033927AB8EF4D4587514F0FB" + }, + { /* Test Case 9 */ + "feffe9928665731c6d6a8f9467308308" + "feffe9928665731c", + "d9313225f88406e5a55909c5aff5269a" + "86a7a9531534f7da2e4c303d8a318a72" + "1c3c0c95956809532fcf0e2449a6b525" + "b16aedf5aa0de657ba637b391aafd255", + "", + "cafebabefacedbaddecaf888", + + "9924A7C8587336BFB118024DB8674A14" + }, + { /* Test Case 10 */ + "feffe9928665731c6d6a8f9467308308" + "feffe9928665731c", + "d9313225f88406e5a55909c5aff5269a" + "86a7a9531534f7da2e4c303d8a318a72" + "1c3c0c95956809532fcf0e2449a6b525" + "b16aedf5aa0de657ba637b39", + "feedfacedeadbeeffeedfacedeadbeef" + "abaddad2", + "cafebabefacedbaddecaf888", + + "2519498E80F1478F37BA55BD6D27618C" + }, + { /* Test Case 11 */ + "feffe9928665731c6d6a8f9467308308" + "feffe9928665731c", + "d9313225f88406e5a55909c5aff5269a" + "86a7a9531534f7da2e4c303d8a318a72" + "1c3c0c95956809532fcf0e2449a6b525" + "b16aedf5aa0de657ba637b39", + "feedfacedeadbeeffeedfacedeadbeef" + "abaddad2", + "cafebabefacedbad", + + "65DCC57FCF623A24094FCCA40D3533F8" + }, + { /* Test Case 12 */ + "feffe9928665731c6d6a8f9467308308" + "feffe9928665731c", + "d9313225f88406e5a55909c5aff5269a" + "86a7a9531534f7da2e4c303d8a318a72" + "1c3c0c95956809532fcf0e2449a6b525" + "b16aedf5aa0de657ba637b39", + "feedfacedeadbeeffeedfacedeadbeef" + "abaddad2", + "9313225df88406e555909c5aff5269aa" + "6a7a9538534f7da1e4c303d2a318a728" + "c3c0c95156809539fcf0e2429a6b5254" + "16aedbf5a0de6a57a637b39b", + + "DCF566FF291C25BBB8568FC3D376A6D9" + }, + { /* Test Case 13 */ + "00000000000000000000000000000000" + "00000000000000000000000000000000", + "", + "", + "000000000000000000000000", + + "530F8AFBC74536B9A963B4F1C4CB738B" + }, + { /* Test Case 14 */ + "00000000000000000000000000000000" + "00000000000000000000000000000000", + "00000000000000000000000000000000", + "", + "000000000000000000000000", + + "D0D1C8A799996BF0265B98B5D48AB919" + }, + { /* Test Case 15 */ + "feffe9928665731c6d6a8f9467308308" + "feffe9928665731c6d6a8f9467308308", + "d9313225f88406e5a55909c5aff5269a" + "86a7a9531534f7da2e4c303d8a318a72" + "1c3c0c95956809532fcf0e2449a6b525" + "b16aedf5aa0de657ba637b391aafd255", + "", + "cafebabefacedbaddecaf888", + + "B094DAC5D93471BDEC1A502270E3CC6C" + }, + { /* Test Case 16 */ + "feffe9928665731c6d6a8f9467308308" + "feffe9928665731c6d6a8f9467308308", + "d9313225f88406e5a55909c5aff5269a" + "86a7a9531534f7da2e4c303d8a318a72" + "1c3c0c95956809532fcf0e2449a6b525" + "b16aedf5aa0de657ba637b39", + "feedfacedeadbeeffeedfacedeadbeef" + "abaddad2", + "cafebabefacedbaddecaf888", + + "76FC6ECE0F4E1768CDDF8853BB2D551B" + }, + { /* Test Case 17 */ + "feffe9928665731c6d6a8f9467308308" + "feffe9928665731c6d6a8f9467308308", + "d9313225f88406e5a55909c5aff5269a" + "86a7a9531534f7da2e4c303d8a318a72" + "1c3c0c95956809532fcf0e2449a6b525" + "b16aedf5aa0de657ba637b39", + "feedfacedeadbeeffeedfacedeadbeef" + "abaddad2", + "cafebabefacedbad", + + "3A337DBF46A792C45E454913FE2EA8F2" + }, + { /* Test Case 18 */ + "feffe9928665731c6d6a8f9467308308" + "feffe9928665731c6d6a8f9467308308", + "d9313225f88406e5a55909c5aff5269a" + "86a7a9531534f7da2e4c303d8a318a72" + "1c3c0c95956809532fcf0e2449a6b525" + "b16aedf5aa0de657ba637b39", + "feedfacedeadbeeffeedfacedeadbeef" + "abaddad2", + "9313225df88406e555909c5aff5269aa" + "6a7a9538534f7da1e4c303d2a318a728" + "c3c0c95156809539fcf0e2429a6b5254" + "16aedbf5a0de6a57a637b39b", + + "A44A8266EE1C8EB0C8B5D4CF5AE9F19A" + }, +}; + +int +parsehex(char *s, uchar *h, char *l) +{ + char *e; + mpint *m; + int n; + + n = strlen(s); + if(n == 0) + return 0; + assert((n & 1) == 0); + n >>= 1; + e = nil; + m = strtomp(s, &e, 16, nil); + if(m == nil || *e != '\0') + abort(); + mptober(m, h, n); + if(l != nil) + print("%s = %.*H\n", l, n, h); + return n; +} + +void +runtest(Test *t) +{ + AESGCMstate s; + uchar key[1024], plain[1024], aad[1024], iv[1024], tag[16], tmp[16]; + int nkey, nplain, naad, niv; + + nkey = parsehex(t->K, key, "K"); + nplain = parsehex(t->P, plain, "P"); + naad = parsehex(t->A, aad, "A"); + niv = parsehex(t->IV, iv, "IV"); + + setupAESGCMstate(&s, key, nkey, iv, niv); + aesgcm_encrypt(plain, nplain, aad, naad, tag, &s); + print("C = %.*H\n", nplain, plain); + print("T = %.*H\n", 16, tag); + + parsehex(t->T, tmp, nil); + assert(memcmp(tmp, tag, 16) == 0); +} + +void +perftest(void) +{ + AESGCMstate s; + static uchar zeros[16]; + uchar buf[1024*1024], tag[16]; + vlong now; + int i, delta; + + now = nsec(); + for(i=0; i<100; i++){ + memset(buf, 0, sizeof(buf)); + if(1){ + setupAESGCMstate(&s, zeros, 16, zeros, 12); + aesgcm_encrypt(buf, sizeof(buf), nil, 0, tag, &s); + } else { + setupAESstate(&s, zeros, 16, zeros); + aesCBCencrypt(buf, sizeof(buf), &s); + } + } + delta = (nsec() - now) / 1000000000LL; + fprint(2, "%ds = %d/s\n", delta, i*sizeof(buf) / delta); +} + +void +main(int argc, char **argv) +{ + int i; + + fmtinstall('H', encodefmt); + + ARGBEGIN { + case 'p': + perftest(); + exits(nil); + } ARGEND; + + for(i=0; i<nelem(tests); i++){ + print("Test Case %d\n", i+1); + runtest(&tests[i]); + print("\n"); + } +} diff --git a/sys/src/libsec/port/mkfile b/sys/src/libsec/port/mkfile index 55e7a8c95..5ed2d23c0 100644 --- a/sys/src/libsec/port/mkfile +++ b/sys/src/libsec/port/mkfile @@ -3,7 +3,7 @@ LIB=/$objtype/lib/libsec.a CFILES = des.c desmodes.c desECB.c desCBC.c des3ECB.c des3CBC.c\ - aes.c blowfish.c \ + aes.c aes_gcm.c blowfish.c \ hmac.c md5.c md5block.c md4.c sha1.c sha1block.c\ sha2_64.c sha2_128.c sha2block64.c sha2block128.c\ sha1pickle.c md5pickle.c\ @@ -61,3 +61,6 @@ $O.rsatest: rsatest.$O $O.chachatest: chachatest.$O $LD -o $target $prereq + +$O.aesgcmtest: aesgcmtest.$O + $LD -o $target $prereq diff --git a/sys/src/libsec/port/tlshand.c b/sys/src/libsec/port/tlshand.c index 7a32e26fd..6efbcb828 100644 --- a/sys/src/libsec/port/tlshand.c +++ b/sys/src/libsec/port/tlshand.c @@ -269,6 +269,23 @@ enum { TLS_RSA_WITH_AES_128_CBC_SHA256 = 0X003C, TLS_RSA_WITH_AES_256_CBC_SHA256 = 0X003D, TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = 0X0067, + + TLS_RSA_WITH_AES_128_GCM_SHA256 = 0x009C, + TLS_RSA_WITH_AES_256_GCM_SHA384 = 0x009D, + TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = 0x009E, + TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 = 0x009F, + TLS_DH_RSA_WITH_AES_128_GCM_SHA256 = 0x00A0, + TLS_DH_RSA_WITH_AES_256_GCM_SHA384 = 0x00A1, + TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 = 0x00A2, + TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 = 0x00A3, + TLS_DH_DSS_WITH_AES_128_GCM_SHA256 = 0x00A4, + TLS_DH_DSS_WITH_AES_256_GCM_SHA384 = 0x00A5, + TLS_DH_anon_WITH_AES_128_GCM_SHA256 = 0x00A6, + TLS_DH_anon_WITH_AES_256_GCM_SHA384 = 0x00A7, + + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02D, + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 0xC031, + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = 0XC013, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0XC014, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = 0xC027, @@ -302,6 +319,11 @@ static Algs cipherAlgs[] = { {"ccpoly64_aead", "clear", 2*32, GOOGLE_ECDHE_ECDSA_WITH_CHACHA20_POLY1305}, {"ccpoly64_aead", "clear", 2*32, GOOGLE_DHE_RSA_WITH_CHACHA20_POLY1305}, + {"aes_128_gcm_aead", "clear", 2*(16+4), TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, + {"aes_128_gcm_aead", "clear", 2*(16+4), TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, + {"aes_128_gcm_aead", "clear", 2*(16+4), TLS_DHE_RSA_WITH_AES_128_GCM_SHA256}, + {"aes_128_gcm_aead", "clear", 2*(16+4), TLS_RSA_WITH_AES_128_GCM_SHA256}, + {"aes_128_cbc", "sha256", 2*(16+16+SHA2_256dlen), TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256}, {"aes_128_cbc", "sha256", 2*(16+16+SHA2_256dlen), TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256}, {"aes_128_cbc", "sha1", 2*(16+16+SHA1dlen), TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}, @@ -856,6 +878,7 @@ static int isDHE(int tlsid) { switch(tlsid){ + case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256: case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256: case TLS_DHE_RSA_WITH_AES_128_CBC_SHA: case TLS_DHE_RSA_WITH_AES_256_CBC_SHA: @@ -877,6 +900,9 @@ isECDHE(int tlsid) case GOOGLE_ECDHE_ECDSA_WITH_CHACHA20_POLY1305: case GOOGLE_ECDHE_RSA_WITH_CHACHA20_POLY1305: + case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: + case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: + case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: |