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 len_block[ 0] = (unsigned char)( ctx->aad_len );
267 len_block[ 1] = (unsigned char)( ctx->aad_len >> 8 );
268 len_block[ 2] = (unsigned char)( ctx->aad_len >> 16 );
269 len_block[ 3] = (unsigned char)( ctx->aad_len >> 24 );
270 len_block[ 4] = (unsigned char)( ctx->aad_len >> 32 );
271 len_block[ 5] = (unsigned char)( ctx->aad_len >> 40 );
272 len_block[ 6] = (unsigned char)( ctx->aad_len >> 48 );
273 len_block[ 7] = (unsigned char)( ctx->aad_len >> 56 );
274 len_block[ 8] = (unsigned char)( ctx->ciphertext_len );
275 len_block[ 9] = (unsigned char)( ctx->ciphertext_len >> 8 );
276 len_block[10] = (unsigned char)( ctx->ciphertext_len >> 16 );
277 len_block[11] = (unsigned char)( ctx->ciphertext_len >> 24 );
278 len_block[12] = (unsigned char)( ctx->ciphertext_len >> 32 );
279 len_block[13] = (unsigned char)( ctx->ciphertext_len >> 40 );
280 len_block[14] = (unsigned char)( ctx->ciphertext_len >> 48 );
281 len_block[15] = (unsigned char)( ctx->ciphertext_len >> 56 );
282
283 ret = mbedtls_poly1305_update( &ctx->poly1305_ctx, len_block, 16U );
284 if( ret != 0 )
285 return( ret );
286
287 ret = mbedtls_poly1305_finish( &ctx->poly1305_ctx, mac );
288
289 return( ret );
290 }
291
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])292 static int chachapoly_crypt_and_tag( mbedtls_chachapoly_context *ctx,
293 mbedtls_chachapoly_mode_t mode,
294 size_t length,
295 const unsigned char nonce[12],
296 const unsigned char *aad,
297 size_t aad_len,
298 const unsigned char *input,
299 unsigned char *output,
300 unsigned char tag[16] )
301 {
302 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
303
304 ret = mbedtls_chachapoly_starts( ctx, nonce, mode );
305 if( ret != 0 )
306 goto cleanup;
307
308 ret = mbedtls_chachapoly_update_aad( ctx, aad, aad_len );
309 if( ret != 0 )
310 goto cleanup;
311
312 ret = mbedtls_chachapoly_update( ctx, length, input, output );
313 if( ret != 0 )
314 goto cleanup;
315
316 ret = mbedtls_chachapoly_finish( ctx, tag );
317
318 cleanup:
319 return( ret );
320 }
321
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])322 int mbedtls_chachapoly_encrypt_and_tag( mbedtls_chachapoly_context *ctx,
323 size_t length,
324 const unsigned char nonce[12],
325 const unsigned char *aad,
326 size_t aad_len,
327 const unsigned char *input,
328 unsigned char *output,
329 unsigned char tag[16] )
330 {
331 CHACHAPOLY_VALIDATE_RET( ctx != NULL );
332 CHACHAPOLY_VALIDATE_RET( nonce != NULL );
333 CHACHAPOLY_VALIDATE_RET( tag != NULL );
334 CHACHAPOLY_VALIDATE_RET( aad_len == 0 || aad != NULL );
335 CHACHAPOLY_VALIDATE_RET( length == 0 || input != NULL );
336 CHACHAPOLY_VALIDATE_RET( length == 0 || output != NULL );
337
338 return( chachapoly_crypt_and_tag( ctx, MBEDTLS_CHACHAPOLY_ENCRYPT,
339 length, nonce, aad, aad_len,
340 input, output, tag ) );
341 }
342
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)343 int mbedtls_chachapoly_auth_decrypt( mbedtls_chachapoly_context *ctx,
344 size_t length,
345 const unsigned char nonce[12],
346 const unsigned char *aad,
347 size_t aad_len,
348 const unsigned char tag[16],
349 const unsigned char *input,
350 unsigned char *output )
351 {
352 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
353 unsigned char check_tag[16];
354 size_t i;
355 int diff;
356 CHACHAPOLY_VALIDATE_RET( ctx != NULL );
357 CHACHAPOLY_VALIDATE_RET( nonce != NULL );
358 CHACHAPOLY_VALIDATE_RET( tag != NULL );
359 CHACHAPOLY_VALIDATE_RET( aad_len == 0 || aad != NULL );
360 CHACHAPOLY_VALIDATE_RET( length == 0 || input != NULL );
361 CHACHAPOLY_VALIDATE_RET( length == 0 || output != NULL );
362
363 if( ( ret = chachapoly_crypt_and_tag( ctx,
364 MBEDTLS_CHACHAPOLY_DECRYPT, length, nonce,
365 aad, aad_len, input, output, check_tag ) ) != 0 )
366 {
367 return( ret );
368 }
369
370 /* Check tag in "constant-time" */
371 for( diff = 0, i = 0; i < sizeof( check_tag ); i++ )
372 diff |= tag[i] ^ check_tag[i];
373
374 if( diff != 0 )
375 {
376 mbedtls_platform_zeroize( output, length );
377 return( MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED );
378 }
379
380 return( 0 );
381 }
382
383 #endif /* MBEDTLS_CHACHAPOLY_ALT */
384
385 #if defined(MBEDTLS_SELF_TEST)
386
387 static const unsigned char test_key[1][32] =
388 {
389 {
390 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
391 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
392 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
393 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
394 }
395 };
396
397 static const unsigned char test_nonce[1][12] =
398 {
399 {
400 0x07, 0x00, 0x00, 0x00, /* 32-bit common part */
401 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47 /* 64-bit IV */
402 }
403 };
404
405 static const unsigned char test_aad[1][12] =
406 {
407 {
408 0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3,
409 0xc4, 0xc5, 0xc6, 0xc7
410 }
411 };
412
413 static const size_t test_aad_len[1] =
414 {
415 12U
416 };
417
418 static const unsigned char test_input[1][114] =
419 {
420 {
421 0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61,
422 0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c,
423 0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20,
424 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73,
425 0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39,
426 0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63,
427 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66,
428 0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f,
429 0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20,
430 0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20,
431 0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75,
432 0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73,
433 0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f,
434 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69,
435 0x74, 0x2e
436 }
437 };
438
439 static const unsigned char test_output[1][114] =
440 {
441 {
442 0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb,
443 0x7b, 0x86, 0xaf, 0xbc, 0x53, 0xef, 0x7e, 0xc2,
444 0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe,
445 0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6,
446 0x3d, 0xbe, 0xa4, 0x5e, 0x8c, 0xa9, 0x67, 0x12,
447 0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b,
448 0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29,
449 0x05, 0xd6, 0xa5, 0xb6, 0x7e, 0xcd, 0x3b, 0x36,
450 0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c,
451 0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58,
452 0xfa, 0xb3, 0x24, 0xe4, 0xfa, 0xd6, 0x75, 0x94,
453 0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc,
454 0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d,
455 0xe5, 0x76, 0xd2, 0x65, 0x86, 0xce, 0xc6, 0x4b,
456 0x61, 0x16
457 }
458 };
459
460 static const size_t test_input_len[1] =
461 {
462 114U
463 };
464
465 static const unsigned char test_mac[1][16] =
466 {
467 {
468 0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a,
469 0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91
470 }
471 };
472
473 /* Make sure no other definition is already present. */
474 #undef ASSERT
475
476 #define ASSERT( cond, args ) \
477 do \
478 { \
479 if( ! ( cond ) ) \
480 { \
481 if( verbose != 0 ) \
482 mbedtls_printf args; \
483 \
484 return( -1 ); \
485 } \
486 } \
487 while( 0 )
488
mbedtls_chachapoly_self_test(int verbose)489 int mbedtls_chachapoly_self_test( int verbose )
490 {
491 mbedtls_chachapoly_context ctx;
492 unsigned i;
493 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
494 unsigned char output[200];
495 unsigned char mac[16];
496
497 for( i = 0U; i < 1U; i++ )
498 {
499 if( verbose != 0 )
500 mbedtls_printf( " ChaCha20-Poly1305 test %u ", i );
501
502 mbedtls_chachapoly_init( &ctx );
503
504 ret = mbedtls_chachapoly_setkey( &ctx, test_key[i] );
505 ASSERT( 0 == ret, ( "setkey() error code: %i\n", ret ) );
506
507 ret = mbedtls_chachapoly_encrypt_and_tag( &ctx,
508 test_input_len[i],
509 test_nonce[i],
510 test_aad[i],
511 test_aad_len[i],
512 test_input[i],
513 output,
514 mac );
515
516 ASSERT( 0 == ret, ( "crypt_and_tag() error code: %i\n", ret ) );
517
518 ASSERT( 0 == memcmp( output, test_output[i], test_input_len[i] ),
519 ( "failure (wrong output)\n" ) );
520
521 ASSERT( 0 == memcmp( mac, test_mac[i], 16U ),
522 ( "failure (wrong MAC)\n" ) );
523
524 mbedtls_chachapoly_free( &ctx );
525
526 if( verbose != 0 )
527 mbedtls_printf( "passed\n" );
528 }
529
530 if( verbose != 0 )
531 mbedtls_printf( "\n" );
532
533 return( 0 );
534 }
535
536 #endif /* MBEDTLS_SELF_TEST */
537
538 #endif /* MBEDTLS_CHACHAPOLY_C */
539