add portable AES-GCM (Galois/Counter Mode) implementation to libsec and devtls

This commit is contained in:
cinap_lenrek 2016-03-23 02:45:35 +01:00
parent 7ff779ff52
commit aa6673fcfb
7 changed files with 669 additions and 22 deletions

View file

@ -27,7 +27,7 @@ struct AESstate
ulong ekey[4*(AESmaxrounds + 1)]; /* encryption key */ ulong ekey[4*(AESmaxrounds + 1)]; /* encryption key */
ulong dkey[4*(AESmaxrounds + 1)]; /* decryption key */ ulong dkey[4*(AESmaxrounds + 1)]; /* decryption key */
uchar ivec[AESbsize]; /* initialization vector */ 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 */ /* block ciphers */
@ -41,6 +41,20 @@ void aesCBCdecrypt(uchar *p, int len, AESstate *s);
void setupAESXCBCstate(AESstate *s); void setupAESXCBCstate(AESstate *s);
uchar* aesXCBCmac(uchar *p, int len, 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 * Blowfish Definitions
*/ */

View file

@ -1,6 +1,6 @@
.TH AES 2 .TH AES 2
.SH NAME .SH NAME
setupAESstate, aesCBCencrypt, aesCBCdecrypt, setupAESXCBCstate, aesXCBCmac - advanced encryption standard (rijndael) setupAESstate, aesCBCencrypt, aesCBCdecrypt, setupAESXCBCstate, aesXCBCmac, setupAESGCMstate - advanced encryption standard (rijndael)
.SH SYNOPSIS .SH SYNOPSIS
.B #include <u.h> .B #include <u.h>
.br .br
@ -32,6 +32,18 @@ void setupAESXCBCstate(AESstate *s)
.PP .PP
.B .B
void aesXCBCmac(uchar *p, int len, AESstate *s) 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 .SH DESCRIPTION
AES (a.k.a. Rijndael) has replaced DES as the preferred AES (a.k.a. Rijndael) has replaced DES as the preferred
block cipher. block cipher.
@ -46,10 +58,27 @@ are the block ciphers, corresponding to
and and
.I aesCBCdecrypt .I aesCBCdecrypt
implement cipher-block-chaining encryption. implement cipher-block-chaining encryption.
.I setupAESXCBCstate .I SetupAESXCBCstate
and and
.I aesXCBCmac .I aesXCBCmac
implement AES XCBC message authentication, per RFC 3566. 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. All ciphering is performed in place.
.I Keybytes .I Keybytes
should be 16, 24, or 32. should be 16, 24, or 32.

View file

@ -88,11 +88,12 @@ struct Secret
int (*unpad)(uchar*, int, int); int (*unpad)(uchar*, int, int);
DigestState *(*mac)(uchar*, ulong, uchar*, ulong, uchar*, DigestState*); DigestState *(*mac)(uchar*, ulong, uchar*, ulong, uchar*, DigestState*);
int (*aead_enc)(Secret*, uchar*, int, uchar*, int); int (*aead_enc)(Secret*, uchar*, int, uchar*, uchar*, int);
int (*aead_dec)(Secret*, uchar*, int, uchar*, int); int (*aead_dec)(Secret*, uchar*, int, uchar*, uchar*, int);
int block; /* encryption block len, 0 if none */ int block; /* encryption block len, 0 if none */
int maclen; int maclen;
int recivlen;
void *enckey; void *enckey;
uchar mackey[MaxMacLen]; 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 des3dec(Secret *sec, uchar *buf, int n);
static int aesenc(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 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_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 *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 noenc(Secret *sec, uchar *buf, int n);
static int sslunpad(uchar *buf, int n, int block); static int sslunpad(uchar *buf, int n, int block);
static int tlsunpad(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:"); if(tr->debug) pdump(unpad_len, p, "decrypted:");
} }
ivlen = sec->recivlen;
if(tr->version >= TLS11Version){ if(tr->version >= TLS11Version){
ivlen = sec->block; if(ivlen == 0)
len -= ivlen; ivlen = sec->block;
if(len < 0)
rcvError(tr, EDecodeError, "runt record message");
unpad_len -= ivlen;
p += ivlen;
} }
len -= ivlen;
if(len < 0)
rcvError(tr, EDecodeError, "runt record message");
unpad_len -= ivlen;
p += ivlen;
if(unpad_len >= sec->maclen) if(unpad_len >= sec->maclen)
len = 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); put16(header+3, len);
aadlen = (*tr->packAAD)(in->seq++, header, aad); aadlen = (*tr->packAAD)(in->seq++, header, aad);
if(sec->aead_dec != nil) { 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) if(len < 0)
rcvError(tr, EBadRecordMac, "record mac mismatch"); rcvError(tr, EBadRecordMac, "record mac mismatch");
} else { } else {
@ -1299,8 +1304,11 @@ if(tr->debug)pdump(BLEN(b), b->rp, "sent:");
if(sec != nil){ if(sec != nil){
maclen = sec->maclen; maclen = sec->maclen;
pad = maclen + sec->block; pad = maclen + sec->block;
if(tr->version >= TLS11Version) ivlen = sec->recivlen;
ivlen = sec->block; if(tr->version >= TLS11Version){
if(ivlen == 0)
ivlen = sec->block;
}
} }
n = BLEN(bb); n = BLEN(bb);
if(n > MaxRecLen){ if(n > MaxRecLen){
@ -1326,12 +1334,12 @@ if(tr->debug)pdump(BLEN(b), b->rp, "sent:");
put16(p+3, n); put16(p+3, n);
if(sec != nil){ if(sec != nil){
if(ivlen > 0)
randfill(p + RecHdrLen, ivlen);
aadlen = (*tr->packAAD)(out->seq++, p, aad); aadlen = (*tr->packAAD)(out->seq++, p, aad);
if(sec->aead_enc != nil) 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 { else {
if(ivlen > 0)
randfill(p + RecHdrLen, ivlen);
packMac(sec, aad, aadlen, p + RecHdrLen + ivlen, n, p + RecHdrLen + ivlen + n); packMac(sec, aad, aadlen, p + RecHdrLen + ivlen, n, p + RecHdrLen + ivlen + n);
n = (*sec->enc)(sec, p + RecHdrLen, ivlen + n + maclen); n = (*sec->enc)(sec, p + RecHdrLen, ivlen + n + maclen);
} }
@ -1526,6 +1534,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 static void
initclearenc(Encalg *, Secret *s, uchar *, uchar *) initclearenc(Encalg *, Secret *s, uchar *, uchar *)
{ {
@ -1543,6 +1568,8 @@ static Encalg encrypttab[] =
{ "aes_256_cbc", 256/8, 16, initAESkey }, { "aes_256_cbc", 256/8, 16, initAESkey },
{ "ccpoly64_aead", 256/8, 0, initccpolykey }, { "ccpoly64_aead", 256/8, 0, initccpolykey },
{ "ccpoly96_aead", 256/8, 96/8, 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 } { 0 }
}; };
@ -1697,6 +1724,7 @@ tlswrite(Chan *c, void *a, long n, vlong off)
if(!tos->mac || !tos->enc || !tos->dec if(!tos->mac || !tos->enc || !tos->dec
|| !toc->mac || !toc->enc || !toc->dec) || !toc->mac || !toc->enc || !toc->dec)
error("missing algorithm implementations"); error("missing algorithm implementations");
if(strtol(cb->f[3], nil, 0) == 0){ if(strtol(cb->f[3], nil, 0) == 0){
tr->in.new = tos; tr->in.new = tos;
tr->out.new = toc; tr->out.new = toc;
@ -2155,16 +2183,18 @@ ccpoly_aead_setiv(Secret *sec, uchar seq[8])
} }
static int 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_aead_setiv(sec, aad);
ccpoly_encrypt(data, len, aad, aadlen, data+len, sec->enckey); ccpoly_encrypt(data, len, aad, aadlen, data+len, sec->enckey);
return len + sec->maclen; return len + sec->maclen;
} }
static int 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; len -= sec->maclen;
if(len < 0) if(len < 0)
return -1; return -1;
@ -2174,6 +2204,37 @@ ccpoly_aead_dec(Secret *sec, uchar *aad, int aadlen, uchar *data, int len)
return 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* static DigestState*
nomac(uchar *, ulong, uchar *, ulong, uchar *, DigestState *) nomac(uchar *, ulong, uchar *, ulong, uchar *, DigestState *)
{ {

View file

@ -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;
}

View file

@ -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");
}
}

View file

@ -3,7 +3,7 @@
LIB=/$objtype/lib/libsec.a LIB=/$objtype/lib/libsec.a
CFILES = des.c desmodes.c desECB.c desCBC.c des3ECB.c des3CBC.c\ 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\ hmac.c md5.c md5block.c md4.c sha1.c sha1block.c\
sha2_64.c sha2_128.c sha2block64.c sha2block128.c\ sha2_64.c sha2_128.c sha2block64.c sha2block128.c\
sha1pickle.c md5pickle.c\ sha1pickle.c md5pickle.c\
@ -61,3 +61,6 @@ $O.rsatest: rsatest.$O
$O.chachatest: chachatest.$O $O.chachatest: chachatest.$O
$LD -o $target $prereq $LD -o $target $prereq
$O.aesgcmtest: aesgcmtest.$O
$LD -o $target $prereq

View file

@ -269,6 +269,23 @@ enum {
TLS_RSA_WITH_AES_128_CBC_SHA256 = 0X003C, TLS_RSA_WITH_AES_128_CBC_SHA256 = 0X003C,
TLS_RSA_WITH_AES_256_CBC_SHA256 = 0X003D, TLS_RSA_WITH_AES_256_CBC_SHA256 = 0X003D,
TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = 0X0067, 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_128_CBC_SHA = 0XC013,
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0XC014, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0XC014,
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = 0xC027, 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_ECDHE_ECDSA_WITH_CHACHA20_POLY1305},
{"ccpoly64_aead", "clear", 2*32, GOOGLE_DHE_RSA_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_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", "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}, {"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) isDHE(int tlsid)
{ {
switch(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_SHA256:
case TLS_DHE_RSA_WITH_AES_128_CBC_SHA: case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
case TLS_DHE_RSA_WITH_AES_256_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_ECDSA_WITH_CHACHA20_POLY1305:
case GOOGLE_ECDHE_RSA_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_ECDSA_WITH_AES_128_CBC_SHA256:
case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: