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