From 1ee9d182cf5f5ce42392158495ddcb947b5cfce2 Mon Sep 17 00:00:00 2001 From: David Garske Date: Mon, 30 Dec 2019 10:04:30 -0800 Subject: [PATCH 1/9] New API's for ChaCha20/Poly1305 AEAD init/update/final: * Provides a context for AEAD to allow "chunked" updates of data then a final calculation for the authentication tag. * New API's are on by default and can be disabled using NO_CHACHAPOLY_AEAD_IUF. --- wolfcrypt/src/chacha20_poly1305.c | 184 +++++++++++++++++++- wolfcrypt/test/test.c | 236 ++++++++++++++++++++++++-- wolfssl/wolfcrypt/chacha20_poly1305.h | 66 +++++-- 3 files changed, 458 insertions(+), 28 deletions(-) diff --git a/wolfcrypt/src/chacha20_poly1305.c b/wolfcrypt/src/chacha20_poly1305.c index a30fbf991..d348d2c08 100644 --- a/wolfcrypt/src/chacha20_poly1305.c +++ b/wolfcrypt/src/chacha20_poly1305.c @@ -32,8 +32,6 @@ #include #include #include -#include -#include #ifdef NO_INLINE #include @@ -121,7 +119,6 @@ int wc_ChaCha20Poly1305_Decrypt( byte calculatedAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE]; /* Validate function arguments */ - if (!inKey || !inIV || !inCiphertext || !inCiphertextLen || !inAuthTag || @@ -152,11 +149,8 @@ int wc_ChaCha20Poly1305_Decrypt( calculatedAuthTag); /* Compare the calculated auth tag with the received one */ - if (err == 0 && ConstantCompare(inAuthTag, calculatedAuthTag, - CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE) != 0) - { - err = MAC_CMP_FAILED_E; - } + if (err == 0) + err = wc_ChaCha20Poly1305_CheckTag(inAuthTag, calculatedAuthTag); /* Decrypt the received ciphertext */ if (err == 0) @@ -167,6 +161,17 @@ int wc_ChaCha20Poly1305_Decrypt( return err; } +int wc_ChaCha20Poly1305_CheckTag( + const byte authTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE], + const byte authTagChk[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE]) +{ + int ret = 0; + if (ConstantCompare(authTag, authTagChk, + CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE) != 0) { + ret = MAC_CMP_FAILED_E; + } + return ret; +} static int calculateAuthTag( const byte inAuthKey[CHACHA20_POLY1305_AEAD_KEYSIZE], @@ -248,4 +253,167 @@ static void word32ToLittle64(const word32 inLittle32, byte outLittle64[8]) } +#ifndef NO_CHACHAPOLY_AEAD_IUF +int wc_ChaCha20Poly1305_Init(ChaChaPoly_Aead* aead, + const byte inKey[CHACHA20_POLY1305_AEAD_KEYSIZE], + const byte inIV[CHACHA20_POLY1305_AEAD_IV_SIZE], + int isEncrypt) +{ + int ret; + byte authKey[CHACHA20_POLY1305_AEAD_KEYSIZE]; + + /* check arguments */ + if (aead == NULL || inKey == NULL || inIV == NULL) { + return BAD_FUNC_ARG; + } + + /* setup aead context */ + XMEMSET(aead, 0, sizeof(ChaChaPoly_Aead)); + XMEMSET(authKey, 0, sizeof(authKey)); + aead->isEncrypt = isEncrypt; + + /* Initialize the ChaCha20 context (key and iv) */ + ret = wc_Chacha_SetKey(&aead->chacha, inKey, + CHACHA20_POLY1305_AEAD_KEYSIZE); + if (ret == 0) { + ret = wc_Chacha_SetIV(&aead->chacha, inIV, + CHACHA20_POLY1305_AEAD_INITIAL_COUNTER); + } + + /* Create the Poly1305 key */ + if (ret == 0) { + ret = wc_Chacha_Process(&aead->chacha, authKey, authKey, + CHACHA20_POLY1305_AEAD_KEYSIZE); + } + + /* Initialize Poly1305 context */ + if (ret == 0) { + ret = wc_Poly1305SetKey(&aead->poly, authKey, + CHACHA20_POLY1305_AEAD_KEYSIZE); + } + + if (ret == 0) { + aead->state = CHACHA20_POLY1305_STATE_READY; + } + + return ret; +} + +/* optional additional authentication data */ +int wc_ChaCha20Poly1305_UpdateAad(ChaChaPoly_Aead* aead, + const byte* inAAD, word32 inAADLen) +{ + int ret = 0; + + if (aead == NULL || inAAD == NULL) { + return BAD_FUNC_ARG; + } + if (aead->state != CHACHA20_POLY1305_STATE_READY && + aead->state != CHACHA20_POLY1305_STATE_AAD) { + return BAD_STATE_E; + } + + if (inAADLen > 0) { + ret = wc_Poly1305Update(&aead->poly, inAAD, inAADLen); + if (ret == 0) { + aead->aadLen += inAADLen; + aead->state = CHACHA20_POLY1305_STATE_AAD; + } + } + + return ret; +} + +int wc_ChaCha20Poly1305_UpdateData(ChaChaPoly_Aead* aead, + byte* data, word32 dataLen) +{ + int ret = 0; + + if (aead == NULL || data == NULL) { + return BAD_FUNC_ARG; + } + if (aead->state != CHACHA20_POLY1305_STATE_READY && + aead->state != CHACHA20_POLY1305_STATE_AAD && + aead->state != CHACHA20_POLY1305_STATE_DATA) { + return BAD_STATE_E; + } + + if (aead->state == CHACHA20_POLY1305_STATE_AAD) { + /* Pad the AAD to 16 bytes */ + byte padding[CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1]; + word32 paddingLen = -(int)aead->aadLen & + (CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1); + if (paddingLen > 0) { + XMEMSET(padding, 0, paddingLen); + ret = wc_Poly1305Update(&aead->poly, padding, paddingLen); + } + } + aead->state = CHACHA20_POLY1305_STATE_DATA; + + if (ret == 0) { + /* Perform ChaCha20 encrypt or decrypt inline and Poly1305 auth calc */ + if (aead->isEncrypt) { + ret = wc_Chacha_Process(&aead->chacha, data, data, dataLen); + if (ret == 0) + ret = wc_Poly1305Update(&aead->poly, data, dataLen); + } + else { + ret = wc_Poly1305Update(&aead->poly, data, dataLen); + if (ret == 0) + ret = wc_Chacha_Process(&aead->chacha, data, data, dataLen); + } + } + if (ret == 0) { + aead->dataLen += dataLen; + } + return ret; +} + +int wc_ChaCha20Poly1305_Final(ChaChaPoly_Aead* aead, + byte outAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE]) +{ + int ret = 0; + byte padding[CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1]; + word32 paddingLen; + byte little64[16]; /* word64 * 2 */ + + if (aead == NULL || outAuthTag == NULL) { + return BAD_FUNC_ARG; + } + if (aead->state != CHACHA20_POLY1305_STATE_DATA) { + return BAD_STATE_E; + } + aead->state = CHACHA20_POLY1305_STATE_FINAL; + + /* Pad the ciphertext to 16 bytes */ + paddingLen = -(int)aead->dataLen & + (CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1); + if (paddingLen > 0) { + XMEMSET(padding, 0, paddingLen); + ret = wc_Poly1305Update(&aead->poly, padding, paddingLen); + } + + /* Add the aad and ciphertext length */ + if (ret == 0) { + /* AAD length as a 64-bit little endian integer */ + word32ToLittle64(aead->aadLen, little64); + /* Ciphertext length as a 64-bit little endian integer */ + word32ToLittle64(aead->dataLen, little64 + 8); + + ret = wc_Poly1305Update(&aead->poly, little64, sizeof(little64)); + } + + /* Finalize the auth tag */ + if (ret == 0) { + ret = wc_Poly1305Final(&aead->poly, outAuthTag); + } + + /* reset and cleanup sensitive context */ + ForceZero(aead, sizeof(ChaChaPoly_Aead)); + + return ret; +} + +#endif /* !NO_CHACHAPOLY_AEAD_IUF */ + #endif /* HAVE_CHACHA && HAVE_POLY1305 */ diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 7a3cba7cd..b0c3fe99f 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -5034,6 +5034,13 @@ int chacha20_poly1305_aead_test(void) byte generatedPlaintext[272]; byte generatedAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE]; int err; +#ifndef NO_CHACHAPOLY_AEAD_IUF + ChaChaPoly_Aead aead; + #define TEST_SMALL_CHACHA_CHUNKS 64 + #ifdef TEST_SMALL_CHACHA_CHUNKS + word32 testLen; + #endif +#endif XMEMSET(generatedCiphertext, 0, sizeof(generatedCiphertext)); XMEMSET(generatedAuthTag, 0, sizeof(generatedAuthTag)); @@ -5092,8 +5099,8 @@ int chacha20_poly1305_aead_test(void) if (err != BAD_FUNC_ARG) return -4511; - /* Test #1 */ + /* Test #1 */ err = wc_ChaCha20Poly1305_Encrypt(key1, iv1, aad1, sizeof(aad1), plaintext1, sizeof(plaintext1), @@ -5103,17 +5110,14 @@ int chacha20_poly1305_aead_test(void) } /* -- Check the ciphertext and authtag */ - if (XMEMCMP(generatedCiphertext, cipher1, sizeof(cipher1))) { return -4512; } - if (XMEMCMP(generatedAuthTag, authTag1, sizeof(authTag1))) { return -4513; } /* -- Verify decryption works */ - err = wc_ChaCha20Poly1305_Decrypt(key1, iv1, aad1, sizeof(aad1), cipher1, sizeof(cipher1), @@ -5121,17 +5125,16 @@ int chacha20_poly1305_aead_test(void) if (err) { return err; } - - if (XMEMCMP(generatedPlaintext, plaintext1, sizeof( plaintext1))) { + if (XMEMCMP(generatedPlaintext, plaintext1, sizeof(plaintext1))) { return -4514; } + XMEMSET(generatedCiphertext, 0, sizeof(generatedCiphertext)); XMEMSET(generatedAuthTag, 0, sizeof(generatedAuthTag)); XMEMSET(generatedPlaintext, 0, sizeof(generatedPlaintext)); /* Test #2 */ - err = wc_ChaCha20Poly1305_Encrypt(key2, iv2, aad2, sizeof(aad2), plaintext2, sizeof(plaintext2), @@ -5141,17 +5144,14 @@ int chacha20_poly1305_aead_test(void) } /* -- Check the ciphertext and authtag */ - if (XMEMCMP(generatedCiphertext, cipher2, sizeof(cipher2))) { return -4515; } - if (XMEMCMP(generatedAuthTag, authTag2, sizeof(authTag2))) { return -4516; } /* -- Verify decryption works */ - err = wc_ChaCha20Poly1305_Decrypt(key2, iv2, aad2, sizeof(aad2), cipher2, sizeof(cipher2), @@ -5164,6 +5164,222 @@ int chacha20_poly1305_aead_test(void) return -4517; } + +#ifndef NO_CHACHAPOLY_AEAD_IUF + /* AEAD init/update/final */ + err = wc_ChaCha20Poly1305_Init(NULL, key1, iv1, 0); + if (err != BAD_FUNC_ARG) + return -4520; + err = wc_ChaCha20Poly1305_Init(&aead, NULL, iv1, 0); + if (err != BAD_FUNC_ARG) + return -4521; + err = wc_ChaCha20Poly1305_Init(&aead, key1, NULL, 0); + if (err != BAD_FUNC_ARG) + return -4522; + err = wc_ChaCha20Poly1305_UpdateAad(NULL, aad1, sizeof(aad1)); + if (err != BAD_FUNC_ARG) + return -4523; + err = wc_ChaCha20Poly1305_UpdateAad(&aead, NULL, sizeof(aad1)); + if (err != BAD_FUNC_ARG) + return -4524; + err = wc_ChaCha20Poly1305_UpdateData(NULL, generatedPlaintext, sizeof(plaintext1)); + if (err != BAD_FUNC_ARG) + return -4525; + err = wc_ChaCha20Poly1305_UpdateData(&aead, NULL, sizeof(plaintext1)); + if (err != BAD_FUNC_ARG) + return -4526; + err = wc_ChaCha20Poly1305_Final(NULL, generatedAuthTag); + if (err != BAD_FUNC_ARG) + return -4527; + err = wc_ChaCha20Poly1305_Final(&aead, NULL); + if (err != BAD_FUNC_ARG) + return -4528; + + /* AEAD init/update/final - state tests */ + aead.state = CHACHA20_POLY1305_STATE_INIT; + err = wc_ChaCha20Poly1305_UpdateAad(&aead, aad1, sizeof(aad1)); + if (err != BAD_STATE_E) + return -4529; + aead.state = CHACHA20_POLY1305_STATE_DATA; + err = wc_ChaCha20Poly1305_UpdateAad(&aead, aad1, sizeof(aad1)); + if (err != BAD_STATE_E) + return -4530; + aead.state = CHACHA20_POLY1305_STATE_FINAL; + err = wc_ChaCha20Poly1305_UpdateAad(&aead, aad1, sizeof(aad1)); + if (err != BAD_STATE_E) + return -4531; + aead.state = CHACHA20_POLY1305_STATE_INIT; + err = wc_ChaCha20Poly1305_UpdateData(&aead, generatedPlaintext, sizeof(plaintext1)); + if (err != BAD_STATE_E) + return -4532; + aead.state = CHACHA20_POLY1305_STATE_FINAL; + err = wc_ChaCha20Poly1305_UpdateData(&aead, generatedPlaintext, sizeof(plaintext1)); + if (err != BAD_STATE_E) + return -4533; + aead.state = CHACHA20_POLY1305_STATE_INIT; + err = wc_ChaCha20Poly1305_Final(&aead, generatedAuthTag); + if (err != BAD_STATE_E) + return -4534; + aead.state = CHACHA20_POLY1305_STATE_READY; + err = wc_ChaCha20Poly1305_Final(&aead, generatedAuthTag); + if (err != BAD_STATE_E) + return -4535; + aead.state = CHACHA20_POLY1305_STATE_AAD; + err = wc_ChaCha20Poly1305_Final(&aead, generatedAuthTag); + if (err != BAD_STATE_E) + return -4536; + + XMEMSET(generatedCiphertext, 0, sizeof(generatedCiphertext)); + XMEMSET(generatedAuthTag, 0, sizeof(generatedAuthTag)); + XMEMSET(generatedPlaintext, 0, sizeof(generatedPlaintext)); + + /* Test 1 - Encrypt */ + err = wc_ChaCha20Poly1305_Init(&aead, key1, iv1, 1); + if (err != 0) + return -4537; + err = wc_ChaCha20Poly1305_UpdateAad(&aead, aad1, sizeof(aad1)); + if (err != 0) + return -4538; +#ifdef TEST_SMALL_CHACHA_CHUNKS + /* test doing data in smaller chunks */ + for (testLen=0; testLen TEST_SMALL_CHACHA_CHUNKS) + dataLen = TEST_SMALL_CHACHA_CHUNKS; + XMEMCPY(&generatedCiphertext[testLen], &plaintext1[testLen], dataLen); + err = wc_ChaCha20Poly1305_UpdateData(&aead, + &generatedCiphertext[testLen], dataLen); + if (err != 0) + return -4539; + testLen += dataLen; + } +#else + XMEMCPY(generatedCiphertext, plaintext1, sizeof(plaintext1)); + err = wc_ChaCha20Poly1305_UpdateData(&aead, generatedCiphertext, + sizeof(plaintext1)); +#endif + err = wc_ChaCha20Poly1305_Final(&aead, generatedAuthTag); + if (err != 0) + return -4540; + err = wc_ChaCha20Poly1305_CheckTag(generatedAuthTag, authTag1); + if (err != 0) + return -4541; + if (XMEMCMP(generatedCiphertext, cipher1, sizeof(cipher1))) { + return -4542; + } + + /* Test 1 - Decrypt */ + err = wc_ChaCha20Poly1305_Init(&aead, key1, iv1, 0); + if (err != 0) + return -4543; + err = wc_ChaCha20Poly1305_UpdateAad(&aead, aad1, sizeof(aad1)); + if (err != 0) + return -4544; +#ifdef TEST_SMALL_CHACHA_CHUNKS + /* test doing data in smaller chunks */ + for (testLen=0; testLen TEST_SMALL_CHACHA_CHUNKS) + dataLen = TEST_SMALL_CHACHA_CHUNKS; + XMEMCPY(&generatedPlaintext[testLen], &generatedCiphertext[testLen], + dataLen); + err = wc_ChaCha20Poly1305_UpdateData(&aead, + &generatedPlaintext[testLen], dataLen); + if (err != 0) + return -4545; + testLen += dataLen; + } +#else + XMEMCPY(generatedPlaintext, generatedCiphertext, sizeof(cipher1)); + err = wc_ChaCha20Poly1305_UpdateData(&aead, generatedPlaintext, + sizeof(cipher1)); +#endif + err = wc_ChaCha20Poly1305_Final(&aead, generatedAuthTag); + if (err != 0) + return -4546; + err = wc_ChaCha20Poly1305_CheckTag(generatedAuthTag, authTag1); + if (err != 0) + return -4547; + if (XMEMCMP(generatedPlaintext, plaintext1, sizeof(plaintext1))) { + return -4548; + } + + XMEMSET(generatedCiphertext, 0, sizeof(generatedCiphertext)); + XMEMSET(generatedAuthTag, 0, sizeof(generatedAuthTag)); + XMEMSET(generatedPlaintext, 0, sizeof(generatedPlaintext)); + + /* Test 2 - Encrypt */ + err = wc_ChaCha20Poly1305_Init(&aead, key2, iv2, 1); + if (err != 0) + return -4550; + err = wc_ChaCha20Poly1305_UpdateAad(&aead, aad2, sizeof(aad2)); + if (err != 0) + return -4551; +#ifdef TEST_SMALL_CHACHA_CHUNKS + /* test doing data in smaller chunks */ + for (testLen=0; testLen TEST_SMALL_CHACHA_CHUNKS) + dataLen = TEST_SMALL_CHACHA_CHUNKS; + XMEMCPY(&generatedCiphertext[testLen], &plaintext2[testLen], dataLen); + err = wc_ChaCha20Poly1305_UpdateData(&aead, + &generatedCiphertext[testLen], dataLen); + if (err != 0) + return -4552; + testLen += dataLen; + } +#else + XMEMCPY(generatedCiphertext, plaintext2, sizeof(plaintext2)); + err = wc_ChaCha20Poly1305_UpdateData(&aead, generatedCiphertext, + sizeof(plaintext2)); +#endif + err = wc_ChaCha20Poly1305_Final(&aead, generatedAuthTag); + if (err != 0) + return -4553; + err = wc_ChaCha20Poly1305_CheckTag(generatedAuthTag, authTag2); + if (err != 0) + return -4554; + if (XMEMCMP(generatedCiphertext, cipher2, sizeof(cipher2))) { + return -4555; + } + + /* Test 2 - Decrypt */ + err = wc_ChaCha20Poly1305_Init(&aead, key2, iv2, 0); + if (err != 0) + return -4556; + err = wc_ChaCha20Poly1305_UpdateAad(&aead, aad2, sizeof(aad2)); + if (err != 0) + return -4557; +#ifdef TEST_SMALL_CHACHA_CHUNKS + /* test doing data in smaller chunks */ + for (testLen=0; testLen TEST_SMALL_CHACHA_CHUNKS) + dataLen = TEST_SMALL_CHACHA_CHUNKS; + XMEMCPY(&generatedPlaintext[testLen], &generatedCiphertext[testLen], + dataLen); + err = wc_ChaCha20Poly1305_UpdateData(&aead, + &generatedPlaintext[testLen], dataLen); + if (err != 0) + return -4558; + testLen += dataLen; + } +#else + XMEMCPY(generatedPlaintext, generatedCiphertext, sizeof(cipher2)); + err = wc_ChaCha20Poly1305_UpdateData(&aead, generatedPlaintext, + sizeof(cipher2)); +#endif + err = wc_ChaCha20Poly1305_Final(&aead, generatedAuthTag); + if (err != 0) + return -4559; + err = wc_ChaCha20Poly1305_CheckTag(generatedAuthTag, authTag2); + if (err != 0) + return -4560; + if (XMEMCMP(generatedPlaintext, plaintext2, sizeof(plaintext2))) { + return -4561; + } +#endif /* !NO_CHACHAPOLY_AEAD_IUF */ + return err; } #endif /* HAVE_CHACHA && HAVE_POLY1305 */ diff --git a/wolfssl/wolfcrypt/chacha20_poly1305.h b/wolfssl/wolfcrypt/chacha20_poly1305.h index aef72540e..4754b17ae 100644 --- a/wolfssl/wolfcrypt/chacha20_poly1305.h +++ b/wolfssl/wolfcrypt/chacha20_poly1305.h @@ -33,6 +33,8 @@ #define WOLF_CRYPT_CHACHA20_POLY1305_H #include +#include +#include #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) @@ -45,18 +47,41 @@ #define CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE 16 enum { - CHACHA20_POLY_1305_ENC_TYPE = 8 /* cipher unique type */ + CHACHA20_POLY_1305_ENC_TYPE = 8, /* cipher unique type */ + + /* AEAD Cipher Direction */ + CHACHA20_POLY1305_AEAD_DECRYPT = 0, + CHACHA20_POLY1305_AEAD_ENCRYPT = 1, + + /* AEAD State */ + CHACHA20_POLY1305_STATE_INIT = 0, + CHACHA20_POLY1305_STATE_READY = 1, + CHACHA20_POLY1305_STATE_AAD = 2, + CHACHA20_POLY1305_STATE_DATA = 3, + CHACHA20_POLY1305_STATE_FINAL = 4, }; - /* - * The IV for this implementation is 96 bits to give the most flexibility. - * - * Some protocols may have unique per-invocation inputs that are not - * 96-bit in length. For example, IPsec may specify a 64-bit nonce. In - * such a case, it is up to the protocol document to define how to - * transform the protocol nonce into a 96-bit nonce, for example by - * concatenating a constant value. - */ +typedef struct ChaChaPoly_Aead { + ChaCha chacha; + Poly1305 poly; + + word32 aadLen; + word32 dataLen; + + byte state; + word32 isEncrypt:1; +} ChaChaPoly_Aead; + + +/* + * The IV for this implementation is 96 bits to give the most flexibility. + * + * Some protocols may have unique per-invocation inputs that are not + * 96-bit in length. For example, IPsec may specify a 64-bit nonce. In + * such a case, it is up to the protocol document to define how to + * transform the protocol nonce into a 96-bit nonce, for example by + * concatenating a constant value. + */ WOLFSSL_API int wc_ChaCha20Poly1305_Encrypt( @@ -76,6 +101,27 @@ int wc_ChaCha20Poly1305_Decrypt( const byte inAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE], byte* outPlaintext); +WOLFSSL_API +int wc_ChaCha20Poly1305_CheckTag( + const byte authTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE], + const byte authTagChk[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE]); + + +#ifndef NO_CHACHAPOLY_AEAD_IUF +/* Implementation of AEAD, which includes support for adding + data, then final calculation of authentication tag */ +WOLFSSL_API int wc_ChaCha20Poly1305_Init(ChaChaPoly_Aead* aead, + const byte inKey[CHACHA20_POLY1305_AEAD_KEYSIZE], + const byte inIV[CHACHA20_POLY1305_AEAD_IV_SIZE], + int isEncrypt); +WOLFSSL_API int wc_ChaCha20Poly1305_UpdateAad(ChaChaPoly_Aead* aead, + const byte* inAAD, word32 inAADLen); +WOLFSSL_API int wc_ChaCha20Poly1305_UpdateData(ChaChaPoly_Aead* aead, + byte* data, word32 dataLen); +WOLFSSL_API int wc_ChaCha20Poly1305_Final(ChaChaPoly_Aead* aead, + byte outAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE]); +#endif /* !NO_CHACHAPOLY_AEAD_IUF */ + #ifdef __cplusplus } /* extern "C" */ #endif From b901a2cd3584a60f10a67721a8e3bca8eef96df8 Mon Sep 17 00:00:00 2001 From: David Garske Date: Mon, 30 Dec 2019 18:05:25 -0800 Subject: [PATCH 2/9] Use `byte` for bit-field. Line length cleanup. --- wolfcrypt/test/test.c | 30 ++++++++++++++++++--------- wolfssl/wolfcrypt/chacha20_poly1305.h | 2 +- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index b0c3fe99f..b638d14ba 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -5167,13 +5167,16 @@ int chacha20_poly1305_aead_test(void) #ifndef NO_CHACHAPOLY_AEAD_IUF /* AEAD init/update/final */ - err = wc_ChaCha20Poly1305_Init(NULL, key1, iv1, 0); + err = wc_ChaCha20Poly1305_Init(NULL, key1, iv1, + CHACHA20_POLY1305_AEAD_DECRYPT); if (err != BAD_FUNC_ARG) return -4520; - err = wc_ChaCha20Poly1305_Init(&aead, NULL, iv1, 0); + err = wc_ChaCha20Poly1305_Init(&aead, NULL, iv1, + CHACHA20_POLY1305_AEAD_DECRYPT); if (err != BAD_FUNC_ARG) return -4521; - err = wc_ChaCha20Poly1305_Init(&aead, key1, NULL, 0); + err = wc_ChaCha20Poly1305_Init(&aead, key1, NULL, + CHACHA20_POLY1305_AEAD_DECRYPT); if (err != BAD_FUNC_ARG) return -4522; err = wc_ChaCha20Poly1305_UpdateAad(NULL, aad1, sizeof(aad1)); @@ -5182,7 +5185,8 @@ int chacha20_poly1305_aead_test(void) err = wc_ChaCha20Poly1305_UpdateAad(&aead, NULL, sizeof(aad1)); if (err != BAD_FUNC_ARG) return -4524; - err = wc_ChaCha20Poly1305_UpdateData(NULL, generatedPlaintext, sizeof(plaintext1)); + err = wc_ChaCha20Poly1305_UpdateData(NULL, generatedPlaintext, + sizeof(plaintext1)); if (err != BAD_FUNC_ARG) return -4525; err = wc_ChaCha20Poly1305_UpdateData(&aead, NULL, sizeof(plaintext1)); @@ -5209,11 +5213,13 @@ int chacha20_poly1305_aead_test(void) if (err != BAD_STATE_E) return -4531; aead.state = CHACHA20_POLY1305_STATE_INIT; - err = wc_ChaCha20Poly1305_UpdateData(&aead, generatedPlaintext, sizeof(plaintext1)); + err = wc_ChaCha20Poly1305_UpdateData(&aead, generatedPlaintext, + sizeof(plaintext1)); if (err != BAD_STATE_E) return -4532; aead.state = CHACHA20_POLY1305_STATE_FINAL; - err = wc_ChaCha20Poly1305_UpdateData(&aead, generatedPlaintext, sizeof(plaintext1)); + err = wc_ChaCha20Poly1305_UpdateData(&aead, generatedPlaintext, + sizeof(plaintext1)); if (err != BAD_STATE_E) return -4533; aead.state = CHACHA20_POLY1305_STATE_INIT; @@ -5234,7 +5240,8 @@ int chacha20_poly1305_aead_test(void) XMEMSET(generatedPlaintext, 0, sizeof(generatedPlaintext)); /* Test 1 - Encrypt */ - err = wc_ChaCha20Poly1305_Init(&aead, key1, iv1, 1); + err = wc_ChaCha20Poly1305_Init(&aead, key1, iv1, + CHACHA20_POLY1305_AEAD_ENCRYPT); if (err != 0) return -4537; err = wc_ChaCha20Poly1305_UpdateAad(&aead, aad1, sizeof(aad1)); @@ -5269,7 +5276,8 @@ int chacha20_poly1305_aead_test(void) } /* Test 1 - Decrypt */ - err = wc_ChaCha20Poly1305_Init(&aead, key1, iv1, 0); + err = wc_ChaCha20Poly1305_Init(&aead, key1, iv1, + CHACHA20_POLY1305_AEAD_DECRYPT); if (err != 0) return -4543; err = wc_ChaCha20Poly1305_UpdateAad(&aead, aad1, sizeof(aad1)); @@ -5309,7 +5317,8 @@ int chacha20_poly1305_aead_test(void) XMEMSET(generatedPlaintext, 0, sizeof(generatedPlaintext)); /* Test 2 - Encrypt */ - err = wc_ChaCha20Poly1305_Init(&aead, key2, iv2, 1); + err = wc_ChaCha20Poly1305_Init(&aead, key2, iv2, + CHACHA20_POLY1305_AEAD_ENCRYPT); if (err != 0) return -4550; err = wc_ChaCha20Poly1305_UpdateAad(&aead, aad2, sizeof(aad2)); @@ -5344,7 +5353,8 @@ int chacha20_poly1305_aead_test(void) } /* Test 2 - Decrypt */ - err = wc_ChaCha20Poly1305_Init(&aead, key2, iv2, 0); + err = wc_ChaCha20Poly1305_Init(&aead, key2, iv2, + CHACHA20_POLY1305_AEAD_DECRYPT); if (err != 0) return -4556; err = wc_ChaCha20Poly1305_UpdateAad(&aead, aad2, sizeof(aad2)); diff --git a/wolfssl/wolfcrypt/chacha20_poly1305.h b/wolfssl/wolfcrypt/chacha20_poly1305.h index 4754b17ae..ec101b133 100644 --- a/wolfssl/wolfcrypt/chacha20_poly1305.h +++ b/wolfssl/wolfcrypt/chacha20_poly1305.h @@ -69,7 +69,7 @@ typedef struct ChaChaPoly_Aead { word32 dataLen; byte state; - word32 isEncrypt:1; + byte isEncrypt:1; } ChaChaPoly_Aead; From f01999b322b32417579fe39ab055b55ac9193faf Mon Sep 17 00:00:00 2001 From: David Garske Date: Tue, 31 Dec 2019 08:08:33 -0800 Subject: [PATCH 3/9] Peer review feedback. --- wolfcrypt/src/chacha20_poly1305.c | 4 +++- wolfcrypt/test/test.c | 25 ++++++++----------------- wolfssl/wolfcrypt/chacha20_poly1305.h | 1 - 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/wolfcrypt/src/chacha20_poly1305.c b/wolfcrypt/src/chacha20_poly1305.c index d348d2c08..1aaba0280 100644 --- a/wolfcrypt/src/chacha20_poly1305.c +++ b/wolfcrypt/src/chacha20_poly1305.c @@ -166,6 +166,9 @@ int wc_ChaCha20Poly1305_CheckTag( const byte authTagChk[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE]) { int ret = 0; + if (authTag == NULL || authTagChk == NULL) { + return BAD_FUNC_ARG; + } if (ConstantCompare(authTag, authTagChk, CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE) != 0) { ret = MAC_CMP_FAILED_E; @@ -383,7 +386,6 @@ int wc_ChaCha20Poly1305_Final(ChaChaPoly_Aead* aead, if (aead->state != CHACHA20_POLY1305_STATE_DATA) { return BAD_STATE_E; } - aead->state = CHACHA20_POLY1305_STATE_FINAL; /* Pad the ciphertext to 16 bytes */ paddingLen = -(int)aead->dataLen & diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index b638d14ba..6462d5e78 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -5030,8 +5030,8 @@ int chacha20_poly1305_aead_test(void) 0x39, 0x23, 0x36, 0xfe, 0xa1, 0x85, 0x1f, 0x38 }; - byte generatedCiphertext[272]; - byte generatedPlaintext[272]; + byte generatedCiphertext[265]; /* max plaintext2/cipher2 */ + byte generatedPlaintext[265]; /* max plaintext2/cipher2 */ byte generatedAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE]; int err; #ifndef NO_CHACHAPOLY_AEAD_IUF @@ -5208,32 +5208,23 @@ int chacha20_poly1305_aead_test(void) err = wc_ChaCha20Poly1305_UpdateAad(&aead, aad1, sizeof(aad1)); if (err != BAD_STATE_E) return -4530; - aead.state = CHACHA20_POLY1305_STATE_FINAL; - err = wc_ChaCha20Poly1305_UpdateAad(&aead, aad1, sizeof(aad1)); + aead.state = CHACHA20_POLY1305_STATE_INIT; + err = wc_ChaCha20Poly1305_UpdateData(&aead, generatedPlaintext, + sizeof(plaintext1)); if (err != BAD_STATE_E) return -4531; aead.state = CHACHA20_POLY1305_STATE_INIT; - err = wc_ChaCha20Poly1305_UpdateData(&aead, generatedPlaintext, - sizeof(plaintext1)); - if (err != BAD_STATE_E) - return -4532; - aead.state = CHACHA20_POLY1305_STATE_FINAL; - err = wc_ChaCha20Poly1305_UpdateData(&aead, generatedPlaintext, - sizeof(plaintext1)); - if (err != BAD_STATE_E) - return -4533; - aead.state = CHACHA20_POLY1305_STATE_INIT; err = wc_ChaCha20Poly1305_Final(&aead, generatedAuthTag); if (err != BAD_STATE_E) - return -4534; + return -4532; aead.state = CHACHA20_POLY1305_STATE_READY; err = wc_ChaCha20Poly1305_Final(&aead, generatedAuthTag); if (err != BAD_STATE_E) - return -4535; + return -4533; aead.state = CHACHA20_POLY1305_STATE_AAD; err = wc_ChaCha20Poly1305_Final(&aead, generatedAuthTag); if (err != BAD_STATE_E) - return -4536; + return -4534; XMEMSET(generatedCiphertext, 0, sizeof(generatedCiphertext)); XMEMSET(generatedAuthTag, 0, sizeof(generatedAuthTag)); diff --git a/wolfssl/wolfcrypt/chacha20_poly1305.h b/wolfssl/wolfcrypt/chacha20_poly1305.h index ec101b133..d19aafae2 100644 --- a/wolfssl/wolfcrypt/chacha20_poly1305.h +++ b/wolfssl/wolfcrypt/chacha20_poly1305.h @@ -58,7 +58,6 @@ enum { CHACHA20_POLY1305_STATE_READY = 1, CHACHA20_POLY1305_STATE_AAD = 2, CHACHA20_POLY1305_STATE_DATA = 3, - CHACHA20_POLY1305_STATE_FINAL = 4, }; typedef struct ChaChaPoly_Aead { From bff6dcec248cb3e7a67d037a1b7b6db606981cbf Mon Sep 17 00:00:00 2001 From: David Garske Date: Tue, 31 Dec 2019 08:25:23 -0800 Subject: [PATCH 4/9] Added support for AAD calc only. Allows Init, UpdateAad and Final sequence. Verfied again with customer test cases. --- wolfcrypt/src/chacha20_poly1305.c | 56 ++++++++++++++++++++----------- wolfcrypt/test/test.c | 4 --- 2 files changed, 37 insertions(+), 23 deletions(-) diff --git a/wolfcrypt/src/chacha20_poly1305.c b/wolfcrypt/src/chacha20_poly1305.c index 1aaba0280..4d93f3643 100644 --- a/wolfcrypt/src/chacha20_poly1305.c +++ b/wolfcrypt/src/chacha20_poly1305.c @@ -327,6 +327,28 @@ int wc_ChaCha20Poly1305_UpdateAad(ChaChaPoly_Aead* aead, return ret; } +static int wc_ChaCha20Poly1305_CalcAad(ChaChaPoly_Aead* aead) +{ + int ret = 0; + if (aead == NULL) { + return BAD_FUNC_ARG; + } + if (aead->state == CHACHA20_POLY1305_STATE_AAD) { + /* Pad the AAD to 16 bytes */ + byte padding[CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1]; + word32 paddingLen = -(int)aead->aadLen & + (CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1); + if (paddingLen > 0) { + XMEMSET(padding, 0, paddingLen); + ret = wc_Poly1305Update(&aead->poly, padding, paddingLen); + } + + /* advance state */ + aead->state = CHACHA20_POLY1305_STATE_DATA; + } + return ret; +} + int wc_ChaCha20Poly1305_UpdateData(ChaChaPoly_Aead* aead, byte* data, word32 dataLen) { @@ -341,17 +363,8 @@ int wc_ChaCha20Poly1305_UpdateData(ChaChaPoly_Aead* aead, return BAD_STATE_E; } - if (aead->state == CHACHA20_POLY1305_STATE_AAD) { - /* Pad the AAD to 16 bytes */ - byte padding[CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1]; - word32 paddingLen = -(int)aead->aadLen & - (CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1); - if (paddingLen > 0) { - XMEMSET(padding, 0, paddingLen); - ret = wc_Poly1305Update(&aead->poly, padding, paddingLen); - } - } - aead->state = CHACHA20_POLY1305_STATE_DATA; + /* calculate AAD */ + ret = wc_ChaCha20Poly1305_CalcAad(aead); if (ret == 0) { /* Perform ChaCha20 encrypt or decrypt inline and Poly1305 auth calc */ @@ -376,27 +389,32 @@ int wc_ChaCha20Poly1305_Final(ChaChaPoly_Aead* aead, byte outAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE]) { int ret = 0; - byte padding[CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1]; - word32 paddingLen; - byte little64[16]; /* word64 * 2 */ if (aead == NULL || outAuthTag == NULL) { return BAD_FUNC_ARG; } + + /* make sure AAD is calculated */ + ret = wc_ChaCha20Poly1305_CalcAad(aead); + if (aead->state != CHACHA20_POLY1305_STATE_DATA) { return BAD_STATE_E; } /* Pad the ciphertext to 16 bytes */ - paddingLen = -(int)aead->dataLen & - (CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1); - if (paddingLen > 0) { - XMEMSET(padding, 0, paddingLen); - ret = wc_Poly1305Update(&aead->poly, padding, paddingLen); + if (ret == 0) { + byte padding[CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1]; + word32 paddingLen = -(int)aead->dataLen & + (CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1); + if (paddingLen > 0) { + XMEMSET(padding, 0, paddingLen); + ret = wc_Poly1305Update(&aead->poly, padding, paddingLen); + } } /* Add the aad and ciphertext length */ if (ret == 0) { + byte little64[16]; /* word64 * 2 */ /* AAD length as a 64-bit little endian integer */ word32ToLittle64(aead->aadLen, little64); /* Ciphertext length as a 64-bit little endian integer */ diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 6462d5e78..0b749cfdf 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -5221,10 +5221,6 @@ int chacha20_poly1305_aead_test(void) err = wc_ChaCha20Poly1305_Final(&aead, generatedAuthTag); if (err != BAD_STATE_E) return -4533; - aead.state = CHACHA20_POLY1305_STATE_AAD; - err = wc_ChaCha20Poly1305_Final(&aead, generatedAuthTag); - if (err != BAD_STATE_E) - return -4534; XMEMSET(generatedCiphertext, 0, sizeof(generatedCiphertext)); XMEMSET(generatedAuthTag, 0, sizeof(generatedAuthTag)); From 784d95afbec81827e5a6dd5380cc171a64e5d9ce Mon Sep 17 00:00:00 2001 From: David Garske Date: Tue, 31 Dec 2019 10:34:06 -0800 Subject: [PATCH 5/9] Improved state handling. --- wolfcrypt/src/chacha20_poly1305.c | 39 +++++++++++++++---------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/wolfcrypt/src/chacha20_poly1305.c b/wolfcrypt/src/chacha20_poly1305.c index 4d93f3643..1657f188d 100644 --- a/wolfcrypt/src/chacha20_poly1305.c +++ b/wolfcrypt/src/chacha20_poly1305.c @@ -329,22 +329,14 @@ int wc_ChaCha20Poly1305_UpdateAad(ChaChaPoly_Aead* aead, static int wc_ChaCha20Poly1305_CalcAad(ChaChaPoly_Aead* aead) { + /* Pad the AAD to 16 bytes */ int ret = 0; - if (aead == NULL) { - return BAD_FUNC_ARG; - } - if (aead->state == CHACHA20_POLY1305_STATE_AAD) { - /* Pad the AAD to 16 bytes */ - byte padding[CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1]; - word32 paddingLen = -(int)aead->aadLen & - (CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1); - if (paddingLen > 0) { - XMEMSET(padding, 0, paddingLen); - ret = wc_Poly1305Update(&aead->poly, padding, paddingLen); - } - - /* advance state */ - aead->state = CHACHA20_POLY1305_STATE_DATA; + byte padding[CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1]; + word32 paddingLen = -(int)aead->aadLen & + (CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1); + if (paddingLen > 0) { + XMEMSET(padding, 0, paddingLen); + ret = wc_Poly1305Update(&aead->poly, padding, paddingLen); } return ret; } @@ -364,7 +356,12 @@ int wc_ChaCha20Poly1305_UpdateData(ChaChaPoly_Aead* aead, } /* calculate AAD */ - ret = wc_ChaCha20Poly1305_CalcAad(aead); + if (aead->state == CHACHA20_POLY1305_STATE_AAD) { + ret = wc_ChaCha20Poly1305_CalcAad(aead); + } + + /* advance state */ + aead->state = CHACHA20_POLY1305_STATE_DATA; if (ret == 0) { /* Perform ChaCha20 encrypt or decrypt inline and Poly1305 auth calc */ @@ -393,12 +390,14 @@ int wc_ChaCha20Poly1305_Final(ChaChaPoly_Aead* aead, if (aead == NULL || outAuthTag == NULL) { return BAD_FUNC_ARG; } + if (aead->state != CHACHA20_POLY1305_STATE_AAD && + aead->state != CHACHA20_POLY1305_STATE_DATA) { + return BAD_STATE_E; + } /* make sure AAD is calculated */ - ret = wc_ChaCha20Poly1305_CalcAad(aead); - - if (aead->state != CHACHA20_POLY1305_STATE_DATA) { - return BAD_STATE_E; + if (aead->state == CHACHA20_POLY1305_STATE_AAD) { + ret = wc_ChaCha20Poly1305_CalcAad(aead); } /* Pad the ciphertext to 16 bytes */ From 01c7cc6502b3aadd018548377c72cc61a354cec8 Mon Sep 17 00:00:00 2001 From: David Garske Date: Tue, 31 Dec 2019 11:43:13 -0800 Subject: [PATCH 6/9] Fixes to avoid declaring any variables mid-function and always initializing. --- wolfcrypt/src/chacha20_poly1305.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/wolfcrypt/src/chacha20_poly1305.c b/wolfcrypt/src/chacha20_poly1305.c index 1657f188d..b645861f1 100644 --- a/wolfcrypt/src/chacha20_poly1305.c +++ b/wolfcrypt/src/chacha20_poly1305.c @@ -329,13 +329,16 @@ int wc_ChaCha20Poly1305_UpdateAad(ChaChaPoly_Aead* aead, static int wc_ChaCha20Poly1305_CalcAad(ChaChaPoly_Aead* aead) { - /* Pad the AAD to 16 bytes */ int ret = 0; + word32 paddingLen; byte padding[CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1]; - word32 paddingLen = -(int)aead->aadLen & + + XMEMSET(padding, 0, sizeof(padding)); + + /* Pad the AAD to 16 bytes */ + paddingLen = -(int)aead->aadLen & (CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1); if (paddingLen > 0) { - XMEMSET(padding, 0, paddingLen); ret = wc_Poly1305Update(&aead->poly, padding, paddingLen); } return ret; @@ -386,6 +389,9 @@ int wc_ChaCha20Poly1305_Final(ChaChaPoly_Aead* aead, byte outAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE]) { int ret = 0; + word32 paddingLen; + byte padding[CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1]; + byte little64[16]; /* word64 * 2 */ if (aead == NULL || outAuthTag == NULL) { return BAD_FUNC_ARG; @@ -395,6 +401,9 @@ int wc_ChaCha20Poly1305_Final(ChaChaPoly_Aead* aead, return BAD_STATE_E; } + XMEMSET(padding, 0, sizeof(padding)); + XMEMSET(little64, 0, sizeof(little64)); + /* make sure AAD is calculated */ if (aead->state == CHACHA20_POLY1305_STATE_AAD) { ret = wc_ChaCha20Poly1305_CalcAad(aead); @@ -402,18 +411,15 @@ int wc_ChaCha20Poly1305_Final(ChaChaPoly_Aead* aead, /* Pad the ciphertext to 16 bytes */ if (ret == 0) { - byte padding[CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1]; - word32 paddingLen = -(int)aead->dataLen & + paddingLen = -(int)aead->dataLen & (CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1); if (paddingLen > 0) { - XMEMSET(padding, 0, paddingLen); ret = wc_Poly1305Update(&aead->poly, padding, paddingLen); } } /* Add the aad and ciphertext length */ if (ret == 0) { - byte little64[16]; /* word64 * 2 */ /* AAD length as a 64-bit little endian integer */ word32ToLittle64(aead->aadLen, little64); /* Ciphertext length as a 64-bit little endian integer */ From d68d5229e1ddb0aa6949d42cf53546a919484084 Mon Sep 17 00:00:00 2001 From: David Garske Date: Mon, 6 Jan 2020 17:07:09 -0800 Subject: [PATCH 7/9] Refactor `wc_ChaCha20Poly1305_Encrypt` and `wc_ChaCha20Poly1305_Decrypt` to use the new `ChaChaPoly_Aead` context and init/update/final functions. --- wolfcrypt/src/chacha20_poly1305.c | 206 ++++++-------------------- wolfcrypt/test/test.c | 50 +++---- wolfssl/wolfcrypt/chacha20_poly1305.h | 6 +- 3 files changed, 73 insertions(+), 189 deletions(-) diff --git a/wolfcrypt/src/chacha20_poly1305.c b/wolfcrypt/src/chacha20_poly1305.c index b645861f1..91b45d16e 100644 --- a/wolfcrypt/src/chacha20_poly1305.c +++ b/wolfcrypt/src/chacha20_poly1305.c @@ -47,12 +47,20 @@ #define CHACHA20_POLY1305_AEAD_INITIAL_COUNTER 0 #define CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT 16 -static void word32ToLittle64(const word32 inLittle32, byte outLittle64[8]); -static int calculateAuthTag( - const byte inAuthKey[CHACHA20_POLY1305_AEAD_KEYSIZE], - const byte* inAAD, const word32 inAADLen, - const byte *inCiphertext, const word32 inCiphertextLen, - byte outAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE]); + +static void word32ToLittle64(const word32 inLittle32, byte outLittle64[8]) +{ +#ifndef WOLFSSL_X86_64_BUILD + XMEMSET(outLittle64 + 4, 0, 4); + + outLittle64[0] = (byte)(inLittle32 & 0x000000FF); + outLittle64[1] = (byte)((inLittle32 & 0x0000FF00) >> 8); + outLittle64[2] = (byte)((inLittle32 & 0x00FF0000) >> 16); + outLittle64[3] = (byte)((inLittle32 & 0xFF000000) >> 24); +#else + *(word64*)outLittle64 = inLittle32; +#endif +} int wc_ChaCha20Poly1305_Encrypt( const byte inKey[CHACHA20_POLY1305_AEAD_KEYSIZE], @@ -62,12 +70,10 @@ int wc_ChaCha20Poly1305_Encrypt( byte* outCiphertext, byte outAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE]) { - int err; - byte poly1305Key[CHACHA20_POLY1305_AEAD_KEYSIZE]; - ChaCha chaChaCtx; + int ret; + ChaChaPoly_Aead aead; /* Validate function arguments */ - if (!inKey || !inIV || !inPlaintext || !inPlaintextLen || !outCiphertext || @@ -76,32 +82,16 @@ int wc_ChaCha20Poly1305_Encrypt( return BAD_FUNC_ARG; } - XMEMSET(poly1305Key, 0, sizeof(poly1305Key)); - - /* Create the Poly1305 key */ - err = wc_Chacha_SetKey(&chaChaCtx, inKey, CHACHA20_POLY1305_AEAD_KEYSIZE); - if (err != 0) return err; - - err = wc_Chacha_SetIV(&chaChaCtx, inIV, - CHACHA20_POLY1305_AEAD_INITIAL_COUNTER); - if (err != 0) return err; - - err = wc_Chacha_Process(&chaChaCtx, poly1305Key, poly1305Key, - CHACHA20_POLY1305_AEAD_KEYSIZE); - if (err != 0) return err; - - /* Encrypt the plaintext using ChaCha20 */ - err = wc_Chacha_Process(&chaChaCtx, outCiphertext, inPlaintext, - inPlaintextLen); - /* Calculate the Poly1305 auth tag */ - if (err == 0) - err = calculateAuthTag(poly1305Key, - inAAD, inAADLen, - outCiphertext, inPlaintextLen, - outAuthTag); - ForceZero(poly1305Key, sizeof(poly1305Key)); - - return err; + ret = wc_ChaCha20Poly1305_Init(&aead, inKey, inIV, + CHACHA20_POLY1305_AEAD_ENCRYPT); + if (ret == 0) + ret = wc_ChaCha20Poly1305_UpdateAad(&aead, inAAD, inAADLen); + if (ret == 0) + ret = wc_ChaCha20Poly1305_UpdateData(&aead, inPlaintext, outCiphertext, + inPlaintextLen); + if (ret == 0) + ret = wc_ChaCha20Poly1305_Final(&aead, outAuthTag); + return ret; } @@ -113,9 +103,8 @@ int wc_ChaCha20Poly1305_Decrypt( const byte inAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE], byte* outPlaintext) { - int err; - byte poly1305Key[CHACHA20_POLY1305_AEAD_KEYSIZE]; - ChaCha chaChaCtx; + int ret; + ChaChaPoly_Aead aead; byte calculatedAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE]; /* Validate function arguments */ @@ -128,37 +117,19 @@ int wc_ChaCha20Poly1305_Decrypt( } XMEMSET(calculatedAuthTag, 0, sizeof(calculatedAuthTag)); - XMEMSET(poly1305Key, 0, sizeof(poly1305Key)); - /* Create the Poly1305 key */ - err = wc_Chacha_SetKey(&chaChaCtx, inKey, CHACHA20_POLY1305_AEAD_KEYSIZE); - if (err != 0) return err; - - err = wc_Chacha_SetIV(&chaChaCtx, inIV, - CHACHA20_POLY1305_AEAD_INITIAL_COUNTER); - if (err != 0) return err; - - err = wc_Chacha_Process(&chaChaCtx, poly1305Key, poly1305Key, - CHACHA20_POLY1305_AEAD_KEYSIZE); - if (err != 0) return err; - - /* Calculate the Poly1305 auth tag */ - err = calculateAuthTag(poly1305Key, - inAAD, inAADLen, - inCiphertext, inCiphertextLen, - calculatedAuthTag); - - /* Compare the calculated auth tag with the received one */ - if (err == 0) - err = wc_ChaCha20Poly1305_CheckTag(inAuthTag, calculatedAuthTag); - - /* Decrypt the received ciphertext */ - if (err == 0) - err = wc_Chacha_Process(&chaChaCtx, outPlaintext, inCiphertext, - inCiphertextLen); - ForceZero(poly1305Key, sizeof(poly1305Key)); - - return err; + ret = wc_ChaCha20Poly1305_Init(&aead, inKey, inIV, + CHACHA20_POLY1305_AEAD_DECRYPT); + if (ret == 0) + ret = wc_ChaCha20Poly1305_UpdateAad(&aead, inAAD, inAADLen); + if (ret == 0) + ret = wc_ChaCha20Poly1305_UpdateData(&aead, inCiphertext, outPlaintext, + inCiphertextLen); + if (ret == 0) + ret = wc_ChaCha20Poly1305_Final(&aead, calculatedAuthTag); + if (ret == 0) + ret = wc_ChaCha20Poly1305_CheckTag(inAuthTag, calculatedAuthTag); + return ret; } int wc_ChaCha20Poly1305_CheckTag( @@ -176,87 +147,6 @@ int wc_ChaCha20Poly1305_CheckTag( return ret; } -static int calculateAuthTag( - const byte inAuthKey[CHACHA20_POLY1305_AEAD_KEYSIZE], - const byte *inAAD, const word32 inAADLen, - const byte *inCiphertext, const word32 inCiphertextLen, - byte outAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE]) -{ - int err; - Poly1305 poly1305Ctx; - byte padding[CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1]; - word32 paddingLen; - byte little64[16]; - - XMEMSET(padding, 0, sizeof(padding)); - - /* Initialize Poly1305 */ - err = wc_Poly1305SetKey(&poly1305Ctx, inAuthKey, - CHACHA20_POLY1305_AEAD_KEYSIZE); - if (err) - return err; - - /* Create the authTag by MAC'ing the following items: */ - /* -- AAD */ - if (inAAD && inAADLen) - { - err = wc_Poly1305Update(&poly1305Ctx, inAAD, inAADLen); - /* -- padding1: pad the AAD to 16 bytes */ - paddingLen = -(int)inAADLen & - (CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1); - if (paddingLen) - err += wc_Poly1305Update(&poly1305Ctx, padding, paddingLen); - - if (err) - return err; - } - - /* -- Ciphertext */ - err = wc_Poly1305Update(&poly1305Ctx, inCiphertext, inCiphertextLen); - if (err) - return err; - - /* -- padding2: pad the ciphertext to 16 bytes */ - paddingLen = -(int)inCiphertextLen & - (CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1); - if (paddingLen) - { - err = wc_Poly1305Update(&poly1305Ctx, padding, paddingLen); - if (err) - return err; - } - - /* -- AAD length as a 64-bit little endian integer */ - word32ToLittle64(inAADLen, little64); - /* -- Ciphertext length as a 64-bit little endian integer */ - word32ToLittle64(inCiphertextLen, little64 + 8); - err = wc_Poly1305Update(&poly1305Ctx, little64, sizeof(little64)); - if (err) - return err; - - /* Finalize the auth tag */ - err = wc_Poly1305Final(&poly1305Ctx, outAuthTag); - - return err; -} - - -static void word32ToLittle64(const word32 inLittle32, byte outLittle64[8]) -{ -#ifndef WOLFSSL_X86_64_BUILD - XMEMSET(outLittle64 + 4, 0, 4); - - outLittle64[0] = (byte)(inLittle32 & 0x000000FF); - outLittle64[1] = (byte)((inLittle32 & 0x0000FF00) >> 8); - outLittle64[2] = (byte)((inLittle32 & 0x00FF0000) >> 16); - outLittle64[3] = (byte)((inLittle32 & 0xFF000000) >> 24); -#else - *(word64*)outLittle64 = inLittle32; -#endif -} - - -#ifndef NO_CHACHAPOLY_AEAD_IUF int wc_ChaCha20Poly1305_Init(ChaChaPoly_Aead* aead, const byte inKey[CHACHA20_POLY1305_AEAD_KEYSIZE], const byte inIV[CHACHA20_POLY1305_AEAD_IV_SIZE], @@ -344,12 +234,13 @@ static int wc_ChaCha20Poly1305_CalcAad(ChaChaPoly_Aead* aead) return ret; } +/* inData and outData can be same pointer (inline) */ int wc_ChaCha20Poly1305_UpdateData(ChaChaPoly_Aead* aead, - byte* data, word32 dataLen) + const byte* inData, byte* outData, word32 dataLen) { int ret = 0; - if (aead == NULL || data == NULL) { + if (aead == NULL || inData == NULL || outData == NULL) { return BAD_FUNC_ARG; } if (aead->state != CHACHA20_POLY1305_STATE_READY && @@ -366,17 +257,17 @@ int wc_ChaCha20Poly1305_UpdateData(ChaChaPoly_Aead* aead, /* advance state */ aead->state = CHACHA20_POLY1305_STATE_DATA; + /* Perform ChaCha20 encrypt or decrypt inline and Poly1305 auth calc */ if (ret == 0) { - /* Perform ChaCha20 encrypt or decrypt inline and Poly1305 auth calc */ if (aead->isEncrypt) { - ret = wc_Chacha_Process(&aead->chacha, data, data, dataLen); + ret = wc_Chacha_Process(&aead->chacha, outData, inData, dataLen); if (ret == 0) - ret = wc_Poly1305Update(&aead->poly, data, dataLen); + ret = wc_Poly1305Update(&aead->poly, outData, dataLen); } else { - ret = wc_Poly1305Update(&aead->poly, data, dataLen); + ret = wc_Poly1305Update(&aead->poly, inData, dataLen); if (ret == 0) - ret = wc_Chacha_Process(&aead->chacha, data, data, dataLen); + ret = wc_Chacha_Process(&aead->chacha, outData, inData, dataLen); } } if (ret == 0) { @@ -439,6 +330,5 @@ int wc_ChaCha20Poly1305_Final(ChaChaPoly_Aead* aead, return ret; } -#endif /* !NO_CHACHAPOLY_AEAD_IUF */ #endif /* HAVE_CHACHA && HAVE_POLY1305 */ diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 0b749cfdf..66b28d5d5 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -5034,13 +5034,12 @@ int chacha20_poly1305_aead_test(void) byte generatedPlaintext[265]; /* max plaintext2/cipher2 */ byte generatedAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE]; int err; -#ifndef NO_CHACHAPOLY_AEAD_IUF + ChaChaPoly_Aead aead; #define TEST_SMALL_CHACHA_CHUNKS 64 #ifdef TEST_SMALL_CHACHA_CHUNKS word32 testLen; #endif -#endif XMEMSET(generatedCiphertext, 0, sizeof(generatedCiphertext)); XMEMSET(generatedAuthTag, 0, sizeof(generatedAuthTag)); @@ -5165,7 +5164,6 @@ int chacha20_poly1305_aead_test(void) } -#ifndef NO_CHACHAPOLY_AEAD_IUF /* AEAD init/update/final */ err = wc_ChaCha20Poly1305_Init(NULL, key1, iv1, CHACHA20_POLY1305_AEAD_DECRYPT); @@ -5186,10 +5184,15 @@ int chacha20_poly1305_aead_test(void) if (err != BAD_FUNC_ARG) return -4524; err = wc_ChaCha20Poly1305_UpdateData(NULL, generatedPlaintext, - sizeof(plaintext1)); + generatedPlaintext, sizeof(plaintext1)); if (err != BAD_FUNC_ARG) return -4525; - err = wc_ChaCha20Poly1305_UpdateData(&aead, NULL, sizeof(plaintext1)); + err = wc_ChaCha20Poly1305_UpdateData(&aead, generatedPlaintext, NULL, + sizeof(plaintext1)); + if (err != BAD_FUNC_ARG) + return -4526; + err = wc_ChaCha20Poly1305_UpdateData(&aead, NULL, generatedPlaintext, + sizeof(plaintext1)); if (err != BAD_FUNC_ARG) return -4526; err = wc_ChaCha20Poly1305_Final(NULL, generatedAuthTag); @@ -5210,7 +5213,7 @@ int chacha20_poly1305_aead_test(void) return -4530; aead.state = CHACHA20_POLY1305_STATE_INIT; err = wc_ChaCha20Poly1305_UpdateData(&aead, generatedPlaintext, - sizeof(plaintext1)); + generatedPlaintext, sizeof(plaintext1)); if (err != BAD_STATE_E) return -4531; aead.state = CHACHA20_POLY1305_STATE_INIT; @@ -5240,17 +5243,15 @@ int chacha20_poly1305_aead_test(void) word32 dataLen = sizeof(plaintext1) - testLen; if (dataLen > TEST_SMALL_CHACHA_CHUNKS) dataLen = TEST_SMALL_CHACHA_CHUNKS; - XMEMCPY(&generatedCiphertext[testLen], &plaintext1[testLen], dataLen); - err = wc_ChaCha20Poly1305_UpdateData(&aead, + err = wc_ChaCha20Poly1305_UpdateData(&aead, &plaintext1[testLen], &generatedCiphertext[testLen], dataLen); if (err != 0) return -4539; testLen += dataLen; } #else - XMEMCPY(generatedCiphertext, plaintext1, sizeof(plaintext1)); - err = wc_ChaCha20Poly1305_UpdateData(&aead, generatedCiphertext, - sizeof(plaintext1)); + err = wc_ChaCha20Poly1305_UpdateData(&aead, plaintext1, + generatedCiphertext, sizeof(plaintext1)); #endif err = wc_ChaCha20Poly1305_Final(&aead, generatedAuthTag); if (err != 0) @@ -5276,18 +5277,16 @@ int chacha20_poly1305_aead_test(void) word32 dataLen = sizeof(plaintext1) - testLen; if (dataLen > TEST_SMALL_CHACHA_CHUNKS) dataLen = TEST_SMALL_CHACHA_CHUNKS; - XMEMCPY(&generatedPlaintext[testLen], &generatedCiphertext[testLen], - dataLen); err = wc_ChaCha20Poly1305_UpdateData(&aead, - &generatedPlaintext[testLen], dataLen); + &generatedCiphertext[testLen], &generatedPlaintext[testLen], + dataLen); if (err != 0) return -4545; testLen += dataLen; } #else - XMEMCPY(generatedPlaintext, generatedCiphertext, sizeof(cipher1)); - err = wc_ChaCha20Poly1305_UpdateData(&aead, generatedPlaintext, - sizeof(cipher1)); + err = wc_ChaCha20Poly1305_UpdateData(&aead, generatedCiphertext, + generatedPlaintext, sizeof(cipher1)); #endif err = wc_ChaCha20Poly1305_Final(&aead, generatedAuthTag); if (err != 0) @@ -5317,16 +5316,14 @@ int chacha20_poly1305_aead_test(void) word32 dataLen = sizeof(plaintext2) - testLen; if (dataLen > TEST_SMALL_CHACHA_CHUNKS) dataLen = TEST_SMALL_CHACHA_CHUNKS; - XMEMCPY(&generatedCiphertext[testLen], &plaintext2[testLen], dataLen); - err = wc_ChaCha20Poly1305_UpdateData(&aead, + err = wc_ChaCha20Poly1305_UpdateData(&aead, &plaintext2[testLen], &generatedCiphertext[testLen], dataLen); if (err != 0) return -4552; testLen += dataLen; } #else - XMEMCPY(generatedCiphertext, plaintext2, sizeof(plaintext2)); - err = wc_ChaCha20Poly1305_UpdateData(&aead, generatedCiphertext, + err = wc_ChaCha20Poly1305_UpdateData(&aead, plaintext2, generatedCiphertext, sizeof(plaintext2)); #endif err = wc_ChaCha20Poly1305_Final(&aead, generatedAuthTag); @@ -5353,18 +5350,16 @@ int chacha20_poly1305_aead_test(void) word32 dataLen = sizeof(plaintext2) - testLen; if (dataLen > TEST_SMALL_CHACHA_CHUNKS) dataLen = TEST_SMALL_CHACHA_CHUNKS; - XMEMCPY(&generatedPlaintext[testLen], &generatedCiphertext[testLen], - dataLen); err = wc_ChaCha20Poly1305_UpdateData(&aead, - &generatedPlaintext[testLen], dataLen); + &generatedCiphertext[testLen], &generatedPlaintext[testLen], + dataLen); if (err != 0) return -4558; testLen += dataLen; } #else - XMEMCPY(generatedPlaintext, generatedCiphertext, sizeof(cipher2)); - err = wc_ChaCha20Poly1305_UpdateData(&aead, generatedPlaintext, - sizeof(cipher2)); + err = wc_ChaCha20Poly1305_UpdateData(&aead, generatedCiphertext, + generatedPlaintext, sizeof(cipher2)); #endif err = wc_ChaCha20Poly1305_Final(&aead, generatedAuthTag); if (err != 0) @@ -5375,7 +5370,6 @@ int chacha20_poly1305_aead_test(void) if (XMEMCMP(generatedPlaintext, plaintext2, sizeof(plaintext2))) { return -4561; } -#endif /* !NO_CHACHAPOLY_AEAD_IUF */ return err; } diff --git a/wolfssl/wolfcrypt/chacha20_poly1305.h b/wolfssl/wolfcrypt/chacha20_poly1305.h index d19aafae2..f654658ac 100644 --- a/wolfssl/wolfcrypt/chacha20_poly1305.h +++ b/wolfssl/wolfcrypt/chacha20_poly1305.h @@ -106,7 +106,7 @@ int wc_ChaCha20Poly1305_CheckTag( const byte authTagChk[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE]); -#ifndef NO_CHACHAPOLY_AEAD_IUF + /* Implementation of AEAD, which includes support for adding data, then final calculation of authentication tag */ WOLFSSL_API int wc_ChaCha20Poly1305_Init(ChaChaPoly_Aead* aead, @@ -116,10 +116,10 @@ WOLFSSL_API int wc_ChaCha20Poly1305_Init(ChaChaPoly_Aead* aead, WOLFSSL_API int wc_ChaCha20Poly1305_UpdateAad(ChaChaPoly_Aead* aead, const byte* inAAD, word32 inAADLen); WOLFSSL_API int wc_ChaCha20Poly1305_UpdateData(ChaChaPoly_Aead* aead, - byte* data, word32 dataLen); + const byte* inData, byte* outData, word32 dataLen); WOLFSSL_API int wc_ChaCha20Poly1305_Final(ChaChaPoly_Aead* aead, byte outAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE]); -#endif /* !NO_CHACHAPOLY_AEAD_IUF */ + #ifdef __cplusplus } /* extern "C" */ From 56e57f32166cd8a8e66d28e5f8e4ff1c87d33e84 Mon Sep 17 00:00:00 2001 From: David Garske Date: Tue, 7 Jan 2020 07:04:01 -0800 Subject: [PATCH 8/9] Refactor Poly1305 AEAD / MAC to reduce duplicate code. Tested with TLS v1.3 interop and AEAD test vectors. --- wolfcrypt/src/chacha20_poly1305.c | 70 +++------------------- wolfcrypt/src/poly1305.c | 98 ++++++++++++++++++++++--------- wolfssl/wolfcrypt/poly1305.h | 5 +- 3 files changed, 82 insertions(+), 91 deletions(-) diff --git a/wolfcrypt/src/chacha20_poly1305.c b/wolfcrypt/src/chacha20_poly1305.c index 91b45d16e..ddd3a576f 100644 --- a/wolfcrypt/src/chacha20_poly1305.c +++ b/wolfcrypt/src/chacha20_poly1305.c @@ -40,28 +40,7 @@ #include #endif -#ifdef CHACHA_AEAD_TEST -#include -#endif - #define CHACHA20_POLY1305_AEAD_INITIAL_COUNTER 0 -#define CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT 16 - - -static void word32ToLittle64(const word32 inLittle32, byte outLittle64[8]) -{ -#ifndef WOLFSSL_X86_64_BUILD - XMEMSET(outLittle64 + 4, 0, 4); - - outLittle64[0] = (byte)(inLittle32 & 0x000000FF); - outLittle64[1] = (byte)((inLittle32 & 0x0000FF00) >> 8); - outLittle64[2] = (byte)((inLittle32 & 0x00FF0000) >> 16); - outLittle64[3] = (byte)((inLittle32 & 0xFF000000) >> 24); -#else - *(word64*)outLittle64 = inLittle32; -#endif -} - int wc_ChaCha20Poly1305_Encrypt( const byte inKey[CHACHA20_POLY1305_AEAD_KEYSIZE], const byte inIV[CHACHA20_POLY1305_AEAD_IV_SIZE], @@ -94,7 +73,6 @@ int wc_ChaCha20Poly1305_Encrypt( return ret; } - int wc_ChaCha20Poly1305_Decrypt( const byte inKey[CHACHA20_POLY1305_AEAD_KEYSIZE], const byte inIV[CHACHA20_POLY1305_AEAD_IV_SIZE], @@ -217,23 +195,6 @@ int wc_ChaCha20Poly1305_UpdateAad(ChaChaPoly_Aead* aead, return ret; } -static int wc_ChaCha20Poly1305_CalcAad(ChaChaPoly_Aead* aead) -{ - int ret = 0; - word32 paddingLen; - byte padding[CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1]; - - XMEMSET(padding, 0, sizeof(padding)); - - /* Pad the AAD to 16 bytes */ - paddingLen = -(int)aead->aadLen & - (CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1); - if (paddingLen > 0) { - ret = wc_Poly1305Update(&aead->poly, padding, paddingLen); - } - return ret; -} - /* inData and outData can be same pointer (inline) */ int wc_ChaCha20Poly1305_UpdateData(ChaChaPoly_Aead* aead, const byte* inData, byte* outData, word32 dataLen) @@ -249,9 +210,9 @@ int wc_ChaCha20Poly1305_UpdateData(ChaChaPoly_Aead* aead, return BAD_STATE_E; } - /* calculate AAD */ + /* Pad the AAD */ if (aead->state == CHACHA20_POLY1305_STATE_AAD) { - ret = wc_ChaCha20Poly1305_CalcAad(aead); + ret = wc_Poly1305_Pad(&aead->poly, aead->aadLen); } /* advance state */ @@ -280,9 +241,6 @@ int wc_ChaCha20Poly1305_Final(ChaChaPoly_Aead* aead, byte outAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE]) { int ret = 0; - word32 paddingLen; - byte padding[CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1]; - byte little64[16]; /* word64 * 2 */ if (aead == NULL || outAuthTag == NULL) { return BAD_FUNC_ARG; @@ -292,31 +250,20 @@ int wc_ChaCha20Poly1305_Final(ChaChaPoly_Aead* aead, return BAD_STATE_E; } - XMEMSET(padding, 0, sizeof(padding)); - XMEMSET(little64, 0, sizeof(little64)); - - /* make sure AAD is calculated */ + /* Pad the AAD - Make sure it is done */ if (aead->state == CHACHA20_POLY1305_STATE_AAD) { - ret = wc_ChaCha20Poly1305_CalcAad(aead); + ret = wc_Poly1305_Pad(&aead->poly, aead->aadLen); } /* Pad the ciphertext to 16 bytes */ if (ret == 0) { - paddingLen = -(int)aead->dataLen & - (CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1); - if (paddingLen > 0) { - ret = wc_Poly1305Update(&aead->poly, padding, paddingLen); - } + ret = wc_Poly1305_Pad(&aead->poly, aead->dataLen); } - /* Add the aad and ciphertext length */ + /* Add the aad length and plaintext/ciphertext length */ if (ret == 0) { - /* AAD length as a 64-bit little endian integer */ - word32ToLittle64(aead->aadLen, little64); - /* Ciphertext length as a 64-bit little endian integer */ - word32ToLittle64(aead->dataLen, little64 + 8); - - ret = wc_Poly1305Update(&aead->poly, little64, sizeof(little64)); + ret = wc_Poly1305_EncodeSizes(&aead->poly, aead->aadLen, + aead->dataLen); } /* Finalize the auth tag */ @@ -330,5 +277,4 @@ int wc_ChaCha20Poly1305_Final(ChaChaPoly_Aead* aead, return ret; } - #endif /* HAVE_CHACHA && HAVE_POLY1305 */ diff --git a/wolfcrypt/src/poly1305.c b/wolfcrypt/src/poly1305.c index b3a4752b8..c43b7ba55 100644 --- a/wolfcrypt/src/poly1305.c +++ b/wolfcrypt/src/poly1305.c @@ -235,16 +235,24 @@ extern void poly1305_final_avx2(Poly1305* ctx, byte* mac); } #endif - -static void U32TO64(word32 v, byte* p) +/* convert 32-bit unsigned to little endian 64 bit type as byte array */ +static WC_INLINE void u32tole64(const word32 inLe32, byte outLe64[8]) { - XMEMSET(p, 0, 8); - p[0] = (v & 0xFF); - p[1] = (v >> 8) & 0xFF; - p[2] = (v >> 16) & 0xFF; - p[3] = (v >> 24) & 0xFF; +#ifndef WOLFSSL_X86_64_BUILD + outLe64[0] = (byte)(inLe32 & 0x000000FF); + outLe64[1] = (byte)((inLe32 & 0x0000FF00) >> 8); + outLe64[2] = (byte)((inLe32 & 0x00FF0000) >> 16); + outLe64[3] = (byte)((inLe32 & 0xFF000000) >> 24); + outLe64[4] = 0; + outLe64[5] = 0; + outLe64[6] = 0; + outLe64[7] = 0; +#else + *(word64*)outLe64 = inLe32; +#endif } + #if !defined(WOLFSSL_ARMASM) || !defined(__aarch64__) void poly1305_blocks(Poly1305* ctx, const unsigned char *m, size_t bytes) @@ -749,6 +757,53 @@ int wc_Poly1305Update(Poly1305* ctx, const byte* m, word32 bytes) return 0; } +/* Takes a Poly1305 struct that has a key loaded and pads the provided length + ctx : Initialized Poly1305 struct to use + lenToPad : Current number of bytes updated that needs padding to 16 + */ +int wc_Poly1305_Pad(Poly1305* ctx, word32 lenToPad) +{ + int ret = 0; + word32 paddingLen; + byte padding[WC_POLY1305_PAD_SZ - 1]; + + if (ctx == NULL) { + return BAD_FUNC_ARG; + } + + XMEMSET(padding, 0, sizeof(padding)); + + /* Pad length to 16 bytes */ + paddingLen = -(int)lenToPad & (WC_POLY1305_PAD_SZ - 1); + if (paddingLen > 0) { + ret = wc_Poly1305Update(ctx, padding, paddingLen); + } + return ret; +} + +/* Takes a Poly1305 struct that has a key loaded and adds the AEAD length + encoding in 64-bit little endian + aadSz : Size of the additional authentication data + dataSz : Size of the plaintext or ciphertext + */ +int wc_Poly1305_EncodeSizes(Poly1305* ctx, word32 aadSz, word32 dataSz) +{ + int ret; + byte little64[16]; /* sizeof(word64) * 2 */ + + if (ctx == NULL) { + return BAD_FUNC_ARG; + } + + XMEMSET(little64, 0, sizeof(little64)); + + /* size of additional data and input data as little endian 64 bit types */ + u32tole64(aadSz, little64); + u32tole64(dataSz, little64 + 8); + ret = wc_Poly1305Update(ctx, little64, sizeof(little64)); + + return ret; +} /* Takes in an initialized Poly1305 struct that has a key loaded and creates a MAC (tag) using recent TLS AEAD padding scheme. @@ -765,11 +820,6 @@ int wc_Poly1305_MAC(Poly1305* ctx, byte* additional, word32 addSz, byte* input, word32 sz, byte* tag, word32 tagSz) { int ret; - byte padding[WC_POLY1305_PAD_SZ - 1]; - word32 paddingLen; - byte little64[16]; - - XMEMSET(padding, 0, sizeof(padding)); /* sanity check on arguments */ if (ctx == NULL || input == NULL || tag == NULL || @@ -786,11 +836,9 @@ int wc_Poly1305_MAC(Poly1305* ctx, byte* additional, word32 addSz, if ((ret = wc_Poly1305Update(ctx, additional, addSz)) != 0) { return ret; } - paddingLen = -((int)addSz) & (WC_POLY1305_PAD_SZ - 1); - if (paddingLen) { - if ((ret = wc_Poly1305Update(ctx, padding, paddingLen)) != 0) { - return ret; - } + /* pad additional data */ + if ((ret = wc_Poly1305_Pad(ctx, addSz)) != 0) { + return ret; } } @@ -798,19 +846,13 @@ int wc_Poly1305_MAC(Poly1305* ctx, byte* additional, word32 addSz, if ((ret = wc_Poly1305Update(ctx, input, sz)) != 0) { return ret; } - paddingLen = -((int)sz) & (WC_POLY1305_PAD_SZ - 1); - if (paddingLen) { - if ((ret = wc_Poly1305Update(ctx, padding, paddingLen)) != 0) { - return ret; - } + /* pad input data */ + if ((ret = wc_Poly1305_Pad(ctx, sz)) != 0) { + return ret; } - /* size of additional data and input as little endian 64 bit types */ - U32TO64(addSz, little64); - U32TO64(sz, little64 + 8); - ret = wc_Poly1305Update(ctx, little64, sizeof(little64)); - if (ret) - { + /* encode size of AAD and input data as little endian 64 bit types */ + if ((ret = wc_Poly1305_EncodeSizes(ctx, addSz, sz)) != 0) { return ret; } diff --git a/wolfssl/wolfcrypt/poly1305.h b/wolfssl/wolfcrypt/poly1305.h index 0f81ca0e7..99fefd47d 100644 --- a/wolfssl/wolfcrypt/poly1305.h +++ b/wolfssl/wolfcrypt/poly1305.h @@ -112,6 +112,10 @@ WOLFSSL_API int wc_Poly1305SetKey(Poly1305* poly1305, const byte* key, word32 kySz); WOLFSSL_API int wc_Poly1305Update(Poly1305* poly1305, const byte*, word32); WOLFSSL_API int wc_Poly1305Final(Poly1305* poly1305, byte* tag); + +/* AEAD Functions */ +WOLFSSL_API int wc_Poly1305_Pad(Poly1305* ctx, word32 lenToPad); +WOLFSSL_API int wc_Poly1305_EncodeSizes(Poly1305* ctx, word32 aadSz, word32 dataSz); WOLFSSL_API int wc_Poly1305_MAC(Poly1305* ctx, byte* additional, word32 addSz, byte* input, word32 sz, byte* tag, word32 tagSz); @@ -124,4 +128,3 @@ void poly1305_blocks(Poly1305* ctx, const unsigned char *m, #endif /* HAVE_POLY1305 */ #endif /* WOLF_CRYPT_POLY1305_H */ - From bc1cb4ead842ab6b82aa4a2eedb451aaa4685619 Mon Sep 17 00:00:00 2001 From: David Garske Date: Tue, 7 Jan 2020 18:58:26 -0800 Subject: [PATCH 9/9] Fix to keep existing behavior where AAD is optional for `wc_ChaCha20Poly1305_Encrypt` and `wc_ChaCha20Poly1305_Decrypt`. --- wolfcrypt/src/chacha20_poly1305.c | 6 +++--- wolfcrypt/src/poly1305.c | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/wolfcrypt/src/chacha20_poly1305.c b/wolfcrypt/src/chacha20_poly1305.c index ddd3a576f..b59495753 100644 --- a/wolfcrypt/src/chacha20_poly1305.c +++ b/wolfcrypt/src/chacha20_poly1305.c @@ -176,7 +176,7 @@ int wc_ChaCha20Poly1305_UpdateAad(ChaChaPoly_Aead* aead, { int ret = 0; - if (aead == NULL || inAAD == NULL) { + if (aead == NULL || (inAAD == NULL && inAADLen > 0)) { return BAD_FUNC_ARG; } if (aead->state != CHACHA20_POLY1305_STATE_READY && @@ -184,7 +184,7 @@ int wc_ChaCha20Poly1305_UpdateAad(ChaChaPoly_Aead* aead, return BAD_STATE_E; } - if (inAADLen > 0) { + if (inAAD && inAADLen > 0) { ret = wc_Poly1305Update(&aead->poly, inAAD, inAADLen); if (ret == 0) { aead->aadLen += inAADLen; @@ -218,7 +218,7 @@ int wc_ChaCha20Poly1305_UpdateData(ChaChaPoly_Aead* aead, /* advance state */ aead->state = CHACHA20_POLY1305_STATE_DATA; - /* Perform ChaCha20 encrypt or decrypt inline and Poly1305 auth calc */ + /* Perform ChaCha20 encrypt/decrypt and Poly1305 auth calc */ if (ret == 0) { if (aead->isEncrypt) { ret = wc_Chacha_Process(&aead->chacha, outData, inData, dataLen); diff --git a/wolfcrypt/src/poly1305.c b/wolfcrypt/src/poly1305.c index c43b7ba55..797785b8d 100644 --- a/wolfcrypt/src/poly1305.c +++ b/wolfcrypt/src/poly1305.c @@ -770,6 +770,9 @@ int wc_Poly1305_Pad(Poly1305* ctx, word32 lenToPad) if (ctx == NULL) { return BAD_FUNC_ARG; } + if (lenToPad == 0) { + return 0; /* nothing needs to be done */ + } XMEMSET(padding, 0, sizeof(padding));