diff options
| author | jsing <> | 2022-08-20 19:22:28 +0000 |
|---|---|---|
| committer | jsing <> | 2022-08-20 19:22:28 +0000 |
| commit | a3f8b46f14c6c096b064180856e49b266aea59fd (patch) | |
| tree | 0abd9c3e0e1498f540108747871fd7d071eb5728 /src | |
| parent | 1234ab8aa026e9e123f816d5ac114bec9b9fa17e (diff) | |
| download | openbsd-a3f8b46f14c6c096b064180856e49b266aea59fd.tar.gz openbsd-a3f8b46f14c6c096b064180856e49b266aea59fd.tar.bz2 openbsd-a3f8b46f14c6c096b064180856e49b266aea59fd.zip | |
Provide EVP_chacha20_poly1305()
EVP_chacha20_poly1305() is an EVP_CIPHER implementation of the
ChaCha20-Poly1305 AEAD. This is potentially used to provide encryption for
the QUIC transport layer.
Where possible, this should be avoided in favour of the significantly saner
EVP_AEAD interface.
ok tb@
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/libcrypto/evp/e_chacha20poly1305.c | 257 | ||||
| -rw-r--r-- | src/lib/libcrypto/evp/evp.h | 10 |
2 files changed, 260 insertions, 7 deletions
diff --git a/src/lib/libcrypto/evp/e_chacha20poly1305.c b/src/lib/libcrypto/evp/e_chacha20poly1305.c index 3b29364586..129adb9ef9 100644 --- a/src/lib/libcrypto/evp/e_chacha20poly1305.c +++ b/src/lib/libcrypto/evp/e_chacha20poly1305.c | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | /* $OpenBSD: e_chacha20poly1305.c,v 1.22 2022/08/20 18:51:09 jsing Exp $ */ | 1 | /* $OpenBSD: e_chacha20poly1305.c,v 1.23 2022/08/20 19:22:28 jsing Exp $ */ |
| 2 | 2 | ||
| 3 | /* | 3 | /* |
| 4 | * Copyright (c) 2022 Joel Sing <jsing@openbsd.org> | ||
| 4 | * Copyright (c) 2015 Reyk Floter <reyk@openbsd.org> | 5 | * Copyright (c) 2015 Reyk Floter <reyk@openbsd.org> |
| 5 | * Copyright (c) 2014, Google Inc. | 6 | * Copyright (c) 2014, Google Inc. |
| 6 | * | 7 | * |
| @@ -29,6 +30,7 @@ | |||
| 29 | #include <openssl/chacha.h> | 30 | #include <openssl/chacha.h> |
| 30 | #include <openssl/poly1305.h> | 31 | #include <openssl/poly1305.h> |
| 31 | 32 | ||
| 33 | #include "bytestring.h" | ||
| 32 | #include "evp_locl.h" | 34 | #include "evp_locl.h" |
| 33 | 35 | ||
| 34 | #define POLY1305_TAG_LEN 16 | 36 | #define POLY1305_TAG_LEN 16 |
| @@ -99,14 +101,11 @@ poly1305_update_with_length(poly1305_state *poly1305, | |||
| 99 | } | 101 | } |
| 100 | 102 | ||
| 101 | static void | 103 | static void |
| 102 | poly1305_update_with_pad16(poly1305_state *poly1305, | 104 | poly1305_pad16(poly1305_state *poly1305, size_t data_len) |
| 103 | const unsigned char *data, size_t data_len) | ||
| 104 | { | 105 | { |
| 105 | static const unsigned char zero_pad16[16]; | 106 | static const unsigned char zero_pad16[16]; |
| 106 | size_t pad_len; | 107 | size_t pad_len; |
| 107 | 108 | ||
| 108 | CRYPTO_poly1305_update(poly1305, data, data_len); | ||
| 109 | |||
| 110 | /* pad16() is defined in RFC 7539 2.8.1. */ | 109 | /* pad16() is defined in RFC 7539 2.8.1. */ |
| 111 | if ((pad_len = data_len % 16) == 0) | 110 | if ((pad_len = data_len % 16) == 0) |
| 112 | return; | 111 | return; |
| @@ -114,6 +113,14 @@ poly1305_update_with_pad16(poly1305_state *poly1305, | |||
| 114 | CRYPTO_poly1305_update(poly1305, zero_pad16, 16 - pad_len); | 113 | CRYPTO_poly1305_update(poly1305, zero_pad16, 16 - pad_len); |
| 115 | } | 114 | } |
| 116 | 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 | |||
| 117 | static int | 124 | static int |
| 118 | aead_chacha20_poly1305_seal(const EVP_AEAD_CTX *ctx, unsigned char *out, | 125 | aead_chacha20_poly1305_seal(const EVP_AEAD_CTX *ctx, unsigned char *out, |
| 119 | size_t *out_len, size_t max_out_len, const unsigned char *nonce, | 126 | size_t *out_len, size_t max_out_len, const unsigned char *nonce, |
| @@ -360,4 +367,244 @@ EVP_aead_xchacha20_poly1305() | |||
| 360 | return &aead_xchacha20_poly1305; | 367 | return &aead_xchacha20_poly1305; |
| 361 | } | 368 | } |
| 362 | 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 int | ||
| 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 | return 0; | ||
| 541 | } | ||
| 542 | |||
| 543 | static int | ||
| 544 | chacha20_poly1305_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr) | ||
| 545 | { | ||
| 546 | struct chacha20_poly1305_ctx *cpx = ctx->cipher_data; | ||
| 547 | |||
| 548 | switch (type) { | ||
| 549 | case EVP_CTRL_INIT: | ||
| 550 | memset(cpx, 0, sizeof(*cpx)); | ||
| 551 | cpx->nonce_len = sizeof(cpx->nonce); | ||
| 552 | return 1; | ||
| 553 | |||
| 554 | case EVP_CTRL_AEAD_SET_IVLEN: | ||
| 555 | if (arg <= 0 || arg > sizeof(cpx->nonce)) | ||
| 556 | return 0; | ||
| 557 | cpx->nonce_len = arg; | ||
| 558 | return 1; | ||
| 559 | |||
| 560 | case EVP_CTRL_AEAD_SET_TAG: | ||
| 561 | if (ctx->encrypt) | ||
| 562 | return 0; | ||
| 563 | if (arg <= 0 || arg > sizeof(cpx->tag)) | ||
| 564 | return 0; | ||
| 565 | if (ptr != NULL) { | ||
| 566 | memcpy(cpx->tag, ptr, arg); | ||
| 567 | cpx->tag_len = arg; | ||
| 568 | } | ||
| 569 | return 1; | ||
| 570 | |||
| 571 | case EVP_CTRL_AEAD_GET_TAG: | ||
| 572 | if (!ctx->encrypt) | ||
| 573 | return 0; | ||
| 574 | if (arg <= 0 || arg > cpx->tag_len) | ||
| 575 | return 0; | ||
| 576 | memcpy(ptr, cpx->tag, arg); | ||
| 577 | return 1; | ||
| 578 | |||
| 579 | case EVP_CTRL_AEAD_SET_IV_FIXED: | ||
| 580 | if (arg != sizeof(cpx->nonce)) | ||
| 581 | return 0; | ||
| 582 | memcpy(cpx->nonce, ptr, arg); | ||
| 583 | return 1; | ||
| 584 | } | ||
| 585 | |||
| 586 | return 0; | ||
| 587 | } | ||
| 588 | |||
| 589 | static const EVP_CIPHER cipher_chacha20_poly1305 = { | ||
| 590 | .nid = NID_chacha20_poly1305, | ||
| 591 | .block_size = 1, | ||
| 592 | .key_len = 32, | ||
| 593 | .iv_len = 12, | ||
| 594 | .flags = EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT | | ||
| 595 | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_AEAD_CIPHER | | ||
| 596 | EVP_CIPH_FLAG_CUSTOM_CIPHER | EVP_CIPH_FLAG_DEFAULT_ASN1, | ||
| 597 | .init = chacha20_poly1305_init, | ||
| 598 | .do_cipher = chacha20_poly1305_cipher, | ||
| 599 | .cleanup = chacha20_poly1305_cleanup, | ||
| 600 | .ctx_size = sizeof(struct chacha20_poly1305_ctx), | ||
| 601 | .ctrl = chacha20_poly1305_ctrl, | ||
| 602 | }; | ||
| 603 | |||
| 604 | const EVP_CIPHER * | ||
| 605 | EVP_chacha20_poly1305(void) | ||
| 606 | { | ||
| 607 | return &cipher_chacha20_poly1305; | ||
| 608 | } | ||
| 609 | |||
| 363 | #endif /* !OPENSSL_NO_CHACHA && !OPENSSL_NO_POLY1305 */ | 610 | #endif /* !OPENSSL_NO_CHACHA && !OPENSSL_NO_POLY1305 */ |
diff --git a/src/lib/libcrypto/evp/evp.h b/src/lib/libcrypto/evp/evp.h index f016b6377c..0b7fc08fc8 100644 --- a/src/lib/libcrypto/evp/evp.h +++ b/src/lib/libcrypto/evp/evp.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* $OpenBSD: evp.h,v 1.103 2022/07/12 14:42:49 kn Exp $ */ | 1 | /* $OpenBSD: evp.h,v 1.104 2022/08/20 19:22:28 jsing Exp $ */ |
| 2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) | 2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
| 3 | * All rights reserved. | 3 | * All rights reserved. |
| 4 | * | 4 | * |
| @@ -251,10 +251,11 @@ extern "C" { | |||
| 251 | #define EVP_CTRL_AEAD_SET_IVLEN 0x9 | 251 | #define EVP_CTRL_AEAD_SET_IVLEN 0x9 |
| 252 | #define EVP_CTRL_AEAD_GET_TAG 0x10 | 252 | #define EVP_CTRL_AEAD_GET_TAG 0x10 |
| 253 | #define EVP_CTRL_AEAD_SET_TAG 0x11 | 253 | #define EVP_CTRL_AEAD_SET_TAG 0x11 |
| 254 | #define EVP_CTRL_AEAD_SET_IV_FIXED 0x12 | ||
| 254 | #define EVP_CTRL_GCM_SET_IVLEN EVP_CTRL_AEAD_SET_IVLEN | 255 | #define EVP_CTRL_GCM_SET_IVLEN EVP_CTRL_AEAD_SET_IVLEN |
| 255 | #define EVP_CTRL_GCM_GET_TAG EVP_CTRL_AEAD_GET_TAG | 256 | #define EVP_CTRL_GCM_GET_TAG EVP_CTRL_AEAD_GET_TAG |
| 256 | #define EVP_CTRL_GCM_SET_TAG EVP_CTRL_AEAD_SET_TAG | 257 | #define EVP_CTRL_GCM_SET_TAG EVP_CTRL_AEAD_SET_TAG |
| 257 | #define EVP_CTRL_GCM_SET_IV_FIXED 0x12 | 258 | #define EVP_CTRL_GCM_SET_IV_FIXED EVP_CTRL_AEAD_SET_IV_FIXED |
| 258 | #define EVP_CTRL_GCM_IV_GEN 0x13 | 259 | #define EVP_CTRL_GCM_IV_GEN 0x13 |
| 259 | #define EVP_CTRL_CCM_SET_IVLEN EVP_CTRL_AEAD_SET_IVLEN | 260 | #define EVP_CTRL_CCM_SET_IVLEN EVP_CTRL_AEAD_SET_IVLEN |
| 260 | #define EVP_CTRL_CCM_GET_TAG EVP_CTRL_AEAD_GET_TAG | 261 | #define EVP_CTRL_CCM_GET_TAG EVP_CTRL_AEAD_GET_TAG |
| @@ -680,6 +681,11 @@ const EVP_CIPHER *EVP_aes_256_ccm(void); | |||
| 680 | const EVP_CIPHER *EVP_aes_256_gcm(void); | 681 | const EVP_CIPHER *EVP_aes_256_gcm(void); |
| 681 | const EVP_CIPHER *EVP_aes_256_wrap(void); | 682 | const EVP_CIPHER *EVP_aes_256_wrap(void); |
| 682 | const EVP_CIPHER *EVP_aes_256_xts(void); | 683 | const EVP_CIPHER *EVP_aes_256_xts(void); |
| 684 | #if defined(LIBRESSL_NEXT_API) || defined(LIBRESSL_INTERNAL) | ||
| 685 | #if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305) | ||
| 686 | const EVP_CIPHER *EVP_chacha20_poly1305(void); | ||
| 687 | #endif | ||
| 688 | #endif | ||
| 683 | #if !defined(OPENSSL_NO_SHA) && !defined(OPENSSL_NO_SHA1) | 689 | #if !defined(OPENSSL_NO_SHA) && !defined(OPENSSL_NO_SHA1) |
| 684 | const EVP_CIPHER *EVP_aes_128_cbc_hmac_sha1(void); | 690 | const EVP_CIPHER *EVP_aes_128_cbc_hmac_sha1(void); |
| 685 | const EVP_CIPHER *EVP_aes_256_cbc_hmac_sha1(void); | 691 | const EVP_CIPHER *EVP_aes_256_cbc_hmac_sha1(void); |
