diff options
author | jsing <> | 2022-08-20 19:22:28 +0000 |
---|---|---|
committer | jsing <> | 2022-08-20 19:22:28 +0000 |
commit | db7a0caa3a5fe243c1367cef69b8d0ef2f38216d (patch) | |
tree | 0abd9c3e0e1498f540108747871fd7d071eb5728 /src | |
parent | 09b6550cab1f0d0c5e0e18da24dfc96374864b58 (diff) | |
download | openbsd-db7a0caa3a5fe243c1367cef69b8d0ef2f38216d.tar.gz openbsd-db7a0caa3a5fe243c1367cef69b8d0ef2f38216d.tar.bz2 openbsd-db7a0caa3a5fe243c1367cef69b8d0ef2f38216d.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); |