• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * \file chachapoly.c
3  *
4  * \brief ChaCha20-Poly1305 AEAD construction based on RFC 7539.
5  *
6  *  Copyright The Mbed TLS Contributors
7  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
8  */
9 #include "common.h"
10 
11 #if defined(MBEDTLS_CHACHAPOLY_C)
12 
13 #include "mbedtls/chachapoly.h"
14 #include "mbedtls/platform_util.h"
15 #include "mbedtls/error.h"
16 #include "mbedtls/constant_time.h"
17 
18 #include <string.h>
19 
20 #include "mbedtls/platform.h"
21 
22 #if !defined(MBEDTLS_CHACHAPOLY_ALT)
23 
24 /* Parameter validation macros */
25 #define CHACHAPOLY_VALIDATE_RET(cond)                                       \
26     MBEDTLS_INTERNAL_VALIDATE_RET(cond, MBEDTLS_ERR_POLY1305_BAD_INPUT_DATA)
27 #define CHACHAPOLY_VALIDATE(cond)                                           \
28     MBEDTLS_INTERNAL_VALIDATE(cond)
29 
30 #define CHACHAPOLY_STATE_INIT       (0)
31 #define CHACHAPOLY_STATE_AAD        (1)
32 #define CHACHAPOLY_STATE_CIPHERTEXT (2)   /* Encrypting or decrypting */
33 #define CHACHAPOLY_STATE_FINISHED   (3)
34 
35 /**
36  * \brief           Adds nul bytes to pad the AAD for Poly1305.
37  *
38  * \param ctx       The ChaCha20-Poly1305 context.
39  */
chachapoly_pad_aad(mbedtls_chachapoly_context * ctx)40 static int chachapoly_pad_aad(mbedtls_chachapoly_context *ctx)
41 {
42     uint32_t partial_block_len = (uint32_t) (ctx->aad_len % 16U);
43     unsigned char zeroes[15];
44 
45     if (partial_block_len == 0U) {
46         return 0;
47     }
48 
49     memset(zeroes, 0, sizeof(zeroes));
50 
51     return mbedtls_poly1305_update(&ctx->poly1305_ctx,
52                                    zeroes,
53                                    16U - partial_block_len);
54 }
55 
56 /**
57  * \brief           Adds nul bytes to pad the ciphertext for Poly1305.
58  *
59  * \param ctx       The ChaCha20-Poly1305 context.
60  */
chachapoly_pad_ciphertext(mbedtls_chachapoly_context * ctx)61 static int chachapoly_pad_ciphertext(mbedtls_chachapoly_context *ctx)
62 {
63     uint32_t partial_block_len = (uint32_t) (ctx->ciphertext_len % 16U);
64     unsigned char zeroes[15];
65 
66     if (partial_block_len == 0U) {
67         return 0;
68     }
69 
70     memset(zeroes, 0, sizeof(zeroes));
71     return mbedtls_poly1305_update(&ctx->poly1305_ctx,
72                                    zeroes,
73                                    16U - partial_block_len);
74 }
75 
mbedtls_chachapoly_init(mbedtls_chachapoly_context * ctx)76 void mbedtls_chachapoly_init(mbedtls_chachapoly_context *ctx)
77 {
78     CHACHAPOLY_VALIDATE(ctx != NULL);
79 
80     mbedtls_chacha20_init(&ctx->chacha20_ctx);
81     mbedtls_poly1305_init(&ctx->poly1305_ctx);
82     ctx->aad_len        = 0U;
83     ctx->ciphertext_len = 0U;
84     ctx->state          = CHACHAPOLY_STATE_INIT;
85     ctx->mode           = MBEDTLS_CHACHAPOLY_ENCRYPT;
86 }
87 
mbedtls_chachapoly_free(mbedtls_chachapoly_context * ctx)88 void mbedtls_chachapoly_free(mbedtls_chachapoly_context *ctx)
89 {
90     if (ctx == NULL) {
91         return;
92     }
93 
94     mbedtls_chacha20_free(&ctx->chacha20_ctx);
95     mbedtls_poly1305_free(&ctx->poly1305_ctx);
96     ctx->aad_len        = 0U;
97     ctx->ciphertext_len = 0U;
98     ctx->state          = CHACHAPOLY_STATE_INIT;
99     ctx->mode           = MBEDTLS_CHACHAPOLY_ENCRYPT;
100 }
101 
mbedtls_chachapoly_setkey(mbedtls_chachapoly_context * ctx,const unsigned char key[32])102 int mbedtls_chachapoly_setkey(mbedtls_chachapoly_context *ctx,
103                               const unsigned char key[32])
104 {
105     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
106     CHACHAPOLY_VALIDATE_RET(ctx != NULL);
107     CHACHAPOLY_VALIDATE_RET(key != NULL);
108 
109     ret = mbedtls_chacha20_setkey(&ctx->chacha20_ctx, key);
110 
111     return ret;
112 }
113 
mbedtls_chachapoly_starts(mbedtls_chachapoly_context * ctx,const unsigned char nonce[12],mbedtls_chachapoly_mode_t mode)114 int mbedtls_chachapoly_starts(mbedtls_chachapoly_context *ctx,
115                               const unsigned char nonce[12],
116                               mbedtls_chachapoly_mode_t mode)
117 {
118     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
119     unsigned char poly1305_key[64];
120     CHACHAPOLY_VALIDATE_RET(ctx != NULL);
121     CHACHAPOLY_VALIDATE_RET(nonce != NULL);
122 
123     /* Set counter = 0, will be update to 1 when generating Poly1305 key */
124     ret = mbedtls_chacha20_starts(&ctx->chacha20_ctx, nonce, 0U);
125     if (ret != 0) {
126         goto cleanup;
127     }
128 
129     /* Generate the Poly1305 key by getting the ChaCha20 keystream output with
130      * counter = 0.  This is the same as encrypting a buffer of zeroes.
131      * Only the first 256-bits (32 bytes) of the key is used for Poly1305.
132      * The other 256 bits are discarded.
133      */
134     memset(poly1305_key, 0, sizeof(poly1305_key));
135     ret = mbedtls_chacha20_update(&ctx->chacha20_ctx, sizeof(poly1305_key),
136                                   poly1305_key, poly1305_key);
137     if (ret != 0) {
138         goto cleanup;
139     }
140 
141     ret = mbedtls_poly1305_starts(&ctx->poly1305_ctx, poly1305_key);
142 
143     if (ret == 0) {
144         ctx->aad_len        = 0U;
145         ctx->ciphertext_len = 0U;
146         ctx->state          = CHACHAPOLY_STATE_AAD;
147         ctx->mode           = mode;
148     }
149 
150 cleanup:
151     mbedtls_platform_zeroize(poly1305_key, 64U);
152     return ret;
153 }
154 
mbedtls_chachapoly_update_aad(mbedtls_chachapoly_context * ctx,const unsigned char * aad,size_t aad_len)155 int mbedtls_chachapoly_update_aad(mbedtls_chachapoly_context *ctx,
156                                   const unsigned char *aad,
157                                   size_t aad_len)
158 {
159     CHACHAPOLY_VALIDATE_RET(ctx != NULL);
160     CHACHAPOLY_VALIDATE_RET(aad_len == 0 || aad != NULL);
161 
162     if (ctx->state != CHACHAPOLY_STATE_AAD) {
163         return MBEDTLS_ERR_CHACHAPOLY_BAD_STATE;
164     }
165 
166     ctx->aad_len += aad_len;
167 
168     return mbedtls_poly1305_update(&ctx->poly1305_ctx, aad, aad_len);
169 }
170 
mbedtls_chachapoly_update(mbedtls_chachapoly_context * ctx,size_t len,const unsigned char * input,unsigned char * output)171 int mbedtls_chachapoly_update(mbedtls_chachapoly_context *ctx,
172                               size_t len,
173                               const unsigned char *input,
174                               unsigned char *output)
175 {
176     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
177     CHACHAPOLY_VALIDATE_RET(ctx != NULL);
178     CHACHAPOLY_VALIDATE_RET(len == 0 || input != NULL);
179     CHACHAPOLY_VALIDATE_RET(len == 0 || output != NULL);
180 
181     if ((ctx->state != CHACHAPOLY_STATE_AAD) &&
182         (ctx->state != CHACHAPOLY_STATE_CIPHERTEXT)) {
183         return MBEDTLS_ERR_CHACHAPOLY_BAD_STATE;
184     }
185 
186     if (ctx->state == CHACHAPOLY_STATE_AAD) {
187         ctx->state = CHACHAPOLY_STATE_CIPHERTEXT;
188 
189         ret = chachapoly_pad_aad(ctx);
190         if (ret != 0) {
191             return ret;
192         }
193     }
194 
195     ctx->ciphertext_len += len;
196 
197     if (ctx->mode == MBEDTLS_CHACHAPOLY_ENCRYPT) {
198         ret = mbedtls_chacha20_update(&ctx->chacha20_ctx, len, input, output);
199         if (ret != 0) {
200             return ret;
201         }
202 
203         ret = mbedtls_poly1305_update(&ctx->poly1305_ctx, output, len);
204         if (ret != 0) {
205             return ret;
206         }
207     } else { /* DECRYPT */
208         ret = mbedtls_poly1305_update(&ctx->poly1305_ctx, input, len);
209         if (ret != 0) {
210             return ret;
211         }
212 
213         ret = mbedtls_chacha20_update(&ctx->chacha20_ctx, len, input, output);
214         if (ret != 0) {
215             return ret;
216         }
217     }
218 
219     return 0;
220 }
221 
mbedtls_chachapoly_finish(mbedtls_chachapoly_context * ctx,unsigned char mac[16])222 int mbedtls_chachapoly_finish(mbedtls_chachapoly_context *ctx,
223                               unsigned char mac[16])
224 {
225     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
226     unsigned char len_block[16];
227     CHACHAPOLY_VALIDATE_RET(ctx != NULL);
228     CHACHAPOLY_VALIDATE_RET(mac != NULL);
229 
230     if (ctx->state == CHACHAPOLY_STATE_INIT) {
231         return MBEDTLS_ERR_CHACHAPOLY_BAD_STATE;
232     }
233 
234     if (ctx->state == CHACHAPOLY_STATE_AAD) {
235         ret = chachapoly_pad_aad(ctx);
236         if (ret != 0) {
237             return ret;
238         }
239     } else if (ctx->state == CHACHAPOLY_STATE_CIPHERTEXT) {
240         ret = chachapoly_pad_ciphertext(ctx);
241         if (ret != 0) {
242             return ret;
243         }
244     }
245 
246     ctx->state = CHACHAPOLY_STATE_FINISHED;
247 
248     /* The lengths of the AAD and ciphertext are processed by
249      * Poly1305 as the final 128-bit block, encoded as little-endian integers.
250      */
251     MBEDTLS_PUT_UINT64_LE(ctx->aad_len, len_block, 0);
252     MBEDTLS_PUT_UINT64_LE(ctx->ciphertext_len, len_block, 8);
253 
254     ret = mbedtls_poly1305_update(&ctx->poly1305_ctx, len_block, 16U);
255     if (ret != 0) {
256         return ret;
257     }
258 
259     ret = mbedtls_poly1305_finish(&ctx->poly1305_ctx, mac);
260 
261     return ret;
262 }
263 
chachapoly_crypt_and_tag(mbedtls_chachapoly_context * ctx,mbedtls_chachapoly_mode_t mode,size_t length,const unsigned char nonce[12],const unsigned char * aad,size_t aad_len,const unsigned char * input,unsigned char * output,unsigned char tag[16])264 static int chachapoly_crypt_and_tag(mbedtls_chachapoly_context *ctx,
265                                     mbedtls_chachapoly_mode_t mode,
266                                     size_t length,
267                                     const unsigned char nonce[12],
268                                     const unsigned char *aad,
269                                     size_t aad_len,
270                                     const unsigned char *input,
271                                     unsigned char *output,
272                                     unsigned char tag[16])
273 {
274     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
275 
276     ret = mbedtls_chachapoly_starts(ctx, nonce, mode);
277     if (ret != 0) {
278         goto cleanup;
279     }
280 
281     ret = mbedtls_chachapoly_update_aad(ctx, aad, aad_len);
282     if (ret != 0) {
283         goto cleanup;
284     }
285 
286     ret = mbedtls_chachapoly_update(ctx, length, input, output);
287     if (ret != 0) {
288         goto cleanup;
289     }
290 
291     ret = mbedtls_chachapoly_finish(ctx, tag);
292 
293 cleanup:
294     return ret;
295 }
296 
mbedtls_chachapoly_encrypt_and_tag(mbedtls_chachapoly_context * ctx,size_t length,const unsigned char nonce[12],const unsigned char * aad,size_t aad_len,const unsigned char * input,unsigned char * output,unsigned char tag[16])297 int mbedtls_chachapoly_encrypt_and_tag(mbedtls_chachapoly_context *ctx,
298                                        size_t length,
299                                        const unsigned char nonce[12],
300                                        const unsigned char *aad,
301                                        size_t aad_len,
302                                        const unsigned char *input,
303                                        unsigned char *output,
304                                        unsigned char tag[16])
305 {
306     CHACHAPOLY_VALIDATE_RET(ctx   != NULL);
307     CHACHAPOLY_VALIDATE_RET(nonce != NULL);
308     CHACHAPOLY_VALIDATE_RET(tag   != NULL);
309     CHACHAPOLY_VALIDATE_RET(aad_len == 0 || aad    != NULL);
310     CHACHAPOLY_VALIDATE_RET(length  == 0 || input  != NULL);
311     CHACHAPOLY_VALIDATE_RET(length  == 0 || output != NULL);
312 
313     return chachapoly_crypt_and_tag(ctx, MBEDTLS_CHACHAPOLY_ENCRYPT,
314                                     length, nonce, aad, aad_len,
315                                     input, output, tag);
316 }
317 
mbedtls_chachapoly_auth_decrypt(mbedtls_chachapoly_context * ctx,size_t length,const unsigned char nonce[12],const unsigned char * aad,size_t aad_len,const unsigned char tag[16],const unsigned char * input,unsigned char * output)318 int mbedtls_chachapoly_auth_decrypt(mbedtls_chachapoly_context *ctx,
319                                     size_t length,
320                                     const unsigned char nonce[12],
321                                     const unsigned char *aad,
322                                     size_t aad_len,
323                                     const unsigned char tag[16],
324                                     const unsigned char *input,
325                                     unsigned char *output)
326 {
327     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
328     unsigned char check_tag[16];
329     int diff;
330     CHACHAPOLY_VALIDATE_RET(ctx   != NULL);
331     CHACHAPOLY_VALIDATE_RET(nonce != NULL);
332     CHACHAPOLY_VALIDATE_RET(tag   != NULL);
333     CHACHAPOLY_VALIDATE_RET(aad_len == 0 || aad    != NULL);
334     CHACHAPOLY_VALIDATE_RET(length  == 0 || input  != NULL);
335     CHACHAPOLY_VALIDATE_RET(length  == 0 || output != NULL);
336 
337     if ((ret = chachapoly_crypt_and_tag(ctx,
338                                         MBEDTLS_CHACHAPOLY_DECRYPT, length, nonce,
339                                         aad, aad_len, input, output, check_tag)) != 0) {
340         return ret;
341     }
342 
343     /* Check tag in "constant-time" */
344     diff = mbedtls_ct_memcmp(tag, check_tag, sizeof(check_tag));
345 
346     if (diff != 0) {
347         mbedtls_platform_zeroize(output, length);
348         return MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED;
349     }
350 
351     return 0;
352 }
353 
354 #endif /* MBEDTLS_CHACHAPOLY_ALT */
355 
356 #if defined(MBEDTLS_SELF_TEST)
357 
358 static const unsigned char test_key[1][32] =
359 {
360     {
361         0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
362         0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
363         0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
364         0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
365     }
366 };
367 
368 static const unsigned char test_nonce[1][12] =
369 {
370     {
371         0x07, 0x00, 0x00, 0x00,                         /* 32-bit common part */
372         0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47  /* 64-bit IV */
373     }
374 };
375 
376 static const unsigned char test_aad[1][12] =
377 {
378     {
379         0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3,
380         0xc4, 0xc5, 0xc6, 0xc7
381     }
382 };
383 
384 static const size_t test_aad_len[1] =
385 {
386     12U
387 };
388 
389 static const unsigned char test_input[1][114] =
390 {
391     {
392         0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61,
393         0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c,
394         0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20,
395         0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73,
396         0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39,
397         0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63,
398         0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66,
399         0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f,
400         0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20,
401         0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20,
402         0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75,
403         0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73,
404         0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f,
405         0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69,
406         0x74, 0x2e
407     }
408 };
409 
410 static const unsigned char test_output[1][114] =
411 {
412     {
413         0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb,
414         0x7b, 0x86, 0xaf, 0xbc, 0x53, 0xef, 0x7e, 0xc2,
415         0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe,
416         0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6,
417         0x3d, 0xbe, 0xa4, 0x5e, 0x8c, 0xa9, 0x67, 0x12,
418         0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b,
419         0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29,
420         0x05, 0xd6, 0xa5, 0xb6, 0x7e, 0xcd, 0x3b, 0x36,
421         0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c,
422         0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58,
423         0xfa, 0xb3, 0x24, 0xe4, 0xfa, 0xd6, 0x75, 0x94,
424         0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc,
425         0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d,
426         0xe5, 0x76, 0xd2, 0x65, 0x86, 0xce, 0xc6, 0x4b,
427         0x61, 0x16
428     }
429 };
430 
431 static const size_t test_input_len[1] =
432 {
433     114U
434 };
435 
436 static const unsigned char test_mac[1][16] =
437 {
438     {
439         0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a,
440         0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91
441     }
442 };
443 
444 /* Make sure no other definition is already present. */
445 #undef ASSERT
446 
447 #define ASSERT(cond, args)            \
448     do                                  \
449     {                                   \
450         if (!(cond))                \
451         {                               \
452             if (verbose != 0)          \
453             mbedtls_printf args;    \
454                                         \
455             return -1;               \
456         }                               \
457     }                                   \
458     while (0)
459 
mbedtls_chachapoly_self_test(int verbose)460 int mbedtls_chachapoly_self_test(int verbose)
461 {
462     mbedtls_chachapoly_context ctx;
463     unsigned i;
464     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
465     unsigned char output[200];
466     unsigned char mac[16];
467 
468     for (i = 0U; i < 1U; i++) {
469         if (verbose != 0) {
470             mbedtls_printf("  ChaCha20-Poly1305 test %u ", i);
471         }
472 
473         mbedtls_chachapoly_init(&ctx);
474 
475         ret = mbedtls_chachapoly_setkey(&ctx, test_key[i]);
476         ASSERT(0 == ret, ("setkey() error code: %i\n", ret));
477 
478         ret = mbedtls_chachapoly_encrypt_and_tag(&ctx,
479                                                  test_input_len[i],
480                                                  test_nonce[i],
481                                                  test_aad[i],
482                                                  test_aad_len[i],
483                                                  test_input[i],
484                                                  output,
485                                                  mac);
486 
487         ASSERT(0 == ret, ("crypt_and_tag() error code: %i\n", ret));
488 
489         ASSERT(0 == memcmp(output, test_output[i], test_input_len[i]),
490                ("failure (wrong output)\n"));
491 
492         ASSERT(0 == memcmp(mac, test_mac[i], 16U),
493                ("failure (wrong MAC)\n"));
494 
495         mbedtls_chachapoly_free(&ctx);
496 
497         if (verbose != 0) {
498             mbedtls_printf("passed\n");
499         }
500     }
501 
502     if (verbose != 0) {
503         mbedtls_printf("\n");
504     }
505 
506     return 0;
507 }
508 
509 #endif /* MBEDTLS_SELF_TEST */
510 
511 #endif /* MBEDTLS_CHACHAPOLY_C */
512