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