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