]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/WolfSSL/wolfcrypt/src/chacha20_poly1305.c
Update WolfSSL library to the latest version.
[freertos] / FreeRTOS-Plus / Source / WolfSSL / wolfcrypt / src / chacha20_poly1305.c
1 /* chacha.c
2  *
3  * Copyright (C) 2006-2015 wolfSSL Inc.
4  *
5  * This file is part of wolfSSL. (formerly known as CyaSSL)
6  *
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.
11  *
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.
16  *
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
20  */
21
22
23 #ifdef HAVE_CONFIG_H
24     #include <config.h>
25 #endif
26
27 #include <wolfssl/wolfcrypt/settings.h>
28
29 #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
30
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>
36
37 #ifdef NO_INLINE
38 #include <wolfssl/wolfcrypt/misc.h>
39 #else
40 #include <wolfcrypt/src/misc.c>
41 #endif
42
43 #ifdef CHACHA_AEAD_TEST
44 #include <stdio.h>
45 #endif
46
47 #define CHACHA20_POLY1305_AEAD_INITIAL_COUNTER  0
48 #define CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT 16
49
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]);
56
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,
62                 byte* outCiphertext,
63                 byte outAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE])
64 {
65     int err;
66     byte poly1305Key[CHACHA20_POLY1305_AEAD_KEYSIZE];
67     ChaCha chaChaCtx;
68
69     /* Validate function arguments */
70
71     if (!inKey || !inIV ||
72         !inPlaintext || !inPlaintextLen ||
73         !outCiphertext ||
74         !outAuthTag)
75     {
76         return BAD_FUNC_ARG;
77     }
78
79     XMEMSET(poly1305Key, 0, sizeof(poly1305Key));
80
81     /* Create the Poly1305 key */
82     err = wc_Chacha_SetKey(&chaChaCtx, inKey, CHACHA20_POLY1305_AEAD_KEYSIZE);
83     if (err != 0) return err;
84
85     err = wc_Chacha_SetIV(&chaChaCtx, inIV,
86                            CHACHA20_POLY1305_AEAD_INITIAL_COUNTER);
87     if (err != 0) return err;
88
89     err = wc_Chacha_Process(&chaChaCtx, poly1305Key, poly1305Key,
90                              CHACHA20_POLY1305_AEAD_KEYSIZE);
91     if (err != 0) return err;
92
93     /* Encrypt the plaintext using ChaCha20 */
94     err = wc_Chacha_Process(&chaChaCtx, outCiphertext, inPlaintext,
95                             inPlaintextLen);
96     /* Calculate the Poly1305 auth tag */
97     if (err == 0)
98         err = calculateAuthTag(poly1305Key,
99                                inAAD, inAADLen,
100                                outCiphertext, inPlaintextLen,
101                                outAuthTag);
102     ForceZero(poly1305Key, sizeof(poly1305Key));
103
104     return err;
105 }
106
107
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],
114                 byte* outPlaintext)
115 {
116     int err;
117     byte poly1305Key[CHACHA20_POLY1305_AEAD_KEYSIZE];
118     ChaCha chaChaCtx;
119     byte calculatedAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE];
120
121     /* Validate function arguments */
122
123     if (!inKey || !inIV ||
124         !inCiphertext || !inCiphertextLen ||
125         !inAuthTag ||
126         !outPlaintext)
127     {
128         return BAD_FUNC_ARG;
129     }
130
131     XMEMSET(calculatedAuthTag, 0, sizeof(calculatedAuthTag));
132     XMEMSET(poly1305Key, 0, sizeof(poly1305Key));
133
134     /* Create the Poly1305 key */
135     err = wc_Chacha_SetKey(&chaChaCtx, inKey, CHACHA20_POLY1305_AEAD_KEYSIZE);
136     if (err != 0) return err;
137
138     err = wc_Chacha_SetIV(&chaChaCtx, inIV,
139                            CHACHA20_POLY1305_AEAD_INITIAL_COUNTER);
140     if (err != 0) return err;
141
142     err = wc_Chacha_Process(&chaChaCtx, poly1305Key, poly1305Key,
143                              CHACHA20_POLY1305_AEAD_KEYSIZE);
144     if (err != 0) return err;
145
146     /* Calculate the Poly1305 auth tag */
147     err = calculateAuthTag(poly1305Key,
148                            inAAD, inAADLen,
149                            inCiphertext, inCiphertextLen,
150                            calculatedAuthTag);
151
152     /* Compare the calculated auth tag with the received one */
153     if (err == 0 && ConstantCompare(inAuthTag, calculatedAuthTag,
154                                     CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE) != 0)
155     {
156         err = MAC_CMP_FAILED_E;
157     }
158
159     /* Decrypt the received ciphertext */
160     if (err == 0)
161         err = wc_Chacha_Process(&chaChaCtx, outPlaintext, inCiphertext,
162                                 inCiphertextLen);
163     ForceZero(poly1305Key, sizeof(poly1305Key));
164
165     return err;
166 }
167
168
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])
174 {
175     int err;
176     Poly1305 poly1305Ctx;
177     byte padding[CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1];
178     word32 paddingLen;
179     byte little64[8];
180
181     XMEMSET(padding, 0, sizeof(padding));
182
183     /* Initialize Poly1305 */
184
185     err = wc_Poly1305SetKey(&poly1305Ctx, inAuthKey,
186                             CHACHA20_POLY1305_AEAD_KEYSIZE);
187     if (err)
188     {
189         return err;
190     }
191
192     /* Create the authTag by MAC'ing the following items: */
193
194     /* -- AAD */
195
196     if (inAAD && inAADLen)
197     {
198         err = wc_Poly1305Update(&poly1305Ctx, inAAD, inAADLen);
199
200         /* -- padding1: pad the AAD to 16 bytes */
201
202         paddingLen = -inAADLen & (CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1);
203         if (paddingLen)
204         {
205             err += wc_Poly1305Update(&poly1305Ctx, padding, paddingLen);
206         }
207
208         if (err)
209         {
210             return err;
211         }
212     }
213
214     /* -- Ciphertext */
215
216     err = wc_Poly1305Update(&poly1305Ctx, inCiphertext, inCiphertextLen);
217     if (err)
218     {
219         return err;
220     }
221
222     /* -- padding2: pad the ciphertext to 16 bytes */
223
224     paddingLen = -inCiphertextLen &
225                                   (CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1);
226     if (paddingLen)
227     {
228         err = wc_Poly1305Update(&poly1305Ctx, padding, paddingLen);
229         if (err)
230         {
231             return err;
232         }
233     }
234
235     /* -- AAD length as a 64-bit little endian integer */
236
237     word32ToLittle64(inAADLen, little64);
238
239     err = wc_Poly1305Update(&poly1305Ctx, little64, sizeof(little64));
240     if (err)
241     {
242         return err;
243     }
244
245     /* -- Ciphertext length as a 64-bit little endian integer */
246
247     word32ToLittle64(inCiphertextLen, little64);
248
249     err = wc_Poly1305Update(&poly1305Ctx, little64, sizeof(little64));
250     if (err)
251     {
252         return err;
253     }
254
255     /* Finalize the auth tag */
256
257     err = wc_Poly1305Final(&poly1305Ctx, outAuthTag);
258
259     return err;
260 }
261
262
263 static void word32ToLittle64(const word32 inLittle32, byte outLittle64[8])
264 {
265     XMEMSET(outLittle64, 0, 8);
266
267     outLittle64[0] = (inLittle32 & 0x000000FF);
268     outLittle64[1] = (inLittle32 & 0x0000FF00) >> 8;
269     outLittle64[2] = (inLittle32 & 0x00FF0000) >> 16;
270     outLittle64[3] = (inLittle32 & 0xFF000000) >> 24;
271 }
272
273
274 #endif /* HAVE_CHACHA && HAVE_POLY1305 */