1 /* 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" 33 #include "mbedtls/error.h" 34 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 */ 64 static 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 */ 84 static 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 98 void 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 110 void 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 123 int mbedtls_chachapoly_setkey( mbedtls_chachapoly_context *ctx, 124 const unsigned char key[32] ) 125 { 126 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 127 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 135 int mbedtls_chachapoly_starts( mbedtls_chachapoly_context *ctx, 136 const unsigned char nonce[12], 137 mbedtls_chachapoly_mode_t mode ) 138 { 139 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 140 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 170 cleanup: 171 mbedtls_platform_zeroize( poly1305_key, 64U ); 172 return( ret ); 173 } 174 175 int 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 190 int mbedtls_chachapoly_update( mbedtls_chachapoly_context *ctx, 191 size_t len, 192 const unsigned char *input, 193 unsigned char *output ) 194 { 195 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 196 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 241 int mbedtls_chachapoly_finish( mbedtls_chachapoly_context *ctx, 242 unsigned char mac[16] ) 243 { 244 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 245 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 298 static 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 { 308 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 309 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 324 cleanup: 325 return( ret ); 326 } 327 328 int 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 349 int 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 { 358 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 359 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 393 static 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 403 static 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 411 static 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 419 static const size_t test_aad_len[1] = 420 { 421 12U 422 }; 423 424 static 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 445 static 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 466 static const size_t test_input_len[1] = 467 { 468 114U 469 }; 470 471 static 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 492 int mbedtls_chachapoly_self_test( int verbose ) 493 { 494 mbedtls_chachapoly_context ctx; 495 unsigned i; 496 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 497 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 */ 542