diff --git a/wolfcrypt/src/chacha20_poly1305.c b/wolfcrypt/src/chacha20_poly1305.c index 533b0d4eb..e048c3067 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 @@ -42,20 +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]); -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 wc_ChaCha20Poly1305_Encrypt( const byte inKey[CHACHA20_POLY1305_AEAD_KEYSIZE], const byte inIV[CHACHA20_POLY1305_AEAD_IV_SIZE], @@ -64,12 +49,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 || @@ -78,35 +61,18 @@ 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; } - int wc_ChaCha20Poly1305_Decrypt( const byte inKey[CHACHA20_POLY1305_AEAD_KEYSIZE], const byte inIV[CHACHA20_POLY1305_AEAD_IV_SIZE], @@ -115,13 +81,11 @@ 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 */ - if (!inKey || !inIV || !inCiphertext || !inCiphertextLen || !inAuthTag || @@ -131,121 +95,186 @@ int wc_ChaCha20Poly1305_Decrypt( } XMEMSET(calculatedAuthTag, 0, sizeof(calculatedAuthTag)); - XMEMSET(poly1305Key, 0, sizeof(poly1305Key)); + + 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( + const byte authTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE], + 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; + } + return ret; +} + +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 */ - 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 && ConstantCompare(inAuthTag, calculatedAuthTag, - CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE) != 0) - { - err = MAC_CMP_FAILED_E; + if (ret == 0) { + ret = wc_Chacha_Process(&aead->chacha, authKey, authKey, + CHACHA20_POLY1305_AEAD_KEYSIZE); } - /* Decrypt the received ciphertext */ - if (err == 0) - err = wc_Chacha_Process(&chaChaCtx, outPlaintext, inCiphertext, - inCiphertextLen); - ForceZero(poly1305Key, sizeof(poly1305Key)); + /* Initialize Poly1305 context */ + if (ret == 0) { + ret = wc_Poly1305SetKey(&aead->poly, authKey, + CHACHA20_POLY1305_AEAD_KEYSIZE); + } - return err; + if (ret == 0) { + aead->state = CHACHA20_POLY1305_STATE_READY; + } + + 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]) +/* optional additional authentication data */ +int wc_ChaCha20Poly1305_UpdateAad(ChaChaPoly_Aead* aead, + const byte* inAAD, word32 inAADLen) { - int err; - Poly1305 poly1305Ctx; - byte padding[CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1]; - word32 paddingLen; - byte little64[16]; + int ret = 0; - 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; + if (aead == NULL || (inAAD == NULL && inAADLen > 0)) { + return BAD_FUNC_ARG; + } + if (aead->state != CHACHA20_POLY1305_STATE_READY && + aead->state != CHACHA20_POLY1305_STATE_AAD) { + return BAD_STATE_E; } - /* -- 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; + if (inAAD && inAADLen > 0) { + ret = wc_Poly1305Update(&aead->poly, inAAD, inAADLen); + if (ret == 0) { + aead->aadLen += inAADLen; + aead->state = CHACHA20_POLY1305_STATE_AAD; + } } - /* -- 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; + return ret; +} + +/* inData and outData can be same pointer (inline) */ +int wc_ChaCha20Poly1305_UpdateData(ChaChaPoly_Aead* aead, + const byte* inData, byte* outData, word32 dataLen) +{ + int ret = 0; + + if (aead == NULL || inData == NULL || outData == 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; + } + + /* Pad the AAD */ + if (aead->state == CHACHA20_POLY1305_STATE_AAD) { + ret = wc_Poly1305_Pad(&aead->poly, aead->aadLen); + } + + /* advance state */ + aead->state = CHACHA20_POLY1305_STATE_DATA; + + /* Perform ChaCha20 encrypt/decrypt and Poly1305 auth calc */ + if (ret == 0) { + if (aead->isEncrypt) { + ret = wc_Chacha_Process(&aead->chacha, outData, inData, dataLen); + if (ret == 0) + ret = wc_Poly1305Update(&aead->poly, outData, dataLen); + } + else { + ret = wc_Poly1305Update(&aead->poly, inData, dataLen); + if (ret == 0) + ret = wc_Chacha_Process(&aead->chacha, outData, inData, 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; + + 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; + } + + /* Pad the AAD - Make sure it is done */ + if (aead->state == CHACHA20_POLY1305_STATE_AAD) { + ret = wc_Poly1305_Pad(&aead->poly, aead->aadLen); + } + + /* Pad the ciphertext to 16 bytes */ + if (ret == 0) { + ret = wc_Poly1305_Pad(&aead->poly, aead->dataLen); + } + + /* Add the aad length and plaintext/ciphertext length */ + if (ret == 0) { + ret = wc_Poly1305_EncodeSizes(&aead->poly, aead->aadLen, + aead->dataLen); + } /* Finalize the auth tag */ - err = wc_Poly1305Final(&poly1305Ctx, outAuthTag); + if (ret == 0) { + ret = wc_Poly1305Final(&aead->poly, outAuthTag); + } - return err; + /* reset and cleanup sensitive context */ + ForceZero(aead, sizeof(ChaChaPoly_Aead)); + + return ret; } - -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 -} - - #endif /* HAVE_CHACHA && HAVE_POLY1305 */ diff --git a/wolfcrypt/src/poly1305.c b/wolfcrypt/src/poly1305.c index a311726ef..174b912b6 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,56 @@ 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; + } + if (lenToPad == 0) { + return 0; /* nothing needs to be done */ + } + + 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 +823,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 +839,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 +849,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/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 087c87dff..27dcecb50 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -5030,11 +5030,17 @@ 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; + ChaChaPoly_Aead aead; + #define TEST_SMALL_CHACHA_CHUNKS 64 + #ifdef TEST_SMALL_CHACHA_CHUNKS + word32 testLen; + #endif + XMEMSET(generatedCiphertext, 0, sizeof(generatedCiphertext)); XMEMSET(generatedAuthTag, 0, sizeof(generatedAuthTag)); XMEMSET(generatedPlaintext, 0, sizeof(generatedPlaintext)); @@ -5092,8 +5098,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 +5109,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 +5124,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 +5143,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 +5163,214 @@ int chacha20_poly1305_aead_test(void) return -4517; } + + /* AEAD init/update/final */ + 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, + CHACHA20_POLY1305_AEAD_DECRYPT); + if (err != BAD_FUNC_ARG) + return -4521; + 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)); + 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, + generatedPlaintext, sizeof(plaintext1)); + if (err != BAD_FUNC_ARG) + return -4525; + 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); + 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_INIT; + err = wc_ChaCha20Poly1305_UpdateData(&aead, generatedPlaintext, + generatedPlaintext, sizeof(plaintext1)); + if (err != BAD_STATE_E) + return -4531; + aead.state = CHACHA20_POLY1305_STATE_INIT; + err = wc_ChaCha20Poly1305_Final(&aead, generatedAuthTag); + if (err != BAD_STATE_E) + return -4532; + aead.state = CHACHA20_POLY1305_STATE_READY; + err = wc_ChaCha20Poly1305_Final(&aead, generatedAuthTag); + if (err != BAD_STATE_E) + return -4533; + + 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, + CHACHA20_POLY1305_AEAD_ENCRYPT); + 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; + err = wc_ChaCha20Poly1305_UpdateData(&aead, &plaintext1[testLen], + &generatedCiphertext[testLen], dataLen); + if (err != 0) + return -4539; + testLen += dataLen; + } +#else + err = wc_ChaCha20Poly1305_UpdateData(&aead, plaintext1, + 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, + CHACHA20_POLY1305_AEAD_DECRYPT); + 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; + err = wc_ChaCha20Poly1305_UpdateData(&aead, + &generatedCiphertext[testLen], &generatedPlaintext[testLen], + dataLen); + if (err != 0) + return -4545; + testLen += dataLen; + } +#else + err = wc_ChaCha20Poly1305_UpdateData(&aead, generatedCiphertext, + 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, + CHACHA20_POLY1305_AEAD_ENCRYPT); + 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; + err = wc_ChaCha20Poly1305_UpdateData(&aead, &plaintext2[testLen], + &generatedCiphertext[testLen], dataLen); + if (err != 0) + return -4552; + testLen += dataLen; + } +#else + err = wc_ChaCha20Poly1305_UpdateData(&aead, plaintext2, 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, + CHACHA20_POLY1305_AEAD_DECRYPT); + 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; + err = wc_ChaCha20Poly1305_UpdateData(&aead, + &generatedCiphertext[testLen], &generatedPlaintext[testLen], + dataLen); + if (err != 0) + return -4558; + testLen += dataLen; + } +#else + err = wc_ChaCha20Poly1305_UpdateData(&aead, generatedCiphertext, + 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; + } + return err; } #endif /* HAVE_CHACHA && HAVE_POLY1305 */ diff --git a/wolfssl/wolfcrypt/chacha20_poly1305.h b/wolfssl/wolfcrypt/chacha20_poly1305.h index b1e4e9a58..7d2b1aa2a 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,40 @@ #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, }; - /* - * 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; + byte 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 +100,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]); + + + +/* 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, + const byte* inData, byte* outData, word32 dataLen); +WOLFSSL_API int wc_ChaCha20Poly1305_Final(ChaChaPoly_Aead* aead, + byte outAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE]); + + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/wolfssl/wolfcrypt/poly1305.h b/wolfssl/wolfcrypt/poly1305.h index 5cc3cb6eb..981ce49a1 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 */ -