1 /* $OpenBSD: e_chacha20poly1305.c,v 1.32 2023/09/28 11:29:10 tb Exp $ */ 2 3 /* 4 * Copyright (c) 2022 Joel Sing <jsing@openbsd.org> 5 * Copyright (c) 2015 Reyk Floter <reyk@openbsd.org> 6 * Copyright (c) 2014, Google Inc. 7 * 8 * Permission to use, copy, modify, and/or distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 15 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 17 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 18 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21 #include <limits.h> 22 #include <stdint.h> 23 #include <string.h> 24 25 #include <openssl/opensslconf.h> 26 27 #if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305) 28 29 #include <openssl/err.h> 30 #include <openssl/evp.h> 31 #include <openssl/chacha.h> 32 #include <openssl/poly1305.h> 33 34 #include "bytestring.h" 35 #include "evp_local.h" 36 37 #define POLY1305_TAG_LEN 16 38 39 #define CHACHA20_CONSTANT_LEN 4 40 #define CHACHA20_IV_LEN 8 41 #define CHACHA20_NONCE_LEN (CHACHA20_CONSTANT_LEN + CHACHA20_IV_LEN) 42 #define XCHACHA20_NONCE_LEN 24 43 44 struct aead_chacha20_poly1305_ctx { 45 unsigned char key[32]; 46 unsigned char tag_len; 47 }; 48 49 static int 50 aead_chacha20_poly1305_init(EVP_AEAD_CTX *ctx, const unsigned char *key, 51 size_t key_len, size_t tag_len) 52 { 53 struct aead_chacha20_poly1305_ctx *c20_ctx; 54 55 if (tag_len == 0) 56 tag_len = POLY1305_TAG_LEN; 57 58 if (tag_len > POLY1305_TAG_LEN) { 59 EVPerror(EVP_R_TOO_LARGE); 60 return 0; 61 } 62 63 /* Internal error - EVP_AEAD_CTX_init should catch this. */ 64 if (key_len != sizeof(c20_ctx->key)) 65 return 0; 66 67 c20_ctx = malloc(sizeof(struct aead_chacha20_poly1305_ctx)); 68 if (c20_ctx == NULL) 69 return 0; 70 71 memcpy(&c20_ctx->key[0], key, key_len); 72 c20_ctx->tag_len = tag_len; 73 ctx->aead_state = c20_ctx; 74 75 return 1; 76 } 77 78 static void 79 aead_chacha20_poly1305_cleanup(EVP_AEAD_CTX *ctx) 80 { 81 struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state; 82 83 freezero(c20_ctx, sizeof(*c20_ctx)); 84 } 85 86 static void 87 poly1305_update_with_length(poly1305_state *poly1305, 88 const unsigned char *data, size_t data_len) 89 { 90 size_t j = data_len; 91 unsigned char length_bytes[8]; 92 unsigned i; 93 94 for (i = 0; i < sizeof(length_bytes); i++) { 95 length_bytes[i] = j; 96 j >>= 8; 97 } 98 99 if (data != NULL) 100 CRYPTO_poly1305_update(poly1305, data, data_len); 101 CRYPTO_poly1305_update(poly1305, length_bytes, sizeof(length_bytes)); 102 } 103 104 static void 105 poly1305_pad16(poly1305_state *poly1305, size_t data_len) 106 { 107 static const unsigned char zero_pad16[16]; 108 size_t pad_len; 109 110 /* pad16() is defined in RFC 8439 2.8.1. */ 111 if ((pad_len = data_len % 16) == 0) 112 return; 113 114 CRYPTO_poly1305_update(poly1305, zero_pad16, 16 - pad_len); 115 } 116 117 static void 118 poly1305_update_with_pad16(poly1305_state *poly1305, 119 const unsigned char *data, size_t data_len) 120 { 121 CRYPTO_poly1305_update(poly1305, data, data_len); 122 poly1305_pad16(poly1305, data_len); 123 } 124 125 static int 126 aead_chacha20_poly1305_seal(const EVP_AEAD_CTX *ctx, unsigned char *out, 127 size_t *out_len, size_t max_out_len, const unsigned char *nonce, 128 size_t nonce_len, const unsigned char *in, size_t in_len, 129 const unsigned char *ad, size_t ad_len) 130 { 131 const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state; 132 unsigned char poly1305_key[32]; 133 poly1305_state poly1305; 134 const unsigned char *iv; 135 uint64_t ctr; 136 137 if (max_out_len < in_len + c20_ctx->tag_len) { 138 EVPerror(EVP_R_BUFFER_TOO_SMALL); 139 return 0; 140 } 141 142 if (nonce_len != ctx->aead->nonce_len) { 143 EVPerror(EVP_R_IV_TOO_LARGE); 144 return 0; 145 } 146 147 ctr = (uint64_t)((uint32_t)(nonce[0]) | (uint32_t)(nonce[1]) << 8 | 148 (uint32_t)(nonce[2]) << 16 | (uint32_t)(nonce[3]) << 24) << 32; 149 iv = nonce + CHACHA20_CONSTANT_LEN; 150 151 memset(poly1305_key, 0, sizeof(poly1305_key)); 152 CRYPTO_chacha_20(poly1305_key, poly1305_key, 153 sizeof(poly1305_key), c20_ctx->key, iv, ctr); 154 155 CRYPTO_poly1305_init(&poly1305, poly1305_key); 156 poly1305_update_with_pad16(&poly1305, ad, ad_len); 157 CRYPTO_chacha_20(out, in, in_len, c20_ctx->key, iv, ctr + 1); 158 poly1305_update_with_pad16(&poly1305, out, in_len); 159 poly1305_update_with_length(&poly1305, NULL, ad_len); 160 poly1305_update_with_length(&poly1305, NULL, in_len); 161 162 if (c20_ctx->tag_len != POLY1305_TAG_LEN) { 163 unsigned char tag[POLY1305_TAG_LEN]; 164 CRYPTO_poly1305_finish(&poly1305, tag); 165 memcpy(out + in_len, tag, c20_ctx->tag_len); 166 *out_len = in_len + c20_ctx->tag_len; 167 return 1; 168 } 169 170 CRYPTO_poly1305_finish(&poly1305, out + in_len); 171 *out_len = in_len + POLY1305_TAG_LEN; 172 return 1; 173 } 174 175 static int 176 aead_chacha20_poly1305_open(const EVP_AEAD_CTX *ctx, unsigned char *out, 177 size_t *out_len, size_t max_out_len, const unsigned char *nonce, 178 size_t nonce_len, const unsigned char *in, size_t in_len, 179 const unsigned char *ad, size_t ad_len) 180 { 181 const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state; 182 unsigned char mac[POLY1305_TAG_LEN]; 183 unsigned char poly1305_key[32]; 184 const unsigned char *iv = nonce; 185 poly1305_state poly1305; 186 size_t plaintext_len; 187 uint64_t ctr = 0; 188 189 if (in_len < c20_ctx->tag_len) { 190 EVPerror(EVP_R_BAD_DECRYPT); 191 return 0; 192 } 193 194 if (nonce_len != ctx->aead->nonce_len) { 195 EVPerror(EVP_R_IV_TOO_LARGE); 196 return 0; 197 } 198 199 plaintext_len = in_len - c20_ctx->tag_len; 200 201 if (max_out_len < plaintext_len) { 202 EVPerror(EVP_R_BUFFER_TOO_SMALL); 203 return 0; 204 } 205 206 ctr = (uint64_t)((uint32_t)(nonce[0]) | (uint32_t)(nonce[1]) << 8 | 207 (uint32_t)(nonce[2]) << 16 | (uint32_t)(nonce[3]) << 24) << 32; 208 iv = nonce + CHACHA20_CONSTANT_LEN; 209 210 memset(poly1305_key, 0, sizeof(poly1305_key)); 211 CRYPTO_chacha_20(poly1305_key, poly1305_key, 212 sizeof(poly1305_key), c20_ctx->key, iv, ctr); 213 214 CRYPTO_poly1305_init(&poly1305, poly1305_key); 215 poly1305_update_with_pad16(&poly1305, ad, ad_len); 216 poly1305_update_with_pad16(&poly1305, in, plaintext_len); 217 poly1305_update_with_length(&poly1305, NULL, ad_len); 218 poly1305_update_with_length(&poly1305, NULL, plaintext_len); 219 220 CRYPTO_poly1305_finish(&poly1305, mac); 221 222 if (timingsafe_memcmp(mac, in + plaintext_len, c20_ctx->tag_len) != 0) { 223 EVPerror(EVP_R_BAD_DECRYPT); 224 return 0; 225 } 226 227 CRYPTO_chacha_20(out, in, plaintext_len, c20_ctx->key, iv, ctr + 1); 228 *out_len = plaintext_len; 229 return 1; 230 } 231 232 static int 233 aead_xchacha20_poly1305_seal(const EVP_AEAD_CTX *ctx, unsigned char *out, 234 size_t *out_len, size_t max_out_len, const unsigned char *nonce, 235 size_t nonce_len, const unsigned char *in, size_t in_len, 236 const unsigned char *ad, size_t ad_len) 237 { 238 const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state; 239 unsigned char poly1305_key[32]; 240 unsigned char subkey[32]; 241 poly1305_state poly1305; 242 243 if (max_out_len < in_len + c20_ctx->tag_len) { 244 EVPerror(EVP_R_BUFFER_TOO_SMALL); 245 return 0; 246 } 247 248 if (nonce_len != ctx->aead->nonce_len) { 249 EVPerror(EVP_R_IV_TOO_LARGE); 250 return 0; 251 } 252 253 CRYPTO_hchacha_20(subkey, c20_ctx->key, nonce); 254 255 CRYPTO_chacha_20(out, in, in_len, subkey, nonce + 16, 1); 256 257 memset(poly1305_key, 0, sizeof(poly1305_key)); 258 CRYPTO_chacha_20(poly1305_key, poly1305_key, sizeof(poly1305_key), 259 subkey, nonce + 16, 0); 260 261 CRYPTO_poly1305_init(&poly1305, poly1305_key); 262 poly1305_update_with_pad16(&poly1305, ad, ad_len); 263 poly1305_update_with_pad16(&poly1305, out, in_len); 264 poly1305_update_with_length(&poly1305, NULL, ad_len); 265 poly1305_update_with_length(&poly1305, NULL, in_len); 266 267 if (c20_ctx->tag_len != POLY1305_TAG_LEN) { 268 unsigned char tag[POLY1305_TAG_LEN]; 269 CRYPTO_poly1305_finish(&poly1305, tag); 270 memcpy(out + in_len, tag, c20_ctx->tag_len); 271 *out_len = in_len + c20_ctx->tag_len; 272 return 1; 273 } 274 275 CRYPTO_poly1305_finish(&poly1305, out + in_len); 276 *out_len = in_len + POLY1305_TAG_LEN; 277 return 1; 278 } 279 280 static int 281 aead_xchacha20_poly1305_open(const EVP_AEAD_CTX *ctx, unsigned char *out, 282 size_t *out_len, size_t max_out_len, const unsigned char *nonce, 283 size_t nonce_len, const unsigned char *in, size_t in_len, 284 const unsigned char *ad, size_t ad_len) 285 { 286 const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state; 287 unsigned char mac[POLY1305_TAG_LEN]; 288 unsigned char poly1305_key[32]; 289 unsigned char subkey[32]; 290 poly1305_state poly1305; 291 size_t plaintext_len; 292 293 if (in_len < c20_ctx->tag_len) { 294 EVPerror(EVP_R_BAD_DECRYPT); 295 return 0; 296 } 297 298 if (nonce_len != ctx->aead->nonce_len) { 299 EVPerror(EVP_R_IV_TOO_LARGE); 300 return 0; 301 } 302 303 plaintext_len = in_len - c20_ctx->tag_len; 304 305 if (max_out_len < plaintext_len) { 306 EVPerror(EVP_R_BUFFER_TOO_SMALL); 307 return 0; 308 } 309 310 CRYPTO_hchacha_20(subkey, c20_ctx->key, nonce); 311 312 memset(poly1305_key, 0, sizeof(poly1305_key)); 313 CRYPTO_chacha_20(poly1305_key, poly1305_key, sizeof(poly1305_key), 314 subkey, nonce + 16, 0); 315 316 CRYPTO_poly1305_init(&poly1305, poly1305_key); 317 poly1305_update_with_pad16(&poly1305, ad, ad_len); 318 poly1305_update_with_pad16(&poly1305, in, plaintext_len); 319 poly1305_update_with_length(&poly1305, NULL, ad_len); 320 poly1305_update_with_length(&poly1305, NULL, plaintext_len); 321 322 CRYPTO_poly1305_finish(&poly1305, mac); 323 if (timingsafe_memcmp(mac, in + plaintext_len, c20_ctx->tag_len) != 0) { 324 EVPerror(EVP_R_BAD_DECRYPT); 325 return 0; 326 } 327 328 CRYPTO_chacha_20(out, in, plaintext_len, subkey, nonce + 16, 1); 329 330 *out_len = plaintext_len; 331 return 1; 332 } 333 334 /* RFC 8439 */ 335 static const EVP_AEAD aead_chacha20_poly1305 = { 336 .key_len = 32, 337 .nonce_len = CHACHA20_NONCE_LEN, 338 .overhead = POLY1305_TAG_LEN, 339 .max_tag_len = POLY1305_TAG_LEN, 340 341 .init = aead_chacha20_poly1305_init, 342 .cleanup = aead_chacha20_poly1305_cleanup, 343 .seal = aead_chacha20_poly1305_seal, 344 .open = aead_chacha20_poly1305_open, 345 }; 346 347 const EVP_AEAD * 348 EVP_aead_chacha20_poly1305() 349 { 350 return &aead_chacha20_poly1305; 351 } 352 353 static const EVP_AEAD aead_xchacha20_poly1305 = { 354 .key_len = 32, 355 .nonce_len = XCHACHA20_NONCE_LEN, 356 .overhead = POLY1305_TAG_LEN, 357 .max_tag_len = POLY1305_TAG_LEN, 358 359 .init = aead_chacha20_poly1305_init, 360 .cleanup = aead_chacha20_poly1305_cleanup, 361 .seal = aead_xchacha20_poly1305_seal, 362 .open = aead_xchacha20_poly1305_open, 363 }; 364 365 const EVP_AEAD * 366 EVP_aead_xchacha20_poly1305() 367 { 368 return &aead_xchacha20_poly1305; 369 } 370 371 struct chacha20_poly1305_ctx { 372 ChaCha_ctx chacha; 373 poly1305_state poly1305; 374 375 unsigned char key[32]; 376 unsigned char nonce[CHACHA20_NONCE_LEN]; 377 size_t nonce_len; 378 unsigned char tag[POLY1305_TAG_LEN]; 379 size_t tag_len; 380 381 size_t ad_len; 382 size_t in_len; 383 384 int in_ad; 385 int started; 386 }; 387 388 static int 389 chacha20_poly1305_init(EVP_CIPHER_CTX *ctx, const unsigned char *key, 390 const unsigned char *iv, int encrypt) 391 { 392 struct chacha20_poly1305_ctx *cpx = ctx->cipher_data; 393 uint8_t *data; 394 CBB cbb; 395 int ret = 0; 396 397 memset(&cbb, 0, sizeof(cbb)); 398 399 if (key == NULL && iv == NULL) 400 goto done; 401 402 cpx->started = 0; 403 404 if (key != NULL) 405 memcpy(cpx->key, key, sizeof(cpx->key)); 406 407 if (iv != NULL) { 408 /* 409 * Left zero pad if configured nonce length is less than ChaCha 410 * nonce length. 411 */ 412 if (!CBB_init_fixed(&cbb, cpx->nonce, sizeof(cpx->nonce))) 413 goto err; 414 if (!CBB_add_space(&cbb, &data, sizeof(cpx->nonce) - cpx->nonce_len)) 415 goto err; 416 if (!CBB_add_bytes(&cbb, iv, cpx->nonce_len)) 417 goto err; 418 if (!CBB_finish(&cbb, NULL, NULL)) 419 goto err; 420 } 421 422 done: 423 ret = 1; 424 425 err: 426 CBB_cleanup(&cbb); 427 428 return ret; 429 } 430 431 static int 432 chacha20_poly1305_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, 433 const unsigned char *in, size_t len) 434 { 435 struct chacha20_poly1305_ctx *cpx = ctx->cipher_data; 436 437 /* 438 * Since we're making AEAD work within the constraints of EVP_CIPHER... 439 * If in is non-NULL then this is an update, while if in is NULL then 440 * this is a final. If in is non-NULL but out is NULL, then the input 441 * being provided is associated data. Plus we have to handle encryption 442 * (sealing) and decryption (opening) in the same function. 443 */ 444 445 if (!cpx->started) { 446 unsigned char poly1305_key[32]; 447 const unsigned char *iv; 448 uint64_t ctr; 449 450 ctr = (uint64_t)((uint32_t)(cpx->nonce[0]) | 451 (uint32_t)(cpx->nonce[1]) << 8 | 452 (uint32_t)(cpx->nonce[2]) << 16 | 453 (uint32_t)(cpx->nonce[3]) << 24) << 32; 454 iv = cpx->nonce + CHACHA20_CONSTANT_LEN; 455 456 ChaCha_set_key(&cpx->chacha, cpx->key, 8 * sizeof(cpx->key)); 457 ChaCha_set_iv(&cpx->chacha, iv, NULL); 458 459 /* See chacha.c for details re handling of counter. */ 460 cpx->chacha.input[12] = (uint32_t)ctr; 461 cpx->chacha.input[13] = (uint32_t)(ctr >> 32); 462 463 memset(poly1305_key, 0, sizeof(poly1305_key)); 464 ChaCha(&cpx->chacha, poly1305_key, poly1305_key, 465 sizeof(poly1305_key)); 466 CRYPTO_poly1305_init(&cpx->poly1305, poly1305_key); 467 468 /* Mark remaining key block as used. */ 469 cpx->chacha.unused = 0; 470 471 cpx->ad_len = 0; 472 cpx->in_len = 0; 473 cpx->in_ad = 0; 474 475 cpx->started = 1; 476 } 477 478 if (len > SIZE_MAX - cpx->in_len) { 479 EVPerror(EVP_R_TOO_LARGE); 480 return 0; 481 } 482 483 /* Disallow authenticated data after plaintext/ciphertext. */ 484 if (cpx->in_len > 0 && in != NULL && out == NULL) 485 return -1; 486 487 if (cpx->in_ad && (in == NULL || out != NULL)) { 488 poly1305_pad16(&cpx->poly1305, cpx->ad_len); 489 cpx->in_ad = 0; 490 } 491 492 /* Update with AD or plaintext/ciphertext. */ 493 if (in != NULL) { 494 if (out == NULL) { 495 cpx->ad_len += len; 496 cpx->in_ad = 1; 497 } else { 498 ChaCha(&cpx->chacha, out, in, len); 499 cpx->in_len += len; 500 } 501 if (ctx->encrypt && out != NULL) 502 CRYPTO_poly1305_update(&cpx->poly1305, out, len); 503 else 504 CRYPTO_poly1305_update(&cpx->poly1305, in, len); 505 506 return len; 507 } 508 509 /* Final. */ 510 poly1305_pad16(&cpx->poly1305, cpx->in_len); 511 poly1305_update_with_length(&cpx->poly1305, NULL, cpx->ad_len); 512 poly1305_update_with_length(&cpx->poly1305, NULL, cpx->in_len); 513 514 if (ctx->encrypt) { 515 CRYPTO_poly1305_finish(&cpx->poly1305, cpx->tag); 516 cpx->tag_len = sizeof(cpx->tag); 517 } else { 518 unsigned char tag[POLY1305_TAG_LEN]; 519 520 /* Ensure that a tag has been provided. */ 521 if (cpx->tag_len <= 0) 522 return -1; 523 524 CRYPTO_poly1305_finish(&cpx->poly1305, tag); 525 if (timingsafe_memcmp(tag, cpx->tag, cpx->tag_len) != 0) 526 return -1; 527 } 528 529 cpx->started = 0; 530 531 return len; 532 } 533 534 static int 535 chacha20_poly1305_cleanup(EVP_CIPHER_CTX *ctx) 536 { 537 struct chacha20_poly1305_ctx *cpx = ctx->cipher_data; 538 539 explicit_bzero(cpx, sizeof(*cpx)); 540 541 return 1; 542 } 543 544 static int 545 chacha20_poly1305_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr) 546 { 547 struct chacha20_poly1305_ctx *cpx = ctx->cipher_data; 548 549 switch (type) { 550 case EVP_CTRL_INIT: 551 memset(cpx, 0, sizeof(*cpx)); 552 cpx->nonce_len = sizeof(cpx->nonce); 553 return 1; 554 555 case EVP_CTRL_AEAD_GET_IVLEN: 556 if (cpx->nonce_len > INT_MAX) 557 return 0; 558 *(int *)ptr = (int)cpx->nonce_len; 559 return 1; 560 561 case EVP_CTRL_AEAD_SET_IVLEN: 562 if (arg <= 0 || arg > sizeof(cpx->nonce)) 563 return 0; 564 cpx->nonce_len = arg; 565 return 1; 566 567 case EVP_CTRL_AEAD_SET_TAG: 568 if (ctx->encrypt) 569 return 0; 570 if (arg <= 0 || arg > sizeof(cpx->tag)) 571 return 0; 572 if (ptr != NULL) { 573 memcpy(cpx->tag, ptr, arg); 574 cpx->tag_len = arg; 575 } 576 return 1; 577 578 case EVP_CTRL_AEAD_GET_TAG: 579 if (!ctx->encrypt) 580 return 0; 581 if (arg <= 0 || arg > cpx->tag_len) 582 return 0; 583 memcpy(ptr, cpx->tag, arg); 584 return 1; 585 586 case EVP_CTRL_AEAD_SET_IV_FIXED: 587 if (arg != sizeof(cpx->nonce)) 588 return 0; 589 memcpy(cpx->nonce, ptr, arg); 590 return 1; 591 } 592 593 return 0; 594 } 595 596 static const EVP_CIPHER cipher_chacha20_poly1305 = { 597 .nid = NID_chacha20_poly1305, 598 .block_size = 1, 599 .key_len = 32, 600 .iv_len = 12, 601 .flags = EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT | 602 EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_IV_LENGTH | 603 EVP_CIPH_FLAG_AEAD_CIPHER | EVP_CIPH_FLAG_CUSTOM_CIPHER | 604 EVP_CIPH_FLAG_DEFAULT_ASN1, 605 .init = chacha20_poly1305_init, 606 .do_cipher = chacha20_poly1305_cipher, 607 .cleanup = chacha20_poly1305_cleanup, 608 .ctx_size = sizeof(struct chacha20_poly1305_ctx), 609 .ctrl = chacha20_poly1305_ctrl, 610 }; 611 612 const EVP_CIPHER * 613 EVP_chacha20_poly1305(void) 614 { 615 return &cipher_chacha20_poly1305; 616 } 617 618 #endif /* !OPENSSL_NO_CHACHA && !OPENSSL_NO_POLY1305 */ 619