summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjsing <>2022-08-20 19:22:28 +0000
committerjsing <>2022-08-20 19:22:28 +0000
commitdb7a0caa3a5fe243c1367cef69b8d0ef2f38216d (patch)
tree0abd9c3e0e1498f540108747871fd7d071eb5728 /src
parent09b6550cab1f0d0c5e0e18da24dfc96374864b58 (diff)
downloadopenbsd-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.c257
-rw-r--r--src/lib/libcrypto/evp/evp.h10
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
101static void 103static void
102poly1305_update_with_pad16(poly1305_state *poly1305, 104poly1305_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
116static void
117poly1305_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
117static int 124static int
118aead_chacha20_poly1305_seal(const EVP_AEAD_CTX *ctx, unsigned char *out, 125aead_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
370struct 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
387static int
388chacha20_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
430static int
431chacha20_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
533static int
534chacha20_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
543static int
544chacha20_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
589static 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
604const EVP_CIPHER *
605EVP_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);
680const EVP_CIPHER *EVP_aes_256_gcm(void); 681const EVP_CIPHER *EVP_aes_256_gcm(void);
681const EVP_CIPHER *EVP_aes_256_wrap(void); 682const EVP_CIPHER *EVP_aes_256_wrap(void);
682const EVP_CIPHER *EVP_aes_256_xts(void); 683const 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)
686const 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)
684const EVP_CIPHER *EVP_aes_128_cbc_hmac_sha1(void); 690const EVP_CIPHER *EVP_aes_128_cbc_hmac_sha1(void);
685const EVP_CIPHER *EVP_aes_256_cbc_hmac_sha1(void); 691const EVP_CIPHER *EVP_aes_256_cbc_hmac_sha1(void);