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