4 * \brief ChaCha20-Poly1305 AEAD construction based on RFC 7539.
\r
6 * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved
\r
7 * SPDX-License-Identifier: Apache-2.0
\r
9 * Licensed under the Apache License, Version 2.0 (the "License"); you may
\r
10 * not use this file except in compliance with the License.
\r
11 * You may obtain a copy of the License at
\r
13 * http://www.apache.org/licenses/LICENSE-2.0
\r
15 * Unless required by applicable law or agreed to in writing, software
\r
16 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
\r
17 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
18 * See the License for the specific language governing permissions and
\r
19 * limitations under the License.
\r
21 * This file is part of mbed TLS (https://tls.mbed.org)
\r
23 #if !defined(MBEDTLS_CONFIG_FILE)
\r
24 #include "mbedtls/config.h"
\r
26 #include MBEDTLS_CONFIG_FILE
\r
29 #if defined(MBEDTLS_CHACHAPOLY_C)
\r
31 #include "mbedtls/chachapoly.h"
\r
32 #include "mbedtls/platform_util.h"
\r
36 #if defined(MBEDTLS_SELF_TEST)
\r
37 #if defined(MBEDTLS_PLATFORM_C)
\r
38 #include "mbedtls/platform.h"
\r
41 #define mbedtls_printf printf
\r
42 #endif /* MBEDTLS_PLATFORM_C */
\r
43 #endif /* MBEDTLS_SELF_TEST */
\r
45 #if !defined(MBEDTLS_CHACHAPOLY_ALT)
\r
47 /* Parameter validation macros */
\r
48 #define CHACHAPOLY_VALIDATE_RET( cond ) \
\r
49 MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_POLY1305_BAD_INPUT_DATA )
\r
50 #define CHACHAPOLY_VALIDATE( cond ) \
\r
51 MBEDTLS_INTERNAL_VALIDATE( cond )
\r
53 #define CHACHAPOLY_STATE_INIT ( 0 )
\r
54 #define CHACHAPOLY_STATE_AAD ( 1 )
\r
55 #define CHACHAPOLY_STATE_CIPHERTEXT ( 2 ) /* Encrypting or decrypting */
\r
56 #define CHACHAPOLY_STATE_FINISHED ( 3 )
\r
59 * \brief Adds nul bytes to pad the AAD for Poly1305.
\r
61 * \param ctx The ChaCha20-Poly1305 context.
\r
63 static int chachapoly_pad_aad( mbedtls_chachapoly_context *ctx )
\r
65 uint32_t partial_block_len = (uint32_t) ( ctx->aad_len % 16U );
\r
66 unsigned char zeroes[15];
\r
68 if( partial_block_len == 0U )
\r
71 memset( zeroes, 0, sizeof( zeroes ) );
\r
73 return( mbedtls_poly1305_update( &ctx->poly1305_ctx,
\r
75 16U - partial_block_len ) );
\r
79 * \brief Adds nul bytes to pad the ciphertext for Poly1305.
\r
81 * \param ctx The ChaCha20-Poly1305 context.
\r
83 static int chachapoly_pad_ciphertext( mbedtls_chachapoly_context *ctx )
\r
85 uint32_t partial_block_len = (uint32_t) ( ctx->ciphertext_len % 16U );
\r
86 unsigned char zeroes[15];
\r
88 if( partial_block_len == 0U )
\r
91 memset( zeroes, 0, sizeof( zeroes ) );
\r
92 return( mbedtls_poly1305_update( &ctx->poly1305_ctx,
\r
94 16U - partial_block_len ) );
\r
97 void mbedtls_chachapoly_init( mbedtls_chachapoly_context *ctx )
\r
99 CHACHAPOLY_VALIDATE( ctx != NULL );
\r
101 mbedtls_chacha20_init( &ctx->chacha20_ctx );
\r
102 mbedtls_poly1305_init( &ctx->poly1305_ctx );
\r
104 ctx->ciphertext_len = 0U;
\r
105 ctx->state = CHACHAPOLY_STATE_INIT;
\r
106 ctx->mode = MBEDTLS_CHACHAPOLY_ENCRYPT;
\r
109 void mbedtls_chachapoly_free( mbedtls_chachapoly_context *ctx )
\r
114 mbedtls_chacha20_free( &ctx->chacha20_ctx );
\r
115 mbedtls_poly1305_free( &ctx->poly1305_ctx );
\r
117 ctx->ciphertext_len = 0U;
\r
118 ctx->state = CHACHAPOLY_STATE_INIT;
\r
119 ctx->mode = MBEDTLS_CHACHAPOLY_ENCRYPT;
\r
122 int mbedtls_chachapoly_setkey( mbedtls_chachapoly_context *ctx,
\r
123 const unsigned char key[32] )
\r
126 CHACHAPOLY_VALIDATE_RET( ctx != NULL );
\r
127 CHACHAPOLY_VALIDATE_RET( key != NULL );
\r
129 ret = mbedtls_chacha20_setkey( &ctx->chacha20_ctx, key );
\r
134 int mbedtls_chachapoly_starts( mbedtls_chachapoly_context *ctx,
\r
135 const unsigned char nonce[12],
\r
136 mbedtls_chachapoly_mode_t mode )
\r
139 unsigned char poly1305_key[64];
\r
140 CHACHAPOLY_VALIDATE_RET( ctx != NULL );
\r
141 CHACHAPOLY_VALIDATE_RET( nonce != NULL );
\r
143 /* Set counter = 0, will be update to 1 when generating Poly1305 key */
\r
144 ret = mbedtls_chacha20_starts( &ctx->chacha20_ctx, nonce, 0U );
\r
148 /* Generate the Poly1305 key by getting the ChaCha20 keystream output with
\r
149 * counter = 0. This is the same as encrypting a buffer of zeroes.
\r
150 * Only the first 256-bits (32 bytes) of the key is used for Poly1305.
\r
151 * The other 256 bits are discarded.
\r
153 memset( poly1305_key, 0, sizeof( poly1305_key ) );
\r
154 ret = mbedtls_chacha20_update( &ctx->chacha20_ctx, sizeof( poly1305_key ),
\r
155 poly1305_key, poly1305_key );
\r
159 ret = mbedtls_poly1305_starts( &ctx->poly1305_ctx, poly1305_key );
\r
164 ctx->ciphertext_len = 0U;
\r
165 ctx->state = CHACHAPOLY_STATE_AAD;
\r
170 mbedtls_platform_zeroize( poly1305_key, 64U );
\r
174 int mbedtls_chachapoly_update_aad( mbedtls_chachapoly_context *ctx,
\r
175 const unsigned char *aad,
\r
178 CHACHAPOLY_VALIDATE_RET( ctx != NULL );
\r
179 CHACHAPOLY_VALIDATE_RET( aad_len == 0 || aad != NULL );
\r
181 if( ctx->state != CHACHAPOLY_STATE_AAD )
\r
182 return( MBEDTLS_ERR_CHACHAPOLY_BAD_STATE );
\r
184 ctx->aad_len += aad_len;
\r
186 return( mbedtls_poly1305_update( &ctx->poly1305_ctx, aad, aad_len ) );
\r
189 int mbedtls_chachapoly_update( mbedtls_chachapoly_context *ctx,
\r
191 const unsigned char *input,
\r
192 unsigned char *output )
\r
195 CHACHAPOLY_VALIDATE_RET( ctx != NULL );
\r
196 CHACHAPOLY_VALIDATE_RET( len == 0 || input != NULL );
\r
197 CHACHAPOLY_VALIDATE_RET( len == 0 || output != NULL );
\r
199 if( ( ctx->state != CHACHAPOLY_STATE_AAD ) &&
\r
200 ( ctx->state != CHACHAPOLY_STATE_CIPHERTEXT ) )
\r
202 return( MBEDTLS_ERR_CHACHAPOLY_BAD_STATE );
\r
205 if( ctx->state == CHACHAPOLY_STATE_AAD )
\r
207 ctx->state = CHACHAPOLY_STATE_CIPHERTEXT;
\r
209 ret = chachapoly_pad_aad( ctx );
\r
214 ctx->ciphertext_len += len;
\r
216 if( ctx->mode == MBEDTLS_CHACHAPOLY_ENCRYPT )
\r
218 ret = mbedtls_chacha20_update( &ctx->chacha20_ctx, len, input, output );
\r
222 ret = mbedtls_poly1305_update( &ctx->poly1305_ctx, output, len );
\r
228 ret = mbedtls_poly1305_update( &ctx->poly1305_ctx, input, len );
\r
232 ret = mbedtls_chacha20_update( &ctx->chacha20_ctx, len, input, output );
\r
240 int mbedtls_chachapoly_finish( mbedtls_chachapoly_context *ctx,
\r
241 unsigned char mac[16] )
\r
244 unsigned char len_block[16];
\r
245 CHACHAPOLY_VALIDATE_RET( ctx != NULL );
\r
246 CHACHAPOLY_VALIDATE_RET( mac != NULL );
\r
248 if( ctx->state == CHACHAPOLY_STATE_INIT )
\r
250 return( MBEDTLS_ERR_CHACHAPOLY_BAD_STATE );
\r
253 if( ctx->state == CHACHAPOLY_STATE_AAD )
\r
255 ret = chachapoly_pad_aad( ctx );
\r
259 else if( ctx->state == CHACHAPOLY_STATE_CIPHERTEXT )
\r
261 ret = chachapoly_pad_ciphertext( ctx );
\r
266 ctx->state = CHACHAPOLY_STATE_FINISHED;
\r
268 /* The lengths of the AAD and ciphertext are processed by
\r
269 * Poly1305 as the final 128-bit block, encoded as little-endian integers.
\r
271 len_block[ 0] = (unsigned char)( ctx->aad_len );
\r
272 len_block[ 1] = (unsigned char)( ctx->aad_len >> 8 );
\r
273 len_block[ 2] = (unsigned char)( ctx->aad_len >> 16 );
\r
274 len_block[ 3] = (unsigned char)( ctx->aad_len >> 24 );
\r
275 len_block[ 4] = (unsigned char)( ctx->aad_len >> 32 );
\r
276 len_block[ 5] = (unsigned char)( ctx->aad_len >> 40 );
\r
277 len_block[ 6] = (unsigned char)( ctx->aad_len >> 48 );
\r
278 len_block[ 7] = (unsigned char)( ctx->aad_len >> 56 );
\r
279 len_block[ 8] = (unsigned char)( ctx->ciphertext_len );
\r
280 len_block[ 9] = (unsigned char)( ctx->ciphertext_len >> 8 );
\r
281 len_block[10] = (unsigned char)( ctx->ciphertext_len >> 16 );
\r
282 len_block[11] = (unsigned char)( ctx->ciphertext_len >> 24 );
\r
283 len_block[12] = (unsigned char)( ctx->ciphertext_len >> 32 );
\r
284 len_block[13] = (unsigned char)( ctx->ciphertext_len >> 40 );
\r
285 len_block[14] = (unsigned char)( ctx->ciphertext_len >> 48 );
\r
286 len_block[15] = (unsigned char)( ctx->ciphertext_len >> 56 );
\r
288 ret = mbedtls_poly1305_update( &ctx->poly1305_ctx, len_block, 16U );
\r
292 ret = mbedtls_poly1305_finish( &ctx->poly1305_ctx, mac );
\r
297 static int chachapoly_crypt_and_tag( mbedtls_chachapoly_context *ctx,
\r
298 mbedtls_chachapoly_mode_t mode,
\r
300 const unsigned char nonce[12],
\r
301 const unsigned char *aad,
\r
303 const unsigned char *input,
\r
304 unsigned char *output,
\r
305 unsigned char tag[16] )
\r
309 ret = mbedtls_chachapoly_starts( ctx, nonce, mode );
\r
313 ret = mbedtls_chachapoly_update_aad( ctx, aad, aad_len );
\r
317 ret = mbedtls_chachapoly_update( ctx, length, input, output );
\r
321 ret = mbedtls_chachapoly_finish( ctx, tag );
\r
327 int mbedtls_chachapoly_encrypt_and_tag( mbedtls_chachapoly_context *ctx,
\r
329 const unsigned char nonce[12],
\r
330 const unsigned char *aad,
\r
332 const unsigned char *input,
\r
333 unsigned char *output,
\r
334 unsigned char tag[16] )
\r
336 CHACHAPOLY_VALIDATE_RET( ctx != NULL );
\r
337 CHACHAPOLY_VALIDATE_RET( nonce != NULL );
\r
338 CHACHAPOLY_VALIDATE_RET( tag != NULL );
\r
339 CHACHAPOLY_VALIDATE_RET( aad_len == 0 || aad != NULL );
\r
340 CHACHAPOLY_VALIDATE_RET( length == 0 || input != NULL );
\r
341 CHACHAPOLY_VALIDATE_RET( length == 0 || output != NULL );
\r
343 return( chachapoly_crypt_and_tag( ctx, MBEDTLS_CHACHAPOLY_ENCRYPT,
\r
344 length, nonce, aad, aad_len,
\r
345 input, output, tag ) );
\r
348 int mbedtls_chachapoly_auth_decrypt( mbedtls_chachapoly_context *ctx,
\r
350 const unsigned char nonce[12],
\r
351 const unsigned char *aad,
\r
353 const unsigned char tag[16],
\r
354 const unsigned char *input,
\r
355 unsigned char *output )
\r
358 unsigned char check_tag[16];
\r
361 CHACHAPOLY_VALIDATE_RET( ctx != NULL );
\r
362 CHACHAPOLY_VALIDATE_RET( nonce != NULL );
\r
363 CHACHAPOLY_VALIDATE_RET( tag != NULL );
\r
364 CHACHAPOLY_VALIDATE_RET( aad_len == 0 || aad != NULL );
\r
365 CHACHAPOLY_VALIDATE_RET( length == 0 || input != NULL );
\r
366 CHACHAPOLY_VALIDATE_RET( length == 0 || output != NULL );
\r
368 if( ( ret = chachapoly_crypt_and_tag( ctx,
\r
369 MBEDTLS_CHACHAPOLY_DECRYPT, length, nonce,
\r
370 aad, aad_len, input, output, check_tag ) ) != 0 )
\r
375 /* Check tag in "constant-time" */
\r
376 for( diff = 0, i = 0; i < sizeof( check_tag ); i++ )
\r
377 diff |= tag[i] ^ check_tag[i];
\r
381 mbedtls_platform_zeroize( output, length );
\r
382 return( MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED );
\r
388 #endif /* MBEDTLS_CHACHAPOLY_ALT */
\r
390 #if defined(MBEDTLS_SELF_TEST)
\r
392 static const unsigned char test_key[1][32] =
\r
395 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
\r
396 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
\r
397 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
\r
398 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
\r
402 static const unsigned char test_nonce[1][12] =
\r
405 0x07, 0x00, 0x00, 0x00, /* 32-bit common part */
\r
406 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47 /* 64-bit IV */
\r
410 static const unsigned char test_aad[1][12] =
\r
413 0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3,
\r
414 0xc4, 0xc5, 0xc6, 0xc7
\r
418 static const size_t test_aad_len[1] =
\r
423 static const unsigned char test_input[1][114] =
\r
426 0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61,
\r
427 0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c,
\r
428 0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20,
\r
429 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73,
\r
430 0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39,
\r
431 0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63,
\r
432 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66,
\r
433 0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f,
\r
434 0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20,
\r
435 0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20,
\r
436 0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75,
\r
437 0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73,
\r
438 0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f,
\r
439 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69,
\r
444 static const unsigned char test_output[1][114] =
\r
447 0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb,
\r
448 0x7b, 0x86, 0xaf, 0xbc, 0x53, 0xef, 0x7e, 0xc2,
\r
449 0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe,
\r
450 0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6,
\r
451 0x3d, 0xbe, 0xa4, 0x5e, 0x8c, 0xa9, 0x67, 0x12,
\r
452 0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b,
\r
453 0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29,
\r
454 0x05, 0xd6, 0xa5, 0xb6, 0x7e, 0xcd, 0x3b, 0x36,
\r
455 0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c,
\r
456 0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58,
\r
457 0xfa, 0xb3, 0x24, 0xe4, 0xfa, 0xd6, 0x75, 0x94,
\r
458 0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc,
\r
459 0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d,
\r
460 0xe5, 0x76, 0xd2, 0x65, 0x86, 0xce, 0xc6, 0x4b,
\r
465 static const size_t test_input_len[1] =
\r
470 static const unsigned char test_mac[1][16] =
\r
473 0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a,
\r
474 0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91
\r
478 #define ASSERT( cond, args ) \
\r
483 if( verbose != 0 ) \
\r
484 mbedtls_printf args; \
\r
491 int mbedtls_chachapoly_self_test( int verbose )
\r
493 mbedtls_chachapoly_context ctx;
\r
496 unsigned char output[200];
\r
497 unsigned char mac[16];
\r
499 for( i = 0U; i < 1U; i++ )
\r
502 mbedtls_printf( " ChaCha20-Poly1305 test %u ", i );
\r
504 mbedtls_chachapoly_init( &ctx );
\r
506 ret = mbedtls_chachapoly_setkey( &ctx, test_key[i] );
\r
507 ASSERT( 0 == ret, ( "setkey() error code: %i\n", ret ) );
\r
509 ret = mbedtls_chachapoly_encrypt_and_tag( &ctx,
\r
518 ASSERT( 0 == ret, ( "crypt_and_tag() error code: %i\n", ret ) );
\r
520 ASSERT( 0 == memcmp( output, test_output[i], test_input_len[i] ),
\r
521 ( "failure (wrong output)\n" ) );
\r
523 ASSERT( 0 == memcmp( mac, test_mac[i], 16U ),
\r
524 ( "failure (wrong MAC)\n" ) );
\r
526 mbedtls_chachapoly_free( &ctx );
\r
529 mbedtls_printf( "passed\n" );
\r
533 mbedtls_printf( "\n" );
\r
538 #endif /* MBEDTLS_SELF_TEST */
\r
540 #endif /* MBEDTLS_CHACHAPOLY_C */
\r