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 */ 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 */ 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 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 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 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 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 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 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 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 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 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 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 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