wolfSSL 3.11.1 for TLS1.3 beta
Fork of wolfSSL by
Diff: wolfcrypt/src/chacha20_poly1305.c
- Revision:
- 13:80fb167dafdf
- Parent:
- 11:cee25a834751
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wolfcrypt/src/chacha20_poly1305.c Tue May 30 06:16:19 2017 +0000 @@ -0,0 +1,277 @@ +/* chacha.c + * + * Copyright (C) 2006-2016 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + + + +#ifdef HAVE_CONFIG_H + #include <config.h> +#endif + +#include <wolfssl/wolfcrypt/settings.h> + +#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) + +#include <wolfssl/wolfcrypt/chacha20_poly1305.h> +#include <wolfssl/wolfcrypt/error-crypt.h> +#include <wolfssl/wolfcrypt/logging.h> +#include <wolfssl/wolfcrypt/chacha.h> +#include <wolfssl/wolfcrypt/poly1305.h> + +#ifdef NO_INLINE +#include <wolfssl/wolfcrypt/misc.h> +#else +#define WOLFSSL_MISC_INCLUDED +#include <wolfcrypt/src/misc.c> +#endif + +#ifdef CHACHA_AEAD_TEST +#include <stdio.h> +#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], + const byte* inAAD, const word32 inAADLen, + const byte* inPlaintext, const word32 inPlaintextLen, + byte* outCiphertext, + byte outAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE]) +{ + int err; + byte poly1305Key[CHACHA20_POLY1305_AEAD_KEYSIZE]; + ChaCha chaChaCtx; + + /* Validate function arguments */ + + if (!inKey || !inIV || + !inPlaintext || !inPlaintextLen || + !outCiphertext || + !outAuthTag) + { + 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; +} + + +int wc_ChaCha20Poly1305_Decrypt( + const byte inKey[CHACHA20_POLY1305_AEAD_KEYSIZE], + const byte inIV[CHACHA20_POLY1305_AEAD_IV_SIZE], + const byte* inAAD, const word32 inAADLen, + const byte* inCiphertext, const word32 inCiphertextLen, + const byte inAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE], + byte* outPlaintext) +{ + int err; + byte poly1305Key[CHACHA20_POLY1305_AEAD_KEYSIZE]; + ChaCha chaChaCtx; + byte calculatedAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE]; + + /* Validate function arguments */ + + if (!inKey || !inIV || + !inCiphertext || !inCiphertextLen || + !inAuthTag || + !outPlaintext) + { + return BAD_FUNC_ARG; + } + + 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 && ConstantCompare(inAuthTag, calculatedAuthTag, + CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE) != 0) + { + err = MAC_CMP_FAILED_E; + } + + /* Decrypt the received ciphertext */ + if (err == 0) + err = wc_Chacha_Process(&chaChaCtx, outPlaintext, inCiphertext, + inCiphertextLen); + ForceZero(poly1305Key, sizeof(poly1305Key)); + + return err; +} + + +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[8]; + + 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); + + err = wc_Poly1305Update(&poly1305Ctx, little64, sizeof(little64)); + if (err) + { + return err; + } + + /* -- Ciphertext length as a 64-bit little endian integer */ + + word32ToLittle64(inCiphertextLen, little64); + + 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]) +{ + XMEMSET(outLittle64, 0, 8); + + outLittle64[0] = (byte)(inLittle32 & 0x000000FF); + outLittle64[1] = (byte)((inLittle32 & 0x0000FF00) >> 8); + outLittle64[2] = (byte)((inLittle32 & 0x00FF0000) >> 16); + outLittle64[3] = (byte)((inLittle32 & 0xFF000000) >> 24); +} + + +#endif /* HAVE_CHACHA && HAVE_POLY1305 */ +