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