From 05165bc09eaa960d564bd91973c0c063755882dd Mon Sep 17 00:00:00 2001 From: John Safranek Date: Thu, 10 Jan 2013 16:38:52 -0800 Subject: [PATCH] Added AES-CCM encrypt/decrypt, test fuction, benchmark function. --- ctaocrypt/benchmark/benchmark.c | 27 ++++ ctaocrypt/src/aes.c | 224 +++++++++++++++++++++++++++----- ctaocrypt/src/error.c | 4 + ctaocrypt/test/test.c | 5 +- cyassl/ctaocrypt/aes.h | 10 +- cyassl/ctaocrypt/error.h | 1 + 6 files changed, 229 insertions(+), 42 deletions(-) diff --git a/ctaocrypt/benchmark/benchmark.c b/ctaocrypt/benchmark/benchmark.c index fa3bc62f7..dc4bfa572 100644 --- a/ctaocrypt/benchmark/benchmark.c +++ b/ctaocrypt/benchmark/benchmark.c @@ -55,6 +55,7 @@ void bench_hc128(void); void bench_rabbit(void); void bench_aes(int); void bench_aesgcm(void); +void bench_aesccm(void); void bench_md5(void); void bench_sha(void); @@ -85,6 +86,9 @@ int main(int argc, char** argv) #ifdef HAVE_AESGCM bench_aesgcm(); #endif +#ifdef HAVE_AESCCM + bench_aesccm(); +#endif #ifndef NO_RC4 bench_arc4(); #endif @@ -211,6 +215,29 @@ void bench_aesgcm(void) #endif +#ifdef HAVE_AESCCM +void bench_aesccm(void) +{ + Aes enc; + double start, total, persec; + int i; + + AesCcmSetKey(&enc, key, 16, iv, 12); + start = current_time(); + + for(i = 0; i < megs; i++) + AesCcmEncrypt(&enc, cipher, plain, sizeof(plain), + tag, 16, additional, 13); + + total = current_time() - start; + + persec = 1 / total * megs; + printf("AES-CCM %d megs took %5.3f seconds, %6.2f MB/s\n", megs, total, + persec); +} +#endif + + #ifndef NO_DES3 void bench_des(void) { diff --git a/ctaocrypt/src/aes.c b/ctaocrypt/src/aes.c index 45a0e0a35..de2bf488c 100644 --- a/ctaocrypt/src/aes.c +++ b/ctaocrypt/src/aes.c @@ -2546,64 +2546,220 @@ int AesGcmDecrypt(Aes* aes, byte* out, const byte* in, word32 sz, void AesCcmSetKey(Aes* aes, const byte* key, word32 keySz, const byte* implicitIV, word32 ivSz) { - (void)aes; - (void)key; - (void)keySz; - (void)implicitIV; - (void)ivSz; + byte fullIV[AES_BLOCK_SIZE]; + + if (!((keySz == 16) || (keySz == 24) || (keySz == 32))) + return; + + if (ivSz > AES_BLOCK_SIZE - 2) { + CYASSL_MSG("AES-CCM IV is too long"); + return; + } + + XMEMSET(fullIV, 0, sizeof(fullIV)); + XMEMCPY(fullIV + 1, implicitIV, ivSz); + + AesSetKeyLocal(aes, key, keySz, fullIV, AES_ENCRYPTION); + aes->lenSz = AES_BLOCK_SIZE - 1 - ivSz; + + XMEMSET(fullIV, 0, sizeof(fullIV)); } -void AesCcmSetExpIV(Aes* aes, const byte* iv, word32 ivSz) +static void roll_x(Aes* aes, const byte* in, word32 inSz, byte* out) { - (void)aes; - (void)iv; - (void)ivSz; + /* process the bulk of the data */ + while (inSz >= AES_BLOCK_SIZE) { + xorbuf(out, in, AES_BLOCK_SIZE); + in += AES_BLOCK_SIZE; + inSz -= AES_BLOCK_SIZE; + + AesEncrypt(aes, out, out); + } + + /* process remainder of the data */ + if (inSz > 0) { + xorbuf(out, in, inSz); + AesEncrypt(aes, out, out); + } } -void AesCcmGetExpIV(Aes* aes, byte* iv, word32 ivSz) +static void roll_auth(Aes* aes, const byte* in, word32 inSz, byte* out) { - (void)aes; - (void)iv; - (void)ivSz; + word32 authLenSz; + word32 remainder; + + /* encode the length in */ + if (inSz <= 0xFEFF) { + authLenSz = 2; + out[0] ^= ((inSz & 0xFF00) >> 8); + out[1] ^= (inSz & 0x00FF); + } + else if (inSz <= 0xFFFFFFFF) { + authLenSz = 6; + out[0] ^= 0xFF; out[1] ^= 0xFE; + out[2] ^= ((inSz & 0xFF000000) >> 24); + out[3] ^= ((inSz & 0x00FF0000) >> 16); + out[4] ^= ((inSz & 0x0000FF00) >> 8); + out[5] ^= (inSz & 0x000000FF); + } + /* Note, the protocol handles auth data up to 2^64, but we are + * using 32-bit sizes right now, so the bigger data isn't handled + * else if (inSz <= 0xFFFFFFFFFFFFFFFF) {} */ + else + return; + + /* start fill out the rest of the first block */ + remainder = AES_BLOCK_SIZE - authLenSz; + if (inSz >= remainder) { + /* plenty of bulk data to fill the remainder of this block */ + xorbuf(out + authLenSz, in, remainder); + inSz -= remainder; + in += remainder; + } + else { + /* not enough bulk data, copy what is available, and pad zero */ + xorbuf(out + authLenSz, in, inSz); + inSz = 0; + } + AesEncrypt(aes, out, out); + + if (inSz > 0) + roll_x(aes, in, inSz, out); } -void AesCcmIncExpIV(Aes* aes) +static INLINE void AesCcmCtrInc(byte* B, word32 lenSz) { - (void)aes; + word32 i; + + for (i = 0; i < lenSz; i++) { + if (++B[AES_BLOCK_SIZE - 1 - i] != 0) return; + } } -void AesCcmEncrypt(Aes* aes, byte* out, const byte* in, word32 sz, +void AesCcmEncrypt(Aes* aes, byte* out, const byte* in, word32 inSz, byte* authTag, word32 authTagSz, const byte* authIn, word32 authInSz) { - (void)aes; - (void)out; - (void)in; - (void)sz; - (void)authTag; - (void)authTagSz; - (void)authIn; - (void)authInSz; + byte A[AES_BLOCK_SIZE]; + byte B[AES_BLOCK_SIZE]; + word32 i; + + XMEMCPY(B, aes->reg, AES_BLOCK_SIZE); + B[0] = (authInSz > 0 ? 64 : 0) + + (8 * ((authTagSz - 2) / 2)) + + (aes->lenSz - 1); + for (i = 0; i < aes->lenSz; i++) + B[AES_BLOCK_SIZE - 1 - i] = (inSz >> (8 * i)) & 0xFF; + + AesEncrypt(aes, B, A); + if (authInSz > 0) + roll_auth(aes, authIn, authInSz, A); + if (inSz > 0) + roll_x(aes, in, inSz, A); + XMEMCPY(authTag, A, authTagSz); + + B[0] = (aes->lenSz - 1); + for (i = 0; i < aes->lenSz; i++) + B[AES_BLOCK_SIZE - 1 - i] = 0; + AesEncrypt(aes, B, A); + xorbuf(authTag, A, authTagSz); + + B[15] = 1; + while (inSz >= AES_BLOCK_SIZE) { + AesEncrypt(aes, B, A); + xorbuf(A, in, AES_BLOCK_SIZE); + XMEMCPY(out, A, AES_BLOCK_SIZE); + + AesCcmCtrInc(B, aes->lenSz); + inSz -= AES_BLOCK_SIZE; + in += AES_BLOCK_SIZE; + out += AES_BLOCK_SIZE; + } + if (inSz > 0) { + AesEncrypt(aes, B, A); + xorbuf(A, in, inSz); + XMEMCPY(out, A, inSz); + } + + XMEMSET(A, 0, AES_BLOCK_SIZE); + XMEMSET(B, 0, AES_BLOCK_SIZE); } -int AesCcmDecrypt(Aes* aes, byte* out, const byte* in, word32 sz, +int AesCcmDecrypt(Aes* aes, byte* out, const byte* in, word32 inSz, const byte* authTag, word32 authTagSz, const byte* authIn, word32 authInSz) { - (void)aes; - (void)out; - (void)in; - (void)sz; - (void)authTag; - (void)authTagSz; - (void)authIn; - (void)authInSz; - return 0; + byte A[AES_BLOCK_SIZE]; + byte B[AES_BLOCK_SIZE]; + byte* o; + word32 i, oSz, result = 0; + + o = out; + oSz = inSz; + XMEMCPY(B, aes->reg, AES_BLOCK_SIZE); + B[0] = (aes->lenSz - 1); + for (i = 0; i < aes->lenSz - 1; i++) + B[AES_BLOCK_SIZE - 1 - i] = 0; + B[15] = 1; + while (oSz >= AES_BLOCK_SIZE) { + AesEncrypt(aes, B, A); + xorbuf(A, in, AES_BLOCK_SIZE); + XMEMCPY(o, A, AES_BLOCK_SIZE); + + AesCcmCtrInc(B, aes->lenSz); + oSz -= AES_BLOCK_SIZE; + in += AES_BLOCK_SIZE; + o += AES_BLOCK_SIZE; + } + if (inSz > 0) { + AesEncrypt(aes, B, A); + xorbuf(A, in, oSz); + XMEMCPY(o, A, oSz); + } + + for (i = 0; i < aes->lenSz; i++) + B[AES_BLOCK_SIZE - 1 - i] = 0; + AesEncrypt(aes, B, A); + + o = out; + oSz = inSz; + + B[0] = (authInSz > 0 ? 64 : 0) + + (8 * ((authTagSz - 2) / 2)) + + (aes->lenSz - 1); + for (i = 0; i < aes->lenSz; i++) + B[AES_BLOCK_SIZE - 1 - i] = (inSz >> (8 * i)) & 0xFF; + + AesEncrypt(aes, B, A); + if (authInSz > 0) + roll_auth(aes, authIn, authInSz, A); + if (inSz > 0) + roll_x(aes, o, oSz, A); + + B[0] = (aes->lenSz - 1); + for (i = 0; i < aes->lenSz; i++) + B[AES_BLOCK_SIZE - 1 - i] = 0; + AesEncrypt(aes, B, B); + xorbuf(A, B, authTagSz); + + if (XMEMCMP(A, authTag, authTagSz) != 0) { + /* If the authTag check fails, don't keep the decrypted data. + * Unfortunately, you need the decrypted data to calculate the + * check value. */ + XMEMSET(out, 0, inSz); + result = AES_CCM_AUTH_E; + } + + XMEMSET(A, 0, AES_BLOCK_SIZE); + XMEMSET(B, 0, AES_BLOCK_SIZE); + o = NULL; + + return result; } #endif diff --git a/ctaocrypt/src/error.c b/ctaocrypt/src/error.c index 6cfe8e729..b4d1eb258 100644 --- a/ctaocrypt/src/error.c +++ b/ctaocrypt/src/error.c @@ -273,6 +273,10 @@ void CTaoCryptErrorString(int error, char* buffer) XSTRNCPY(buffer, "AES-GCM Authentication check fail", max); break; + case AES_CCM_AUTH_E: + XSTRNCPY(buffer, "AES-CCM Authentication check fail", max); + break; + default: XSTRNCPY(buffer, "unknown error number", max); diff --git a/ctaocrypt/test/test.c b/ctaocrypt/test/test.c index e681e4084..e644d878e 100644 --- a/ctaocrypt/test/test.c +++ b/ctaocrypt/test/test.c @@ -1615,13 +1615,12 @@ int aesccm_test(void) { 0x58, 0x8c, 0x97, 0x9a, 0x61, 0xc6, 0x63, 0xd2, 0xf0, 0x66, 0xd0, 0xc2, 0xc0, 0xf9, 0x89, 0x80, - 0x6d, 0x5f, 0x6b, 0x61, 0xda, 0xc3, 0x84, 0x17, - 0xe8, 0xd1, 0x2c, 0xfd, 0xf9, 0x26, 0xe0 + 0x6d, 0x5f, 0x6b, 0x61, 0xda, 0xc3, 0x84 }; const byte t[] = { - 0x3a, 0x2e, 0x46, 0xc8, 0xec, 0x33, 0xa5, 0x48 + 0x17, 0xe8, 0xd1, 0x2c, 0xfd, 0xf9, 0x26, 0xe0 }; byte t2[sizeof(t)]; diff --git a/cyassl/ctaocrypt/aes.h b/cyassl/ctaocrypt/aes.h index aa8d674ef..1c5e93bf0 100644 --- a/cyassl/ctaocrypt/aes.h +++ b/cyassl/ctaocrypt/aes.h @@ -76,6 +76,9 @@ typedef struct Aes { ALIGN16 byte M0[256][AES_BLOCK_SIZE]; #endif /* GCM_TABLE */ #endif /* HAVE_AESGCM */ +#ifdef HAVE_AESCCM + word32 lenSz; +#endif #ifdef CYASSL_AESNI byte use_aesni; #endif /* CYASSL_AESNI */ @@ -108,13 +111,10 @@ CYASSL_API int AesGcmDecrypt(Aes* aes, byte* out, const byte* in, word32 sz, #ifdef HAVE_AESCCM CYASSL_API void AesCcmSetKey(Aes* aes, const byte* key, word32 keySz, const byte* implicitIV, word32 ivSz); -CYASSL_API void AesCcmSetExpIV(Aes* aes, const byte* iv, word32 ivSz); -CYASSL_API void AesCcmGetExpIV(Aes* aes, byte* iv, word32 ivSz); -CYASSL_API void AesCcmIncExpIV(Aes* aes); -CYASSL_API void AesCcmEncrypt(Aes* aes, byte* out, const byte* in, word32 sz, +CYASSL_API void AesCcmEncrypt(Aes* aes, byte* out, const byte* in, word32 inSz, byte* authTag, word32 authTagSz, const byte* authIn, word32 authInSz); -CYASSL_API int AesCcmDecrypt(Aes* aes, byte* out, const byte* in, word32 sz, +CYASSL_API int AesCcmDecrypt(Aes* aes, byte* out, const byte* in, word32 inSz, const byte* authTag, word32 authTagSz, const byte* authIn, word32 authInSz); #endif /* HAVE_AESCCM */ diff --git a/cyassl/ctaocrypt/error.h b/cyassl/ctaocrypt/error.h index 8a0d58628..308fb1d81 100644 --- a/cyassl/ctaocrypt/error.h +++ b/cyassl/ctaocrypt/error.h @@ -99,6 +99,7 @@ enum { ALT_NAME_E = -177, /* alt name size problem, too big */ AES_GCM_AUTH_E = -180, /* AES-GCM Authentication check failure */ + AES_CCM_AUTH_E = -181, /* AES-CCM Authentication check failure */ MIN_CODE_E = -200 /* errors -101 - -199 */ };