ref: aa6673fcfbe3bc41078487f4ef5d5aea459cd953
parent: 7ff779ff52b3da9c3b4cfee38cd90088ac65d6c3
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Tue Mar 22 22:45:35 EDT 2016
add portable AES-GCM (Galois/Counter Mode) implementation to libsec and devtls
--- a/sys/include/libsec.h
+++ b/sys/include/libsec.h
@@ -27,7 +27,7 @@
ulong ekey[4*(AESmaxrounds + 1)]; /* encryption key */
ulong dkey[4*(AESmaxrounds + 1)]; /* decryption key */
uchar ivec[AESbsize]; /* initialization vector */
- uchar mackey[3 * AESbsize]; /* 3 XCBC mac 96 keys */
+ uchar mackey[3 * AESbsize]; /* 3 XCBC mac 96 keys */
};
/* block ciphers */
@@ -40,6 +40,20 @@
void setupAESXCBCstate(AESstate *s);
uchar* aesXCBCmac(uchar *p, int len, AESstate *s);
+
+typedef struct AESGCMstate AESGCMstate;
+struct AESGCMstate
+{
+ AESstate;
+
+ ulong H[4];
+ ulong M[16][256][4];
+};
+
+void setupAESGCMstate(AESGCMstate *s, uchar *key, int keylen, uchar *iv, int ivlen);
+void aesgcm_setiv(AESGCMstate *s, uchar *iv, int ivlen);
+void aesgcm_encrypt(uchar *dat, ulong ndat, uchar *aad, ulong naad, uchar tag[16], AESGCMstate *s);
+int aesgcm_decrypt(uchar *dat, ulong ndat, uchar *aad, ulong naad, uchar tag[16], AESGCMstate *s);
/*
* Blowfish Definitions
--- a/sys/man/2/aes
+++ b/sys/man/2/aes
@@ -1,6 +1,6 @@
.TH AES 2
.SH NAME
-setupAESstate, aesCBCencrypt, aesCBCdecrypt, setupAESXCBCstate, aesXCBCmac - advanced encryption standard (rijndael)
+setupAESstate, aesCBCencrypt, aesCBCdecrypt, setupAESXCBCstate, aesXCBCmac, setupAESGCMstate - advanced encryption standard (rijndael)
.SH SYNOPSIS
.B #include <u.h>
.br
@@ -32,6 +32,18 @@
.PP
.B
void aesXCBCmac(uchar *p, int len, AESstate *s)
+.PP
+.B
+void setupAESGCMstate(AESGCMstate *s, uchar *key, int keylen, uchar *iv, int ivlen)
+.PP
+.B
+void aesgcm_setiv(AESGCMstate *s, uchar *iv, int ivlen)
+.PP
+.B
+void aesgcm_encrypt(uchar *dat, ulong ndat, uchar *aad, ulong naad, uchar tag[16], AESGCMstate *s)
+.PP
+.B
+int aesgcm_decrypt(uchar *dat, ulong ndat, uchar *aad, ulong naad, uchar tag[16], AESGCMstate *s)
.SH DESCRIPTION
AES (a.k.a. Rijndael) has replaced DES as the preferred
block cipher.
@@ -46,10 +58,27 @@
and
.I aesCBCdecrypt
implement cipher-block-chaining encryption.
-.I setupAESXCBCstate
+.I SetupAESXCBCstate
and
.I aesXCBCmac
implement AES XCBC message authentication, per RFC 3566.
+.IR SetupAESGCMstate ,
+.IR aesgcm_setiv ,
+.I aesgcm_encrypt
+and
+.I aesgcm_decrypt
+implement Galois/Counter Mode (GCM) authenticated encryption with associated data (AEAD).
+Before encryption or decryption, a new initialization vector (nonce) has to be set with
+.I aesgcm_setiv
+or by calling
+.I setupAESGCMstate
+with non-zero
+.I iv
+and
+.I ivlen
+arguments.
+Aesgcm_decrypt returns zero when authentication and decryption where successfull and
+non-zero otherwise.
All ciphering is performed in place.
.I Keybytes
should be 16, 24, or 32.
--- a/sys/src/9/port/devtls.c
+++ b/sys/src/9/port/devtls.c
@@ -88,11 +88,12 @@
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 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) 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 @@
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(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 @@
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 @@
}
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 @@
{ "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 @@
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,8 +2183,9 @@
}
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;
@@ -2163,8 +2192,9 @@
}
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;
@@ -2173,6 +2203,37 @@
return -1;
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 *)
--- /dev/null
+++ b/sys/src/libsec/port/aes_gcm.c
@@ -1,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;
+}
--- /dev/null
+++ b/sys/src/libsec/port/aesgcmtest.c
@@ -1,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");
+ }
+}
--- 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\
@@ -60,4 +60,7 @@
$LD -o $target $prereq
$O.chachatest: chachatest.$O
+ $LD -o $target $prereq
+
+$O.aesgcmtest: aesgcmtest.$O
$LD -o $target $prereq
--- a/sys/src/libsec/port/tlshand.c
+++ b/sys/src/libsec/port/tlshand.c
@@ -269,6 +269,23 @@
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 @@
{"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 @@
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:
@@ -876,6 +899,9 @@
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: