diff --git a/configure.ac b/configure.ac index 82856d0fd..7b36adfed 100644 --- a/configure.ac +++ b/configure.ac @@ -296,9 +296,27 @@ AC_ARG_ENABLE(aesgcm, [ ENABLED_AESGCM=no ] ) +if test "$ENABLED_AESGCM" = "word32" +then + AM_CFLAGS="$AM_CFLAGS -DGCM_WORD32" + ENABLED_AESGCM=yes +fi + +if test "$ENABLED_AESGCM" = "small" +then + AM_CFLAGS="$AM_CFLAGS -DGCM_SMALL" + ENABLED_AESGCM=yes +fi + +if test "$ENABLED_AESGCM" = "table" +then + AM_CFLAGS="$AM_CFLAGS -DGCM_TABLE" + ENABLED_AESGCM=yes +fi + if test "$ENABLED_AESGCM" = "yes" then - AM_CFLAGS="$AM_CFLAGS -DHAVE_AESGCM" + AM_CFLAGS="$AM_CFLAGS -DHAVE_AESGCM -DCYASSL_SHA384 -DCYASSL_SHA512" fi AM_CONDITIONAL([BUILD_AESGCM], [test "x$ENABLED_AESGCM" = "xyes"]) @@ -355,6 +373,11 @@ then ENABLED_SHA512="yes" fi +if test "$ENABLED_AESGCM" = "yes" +then + ENABLED_SHA512="yes" +fi + AM_CONDITIONAL([BUILD_SHA512], [test "x$ENABLED_SHA512" = "xyes"]) diff --git a/ctaocrypt/benchmark/benchmark.c b/ctaocrypt/benchmark/benchmark.c index 701061e40..e7100ba95 100644 --- a/ctaocrypt/benchmark/benchmark.c +++ b/ctaocrypt/benchmark/benchmark.c @@ -54,6 +54,7 @@ void bench_arc4(); void bench_hc128(); void bench_rabbit(); void bench_aes(int); +void bench_aesgcm(); void bench_md5(); void bench_sha(); @@ -78,6 +79,9 @@ int main(int argc, char** argv) #ifndef NO_AES bench_aes(0); bench_aes(1); +#endif +#ifdef HAVE_AESGCM + bench_aesgcm(); #endif bench_arc4(); #ifdef HAVE_HC128 @@ -171,6 +175,34 @@ void bench_aes(int show) #endif +byte additional[13]; +byte tag[16]; + + +#ifdef HAVE_AESGCM +void bench_aesgcm() +{ + Aes enc; + double start, total, persec; + int i; + + AesGcmSetKey(&enc, key, 16); + AesSetIV(&enc, iv); + start = current_time(); + + for(i = 0; i < megs; i++) + AesGcmEncrypt(&enc, cipher, plain, sizeof(plain), + tag, 16, additional, 13); + + total = current_time() - start; + + persec = 1 / total * megs; + printf("AES-GCM %d megs took %5.3f seconds, %6.2f MB/s\n", megs, total, + persec); +} +#endif + + #ifndef NO_DES3 void bench_des() { diff --git a/ctaocrypt/src/aes.c b/ctaocrypt/src/aes.c index 5eac4f93f..15e486b03 100644 --- a/ctaocrypt/src/aes.c +++ b/ctaocrypt/src/aes.c @@ -1428,29 +1428,92 @@ static INLINE void IncrementGcmCounter(byte* inOutCtr) } -static void RIGHTSHIFT(byte* x) +#if defined(GCM_SMALL) || defined(GCM_TABLE) + +static INLINE void FlattenSzInBits(byte* buf, word32 sz) +{ + /* Multiply the sz by 8 */ + word32 szHi = (sz >> (8*sizeof(sz) - 3)); + sz <<= 3; + + /* copy over the words of the sz into the destination buffer */ + buf[0] = (szHi >> 24) & 0xff; + buf[1] = (szHi >> 16) & 0xff; + buf[2] = (szHi >> 8) & 0xff; + buf[3] = szHi & 0xff; + buf[4] = (sz >> 24) & 0xff; + buf[5] = (sz >> 16) & 0xff; + buf[6] = (sz >> 8) & 0xff; + buf[7] = sz & 0xff; +} + + +static INLINE void RIGHTSHIFTX(byte* x) { int i; int carryOut = 0; int carryIn = 0; + int borrow = x[15] & 0x01; for (i = 0; i < AES_BLOCK_SIZE; i++) { carryOut = x[i] & 0x01; x[i] = (x[i] >> 1) | (carryIn ? 0x80 : 0); carryIn = carryOut; } + if (borrow) x[0] ^= 0xE1; +} + +#endif /* defined(GCM_SMALL) || defined(GCM_TABLE) */ + + +#ifdef GCM_TABLE + +static void GenerateM0(Aes* aes) +{ + int i, j; + byte (*m)[AES_BLOCK_SIZE] = aes->M0; + + XMEMCPY(m[128], aes->H, AES_BLOCK_SIZE); + + for (i = 64; i > 0; i /= 2) { + XMEMCPY(m[i], m[i*2], AES_BLOCK_SIZE); + RIGHTSHIFTX(m[i]); + } + + for (i = 2; i < 256; i *= 2) { + for (j = 1; j < i; j++) { + XMEMCPY(m[i+j], m[i], AES_BLOCK_SIZE); + xorbuf(m[i+j], m[j], AES_BLOCK_SIZE); + } + } + + XMEMSET(m[0], 0, AES_BLOCK_SIZE); +} + +#endif /* GCM_TABLE */ + + +void AesGcmSetKey(Aes* aes, const byte* key, word32 len) +{ + byte iv[AES_BLOCK_SIZE]; + + XMEMSET(iv, 0, AES_BLOCK_SIZE); + AesSetKey(aes, key, len, iv, AES_ENCRYPTION); + AesEncrypt(aes, iv, aes->H); +#ifdef GCM_TABLE + GenerateM0(aes); +#endif /* GCM_TABLE */ } +#if defined(GCM_SMALL) + static void GMULT(byte* X, byte* Y) { - byte R[AES_BLOCK_SIZE]; byte Z[AES_BLOCK_SIZE]; byte V[AES_BLOCK_SIZE]; int i, j; - XMEMSET(R, 0, AES_BLOCK_SIZE); - R[0] = 0xE1; XMEMSET(Z, 0, AES_BLOCK_SIZE); XMEMCPY(V, X, AES_BLOCK_SIZE); for (i = 0; i < AES_BLOCK_SIZE; i++) @@ -1462,12 +1525,7 @@ static void GMULT(byte* X, byte* Y) xorbuf(Z, V, AES_BLOCK_SIZE); } - if (V[15] & 0x01) { - RIGHTSHIFT(V); - xorbuf(V, R, AES_BLOCK_SIZE); - } else { - RIGHTSHIFT(V); - } + RIGHTSHIFTX(V); y = y << 1; } } @@ -1475,11 +1533,13 @@ static void GMULT(byte* X, byte* Y) } -static void GHASH(byte* h, const byte* a, word32 aSz, +static void GHASH(Aes* aes, const byte* a, word32 aSz, const byte* c, word32 cSz, byte* s, word32 sSz) { byte x[AES_BLOCK_SIZE]; + byte scratch[AES_BLOCK_SIZE]; word32 blocks, partial; + byte* h = aes->H; XMEMSET(x, 0, AES_BLOCK_SIZE); @@ -1493,7 +1553,6 @@ static void GHASH(byte* h, const byte* a, word32 aSz, a += AES_BLOCK_SIZE; } if (partial != 0) { - byte scratch[AES_BLOCK_SIZE]; XMEMSET(scratch, 0, AES_BLOCK_SIZE); XMEMCPY(scratch, a, partial); xorbuf(x, scratch, AES_BLOCK_SIZE); @@ -1511,7 +1570,6 @@ static void GHASH(byte* h, const byte* a, word32 aSz, c += AES_BLOCK_SIZE; } if (partial != 0) { - byte scratch[AES_BLOCK_SIZE]; XMEMSET(scratch, 0, AES_BLOCK_SIZE); XMEMCPY(scratch, c, partial); xorbuf(x, scratch, AES_BLOCK_SIZE); @@ -1519,27 +1577,433 @@ static void GHASH(byte* h, const byte* a, word32 aSz, } } - /* Hash in the lengths in bits of A and C */ - { - byte len[AES_BLOCK_SIZE]; - XMEMSET(len, 0, AES_BLOCK_SIZE); - len[3] = aSz >> 29; - len[4] = aSz >> 21; - len[5] = aSz >> 13; - len[6] = aSz >> 5; - len[7] = aSz << 3; + /* Hash in the lengths of A and C in bits */ + FlattenSzInBits(&scratch[0], aSz); + FlattenSzInBits(&scratch[8], cSz); + xorbuf(x, scratch, AES_BLOCK_SIZE); + GMULT(x, h); - len[11] = cSz >> 29; - len[12] = cSz >> 21; - len[13] = cSz >> 13; - len[14] = cSz >> 5; - len[15] = cSz << 3; - xorbuf(x, len, AES_BLOCK_SIZE); - GMULT(x, h); - } + /* Copy the result into s. */ XMEMCPY(s, x, sSz); } +/* end GCM_SMALL */ +#elif defined(GCM_TABLE) + +static const byte R[256][2] = { + {0x00, 0x00}, {0x01, 0xc2}, {0x03, 0x84}, {0x02, 0x46}, + {0x07, 0x08}, {0x06, 0xca}, {0x04, 0x8c}, {0x05, 0x4e}, + {0x0e, 0x10}, {0x0f, 0xd2}, {0x0d, 0x94}, {0x0c, 0x56}, + {0x09, 0x18}, {0x08, 0xda}, {0x0a, 0x9c}, {0x0b, 0x5e}, + {0x1c, 0x20}, {0x1d, 0xe2}, {0x1f, 0xa4}, {0x1e, 0x66}, + {0x1b, 0x28}, {0x1a, 0xea}, {0x18, 0xac}, {0x19, 0x6e}, + {0x12, 0x30}, {0x13, 0xf2}, {0x11, 0xb4}, {0x10, 0x76}, + {0x15, 0x38}, {0x14, 0xfa}, {0x16, 0xbc}, {0x17, 0x7e}, + {0x38, 0x40}, {0x39, 0x82}, {0x3b, 0xc4}, {0x3a, 0x06}, + {0x3f, 0x48}, {0x3e, 0x8a}, {0x3c, 0xcc}, {0x3d, 0x0e}, + {0x36, 0x50}, {0x37, 0x92}, {0x35, 0xd4}, {0x34, 0x16}, + {0x31, 0x58}, {0x30, 0x9a}, {0x32, 0xdc}, {0x33, 0x1e}, + {0x24, 0x60}, {0x25, 0xa2}, {0x27, 0xe4}, {0x26, 0x26}, + {0x23, 0x68}, {0x22, 0xaa}, {0x20, 0xec}, {0x21, 0x2e}, + {0x2a, 0x70}, {0x2b, 0xb2}, {0x29, 0xf4}, {0x28, 0x36}, + {0x2d, 0x78}, {0x2c, 0xba}, {0x2e, 0xfc}, {0x2f, 0x3e}, + {0x70, 0x80}, {0x71, 0x42}, {0x73, 0x04}, {0x72, 0xc6}, + {0x77, 0x88}, {0x76, 0x4a}, {0x74, 0x0c}, {0x75, 0xce}, + {0x7e, 0x90}, {0x7f, 0x52}, {0x7d, 0x14}, {0x7c, 0xd6}, + {0x79, 0x98}, {0x78, 0x5a}, {0x7a, 0x1c}, {0x7b, 0xde}, + {0x6c, 0xa0}, {0x6d, 0x62}, {0x6f, 0x24}, {0x6e, 0xe6}, + {0x6b, 0xa8}, {0x6a, 0x6a}, {0x68, 0x2c}, {0x69, 0xee}, + {0x62, 0xb0}, {0x63, 0x72}, {0x61, 0x34}, {0x60, 0xf6}, + {0x65, 0xb8}, {0x64, 0x7a}, {0x66, 0x3c}, {0x67, 0xfe}, + {0x48, 0xc0}, {0x49, 0x02}, {0x4b, 0x44}, {0x4a, 0x86}, + {0x4f, 0xc8}, {0x4e, 0x0a}, {0x4c, 0x4c}, {0x4d, 0x8e}, + {0x46, 0xd0}, {0x47, 0x12}, {0x45, 0x54}, {0x44, 0x96}, + {0x41, 0xd8}, {0x40, 0x1a}, {0x42, 0x5c}, {0x43, 0x9e}, + {0x54, 0xe0}, {0x55, 0x22}, {0x57, 0x64}, {0x56, 0xa6}, + {0x53, 0xe8}, {0x52, 0x2a}, {0x50, 0x6c}, {0x51, 0xae}, + {0x5a, 0xf0}, {0x5b, 0x32}, {0x59, 0x74}, {0x58, 0xb6}, + {0x5d, 0xf8}, {0x5c, 0x3a}, {0x5e, 0x7c}, {0x5f, 0xbe}, + {0xe1, 0x00}, {0xe0, 0xc2}, {0xe2, 0x84}, {0xe3, 0x46}, + {0xe6, 0x08}, {0xe7, 0xca}, {0xe5, 0x8c}, {0xe4, 0x4e}, + {0xef, 0x10}, {0xee, 0xd2}, {0xec, 0x94}, {0xed, 0x56}, + {0xe8, 0x18}, {0xe9, 0xda}, {0xeb, 0x9c}, {0xea, 0x5e}, + {0xfd, 0x20}, {0xfc, 0xe2}, {0xfe, 0xa4}, {0xff, 0x66}, + {0xfa, 0x28}, {0xfb, 0xea}, {0xf9, 0xac}, {0xf8, 0x6e}, + {0xf3, 0x30}, {0xf2, 0xf2}, {0xf0, 0xb4}, {0xf1, 0x76}, + {0xf4, 0x38}, {0xf5, 0xfa}, {0xf7, 0xbc}, {0xf6, 0x7e}, + {0xd9, 0x40}, {0xd8, 0x82}, {0xda, 0xc4}, {0xdb, 0x06}, + {0xde, 0x48}, {0xdf, 0x8a}, {0xdd, 0xcc}, {0xdc, 0x0e}, + {0xd7, 0x50}, {0xd6, 0x92}, {0xd4, 0xd4}, {0xd5, 0x16}, + {0xd0, 0x58}, {0xd1, 0x9a}, {0xd3, 0xdc}, {0xd2, 0x1e}, + {0xc5, 0x60}, {0xc4, 0xa2}, {0xc6, 0xe4}, {0xc7, 0x26}, + {0xc2, 0x68}, {0xc3, 0xaa}, {0xc1, 0xec}, {0xc0, 0x2e}, + {0xcb, 0x70}, {0xca, 0xb2}, {0xc8, 0xf4}, {0xc9, 0x36}, + {0xcc, 0x78}, {0xcd, 0xba}, {0xcf, 0xfc}, {0xce, 0x3e}, + {0x91, 0x80}, {0x90, 0x42}, {0x92, 0x04}, {0x93, 0xc6}, + {0x96, 0x88}, {0x97, 0x4a}, {0x95, 0x0c}, {0x94, 0xce}, + {0x9f, 0x90}, {0x9e, 0x52}, {0x9c, 0x14}, {0x9d, 0xd6}, + {0x98, 0x98}, {0x99, 0x5a}, {0x9b, 0x1c}, {0x9a, 0xde}, + {0x8d, 0xa0}, {0x8c, 0x62}, {0x8e, 0x24}, {0x8f, 0xe6}, + {0x8a, 0xa8}, {0x8b, 0x6a}, {0x89, 0x2c}, {0x88, 0xee}, + {0x83, 0xb0}, {0x82, 0x72}, {0x80, 0x34}, {0x81, 0xf6}, + {0x84, 0xb8}, {0x85, 0x7a}, {0x87, 0x3c}, {0x86, 0xfe}, + {0xa9, 0xc0}, {0xa8, 0x02}, {0xaa, 0x44}, {0xab, 0x86}, + {0xae, 0xc8}, {0xaf, 0x0a}, {0xad, 0x4c}, {0xac, 0x8e}, + {0xa7, 0xd0}, {0xa6, 0x12}, {0xa4, 0x54}, {0xa5, 0x96}, + {0xa0, 0xd8}, {0xa1, 0x1a}, {0xa3, 0x5c}, {0xa2, 0x9e}, + {0xb5, 0xe0}, {0xb4, 0x22}, {0xb6, 0x64}, {0xb7, 0xa6}, + {0xb2, 0xe8}, {0xb3, 0x2a}, {0xb1, 0x6c}, {0xb0, 0xae}, + {0xbb, 0xf0}, {0xba, 0x32}, {0xb8, 0x74}, {0xb9, 0xb6}, + {0xbc, 0xf8}, {0xbd, 0x3a}, {0xbf, 0x7c}, {0xbe, 0xbe} }; + + +static void GMULT(byte *x, byte m[256][AES_BLOCK_SIZE]) +{ + int i, j; + byte Z[AES_BLOCK_SIZE]; + byte a; + + XMEMSET(Z, 0, sizeof(Z)); + + for (i = 15; i > 0; i--) { + xorbuf(Z, m[x[i]], AES_BLOCK_SIZE); + a = Z[15]; + + for (j = 15; j > 0; j--) { + Z[j] = Z[j-1]; + } + + Z[0] = R[a][0]; + Z[1] ^= R[a][1]; + } + xorbuf(Z, m[x[0]], AES_BLOCK_SIZE); + + XMEMCPY(x, Z, AES_BLOCK_SIZE); +} + + +static void GHASH(Aes* aes, const byte* a, word32 aSz, + const byte* c, word32 cSz, byte* s, word32 sSz) +{ + byte x[AES_BLOCK_SIZE]; + byte scratch[AES_BLOCK_SIZE]; + word32 blocks, partial; + + XMEMSET(x, 0, AES_BLOCK_SIZE); + + /* Hash in A, the Additional Authentication Data */ + if (aSz != 0 && a != NULL) { + blocks = aSz / AES_BLOCK_SIZE; + partial = aSz % AES_BLOCK_SIZE; + while (blocks--) { + xorbuf(x, a, AES_BLOCK_SIZE); + GMULT(x, aes->M0); + a += AES_BLOCK_SIZE; + } + if (partial != 0) { + XMEMSET(scratch, 0, AES_BLOCK_SIZE); + XMEMCPY(scratch, a, partial); + xorbuf(x, scratch, AES_BLOCK_SIZE); + GMULT(x, aes->M0); + } + } + + /* Hash in C, the Ciphertext */ + if (cSz != 0 && c != NULL) { + blocks = cSz / AES_BLOCK_SIZE; + partial = cSz % AES_BLOCK_SIZE; + while (blocks--) { + xorbuf(x, c, AES_BLOCK_SIZE); + GMULT(x, aes->M0); + c += AES_BLOCK_SIZE; + } + if (partial != 0) { + XMEMSET(scratch, 0, AES_BLOCK_SIZE); + XMEMCPY(scratch, c, partial); + xorbuf(x, scratch, AES_BLOCK_SIZE); + GMULT(x, aes->M0); + } + } + + /* Hash in the lengths of A and C in bits */ + FlattenSzInBits(&scratch[0], aSz); + FlattenSzInBits(&scratch[8], cSz); + xorbuf(x, scratch, AES_BLOCK_SIZE); + GMULT(x, aes->M0); + + /* Copy the result into s. */ + XMEMCPY(s, x, sSz); +} + +/* end GCM_TABLE */ +#elif defined(WORD64_AVAILABLE) && !defined(GCM_WORD32) + +static void GMULT(word64* X, word64* Y) +{ + word64 Z[2] = {0,0}; + word64 V[2] = {X[0], X[1]}; + int i, j; + + for (i = 0; i < 2; i++) + { + word64 y = Y[i]; + for (j = 0; j < 64; j++) + { + if (y & 0x8000000000000000) { + Z[0] ^= V[0]; + Z[1] ^= V[1]; + } + + if (V[1] & 0x0000000000000001) { + V[1] >>= 1; + V[1] |= ((V[0] & 0x0000000000000001) ? 0x8000000000000000 : 0); + V[0] >>= 1; + V[0] ^= 0xE100000000000000; + } + else { + V[1] >>= 1; + V[1] |= ((V[0] & 0x0000000000000001) ? 0x8000000000000000 : 0); + V[0] >>= 1; + } + y <<= 1; + } + } + X[0] = Z[0]; + X[1] = Z[1]; +} + + +static void GHASH(Aes* aes, const byte* a, word32 aSz, + const byte* c, word32 cSz, byte* s, word32 sSz) +{ + word64 x[2] = {0,0}; + word32 blocks, partial; + word64 bigH[2]; + + XMEMCPY(bigH, aes->H, AES_BLOCK_SIZE); + #ifdef LITTLE_ENDIAN_ORDER + ByteReverseWords64(bigH, bigH, AES_BLOCK_SIZE); + #endif + + /* Hash in A, the Additional Authentication Data */ + if (aSz != 0 && a != NULL) { + word64 bigA[2]; + blocks = aSz / AES_BLOCK_SIZE; + partial = aSz % AES_BLOCK_SIZE; + while (blocks--) { + XMEMCPY(bigA, a, AES_BLOCK_SIZE); + #ifdef LITTLE_ENDIAN_ORDER + ByteReverseWords64(bigA, bigA, AES_BLOCK_SIZE); + #endif + x[0] ^= bigA[0]; + x[1] ^= bigA[1]; + GMULT(x, bigH); + a += AES_BLOCK_SIZE; + } + if (partial != 0) { + XMEMSET(bigA, 0, AES_BLOCK_SIZE); + XMEMCPY(bigA, a, partial); + #ifdef LITTLE_ENDIAN_ORDER + ByteReverseWords64(bigA, bigA, AES_BLOCK_SIZE); + #endif + x[0] ^= bigA[0]; + x[1] ^= bigA[1]; + GMULT(x, bigH); + } + } + + /* Hash in C, the Ciphertext */ + if (cSz != 0 && c != NULL) { + word64 bigC[2]; + blocks = cSz / AES_BLOCK_SIZE; + partial = cSz % AES_BLOCK_SIZE; + while (blocks--) { + XMEMCPY(bigC, c, AES_BLOCK_SIZE); + #ifdef LITTLE_ENDIAN_ORDER + ByteReverseWords64(bigC, bigC, AES_BLOCK_SIZE); + #endif + x[0] ^= bigC[0]; + x[1] ^= bigC[1]; + GMULT(x, bigH); + c += AES_BLOCK_SIZE; + } + if (partial != 0) { + XMEMSET(bigC, 0, AES_BLOCK_SIZE); + XMEMCPY(bigC, c, partial); + #ifdef LITTLE_ENDIAN_ORDER + ByteReverseWords64(bigC, bigC, AES_BLOCK_SIZE); + #endif + x[0] ^= bigC[0]; + x[1] ^= bigC[1]; + GMULT(x, bigH); + } + } + + /* Hash in the lengths in bits of A and C */ + { + word64 len[2] = {aSz, cSz}; + + /* Lengths are in bytes. Convert to bits. */ + len[0] *= 8; + len[1] *= 8; + + x[0] ^= len[0]; + x[1] ^= len[1]; + GMULT(x, bigH); + } + #ifdef LITTLE_ENDIAN_ORDER + ByteReverseWords64(x, x, AES_BLOCK_SIZE); + #endif + XMEMCPY(s, x, sSz); +} + +/* end defined(WORD64_AVAILABLE) && !defined(GCM_WORD32) */ +#else /* GCM_WORD32 */ + +static void GMULT(word32* X, word32* Y) +{ + word32 Z[4] = {0,0,0,0}; + word32 V[4] = {X[0], X[1], X[2], X[3]}; + int i, j; + + for (i = 0; i < 4; i++) + { + word32 y = Y[i]; + for (j = 0; j < 32; j++) + { + if (y & 0x80000000) { + Z[0] ^= V[0]; + Z[1] ^= V[1]; + Z[2] ^= V[2]; + Z[3] ^= V[3]; + } + + if (V[3] & 0x00000001) { + V[3] >>= 1; + V[3] |= ((V[2] & 0x00000001) ? 0x80000000 : 0); + V[2] >>= 1; + V[2] |= ((V[1] & 0x00000001) ? 0x80000000 : 0); + V[1] >>= 1; + V[1] |= ((V[0] & 0x00000001) ? 0x80000000 : 0); + V[0] >>= 1; + V[0] ^= 0xE1000000; + } else { + V[3] >>= 1; + V[3] |= ((V[2] & 0x00000001) ? 0x80000000 : 0); + V[2] >>= 1; + V[2] |= ((V[1] & 0x00000001) ? 0x80000000 : 0); + V[1] >>= 1; + V[1] |= ((V[0] & 0x00000001) ? 0x80000000 : 0); + V[0] >>= 1; + } + y <<= 1; + } + } + X[0] = Z[0]; + X[1] = Z[1]; + X[2] = Z[2]; + X[3] = Z[3]; +} + + +static void GHASH(Aes* aes, const byte* a, word32 aSz, + const byte* c, word32 cSz, byte* s, word32 sSz) +{ + word32 x[4] = {0,0,0,0}; + word32 blocks, partial; + word32 bigH[4]; + + XMEMCPY(bigH, aes->H, AES_BLOCK_SIZE); + #ifdef LITTLE_ENDIAN_ORDER + ByteReverseWords(bigH, bigH, AES_BLOCK_SIZE); + #endif + + /* Hash in A, the Additional Authentication Data */ + if (aSz != 0 && a != NULL) { + word32 bigA[4]; + blocks = aSz / AES_BLOCK_SIZE; + partial = aSz % AES_BLOCK_SIZE; + while (blocks--) { + XMEMCPY(bigA, a, AES_BLOCK_SIZE); + #ifdef LITTLE_ENDIAN_ORDER + ByteReverseWords(bigA, bigA, AES_BLOCK_SIZE); + #endif + x[0] ^= bigA[0]; + x[1] ^= bigA[1]; + x[2] ^= bigA[2]; + x[3] ^= bigA[3]; + GMULT(x, bigH); + a += AES_BLOCK_SIZE; + } + if (partial != 0) { + XMEMSET(bigA, 0, AES_BLOCK_SIZE); + XMEMCPY(bigA, a, partial); + #ifdef LITTLE_ENDIAN_ORDER + ByteReverseWords(bigA, bigA, AES_BLOCK_SIZE); + #endif + x[0] ^= bigA[0]; + x[1] ^= bigA[1]; + x[2] ^= bigA[2]; + x[3] ^= bigA[3]; + GMULT(x, bigH); + } + } + + /* Hash in C, the Ciphertext */ + if (cSz != 0 && c != NULL) { + word32 bigC[4]; + blocks = cSz / AES_BLOCK_SIZE; + partial = cSz % AES_BLOCK_SIZE; + while (blocks--) { + XMEMCPY(bigC, c, AES_BLOCK_SIZE); + #ifdef LITTLE_ENDIAN_ORDER + ByteReverseWords(bigC, bigC, AES_BLOCK_SIZE); + #endif + x[0] ^= bigC[0]; + x[1] ^= bigC[1]; + x[2] ^= bigC[2]; + x[3] ^= bigC[3]; + GMULT(x, bigH); + c += AES_BLOCK_SIZE; + } + if (partial != 0) { + XMEMSET(bigC, 0, AES_BLOCK_SIZE); + XMEMCPY(bigC, c, partial); + #ifdef LITTLE_ENDIAN_ORDER + ByteReverseWords(bigC, bigC, AES_BLOCK_SIZE); + #endif + x[0] ^= bigC[0]; + x[1] ^= bigC[1]; + x[2] ^= bigC[2]; + x[3] ^= bigC[3]; + GMULT(x, bigH); + } + } + + /* Hash in the lengths in bits of A and C */ + { + word32 len[4]; + + /* Lengths are in bytes. Convert to bits. */ + len[0] = (aSz >> (8*sizeof(aSz) - 3)); + len[1] = aSz << 3; + len[2] = (cSz >> (8*sizeof(cSz) - 3)); + len[3] = cSz << 3; + + x[0] ^= len[0]; + x[1] ^= len[1]; + x[2] ^= len[2]; + x[3] ^= len[3]; + GMULT(x, bigH); + } + #ifdef LITTLE_ENDIAN_ORDER + ByteReverseWords(x, x, AES_BLOCK_SIZE); + #endif + XMEMCPY(s, x, sSz); +} + +#endif /* end GCM_WORD32 */ + void AesGcmEncrypt(Aes* aes, byte* out, const byte* in, word32 sz, byte* authTag, word32 authTagSz, @@ -1549,40 +2013,35 @@ void AesGcmEncrypt(Aes* aes, byte* out, const byte* in, word32 sz, word32 partial = sz % AES_BLOCK_SIZE; const byte* p = in; byte* c = out; - byte h[AES_BLOCK_SIZE]; byte ctr[AES_BLOCK_SIZE]; + byte scratch[AES_BLOCK_SIZE]; CYASSL_ENTER("AesGcmEncrypt"); - /* Set up the H block by encrypting an array of zeroes with the key. */ - XMEMSET(ctr, 0, AES_BLOCK_SIZE); - AesEncrypt(aes, ctr, h); - /* Initialize the counter with the MS 96 bits of IV, and the counter * portion set to "1". */ - XMEMCPY(ctr, aes->reg, AES_BLOCK_SIZE - 4); + XMEMCPY(ctr, aes->reg, AES_BLOCK_SIZE); InitGcmCounter(ctr); while (blocks--) { IncrementGcmCounter(ctr); - AesEncrypt(aes, ctr, c); - xorbuf(c, p, AES_BLOCK_SIZE); + AesEncrypt(aes, ctr, scratch); + xorbuf(scratch, p, AES_BLOCK_SIZE); + XMEMCPY(c, scratch, AES_BLOCK_SIZE); p += AES_BLOCK_SIZE; c += AES_BLOCK_SIZE; } if (partial != 0) { - byte cPartial[AES_BLOCK_SIZE]; - IncrementGcmCounter(ctr); - AesEncrypt(aes, ctr, cPartial); - XMEMCPY(c, cPartial, partial); - xorbuf(c, p, partial); + AesEncrypt(aes, ctr, scratch); + xorbuf(scratch, p, partial); + XMEMCPY(c, scratch, partial); } - GHASH(h, authIn, authInSz, out, sz, authTag, authTagSz); + GHASH(aes, authIn, authInSz, out, sz, authTag, authTagSz); InitGcmCounter(ctr); - AesEncrypt(aes, ctr, h); - xorbuf(authTag, h, authTagSz); + AesEncrypt(aes, ctr, scratch); + xorbuf(authTag, scratch, authTagSz); } @@ -1594,18 +2053,14 @@ int AesGcmDecrypt(Aes* aes, byte* out, const byte* in, word32 sz, word32 partial = sz % AES_BLOCK_SIZE; const byte* c = in; byte* p = out; - byte h[AES_BLOCK_SIZE]; byte ctr[AES_BLOCK_SIZE]; + byte scratch[AES_BLOCK_SIZE]; CYASSL_ENTER("AesGcmDecrypt"); - /* Set up the H block by encrypting an array of zeroes with the key. */ - XMEMSET(ctr, 0, AES_BLOCK_SIZE); - AesEncrypt(aes, ctr, h); - /* Initialize the counter with the MS 96 bits of IV, and the counter * portion set to "1". */ - XMEMCPY(ctr, aes->reg, AES_BLOCK_SIZE - 4); + XMEMCPY(ctr, aes->reg, AES_BLOCK_SIZE); InitGcmCounter(ctr); /* Calculate the authTag again using the received auth data and the @@ -1614,7 +2069,7 @@ int AesGcmDecrypt(Aes* aes, byte* out, const byte* in, word32 sz, byte Tprime[AES_BLOCK_SIZE]; byte EKY0[AES_BLOCK_SIZE]; - GHASH(h, authIn, authInSz, in, sz, Tprime, sizeof(Tprime)); + GHASH(aes, authIn, authInSz, in, sz, Tprime, sizeof(Tprime)); AesEncrypt(aes, ctr, EKY0); xorbuf(Tprime, EKY0, sizeof(Tprime)); if (XMEMCMP(authTag, Tprime, authTagSz) != 0) { @@ -1624,19 +2079,18 @@ int AesGcmDecrypt(Aes* aes, byte* out, const byte* in, word32 sz, while (blocks--) { IncrementGcmCounter(ctr); - AesEncrypt(aes, ctr, p); - xorbuf(p, c, AES_BLOCK_SIZE); + AesEncrypt(aes, ctr, scratch); + xorbuf(scratch, c, AES_BLOCK_SIZE); + XMEMCPY(p, scratch, AES_BLOCK_SIZE); p += AES_BLOCK_SIZE; c += AES_BLOCK_SIZE; } if (partial != 0) { - byte pPartial[AES_BLOCK_SIZE]; - IncrementGcmCounter(ctr); - AesEncrypt(aes, ctr, pPartial); - XMEMCPY(p, pPartial, partial); - xorbuf(p, c, partial); + AesEncrypt(aes, ctr, scratch); + xorbuf(scratch, c, partial); + XMEMCPY(p, scratch, partial); } return 0; diff --git a/ctaocrypt/src/hmac.c b/ctaocrypt/src/hmac.c index 1f777ab5b..880581e8c 100644 --- a/ctaocrypt/src/hmac.c +++ b/ctaocrypt/src/hmac.c @@ -34,7 +34,7 @@ static int InitHmac(Hmac* hmac, int type) hmac->innerHashKeyed = 0; hmac->macType = (byte)type; - if (!(type == MD5 || type == SHA || type == SHA256)) + if (!(type == MD5 || type == SHA || type == SHA256 || type == SHA384)) return BAD_FUNC_ARG; if (type == MD5) @@ -45,6 +45,10 @@ static int InitHmac(Hmac* hmac, int type) else if (type == SHA256) InitSha256(&hmac->hash.sha256); #endif +#ifdef CYASSL_SHA384 + else if (type == SHA384) + InitSha384(&hmac->hash.sha384); +#endif return 0; } @@ -54,34 +58,60 @@ void HmacSetKey(Hmac* hmac, int type, const byte* key, word32 length) { byte* ip = (byte*) hmac->ipad; byte* op = (byte*) hmac->opad; - word32 i; + word32 i, hmac_block_size = MD5_BLOCK_SIZE; InitHmac(hmac, type); - if (length <= HMAC_BLOCK_SIZE) - XMEMCPY(ip, key, length); - else { - if (hmac->macType == MD5) { + if (hmac->macType == MD5) { + if (length <= MD5_BLOCK_SIZE) { + XMEMCPY(ip, key, length); + } + else { Md5Update(&hmac->hash.md5, key, length); Md5Final(&hmac->hash.md5, ip); length = MD5_DIGEST_SIZE; } - else if (hmac->macType == SHA) { + } + else if (hmac->macType == SHA) { + hmac_block_size = SHA_BLOCK_SIZE; + if (length <= SHA_BLOCK_SIZE) { + XMEMCPY(ip, key, length); + } + else { ShaUpdate(&hmac->hash.sha, key, length); ShaFinal(&hmac->hash.sha, ip); length = SHA_DIGEST_SIZE; } + } #ifndef NO_SHA256 - else if (hmac->macType == SHA256) { + else if (hmac->macType == SHA256) { + hmac_block_size = SHA256_BLOCK_SIZE; + if (length <= SHA256_BLOCK_SIZE) { + XMEMCPY(ip, key, length); + } + else { Sha256Update(&hmac->hash.sha256, key, length); Sha256Final(&hmac->hash.sha256, ip); length = SHA256_DIGEST_SIZE; } -#endif } - XMEMSET(ip + length, 0, HMAC_BLOCK_SIZE - length); +#endif +#ifdef CYASSL_SHA384 + else if (hmac->macType == SHA384) { + hmac_block_size = SHA384_BLOCK_SIZE; + if (length <= SHA384_BLOCK_SIZE) { + XMEMCPY(ip, key, length); + } + else { + Sha384Update(&hmac->hash.sha384, key, length); + Sha384Final(&hmac->hash.sha384, ip); + length = SHA384_DIGEST_SIZE; + } + } +#endif + XMEMSET(ip + length, 0, hmac_block_size - length); - for(i = 0; i < HMAC_BLOCK_SIZE; i++) { + for(i = 0; i < hmac_block_size; i++) { op[i] = ip[i] ^ OPAD; ip[i] ^= IPAD; } @@ -91,12 +121,16 @@ void HmacSetKey(Hmac* hmac, int type, const byte* key, word32 length) static void HmacKeyInnerHash(Hmac* hmac) { if (hmac->macType == MD5) - Md5Update(&hmac->hash.md5, (byte*) hmac->ipad, HMAC_BLOCK_SIZE); + Md5Update(&hmac->hash.md5, (byte*) hmac->ipad, MD5_BLOCK_SIZE); else if (hmac->macType == SHA) - ShaUpdate(&hmac->hash.sha, (byte*) hmac->ipad, HMAC_BLOCK_SIZE); + ShaUpdate(&hmac->hash.sha, (byte*) hmac->ipad, SHA_BLOCK_SIZE); #ifndef NO_SHA256 else if (hmac->macType == SHA256) - Sha256Update(&hmac->hash.sha256, (byte*) hmac->ipad, HMAC_BLOCK_SIZE); + Sha256Update(&hmac->hash.sha256, (byte*) hmac->ipad, SHA256_BLOCK_SIZE); +#endif +#ifdef CYASSL_SHA384 + else if (hmac->macType == SHA384) + Sha384Update(&hmac->hash.sha384, (byte*) hmac->ipad, SHA384_BLOCK_SIZE); #endif hmac->innerHashKeyed = 1; @@ -116,6 +150,10 @@ void HmacUpdate(Hmac* hmac, const byte* msg, word32 length) else if (hmac->macType == SHA256) Sha256Update(&hmac->hash.sha256, msg, length); #endif +#ifdef CYASSL_SHA384 + else if (hmac->macType == SHA384) + Sha384Update(&hmac->hash.sha384, msg, length); +#endif } @@ -128,30 +166,41 @@ void HmacFinal(Hmac* hmac, byte* hash) if (hmac->macType == MD5) { Md5Final(&hmac->hash.md5, (byte*) hmac->innerHash); - Md5Update(&hmac->hash.md5, (byte*) hmac->opad, HMAC_BLOCK_SIZE); + Md5Update(&hmac->hash.md5, (byte*) hmac->opad, MD5_BLOCK_SIZE); Md5Update(&hmac->hash.md5, (byte*) hmac->innerHash, MD5_DIGEST_SIZE); Md5Final(&hmac->hash.md5, hash); } - else if (hmac->macType ==SHA) { + else if (hmac->macType == SHA) { ShaFinal(&hmac->hash.sha, (byte*) hmac->innerHash); - ShaUpdate(&hmac->hash.sha, (byte*) hmac->opad, HMAC_BLOCK_SIZE); + ShaUpdate(&hmac->hash.sha, (byte*) hmac->opad, SHA_BLOCK_SIZE); ShaUpdate(&hmac->hash.sha, (byte*) hmac->innerHash, SHA_DIGEST_SIZE); ShaFinal(&hmac->hash.sha, hash); } #ifndef NO_SHA256 - else if (hmac->macType ==SHA256) { + else if (hmac->macType == SHA256) { Sha256Final(&hmac->hash.sha256, (byte*) hmac->innerHash); - Sha256Update(&hmac->hash.sha256, (byte*) hmac->opad, HMAC_BLOCK_SIZE); + Sha256Update(&hmac->hash.sha256, (byte*) hmac->opad, SHA256_BLOCK_SIZE); Sha256Update(&hmac->hash.sha256, (byte*) hmac->innerHash, SHA256_DIGEST_SIZE); Sha256Final(&hmac->hash.sha256, hash); } #endif +#ifdef CYASSL_SHA384 + else if (hmac->macType == SHA384) { + Sha384Final(&hmac->hash.sha384, (byte*) hmac->innerHash); + + Sha384Update(&hmac->hash.sha384, (byte*) hmac->opad, SHA384_BLOCK_SIZE); + Sha384Update(&hmac->hash.sha384, (byte*) hmac->innerHash, + SHA384_DIGEST_SIZE); + + Sha384Final(&hmac->hash.sha384, hash); + } +#endif hmac->innerHashKeyed = 0; } diff --git a/ctaocrypt/test/test.c b/ctaocrypt/test/test.c index 18a976cf6..8dcb5cd4b 100644 --- a/ctaocrypt/test/test.c +++ b/ctaocrypt/test/test.c @@ -99,6 +99,7 @@ int rabbit_test(); int des_test(); int des3_test(); int aes_test(); +int aesgcm_test(); int rsa_test(); int dh_test(); int dsa_test(); @@ -233,6 +234,13 @@ void ctaocrypt_test(void* args) err_sys("AES test failed!\n", ret); else printf( "AES test passed!\n"); + +#ifdef HAVE_AESGCM + if ( (ret = aesgcm_test()) ) + err_sys("AES-GCM test failed!\n", ret); + else + printf( "AES-GCM test passed!\n"); +#endif #endif if ( (ret = random_test()) ) @@ -1144,93 +1152,101 @@ int aes_test() } #endif /* CYASSL_AES_COUNTER */ + return 0; +} + #ifdef HAVE_AESGCM +int aesgcm_test() +{ + Aes enc; + + /* + * This is Test Case 16 from the document Galois/ + * Counter Mode of Operation (GCM) by McGrew and + * Viega. + */ + const byte k[] = { - /* - * This is Test Case 16 from the document Galois/ - * Counter Mode of Operation (GCM) by McGrew and - * Viega. - */ - const byte k[] = - { - 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, - 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, - 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, - 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 - }; + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 + }; - const byte iv[] = - { - 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, - 0xde, 0xca, 0xf8, 0x88, 0x00, 0x00, 0x00, 0x00 - }; - - const byte p[] = - { - 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, - 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, - 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, - 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, - 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, - 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, - 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, - 0xba, 0x63, 0x7b, 0x39 - }; - - const byte a[] = - { - 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, - 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, - 0xab, 0xad, 0xda, 0xd2 - }; - - const byte c[] = - { - 0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07, - 0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d, - 0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9, - 0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa, - 0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d, - 0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38, - 0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a, - 0xbc, 0xc9, 0xf6, 0x62 - }; + const byte iv[] = + { + 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88, 0x00, 0x00, 0x00, 0x00 + }; + + const byte p[] = + { + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39 + }; + + const byte a[] = + { + 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, + 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, + 0xab, 0xad, 0xda, 0xd2 + }; + + const byte c[] = + { + 0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07, + 0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d, + 0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9, + 0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa, + 0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d, + 0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38, + 0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a, + 0xbc, 0xc9, 0xf6, 0x62 + }; - const byte t[] = - { - 0x76, 0xfc, 0x6e, 0xce, 0x0f, 0x4e, 0x17, 0x68, - 0xcd, 0xdf, 0x88, 0x53, 0xbb, 0x2d, 0x55, 0x1b - }; + const byte t[] = + { + 0x76, 0xfc, 0x6e, 0xce, 0x0f, 0x4e, 0x17, 0x68, + 0xcd, 0xdf, 0x88, 0x53, 0xbb, 0x2d, 0x55, 0x1b + }; - byte t2[16]; - byte p2[60]; - byte c2[60]; + byte t2[16]; + byte p2[60]; + byte c2[60]; - int result; + int result; - memset(t2, 0, 16); - memset(c2, 0, 60); - memset(p2, 0, 60); + memset(t2, 0, 16); + memset(c2, 0, 60); + memset(p2, 0, 60); - AesSetKey(&enc, k, sizeof(k), iv, AES_ENCRYPTION); - /* AES-GCM encrypt and decrypt both use AES encrypt internally */ - AesGcmEncrypt(&enc, c2, p, sizeof(c2), t2, sizeof(t2), a, sizeof(a)); - if (memcmp(c, c2, sizeof(c2))) - return -68; - if (memcmp(t, t2, sizeof(t2))) - return -69; + AesGcmSetKey(&enc, k, sizeof(k)); + AesSetIV(&enc, iv); + /* AES-GCM encrypt and decrypt both use AES encrypt internally */ + AesGcmEncrypt(&enc, c2, p, sizeof(c2), t2, sizeof(t2), a, sizeof(a)); + if (memcmp(c, c2, sizeof(c2))) + return -68; + if (memcmp(t, t2, sizeof(t2))) + return -69; - result = AesGcmDecrypt(&enc, - p2, c2, sizeof(p2), t2, sizeof(t2), a, sizeof(a)); - if (result != 0) - return -70; - if (memcmp(p, p2, sizeof(p2))) - return -71; - } -#endif /* HAVE_AESGCM */ + result = AesGcmDecrypt(&enc, + p2, c2, sizeof(p2), t2, sizeof(t2), a, sizeof(a)); + if (result != 0) + return -70; + if (memcmp(p, p2, sizeof(p2))) + return -71; return 0; } +#endif /* HAVE_AESGCM */ + + #endif /* NO_AES */ diff --git a/cyassl/ctaocrypt/aes.h b/cyassl/ctaocrypt/aes.h index 73e84b499..86875d4f1 100644 --- a/cyassl/ctaocrypt/aes.h +++ b/cyassl/ctaocrypt/aes.h @@ -68,6 +68,14 @@ typedef struct Aes { ALIGN16 word32 reg[AES_BLOCK_SIZE / sizeof(word32)]; /* for CBC mode */ ALIGN16 word32 tmp[AES_BLOCK_SIZE / sizeof(word32)]; /* same */ + +#ifdef HAVE_AESGCM + ALIGN16 byte H[AES_BLOCK_SIZE]; +#ifdef GCM_TABLE + /* key-based fast multiplication table. */ + ALIGN16 byte M0[256][AES_BLOCK_SIZE]; +#endif /* GCM_TABLE */ +#endif /* HAVE_AESGCM */ } Aes; @@ -81,6 +89,7 @@ CYASSL_API void AesEncryptDirect(Aes* aes, byte* out, const byte* in); CYASSL_API void AesDecryptDirect(Aes* aes, byte* out, const byte* in); #ifdef HAVE_AESGCM +CYASSL_API void AesGcmSetKey(Aes* aes, const byte* key, word32 len); CYASSL_API void AesGcmEncrypt(Aes* aes, byte* out, const byte* in, word32 sz, byte* authTag, word32 authTagSz, const byte* authIn, word32 authInSz); diff --git a/cyassl/ctaocrypt/hmac.h b/cyassl/ctaocrypt/hmac.h index 6f022748b..ee11669d0 100644 --- a/cyassl/ctaocrypt/hmac.h +++ b/cyassl/ctaocrypt/hmac.h @@ -32,6 +32,10 @@ #include #endif +#ifdef CYASSL_SHA384 + #include +#endif + #ifdef __cplusplus extern "C" { #endif @@ -40,13 +44,19 @@ enum { IPAD = 0x36, OPAD = 0x5C, -#ifndef NO_SHA256 +#if defined(CYASSL_SHA384) + INNER_HASH_SIZE = SHA384_DIGEST_SIZE, + HMAC_BLOCK_SIZE = SHA384_BLOCK_SIZE +#elif !defined(NO_SHA256) INNER_HASH_SIZE = SHA256_DIGEST_SIZE, + HMAC_BLOCK_SIZE = SHA256_BLOCK_SIZE, + SHA384 = 5 #else INNER_HASH_SIZE = SHA_DIGEST_SIZE, + HMAC_BLOCK_SIZE = SHA_BLOCK_SIZE, SHA256 = 2, /* hash type unique */ + SHA384 = 5 #endif - HMAC_BLOCK_SIZE = MD5_BLOCK_SIZE }; @@ -57,6 +67,9 @@ typedef union { #ifndef NO_SHA256 Sha256 sha256; #endif + #ifdef CYASSL_SHA384 + Sha384 sha384; + #endif } Hash; /* Hmac digest */ diff --git a/cyassl/internal.h b/cyassl/internal.h index 9e7dfa928..c843a081c 100644 --- a/cyassl/internal.h +++ b/cyassl/internal.h @@ -44,6 +44,9 @@ #ifdef HAVE_OCSP #include #endif +#ifdef CYASSL_SHA512 + #include +#endif #ifdef CYASSL_CALLBACKS #include @@ -147,6 +150,10 @@ void c32to24(word32 in, word24 out); #define BUILD_TLS_RSA_WITH_AES_128_CBC_SHA256 #define BUILD_TLS_RSA_WITH_AES_256_CBC_SHA256 #endif + #if defined (HAVE_AESGCM) + #define BUILD_TLS_RSA_WITH_AES_128_GCM_SHA256 + #define BUILD_TLS_RSA_WITH_AES_256_GCM_SHA384 + #endif #endif #if !defined(NO_HC128) && !defined(NO_TLS) @@ -164,6 +171,10 @@ void c32to24(word32 in, word24 out); #if !defined (NO_SHA256) #define BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 #define BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + #if defined (HAVE_AESGCM) + #define BUILD_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + #define BUILD_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + #endif #endif #endif @@ -178,6 +189,18 @@ void c32to24(word32 in, word24 out); #define BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA #define BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA #define BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA + + #if defined (HAVE_AESGCM) + #define BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + #define BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + #define BUILD_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + #define BUILD_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + + #define BUILD_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + #define BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + #define BUILD_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + #define BUILD_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + #endif #endif #if !defined(NO_RC4) #define BUILD_TLS_ECDHE_RSA_WITH_RC4_128_SHA @@ -210,6 +233,11 @@ void c32to24(word32 in, word24 out); #define BUILD_AES #endif +#if defined(BUILD_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256) || \ + defined(BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) + #define BUILD_AESGCM +#endif + #if defined(BUILD_TLS_RSA_WITH_HC_128_CBC_SHA) || \ defined(BUILD_TLS_RSA_WITH_HC_128_CBC_MD5) #define BUILD_HC128 @@ -275,7 +303,23 @@ enum { TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = 0x6b, TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = 0x67, TLS_RSA_WITH_AES_256_CBC_SHA256 = 0x3d, - TLS_RSA_WITH_AES_128_CBC_SHA256 = 0x3c + TLS_RSA_WITH_AES_128_CBC_SHA256 = 0x3c, + + /* AES-GCM */ + TLS_RSA_WITH_AES_128_GCM_SHA256 = 0x9c, + TLS_RSA_WITH_AES_256_GCM_SHA384 = 0x9d, + TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = 0x9e, + TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 = 0x9f, + + /* ECC AES-GCM, first byte is 0xC0 (ECC_BYTE) */ + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = 0x2b, + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = 0x2c, + TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 = 0x2d, + TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 = 0x2e, + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 0x2f, + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = 0x30, + TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 = 0x31, + TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 = 0x32 }; @@ -297,6 +341,7 @@ enum Misc { TLSv1_2_MINOR = 3, /* TLSv1_2 minor version number */ NO_COMPRESSION = 0, ZLIB_COMPRESSION = 221, /* CyaSSL zlib compression */ + HELLO_EXT_SIG_ALGO = 13, /* ID for the sig_algo hello extension */ SECRET_LEN = 48, /* pre RSA and all master */ ENCRYPT_LEN = 512, /* allow 4096 bit static buffer */ SIZEOF_SENDER = 4, /* clnt or srvr */ @@ -338,6 +383,10 @@ enum Misc { CERT_HEADER_SZ = 3, /* always 3 bytes */ REQ_HEADER_SZ = 2, /* cert request header sz */ HINT_LEN_SZ = 2, /* length of hint size field */ + HELLO_EXT_SZ = 14, /* total length of the lazy hello extensions */ + HELLO_EXT_LEN = 12, /* length of the lazy hello extensions */ + HELLO_EXT_SIGALGO_SZ = 8, /* length of signature algo extension */ + HELLO_EXT_SIGALGO_LEN = 6, /* number of items in the signature algo list */ DTLS_HANDSHAKE_HEADER_SZ = 12, /* normal + seq(2) + offset(3) + length(3) */ DTLS_RECORD_HEADER_SZ = 13, /* normal + epoch(2) + seq_num(6) */ @@ -361,8 +410,19 @@ enum Misc { AES_256_KEY_SIZE = 32, /* for 256 bit */ AES_192_KEY_SIZE = 24, /* for 192 bit */ AES_IV_SIZE = 16, /* always block size */ + AES_GCM_IMP_IV_SZ = 4, /* Implicit part of IV */ + AES_GCM_EXP_IV_SZ = 8, /* Explicit part of IV */ + AES_GCM_CTR_IV_SZ = 4, /* Counter part of IV */ AES_128_KEY_SIZE = 16, /* for 128 bit */ + AEAD_SEQ_OFFSET = 4, /* Auth Data: Sequence number */ + AEAD_TYPE_OFFSET = 8, /* Auth Data: Type */ + AEAD_VMAJ_OFFSET = 9, /* Auth Data: Major Version */ + AEAD_VMIN_OFFSET = 10, /* Auth Data: Minor Version */ + AEAD_LEN_OFFSET = 11, /* Auth Data: Length */ + AEAD_AUTH_TAG_SZ = 16, /* Size of the authentication tag */ + AEAD_AUTH_DATA_SZ = 13, /* Size of the data to authenticate */ + HC_128_KEY_SIZE = 16, /* 128 bits */ HC_128_IV_SIZE = 16, /* also 128 bits */ @@ -765,7 +825,7 @@ int AlreadySigner(CYASSL_CERT_MANAGER* cm, byte* hash); /* All cipher suite related info */ typedef struct CipherSpecs { byte bulk_cipher_algorithm; - byte cipher_type; /* block or stream */ + byte cipher_type; /* block, stream, or aead */ byte mac_algorithm; byte kea; /* key exchange algo */ byte sig_algo; @@ -789,6 +849,7 @@ enum BulkCipherAlgorithm { des40, idea, aes, + aes_gcm, hc128, /* CyaSSL extensions */ rabbit }; @@ -859,7 +920,7 @@ enum ClientCertificateType { }; -enum CipherType { stream, block }; +enum CipherType { stream, block, aead }; /* keys and secrets */ @@ -1129,6 +1190,9 @@ struct CYASSL { Sha hashSha; /* sha hash of handshake msgs */ #ifndef NO_SHA256 Sha256 hashSha256; /* sha256 hash of handshake msgs */ +#endif +#ifdef CYASSL_SHA384 + Sha384 hashSha384; /* sha384 hash of handshake msgs */ #endif Hashes verifyHashes; Hashes certHashes; /* for cert verify */ diff --git a/examples/echoclient/echoclient.c b/examples/echoclient/echoclient.c index a800555ec..d33d2da86 100644 --- a/examples/echoclient/echoclient.c +++ b/examples/echoclient/echoclient.c @@ -69,7 +69,7 @@ void echoclient_test(void* args) #if defined(CYASSL_DTLS) method = DTLSv1_client_method(); #elif !defined(NO_TLS) - method = TLSv1_client_method(); + method = CyaSSLv23_client_method(); #else method = SSLv3_client_method(); #endif @@ -105,7 +105,7 @@ void echoclient_test(void* args) while (fgets(send, sizeof(send), fin)) { - sendSz = (int)strlen(send) + 1; + sendSz = (int)strlen(send); if (SSL_write(ssl, send, sendSz) != sendSz) err_sys("SSL_write failed"); @@ -115,7 +115,7 @@ void echoclient_test(void* args) break; } - if (strncmp(send, "break", 4) == 0) { + if (strncmp(send, "break", 5) == 0) { fputs("sending server session close: break!\n", fout); break; } @@ -123,6 +123,7 @@ void echoclient_test(void* args) while (sendSz) { int got; if ( (got = SSL_read(ssl, reply, sizeof(reply))) > 0) { + reply[got] = 0; fputs(reply, fout); sendSz -= got; } @@ -165,6 +166,9 @@ void echoclient_test(void* args) args.argv = argv; CyaSSL_Init(); +#ifdef DEBUG_CYASSL + CyaSSL_Debugging_ON(); +#endif if (CurrentDir("echoclient") || CurrentDir("build")) ChangeDirBack(2); echoclient_test(&args); diff --git a/src/internal.c b/src/internal.c index 6e106d485..59637670a 100644 --- a/src/internal.c +++ b/src/internal.c @@ -55,7 +55,7 @@ #ifndef NO_CYASSL_CLIENT static int DoHelloVerifyRequest(CYASSL* ssl, const byte* input, word32*); - static int DoServerHello(CYASSL* ssl, const byte* input, word32*); + static int DoServerHello(CYASSL* ssl, const byte* input, word32*, word32); static int DoCertificateRequest(CYASSL* ssl, const byte* input, word32*); static int DoServerKeyExchange(CYASSL* ssl, const byte* input, word32*); #endif @@ -239,7 +239,8 @@ static INLINE void ato32(const byte* c, word32* u32) ssl->c_stream.zfree = (free_func)myFree; ssl->c_stream.opaque = (voidpf)ssl->heap; - if (deflateInit(&ssl->c_stream, 8) != Z_OK) return ZLIB_INIT_ERROR; + if (deflateInit(&ssl->c_stream, Z_DEFAULT_COMPRESSION) != Z_OK) + return ZLIB_INIT_ERROR; ssl->didStreamInit = 1; @@ -268,11 +269,6 @@ static INLINE void ato32(const byte* c, word32* u32) int err; int currTotal = ssl->c_stream.total_out; - /* put size in front of compression */ - c16toa((word16)inSz, out); - out += 2; - outSz -= 2; - ssl->c_stream.next_in = in; ssl->c_stream.avail_in = inSz; ssl->c_stream.next_out = out; @@ -281,7 +277,7 @@ static INLINE void ato32(const byte* c, word32* u32) err = deflate(&ssl->c_stream, Z_SYNC_FLUSH); if (err != Z_OK && err != Z_STREAM_END) return ZLIB_COMPRESS_ERROR; - return ssl->c_stream.total_out - currTotal + sizeof(word16); + return ssl->c_stream.total_out - currTotal; } @@ -290,12 +286,6 @@ static INLINE void ato32(const byte* c, word32* u32) { int err; int currTotal = ssl->d_stream.total_out; - word16 len; - - /* find size in front of compression */ - ato16(in, &len); - in += 2; - inSz -= 2; ssl->d_stream.next_in = in; ssl->d_stream.avail_in = inSz; @@ -498,6 +488,13 @@ void InitSuites(Suites* suites, ProtocolVersion pv, byte haveDH, byte havePSK, } #endif +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + if (tls1_2 && haveECDSA) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384; + } +#endif + #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA if (tls && haveECDSA) { suites->suites[idx++] = ECC_BYTE; @@ -505,6 +502,13 @@ void InitSuites(Suites* suites, ProtocolVersion pv, byte haveDH, byte havePSK, } #endif +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + if (tls1_2 && haveECDSA && haveStaticECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384; + } +#endif + #ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA if (tls && haveECDSA && haveStaticECC) { suites->suites[idx++] = ECC_BYTE; @@ -512,6 +516,13 @@ void InitSuites(Suites* suites, ProtocolVersion pv, byte haveDH, byte havePSK, } #endif +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + if (tls1_2 && haveECDSA) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256; + } +#endif + #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA if (tls && haveECDSA) { suites->suites[idx++] = ECC_BYTE; @@ -519,6 +530,13 @@ void InitSuites(Suites* suites, ProtocolVersion pv, byte haveDH, byte havePSK, } #endif +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + if (tls1_2 && haveECDSA && haveStaticECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256; + } +#endif + #ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA if (tls && haveECDSA && haveStaticECC) { suites->suites[idx++] = ECC_BYTE; @@ -554,6 +572,13 @@ void InitSuites(Suites* suites, ProtocolVersion pv, byte haveDH, byte havePSK, } #endif +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + if (tls1_2 && haveRSA) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384; + } +#endif + #ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA if (tls && haveRSA) { suites->suites[idx++] = ECC_BYTE; @@ -561,6 +586,13 @@ void InitSuites(Suites* suites, ProtocolVersion pv, byte haveDH, byte havePSK, } #endif +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + if (tls1_2 && haveRSA && haveStaticECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384; + } +#endif + #ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA if (tls && haveRSA && haveStaticECC) { suites->suites[idx++] = ECC_BYTE; @@ -568,6 +600,13 @@ void InitSuites(Suites* suites, ProtocolVersion pv, byte haveDH, byte havePSK, } #endif +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + if (tls1_2 && haveRSA) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256; + } +#endif + #ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA if (tls && haveRSA) { suites->suites[idx++] = ECC_BYTE; @@ -575,6 +614,13 @@ void InitSuites(Suites* suites, ProtocolVersion pv, byte haveDH, byte havePSK, } #endif +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + if (tls1_2 && haveRSA && haveStaticECC) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256; + } +#endif + #ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA if (tls && haveRSA && haveStaticECC) { suites->suites[idx++] = ECC_BYTE; @@ -610,6 +656,13 @@ void InitSuites(Suites* suites, ProtocolVersion pv, byte haveDH, byte havePSK, } #endif +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + if (tls1_2 && haveDH && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_256_GCM_SHA384; + } +#endif + #ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 if (tls1_2 && haveDH && haveRSA) { suites->suites[idx++] = 0; @@ -617,6 +670,13 @@ void InitSuites(Suites* suites, ProtocolVersion pv, byte haveDH, byte havePSK, } #endif +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + if (tls1_2 && haveDH && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_128_GCM_SHA256; + } +#endif + #ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 if (tls1_2 && haveDH && haveRSA) { suites->suites[idx++] = 0; @@ -638,6 +698,13 @@ void InitSuites(Suites* suites, ProtocolVersion pv, byte haveDH, byte havePSK, } #endif +#ifdef BUILD_TLS_RSA_WITH_AES_256_GCM_SHA384 + if (tls1_2 && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_RSA_WITH_AES_256_GCM_SHA384; + } +#endif + #ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA256 if (tls1_2 && haveRSA) { suites->suites[idx++] = 0; @@ -645,6 +712,13 @@ void InitSuites(Suites* suites, ProtocolVersion pv, byte haveDH, byte havePSK, } #endif +#ifdef BUILD_TLS_RSA_WITH_AES_128_GCM_SHA256 + if (tls1_2 && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_RSA_WITH_AES_128_GCM_SHA256; + } +#endif + #ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA256 if (tls1_2 && haveRSA) { suites->suites[idx++] = 0; @@ -793,6 +867,9 @@ int InitSSL(CYASSL* ssl, CYASSL_CTX* ctx) InitSha(&ssl->hashSha); #ifndef NO_SHA256 InitSha256(&ssl->hashSha256); +#endif +#ifdef CYASSL_SHA384 + InitSha384(&ssl->hashSha384); #endif InitRsaKey(&ssl->peerRsaKey, ctx->heap); @@ -1096,10 +1173,14 @@ static void HashOutput(CYASSL* ssl, const byte* output, int sz, int ivSz) Md5Update(&ssl->hashMd5, adj, sz); ShaUpdate(&ssl->hashSha, adj, sz); + if (IsAtLeastTLSv1_2(ssl)) { #ifndef NO_SHA256 - if (IsAtLeastTLSv1_2(ssl)) Sha256Update(&ssl->hashSha256, adj, sz); #endif +#ifdef CYASSL_SHA384 + Sha384Update(&ssl->hashSha384, adj, sz); +#endif + } } @@ -1118,10 +1199,14 @@ static void HashInput(CYASSL* ssl, const byte* input, int sz) Md5Update(&ssl->hashMd5, adj, sz); ShaUpdate(&ssl->hashSha, adj, sz); + if (IsAtLeastTLSv1_2(ssl)) { #ifndef NO_SHA256 - if (IsAtLeastTLSv1_2(ssl)) Sha256Update(&ssl->hashSha256, adj, sz); #endif +#ifdef CYASSL_SHA384 + Sha384Update(&ssl->hashSha384, adj, sz); +#endif + } } @@ -1539,10 +1624,21 @@ static void BuildFinished(CYASSL* ssl, Hashes* hashes, const byte* sender) Sha sha = ssl->hashSha; #ifndef NO_SHA256 Sha256 sha256; +#endif +#ifdef CYASSL_SHA384 + Sha384 sha384; +#endif + +#ifndef NO_SHA256 InitSha256(&sha256); if (IsAtLeastTLSv1_2(ssl)) sha256 = ssl->hashSha256; #endif +#ifdef CYASSL_SHA384 + InitSha384(&sha384); + if (IsAtLeastTLSv1_2(ssl)) + sha384 = ssl->hashSha384; +#endif if (ssl->options.tls) BuildTlsFinished(ssl, hashes, sender); @@ -1554,10 +1650,14 @@ static void BuildFinished(CYASSL* ssl, Hashes* hashes, const byte* sender) /* restore */ ssl->hashMd5 = md5; ssl->hashSha = sha; + if (IsAtLeastTLSv1_2(ssl)) { #ifndef NO_SHA256 - if (IsAtLeastTLSv1_2(ssl)) ssl->hashSha256 = sha256; #endif +#ifdef CYASSL_SHA384 + ssl->hashSha384 = sha384; +#endif + } } @@ -1936,23 +2036,28 @@ int DoFinished(CYASSL* ssl, const byte* input, word32* inOutIdx, int sniff) } } - ssl->hmac(ssl, verifyMAC, input + idx - headerSz, macSz, - handshake, 1); - idx += finishedSz; + if (ssl->specs.cipher_type != aead) { + ssl->hmac(ssl, verifyMAC, input + idx - headerSz, macSz, + handshake, 1); + idx += finishedSz; - /* read mac and fill */ - mac = input + idx; - idx += ssl->specs.hash_size; + /* read mac and fill */ + mac = input + idx; + idx += ssl->specs.hash_size; - if (ssl->options.tls1_1 && ssl->specs.cipher_type == block) - padSz -= ssl->specs.block_size; + if (ssl->options.tls1_1 && ssl->specs.cipher_type == block) + padSz -= ssl->specs.block_size; - idx += padSz; + idx += padSz; - /* verify mac */ - if (XMEMCMP(mac, verifyMAC, ssl->specs.hash_size)) { - CYASSL_MSG("Verify finished error on mac"); - return VERIFY_MAC_ERROR; + /* verify mac */ + if (XMEMCMP(mac, verifyMAC, ssl->specs.hash_size)) { + CYASSL_MSG("Verify finished error on mac"); + return VERIFY_MAC_ERROR; + } + } + else { + idx += (finishedSz + AEAD_AUTH_TAG_SZ); } if (ssl->options.side == CLIENT_END) { @@ -2012,7 +2117,7 @@ static int DoHandShakeMsg(CYASSL* ssl, byte* input, word32* inOutIdx, case server_hello: CYASSL_MSG("processing server hello"); - ret = DoServerHello(ssl, input, inOutIdx); + ret = DoServerHello(ssl, input, inOutIdx, size); break; case certificate_request: @@ -2075,6 +2180,15 @@ static int DoHandShakeMsg(CYASSL* ssl, byte* input, word32* inOutIdx, } +static INLINE word32 GetSEQIncrement(CYASSL* ssl, int verify) +{ + if (verify) + return ssl->keys.peer_sequence_number++; + else + return ssl->keys.sequence_number++; +} + + static INLINE void Encrypt(CYASSL* ssl, byte* out, const byte* input, word32 sz) { switch (ssl->specs.bulk_cipher_algorithm) { @@ -2105,6 +2219,50 @@ static INLINE void Encrypt(CYASSL* ssl, byte* out, const byte* input, word32 sz) break; #endif + #ifdef BUILD_AESGCM + case aes_gcm: + { + byte additional[AES_BLOCK_SIZE]; + byte nonce[AES_BLOCK_SIZE]; + + /* use this side's IV */ + if (ssl->options.side == SERVER_END) { + XMEMCPY(nonce, ssl->keys.server_write_IV, + AES_GCM_IMP_IV_SZ); + } + else { + XMEMCPY(nonce, ssl->keys.client_write_IV, + AES_GCM_IMP_IV_SZ); + } + XMEMCPY(nonce + AES_GCM_IMP_IV_SZ, + input, AES_GCM_EXP_IV_SZ); + XMEMSET(nonce + AES_GCM_IMP_IV_SZ + AES_GCM_EXP_IV_SZ, + 0, AES_GCM_CTR_IV_SZ); + AesSetIV(&ssl->encrypt.aes, nonce); + + XMEMSET(additional, 0, AES_BLOCK_SIZE); + + /* sequence number field is 64-bits, we only use 32-bits */ + c32toa(GetSEQIncrement(ssl, 0), + additional + AEAD_SEQ_OFFSET); + + /* Store the type, version. Unfortunately, they are in + * the input buffer ahead of the plaintext. */ + XMEMCPY(additional + AEAD_TYPE_OFFSET, input - 5, 3); + + /* Store the length of the plain text minus the explicit + * IV length minus the authentication tag size. */ + c16toa(sz - AES_GCM_EXP_IV_SZ - AEAD_AUTH_TAG_SZ, + additional + AEAD_LEN_OFFSET); + AesGcmEncrypt(&ssl->encrypt.aes, + out + AES_GCM_EXP_IV_SZ, input + AES_GCM_EXP_IV_SZ, + sz - AES_GCM_EXP_IV_SZ - AEAD_AUTH_TAG_SZ, + out + sz - AEAD_AUTH_TAG_SZ, AEAD_AUTH_TAG_SZ, + additional, AEAD_AUTH_DATA_SZ); + } + break; + #endif + #ifdef HAVE_HC128 case hc128: Hc128_Process(&ssl->encrypt.hc128, out, input, sz); @@ -2123,7 +2281,7 @@ static INLINE void Encrypt(CYASSL* ssl, byte* out, const byte* input, word32 sz) } -static INLINE void Decrypt(CYASSL* ssl, byte* plain, const byte* input, +static INLINE int Decrypt(CYASSL* ssl, byte* plain, const byte* input, word32 sz) { switch (ssl->specs.bulk_cipher_algorithm) { @@ -2145,6 +2303,51 @@ static INLINE void Decrypt(CYASSL* ssl, byte* plain, const byte* input, break; #endif + #ifdef BUILD_AESGCM + case aes_gcm: + { + byte additional[AES_BLOCK_SIZE]; + byte nonce[AES_BLOCK_SIZE]; + + /* use the other side's IV */ + if (ssl->options.side == SERVER_END) { + XMEMCPY(nonce, ssl->keys.client_write_IV, + AES_GCM_IMP_IV_SZ); + } + else { + XMEMCPY(nonce, ssl->keys.server_write_IV, + AES_GCM_IMP_IV_SZ); + } + XMEMCPY(nonce + AES_GCM_IMP_IV_SZ, + input, AES_GCM_EXP_IV_SZ); + XMEMSET(nonce + AES_GCM_IMP_IV_SZ + AES_GCM_EXP_IV_SZ, + 0, AES_GCM_CTR_IV_SZ); + AesSetIV(&ssl->decrypt.aes, nonce); + + XMEMSET(additional, 0, AES_BLOCK_SIZE); + + /* sequence number field is 64-bits, we only use 32-bits */ + c32toa(GetSEQIncrement(ssl, 1), additional + AEAD_SEQ_OFFSET); + + additional[AEAD_TYPE_OFFSET] = ssl->curRL.type; + additional[AEAD_VMAJ_OFFSET] = ssl->curRL.version.major; + additional[AEAD_VMIN_OFFSET] = ssl->curRL.version.minor; + + c16toa(sz - AES_GCM_EXP_IV_SZ - AEAD_AUTH_TAG_SZ, + additional + AEAD_LEN_OFFSET); + if (AesGcmDecrypt(&ssl->decrypt.aes, + plain + AES_GCM_EXP_IV_SZ, + input + AES_GCM_EXP_IV_SZ, + sz - AES_GCM_EXP_IV_SZ - AEAD_AUTH_TAG_SZ, + input + sz - AEAD_AUTH_TAG_SZ, AEAD_AUTH_TAG_SZ, + additional, AEAD_AUTH_DATA_SZ) < 0) { + SendAlert(ssl, alert_fatal, bad_record_mac); + return VERIFY_MAC_ERROR; + } + break; + } + #endif + #ifdef HAVE_HC128 case hc128: Hc128_Process(&ssl->decrypt.hc128, plain, input, sz); @@ -2160,27 +2363,25 @@ static INLINE void Decrypt(CYASSL* ssl, byte* plain, const byte* input, default: CYASSL_MSG("CyaSSL Decrypt programming error"); } + return 0; } /* decrypt input message in place */ static int DecryptMessage(CYASSL* ssl, byte* input, word32 sz, word32* idx) { - Decrypt(ssl, input, input, sz); - ssl->keys.encryptSz = sz; - if (ssl->options.tls1_1 && ssl->specs.cipher_type == block) - *idx += ssl->specs.block_size; /* go past TLSv1.1 IV */ + int decryptResult = Decrypt(ssl, input, input, sz); - return 0; -} + if (decryptResult == 0) + { + ssl->keys.encryptSz = sz; + if (ssl->options.tls1_1 && ssl->specs.cipher_type == block) + *idx += ssl->specs.block_size; /* go past TLSv1.1 IV */ + if (ssl->specs.cipher_type == aead) + *idx += AES_GCM_EXP_IV_SZ; + } - -static INLINE word32 GetSEQIncrement(CYASSL* ssl, int verify) -{ - if (verify) - return ssl->keys.peer_sequence_number++; - else - return ssl->keys.sequence_number++; + return decryptResult; } @@ -2207,6 +2408,10 @@ int DoApplicationData(CYASSL* ssl, byte* input, word32* inOutIdx) pad = *(input + idx + msgSz - ivExtra - 1); padByte = 1; } + if (ssl->specs.cipher_type == aead) { + ivExtra = AES_GCM_EXP_IV_SZ; + digestSz = AEAD_AUTH_TAG_SZ; + } dataSz = msgSz - ivExtra - digestSz - pad - padByte; if (dataSz < 0) { @@ -2218,7 +2423,8 @@ int DoApplicationData(CYASSL* ssl, byte* input, word32* inOutIdx) if (dataSz) { int rawSz = dataSz; /* keep raw size for hmac */ - ssl->hmac(ssl, verify, rawData, rawSz, application_data, 1); + if (ssl->specs.cipher_type != aead) + ssl->hmac(ssl, verify, rawData, rawSz, application_data, 1); #ifdef HAVE_LIBZ if (ssl->options.usingCompression) { @@ -2244,14 +2450,9 @@ int DoApplicationData(CYASSL* ssl, byte* input, word32* inOutIdx) if (padByte) idx++; -#ifdef HAVE_LIBZ - if (ssl->options.usingCompression) - XMEMMOVE(rawData, decomp, dataSz); -#endif - /* verify */ if (dataSz) { - if (XMEMCMP(mac, verify, digestSz)) { + if (ssl->specs.cipher_type != aead && XMEMCMP(mac, verify, digestSz)) { CYASSL_MSG("App data verify mac error"); return VERIFY_MAC_ERROR; } @@ -2259,6 +2460,12 @@ int DoApplicationData(CYASSL* ssl, byte* input, word32* inOutIdx) else GetSEQIncrement(ssl, 1); /* even though no data, increment verify */ +#ifdef HAVE_LIBZ + /* decompress could be bigger, overwrite after verify */ + if (ssl->options.usingCompression) + XMEMMOVE(rawData, decomp, dataSz); +#endif + *inOutIdx = idx; return 0; } @@ -2288,21 +2495,26 @@ static int DoAlert(CYASSL* ssl, byte* input, word32* inOutIdx, int* type) CYASSL_ERROR(*type); if (ssl->keys.encryptionOn) { - int aSz = ALERT_SIZE; - const byte* mac; - byte verify[SHA256_DIGEST_SIZE]; - int padSz = ssl->keys.encryptSz - aSz - ssl->specs.hash_size; - - ssl->hmac(ssl, verify, input + *inOutIdx - aSz, aSz, alert, 1); + if (ssl->specs.cipher_type != aead) { + int aSz = ALERT_SIZE; + const byte* mac; + byte verify[SHA256_DIGEST_SIZE]; + int padSz = ssl->keys.encryptSz - aSz - ssl->specs.hash_size; - /* read mac and fill */ - mac = input + *inOutIdx; - *inOutIdx += (ssl->specs.hash_size + padSz); - - /* verify */ - if (XMEMCMP(mac, verify, ssl->specs.hash_size)) { - CYASSL_MSG(" alert verify mac error"); - return VERIFY_MAC_ERROR; + ssl->hmac(ssl, verify, input + *inOutIdx - aSz, aSz, alert, 1); + + /* read mac and fill */ + mac = input + *inOutIdx; + *inOutIdx += (ssl->specs.hash_size + padSz); + + /* verify */ + if (XMEMCMP(mac, verify, ssl->specs.hash_size)) { + CYASSL_MSG(" alert verify mac error"); + return VERIFY_MAC_ERROR; + } + } + else { + *inOutIdx += AEAD_AUTH_TAG_SZ; } } @@ -2820,6 +3032,11 @@ static int BuildMessage(CYASSL* ssl, byte* output, const byte* input, int inSz, sz += pad; } + if (ssl->specs.cipher_type == aead) { + ivSz = AES_GCM_EXP_IV_SZ; + sz += (ivSz + 16 - digestSz); + RNG_GenerateBlock(&ssl->rng, iv, ivSz); + } size = (word16)(sz - headerSz); /* include mac and digest */ AddRecordHeader(output, size, (byte)type, ssl); @@ -2833,8 +3050,10 @@ static int BuildMessage(CYASSL* ssl, byte* output, const byte* input, int inSz, if (type == handshake) HashOutput(ssl, output, headerSz + inSz, ivSz); - ssl->hmac(ssl, output+idx, output + headerSz + ivSz, inSz, type, 0); - idx += digestSz; + if (ssl->specs.cipher_type != aead) { + ssl->hmac(ssl, output+idx, output + headerSz + ivSz, inSz, type, 0); + idx += digestSz; + } if (ssl->specs.cipher_type == block) for (i = 0; i <= pad; i++) @@ -3715,7 +3934,55 @@ const char* const cipher_names[] = #endif #ifdef BUILD_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA - "ECDH-ECDSA-DES-CBC3-SHA" + "ECDH-ECDSA-DES-CBC3-SHA", +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_128_GCM_SHA256 + "AES128-GCM-SHA256", +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_GCM_SHA384 + "AES256-GCM-SHA384", +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + "DHE-RSA-AES128-GCM-SHA256", +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + "DHE-RSA-AES256-GCM-SHA384", +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + "ECDHE-RSA-AES128-GCM-SHA256", +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + "ECDHE-RSA-AES256-GCM-SHA384", +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + "ECDHE-ECDSA-AES128-GCM-SHA256", +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + "ECDHE-ECDSA-AES256-GCM-SHA384", +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + "ECDH-RSA-AES128-GCM-SHA256", +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + "ECDH-RSA-AES256-GCM-SHA384", +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + "ECDH-ECDSA-AES128-GCM-SHA256", +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + "ECDH-ECDSA-AES256-GCM-SHA384" #endif }; @@ -3867,7 +4134,55 @@ int cipher_name_idx[] = #endif #ifdef BUILD_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA - TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA + TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_128_GCM_SHA256 + TLS_RSA_WITH_AES_128_GCM_SHA256, +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_GCM_SHA384 + TLS_RSA_WITH_AES_256_GCM_SHA384, +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 #endif }; @@ -4089,7 +4404,10 @@ int SetCipherList(Suites* s, const char* list) length = sizeof(ProtocolVersion) + RAN_LEN + idSz + ENUM_LEN + ssl->suites.suiteSz + SUITE_LEN - + COMP_LEN + ENUM_LEN; + + COMP_LEN + ENUM_LEN; + + if (IsAtLeastTLSv1_2(ssl)) + length += HELLO_EXT_SZ; sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; @@ -4155,7 +4473,29 @@ int SetCipherList(Suites* s, const char* list) output[idx++] = ZLIB_COMPRESSION; else output[idx++] = NO_COMPRESSION; - + + if (IsAtLeastTLSv1_2(ssl)) + { + /* add in the extensions length */ + c16toa(HELLO_EXT_LEN, output + idx); + idx += 2; + + c16toa(HELLO_EXT_SIG_ALGO, output + idx); + idx += 2; + c16toa(HELLO_EXT_SIGALGO_SZ, output + idx); + idx += 2; + /* This is a lazy list setup. Eventually, we'll need to support + * using other hash types or even other extensions. */ + c16toa(HELLO_EXT_SIGALGO_LEN, output + idx); + idx += 2; + output[idx++] = sha_mac; + output[idx++] = rsa_sa_algo; + output[idx++] = sha_mac; + output[idx++] = dsa_sa_algo; + output[idx++] = sha_mac; + output[idx++] = ecc_dsa_sa_algo; + } + HashOutput(ssl, output, sendSz, 0); ssl->options.clientState = CLIENT_HELLO_COMPLETE; @@ -4197,12 +4537,14 @@ int SetCipherList(Suites* s, const char* list) } - static int DoServerHello(CYASSL* ssl, const byte* input, word32* inOutIdx) + static int DoServerHello(CYASSL* ssl, const byte* input, word32* inOutIdx, + word32 helloSz) { byte b; byte compression; ProtocolVersion pv; word32 i = *inOutIdx; + word32 begin = i; #ifdef CYASSL_CALLBACKS if (ssl->hsInfoOn) AddPacketName("ServerHello", &ssl->handShakeInfo); @@ -4254,7 +4596,11 @@ int SetCipherList(Suites* s, const char* list) CYASSL_MSG("Server refused compression, turning off"); ssl->options.usingCompression = 0; /* turn off if server refused */ } - + + *inOutIdx = i; + if ( (i - begin) < helloSz) + *inOutIdx = begin + helloSz; /* skip extensions */ + ssl->options.serverState = SERVER_HELLO_COMPLETE; *inOutIdx = i; @@ -5563,6 +5909,46 @@ int SetCipherList(Suites* s, const char* list) return 1; break; + case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 : + if (requirement == ecc_dsa_sa_algo) + return 1; + break; + + case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 : + if (requirement == ecc_dsa_sa_algo) + return 1; + break; + + case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 : + if (requirement == ecc_static_diffie_hellman_kea) + return 1; + break; + + case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 : + if (requirement == ecc_static_diffie_hellman_kea) + return 1; + break; + + case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 : + if (requirement == rsa_kea) + return 1; + break; + + case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 : + if (requirement == rsa_kea) + return 1; + break; + + case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 : + if (requirement == ecc_static_diffie_hellman_kea) + return 1; + break; + + case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 : + if (requirement == ecc_static_diffie_hellman_kea) + return 1; + break; + default: CYASSL_MSG("Unsupported cipher suite, CipherRequires ECC"); return 0; @@ -5679,6 +6065,20 @@ int SetCipherList(Suites* s, const char* list) return 1; break; + case TLS_RSA_WITH_AES_128_GCM_SHA256 : + case TLS_RSA_WITH_AES_256_GCM_SHA384 : + if (requirement == rsa_kea) + return 1; + break; + + case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 : + case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 : + if (requirement == rsa_kea) + return 1; + if (requirement == diffie_hellman_kea) + return 1; + break; + default: CYASSL_MSG("Unsupported cipher suite, CipherRequires"); return 0; diff --git a/src/keys.c b/src/keys.c index 3fb4c8a60..d6ef0c6e6 100644 --- a/src/keys.c +++ b/src/keys.c @@ -311,6 +311,142 @@ int SetCipherSpecs(CYASSL* ssl) break; #endif +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 : + ssl->specs.bulk_cipher_algorithm = aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_GCM_IMP_IV_SZ; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 : + ssl->specs.bulk_cipher_algorithm = aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha384_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA384_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_GCM_IMP_IV_SZ; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 : + ssl->specs.bulk_cipher_algorithm = aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_GCM_IMP_IV_SZ; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 : + ssl->specs.bulk_cipher_algorithm = aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha384_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = SHA384_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_GCM_IMP_IV_SZ; + + break; +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 : + ssl->specs.bulk_cipher_algorithm = aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 1; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_GCM_IMP_IV_SZ; + + break; +#endif + +#ifdef BUILD_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 : + ssl->specs.bulk_cipher_algorithm = aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha384_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA384_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 1; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_GCM_IMP_IV_SZ; + + break; +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 : + ssl->specs.bulk_cipher_algorithm = aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 1; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_GCM_IMP_IV_SZ; + + break; +#endif + +#ifdef BUILD_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 : + ssl->specs.bulk_cipher_algorithm = aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha384_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = SHA384_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 1; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_GCM_IMP_IV_SZ; + + break; +#endif + default: CYASSL_MSG("Unsupported cipher suite, SetCipherSpecs ECC"); return UNSUPPORTED_SUITE; @@ -646,6 +782,74 @@ int SetCipherSpecs(CYASSL* ssl) break; #endif +#ifdef BUILD_TLS_RSA_WITH_AES_128_GCM_SHA256 + case TLS_RSA_WITH_AES_128_GCM_SHA256 : + ssl->specs.bulk_cipher_algorithm = aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_GCM_IMP_IV_SZ; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_GCM_SHA384 + case TLS_RSA_WITH_AES_256_GCM_SHA384 : + ssl->specs.bulk_cipher_algorithm = aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha384_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA384_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_GCM_IMP_IV_SZ; + + break; +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 : + ssl->specs.bulk_cipher_algorithm = aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha256_mac; + ssl->specs.kea = diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA256_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_GCM_IMP_IV_SZ; + + break; +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 : + ssl->specs.bulk_cipher_algorithm = aes_gcm; + ssl->specs.cipher_type = aead; + ssl->specs.mac_algorithm = sha384_mac; + ssl->specs.kea = diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA384_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.static_ecdh = 0; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_GCM_IMP_IV_SZ; + + break; +#endif + default: CYASSL_MSG("Unsupported cipher suite, SetCipherSpecs"); return UNSUPPORTED_SUITE; @@ -802,6 +1006,19 @@ static int SetKeys(Ciphers* enc, Ciphers* dec, Keys* keys, CipherSpecs* specs, } #endif +#ifdef BUILD_AESGCM + if (specs->bulk_cipher_algorithm == aes_gcm) { + if (side == CLIENT_END) { + AesGcmSetKey(&enc->aes, keys->client_write_key, specs->key_size); + AesGcmSetKey(&dec->aes, keys->server_write_key, specs->key_size); + } + else { + AesGcmSetKey(&enc->aes, keys->server_write_key, specs->key_size); + AesGcmSetKey(&dec->aes, keys->client_write_key, specs->key_size); + } + } +#endif + keys->sequence_number = 0; keys->peer_sequence_number = 0; keys->encryptionOn = 0; @@ -813,12 +1030,15 @@ static int SetKeys(Ciphers* enc, Ciphers* dec, Keys* keys, CipherSpecs* specs, /* TLS can call too */ int StoreKeys(CYASSL* ssl, const byte* keyData) { - int sz = ssl->specs.hash_size, i; + int sz, i = 0; - XMEMCPY(ssl->keys.client_write_MAC_secret, keyData, sz); - i = sz; - XMEMCPY(ssl->keys.server_write_MAC_secret,&keyData[i], sz); - i += sz; + if (ssl->specs.cipher_type != aead) { + sz = ssl->specs.hash_size; + XMEMCPY(ssl->keys.client_write_MAC_secret,&keyData[i], sz); + i += sz; + XMEMCPY(ssl->keys.server_write_MAC_secret,&keyData[i], sz); + i += sz; + } sz = ssl->specs.key_size; XMEMCPY(ssl->keys.client_write_key, &keyData[i], sz); diff --git a/src/ssl.c b/src/ssl.c index 2ad62451d..225c76254 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -5018,6 +5018,23 @@ int CyaSSL_set_compression(CYASSL* ssl) case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA : return "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA"; + case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 : + return "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"; + case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 : + return "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"; + case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 : + return "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"; + case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 : + return "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"; + case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 : + return "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256"; + case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 : + return "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384"; + case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 : + return "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256"; + case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 : + return "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384"; + default: return "NONE"; } @@ -5066,6 +5083,14 @@ int CyaSSL_set_compression(CYASSL* ssl) return "TLS_NTRU_RSA_WITH_AES_128_CBC_SHA"; case TLS_NTRU_RSA_WITH_AES_256_CBC_SHA : return "TLS_NTRU_RSA_WITH_AES_256_CBC_SHA"; + case TLS_RSA_WITH_AES_128_GCM_SHA256 : + return "TLS_RSA_WITH_AES_128_GCM_SHA256"; + case TLS_RSA_WITH_AES_256_GCM_SHA384 : + return "TLS_RSA_WITH_AES_256_GCM_SHA384"; + case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 : + return "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"; + case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 : + return "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384"; default: return "NONE"; } /* switch */ diff --git a/src/tls.c b/src/tls.c index 447f0d819..f5ef46007 100644 --- a/src/tls.c +++ b/src/tls.c @@ -53,28 +53,51 @@ static INLINE void get_xor(byte *digest, word32 digLen, byte* md5, byte* sha) } +#ifdef CYASSL_SHA384 + #define PHASH_MAX_DIGEST_SIZE SHA384_DIGEST_SIZE +#else + #define PHASH_MAX_DIGEST_SIZE SHA256_DIGEST_SIZE +#endif -/* compute p_hash for MD5, SHA-1, or SHA-256 for TLSv1 PRF */ +/* compute p_hash for MD5, SHA-1, SHA-256, or SHA-384 for TLSv1 PRF */ static void p_hash(byte* result, word32 resLen, const byte* secret, word32 secLen, const byte* seed, word32 seedLen, int hash) { - word32 len = hash == md5_mac ? MD5_DIGEST_SIZE : hash == sha_mac ? - SHA_DIGEST_SIZE : SHA256_DIGEST_SIZE; - word32 times = resLen / len; - word32 lastLen = resLen % len; + word32 len = MD5_DIGEST_SIZE; + word32 times; + word32 lastLen; word32 lastTime; word32 i; word32 idx = 0; - byte previous[SHA256_DIGEST_SIZE]; /* max size */ - byte current[SHA256_DIGEST_SIZE]; /* max size */ + byte previous[PHASH_MAX_DIGEST_SIZE]; /* max size */ + byte current[PHASH_MAX_DIGEST_SIZE]; /* max size */ Hmac hmac; + if (hash == md5_mac) { + hash = MD5; + } + else if (hash == sha_mac) { + len = SHA_DIGEST_SIZE; + hash = SHA; + } else if (hash == sha256_mac) { + len = SHA256_DIGEST_SIZE; + hash = SHA256; + } +#ifdef CYASSL_SHA384 + else if (hash == sha384_mac) + { + len = SHA384_DIGEST_SIZE; + hash = SHA384; + } +#endif + + times = resLen / len; + lastLen = resLen % len; if (lastLen) times += 1; lastTime = times - 1; - HmacSetKey(&hmac, hash == md5_mac ? MD5 : hash == sha_mac ? SHA : SHA256, - secret, secLen); + HmacSetKey(&hmac, hash, secret, secLen); HmacUpdate(&hmac, seed, seedLen); /* A0 = seed */ HmacFinal(&hmac, previous); /* A1 */ @@ -99,7 +122,7 @@ static void p_hash(byte* result, word32 resLen, const byte* secret, /* compute TLSv1 PRF (pseudo random function using HMAC) */ static void PRF(byte* digest, word32 digLen, const byte* secret, word32 secLen, const byte* label, word32 labLen, const byte* seed, word32 seedLen, - int useSha256) + int useAtLeastSha256, int hash_type) { word32 half = (secLen + 1) / 2; @@ -122,9 +145,13 @@ static void PRF(byte* digest, word32 digLen, const byte* secret, word32 secLen, XMEMCPY(labelSeed, label, labLen); XMEMCPY(labelSeed + labLen, seed, seedLen); - if (useSha256) { + if (useAtLeastSha256) { + /* If a cipher suite wants an algorithm better than sha256, it + * should use better. */ + if (hash_type < sha256_mac) + hash_type = sha256_mac; p_hash(digest, digLen, secret, secLen, labelSeed, labLen + seedLen, - sha256_mac); + hash_type); return; } @@ -136,20 +163,35 @@ static void PRF(byte* digest, word32 digLen, const byte* secret, word32 secLen, } +#ifdef CYASSL_SHA384 + #define HSHASH_SZ SHA384_DIGEST_SIZE +#else + #define HSHASH_SZ FINISHED_SZ +#endif + + void BuildTlsFinished(CYASSL* ssl, Hashes* hashes, const byte* sender) { const byte* side; - byte handshake_hash[FINISHED_SZ]; + byte handshake_hash[HSHASH_SZ]; word32 hashSz = FINISHED_SZ; Md5Final(&ssl->hashMd5, handshake_hash); ShaFinal(&ssl->hashSha, &handshake_hash[MD5_DIGEST_SIZE]); -#ifndef NO_SHA256 if (IsAtLeastTLSv1_2(ssl)) { - Sha256Final(&ssl->hashSha256, handshake_hash); - hashSz = SHA256_DIGEST_SIZE; - } +#ifndef NO_SHA256 + if (ssl->specs.mac_algorithm <= sha256_mac) { + Sha256Final(&ssl->hashSha256, handshake_hash); + hashSz = SHA256_DIGEST_SIZE; + } #endif +#ifdef CYASSL_SHA384 + if (ssl->specs.mac_algorithm == sha384_mac) { + Sha384Final(&ssl->hashSha384, handshake_hash); + hashSz = SHA384_DIGEST_SIZE; + } +#endif + } if ( XSTRNCMP((const char*)sender, (const char*)client, SIZEOF_SENDER) == 0) side = tls_client; @@ -157,7 +199,8 @@ void BuildTlsFinished(CYASSL* ssl, Hashes* hashes, const byte* sender) side = tls_server; PRF(hashes->md5, TLS_FINISHED_SZ, ssl->arrays.masterSecret, SECRET_LEN, - side, FINISHED_LABEL_SZ, handshake_hash, hashSz, IsAtLeastTLSv1_2(ssl)); + side, FINISHED_LABEL_SZ, handshake_hash, hashSz, IsAtLeastTLSv1_2(ssl), + ssl->specs.mac_algorithm); } @@ -207,7 +250,8 @@ int DeriveTlsKeys(CYASSL* ssl) XMEMCPY(&seed[RAN_LEN], ssl->arrays.clientRandom, RAN_LEN); PRF(key_data, length, ssl->arrays.masterSecret, SECRET_LEN, key_label, - KEY_LABEL_SZ, seed, SEED_LEN, IsAtLeastTLSv1_2(ssl)); + KEY_LABEL_SZ, seed, SEED_LEN, IsAtLeastTLSv1_2(ssl), + ssl->specs.mac_algorithm); return StoreKeys(ssl, key_data); } @@ -223,7 +267,7 @@ int MakeTlsMasterSecret(CYASSL* ssl) PRF(ssl->arrays.masterSecret, SECRET_LEN, ssl->arrays.preMasterSecret, ssl->arrays.preMasterSz, master_label, MASTER_LABEL_SZ, - seed, SEED_LEN, IsAtLeastTLSv1_2(ssl)); + seed, SEED_LEN, IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm); #ifdef SHOW_SECRETS {