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