3 * Copyright (C) 2006-2015 wolfSSL Inc.
5 * This file is part of wolfSSL. (formerly known as CyaSSL)
7 * wolfSSL is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * wolfSSL is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
27 #include <wolfssl/wolfcrypt/settings.h>
29 #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
31 #include <wolfssl/wolfcrypt/chacha20_poly1305.h>
32 #include <wolfssl/wolfcrypt/error-crypt.h>
33 #include <wolfssl/wolfcrypt/logging.h>
34 #include <wolfssl/wolfcrypt/chacha.h>
35 #include <wolfssl/wolfcrypt/poly1305.h>
38 #include <wolfssl/wolfcrypt/misc.h>
40 #include <wolfcrypt/src/misc.c>
43 #ifdef CHACHA_AEAD_TEST
47 #define CHACHA20_POLY1305_AEAD_INITIAL_COUNTER 0
48 #define CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT 16
50 static void word32ToLittle64(const word32 inLittle32, byte outLittle64[8]);
51 static int calculateAuthTag(
52 const byte inAuthKey[CHACHA20_POLY1305_AEAD_KEYSIZE],
53 const byte* inAAD, const word32 inAADLen,
54 const byte *inCiphertext, const word32 inCiphertextLen,
55 byte outAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE]);
57 int wc_ChaCha20Poly1305_Encrypt(
58 const byte inKey[CHACHA20_POLY1305_AEAD_KEYSIZE],
59 const byte inIV[CHACHA20_POLY1305_AEAD_IV_SIZE],
60 const byte* inAAD, const word32 inAADLen,
61 const byte* inPlaintext, const word32 inPlaintextLen,
63 byte outAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE])
66 byte poly1305Key[CHACHA20_POLY1305_AEAD_KEYSIZE];
69 /* Validate function arguments */
71 if (!inKey || !inIV ||
72 !inPlaintext || !inPlaintextLen ||
79 XMEMSET(poly1305Key, 0, sizeof(poly1305Key));
81 /* Create the Poly1305 key */
82 err = wc_Chacha_SetKey(&chaChaCtx, inKey, CHACHA20_POLY1305_AEAD_KEYSIZE);
83 if (err != 0) return err;
85 err = wc_Chacha_SetIV(&chaChaCtx, inIV,
86 CHACHA20_POLY1305_AEAD_INITIAL_COUNTER);
87 if (err != 0) return err;
89 err = wc_Chacha_Process(&chaChaCtx, poly1305Key, poly1305Key,
90 CHACHA20_POLY1305_AEAD_KEYSIZE);
91 if (err != 0) return err;
93 /* Encrypt the plaintext using ChaCha20 */
94 err = wc_Chacha_Process(&chaChaCtx, outCiphertext, inPlaintext,
96 /* Calculate the Poly1305 auth tag */
98 err = calculateAuthTag(poly1305Key,
100 outCiphertext, inPlaintextLen,
102 ForceZero(poly1305Key, sizeof(poly1305Key));
108 int wc_ChaCha20Poly1305_Decrypt(
109 const byte inKey[CHACHA20_POLY1305_AEAD_KEYSIZE],
110 const byte inIV[CHACHA20_POLY1305_AEAD_IV_SIZE],
111 const byte* inAAD, const word32 inAADLen,
112 const byte* inCiphertext, const word32 inCiphertextLen,
113 const byte inAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE],
117 byte poly1305Key[CHACHA20_POLY1305_AEAD_KEYSIZE];
119 byte calculatedAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE];
121 /* Validate function arguments */
123 if (!inKey || !inIV ||
124 !inCiphertext || !inCiphertextLen ||
131 XMEMSET(calculatedAuthTag, 0, sizeof(calculatedAuthTag));
132 XMEMSET(poly1305Key, 0, sizeof(poly1305Key));
134 /* Create the Poly1305 key */
135 err = wc_Chacha_SetKey(&chaChaCtx, inKey, CHACHA20_POLY1305_AEAD_KEYSIZE);
136 if (err != 0) return err;
138 err = wc_Chacha_SetIV(&chaChaCtx, inIV,
139 CHACHA20_POLY1305_AEAD_INITIAL_COUNTER);
140 if (err != 0) return err;
142 err = wc_Chacha_Process(&chaChaCtx, poly1305Key, poly1305Key,
143 CHACHA20_POLY1305_AEAD_KEYSIZE);
144 if (err != 0) return err;
146 /* Calculate the Poly1305 auth tag */
147 err = calculateAuthTag(poly1305Key,
149 inCiphertext, inCiphertextLen,
152 /* Compare the calculated auth tag with the received one */
153 if (err == 0 && ConstantCompare(inAuthTag, calculatedAuthTag,
154 CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE) != 0)
156 err = MAC_CMP_FAILED_E;
159 /* Decrypt the received ciphertext */
161 err = wc_Chacha_Process(&chaChaCtx, outPlaintext, inCiphertext,
163 ForceZero(poly1305Key, sizeof(poly1305Key));
169 static int calculateAuthTag(
170 const byte inAuthKey[CHACHA20_POLY1305_AEAD_KEYSIZE],
171 const byte *inAAD, const word32 inAADLen,
172 const byte *inCiphertext, const word32 inCiphertextLen,
173 byte outAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE])
176 Poly1305 poly1305Ctx;
177 byte padding[CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1];
181 XMEMSET(padding, 0, sizeof(padding));
183 /* Initialize Poly1305 */
185 err = wc_Poly1305SetKey(&poly1305Ctx, inAuthKey,
186 CHACHA20_POLY1305_AEAD_KEYSIZE);
192 /* Create the authTag by MAC'ing the following items: */
196 if (inAAD && inAADLen)
198 err = wc_Poly1305Update(&poly1305Ctx, inAAD, inAADLen);
200 /* -- padding1: pad the AAD to 16 bytes */
202 paddingLen = -inAADLen & (CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1);
205 err += wc_Poly1305Update(&poly1305Ctx, padding, paddingLen);
216 err = wc_Poly1305Update(&poly1305Ctx, inCiphertext, inCiphertextLen);
222 /* -- padding2: pad the ciphertext to 16 bytes */
224 paddingLen = -inCiphertextLen &
225 (CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1);
228 err = wc_Poly1305Update(&poly1305Ctx, padding, paddingLen);
235 /* -- AAD length as a 64-bit little endian integer */
237 word32ToLittle64(inAADLen, little64);
239 err = wc_Poly1305Update(&poly1305Ctx, little64, sizeof(little64));
245 /* -- Ciphertext length as a 64-bit little endian integer */
247 word32ToLittle64(inCiphertextLen, little64);
249 err = wc_Poly1305Update(&poly1305Ctx, little64, sizeof(little64));
255 /* Finalize the auth tag */
257 err = wc_Poly1305Final(&poly1305Ctx, outAuthTag);
263 static void word32ToLittle64(const word32 inLittle32, byte outLittle64[8])
265 XMEMSET(outLittle64, 0, 8);
267 outLittle64[0] = (inLittle32 & 0x000000FF);
268 outLittle64[1] = (inLittle32 & 0x0000FF00) >> 8;
269 outLittle64[2] = (inLittle32 & 0x00FF0000) >> 16;
270 outLittle64[3] = (inLittle32 & 0xFF000000) >> 24;
274 #endif /* HAVE_CHACHA && HAVE_POLY1305 */