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