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