summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShane Lontis <shane.lontis@oracle.com>2019-10-16 16:18:42 +1000
committerShane Lontis <shane.lontis@oracle.com>2019-10-16 16:18:42 +1000
commit3d5a7578e09a984c6475b1c008f5c76f850328cb (patch)
tree0ec32eba328e21a6e1face34415c67dcdce365c2
parent64fd90fbe99dde18de3fc7c3a6b06793d87a4aad (diff)
Add ChaCha related ciphers to default provider
Reviewed-by: Richard Levitte <levitte@openssl.org> (Merged from https://github.com/openssl/openssl/pull/10081)
-rw-r--r--crypto/evp/evp_enc.c7
-rw-r--r--crypto/poly1305/poly1305.c1
-rw-r--r--crypto/poly1305/poly1305_ameth.c1
-rw-r--r--crypto/poly1305/poly1305_local.h27
-rw-r--r--doc/man7/provider-cipher.pod4
-rw-r--r--include/crypto/poly1305.h19
-rw-r--r--include/openssl/core_names.h1
-rw-r--r--providers/defltprov.c6
-rw-r--r--providers/implementations/ciphers/build.info12
-rw-r--r--providers/implementations/ciphers/cipher_chacha20.c187
-rw-r--r--providers/implementations/ciphers/cipher_chacha20.h34
-rw-r--r--providers/implementations/ciphers/cipher_chacha20_hw.c121
-rw-r--r--providers/implementations/ciphers/cipher_chacha20_poly1305.c314
-rw-r--r--providers/implementations/ciphers/cipher_chacha20_poly1305.h43
-rw-r--r--providers/implementations/ciphers/cipher_chacha20_poly1305_hw.c408
-rw-r--r--providers/implementations/include/prov/implementations.h7
-rw-r--r--providers/implementations/macs/poly1305_prov.c6
-rw-r--r--test/poly1305_internal_test.c1
-rw-r--r--test/recipes/30-test_evp.t3
-rw-r--r--test/recipes/30-test_evp_data/evpciph.txt187
-rw-r--r--test/recipes/30-test_evp_data/evpciph_chacha.txt199
21 files changed, 1365 insertions, 223 deletions
diff --git a/crypto/evp/evp_enc.c b/crypto/evp/evp_enc.c
index 5a6a4033ce..18adc5b586 100644
--- a/crypto/evp/evp_enc.c
+++ b/crypto/evp/evp_enc.c
@@ -278,6 +278,8 @@ int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
case NID_rc2_64_cbc:
case NID_rc2_cfb64:
case NID_rc2_ofb64:
+ case NID_chacha20:
+ case NID_chacha20_poly1305:
break;
default:
goto legacy;
@@ -1120,6 +1122,11 @@ int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr)
params[0] = OSSL_PARAM_construct_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG,
ptr, sz);
break;
+ case EVP_CTRL_AEAD_SET_MAC_KEY:
+ params[0] =
+ OSSL_PARAM_construct_octet_string(OSSL_CIPHER_PARAM_AEAD_MAC_KEY,
+ ptr, sz);
+ break;
case EVP_CTRL_AEAD_TLS1_AAD:
/* This one does a set and a get - since it returns a padding size */
params[0] =
diff --git a/crypto/poly1305/poly1305.c b/crypto/poly1305/poly1305.c
index 97c0530500..127ce7da2f 100644
--- a/crypto/poly1305/poly1305.c
+++ b/crypto/poly1305/poly1305.c
@@ -12,7 +12,6 @@
#include <openssl/crypto.h>
#include "crypto/poly1305.h"
-#include "poly1305_local.h"
size_t Poly1305_ctx_size(void)
{
diff --git a/crypto/poly1305/poly1305_ameth.c b/crypto/poly1305/poly1305_ameth.c
index d69607c7bb..2feec9ccc3 100644
--- a/crypto/poly1305/poly1305_ameth.c
+++ b/crypto/poly1305/poly1305_ameth.c
@@ -12,7 +12,6 @@
#include <openssl/evp.h>
#include "crypto/asn1.h"
#include "crypto/poly1305.h"
-#include "poly1305_local.h"
#include "crypto/evp.h"
/*
diff --git a/crypto/poly1305/poly1305_local.h b/crypto/poly1305/poly1305_local.h
deleted file mode 100644
index 23930c8ef4..0000000000
--- a/crypto/poly1305/poly1305_local.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved.
- *
- * Licensed under the Apache License 2.0 (the "License"). You may not use
- * this file except in compliance with the License. You can obtain a copy
- * in the file LICENSE in the source distribution or at
- * https://www.openssl.org/source/license.html
- */
-
-typedef void (*poly1305_blocks_f) (void *ctx, const unsigned char *inp,
- size_t len, unsigned int padbit);
-typedef void (*poly1305_emit_f) (void *ctx, unsigned char mac[16],
- const unsigned int nonce[4]);
-
-struct poly1305_context {
- double opaque[24]; /* large enough to hold internal state, declared
- * 'double' to ensure at least 64-bit invariant
- * alignment across all platforms and
- * configurations */
- unsigned int nonce[4];
- unsigned char data[POLY1305_BLOCK_SIZE];
- size_t num;
- struct {
- poly1305_blocks_f blocks;
- poly1305_emit_f emit;
- } func;
-};
diff --git a/doc/man7/provider-cipher.pod b/doc/man7/provider-cipher.pod
index af97735730..e1312b31eb 100644
--- a/doc/man7/provider-cipher.pod
+++ b/doc/man7/provider-cipher.pod
@@ -315,6 +315,10 @@ IV length and the tag length.
Sets the IV length to be used for an AEAD cipher for the associated cipher ctx.
The length of the "ivlen" parameter should not exceed that of a B<size_t>.
+=item "mackey" (B<OSSL_CIPHER_PARAM_AEAD_MAC_KEY>) <octet string>
+
+Sets the MAC key used by composite AEAD ciphers such as AES-CBC-HMAC-SHA256.
+
=item "randkey" (B<OSSL_CIPHER_PARAM_RANDOM_KEY>) <octet string>
Gets a implementation specific randomly generated key for the associated
diff --git a/include/crypto/poly1305.h b/include/crypto/poly1305.h
index 46f834e231..a73c2311d4 100644
--- a/include/crypto/poly1305.h
+++ b/include/crypto/poly1305.h
@@ -15,6 +15,25 @@
typedef struct poly1305_context POLY1305;
+typedef void (*poly1305_blocks_f) (void *ctx, const unsigned char *inp,
+ size_t len, unsigned int padbit);
+typedef void (*poly1305_emit_f) (void *ctx, unsigned char mac[16],
+ const unsigned int nonce[4]);
+
+struct poly1305_context {
+ double opaque[24]; /* large enough to hold internal state, declared
+ * 'double' to ensure at least 64-bit invariant
+ * alignment across all platforms and
+ * configurations */
+ unsigned int nonce[4];
+ unsigned char data[POLY1305_BLOCK_SIZE];
+ size_t num;
+ struct {
+ poly1305_blocks_f blocks;
+ poly1305_emit_f emit;
+ } func;
+};
+
size_t Poly1305_ctx_size(void);
void Poly1305_Init(POLY1305 *ctx, const unsigned char key[32]);
void Poly1305_Update(POLY1305 *ctx, const unsigned char *inp, size_t len);
diff --git a/include/openssl/core_names.h b/include/openssl/core_names.h
index 4bf1740105..d9ef31cff0 100644
--- a/include/openssl/core_names.h
+++ b/include/openssl/core_names.h
@@ -66,6 +66,7 @@ extern "C" {
#define OSSL_CIPHER_PARAM_AEAD_TLS1_IV_FIXED "tlsivfixed" /* octet_string */
#define OSSL_CIPHER_PARAM_AEAD_IVLEN OSSL_CIPHER_PARAM_IVLEN
#define OSSL_CIPHER_PARAM_AEAD_TAGLEN "taglen" /* size_t */
+#define OSSL_CIPHER_PARAM_AEAD_MAC_KEY "mackey" /* octet_string */
#define OSSL_CIPHER_PARAM_RANDOM_KEY "randkey" /* octet_string */
#define OSSL_CIPHER_PARAM_RC2_KEYBITS "keybits" /* size_t */
/* For passing the AlgorithmIdentifier parameter in DER form */
diff --git a/providers/defltprov.c b/providers/defltprov.c
index 7dd0cf5012..2d457ae53f 100644
--- a/providers/defltprov.c
+++ b/providers/defltprov.c
@@ -295,6 +295,12 @@ static const OSSL_ALGORITHM deflt_ciphers[] = {
{ "RC2-CFB", "default=yes", rc2128cfb128_functions },
{ "RC2-OFB", "default=yes", rc2128ofb128_functions },
#endif /* OPENSSL_NO_RC2 */
+#ifndef OPENSSL_NO_CHACHA
+ { "ChaCha20", "default=yes", chacha20_functions },
+# ifndef OPENSSL_NO_POLY1305
+ { "ChaCha20-Poly1305", "default=yes", chacha20_poly1305_functions },
+# endif /* OPENSSL_NO_POLY1305 */
+#endif /* OPENSSL_NO_CHACHA */
{ NULL, NULL, NULL }
};
diff --git a/providers/implementations/ciphers/build.info b/providers/implementations/ciphers/build.info
index fb2b53e58a..7f0b76c01b 100644
--- a/providers/implementations/ciphers/build.info
+++ b/providers/implementations/ciphers/build.info
@@ -19,6 +19,8 @@ $SM4_GOAL=../../libimplementations.a
$RC4_GOAL=../../libimplementations.a
$RC5_GOAL=../../libimplementations.a
$RC2_GOAL=../../libimplementations.a
+$CHACHA_GOAL=../../libimplementations.a
+$CHACHAPOLY_GOAL=../../libimplementations.a
IF[{- !$disabled{des} -}]
SOURCE[$TDES_1_GOAL]=cipher_tdes.c cipher_tdes_hw.c
@@ -100,3 +102,13 @@ IF[{- !$disabled{rc2} -}]
SOURCE[$RC2_GOAL]=\
cipher_rc2.c cipher_rc2_hw.c
ENDIF
+
+IF[{- !$disabled{chacha} -}]
+ SOURCE[$CHACHA_GOAL]=\
+ cipher_chacha20.c cipher_chacha20_hw.c
+ IF[{- !$disabled{poly1305} -}]
+ SOURCE[$CHACHAPOLY_GOAL]=\
+ cipher_chacha20_poly1305.c cipher_chacha20_poly1305_hw.c
+ ENDIF
+ENDIF
+
diff --git a/providers/implementations/ciphers/cipher_chacha20.c b/providers/implementations/ciphers/cipher_chacha20.c
new file mode 100644
index 0000000000..7cc57e7043
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_chacha20.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/* Dispatch functions for chacha20 cipher */
+
+#include "cipher_chacha20.h"
+#include "prov/implementations.h"
+#include "prov/providercommonerr.h"
+
+#define CHACHA20_KEYLEN (CHACHA_KEY_SIZE)
+#define CHACHA20_BLKLEN (1)
+#define CHACHA20_IVLEN (CHACHA_CTR_SIZE)
+/* TODO(3.0) Figure out what flags are required */
+#define CHACHA20_FLAGS (EVP_CIPH_CUSTOM_IV | EVP_CIPH_ALWAYS_CALL_INIT)
+
+static OSSL_OP_cipher_newctx_fn chacha20_newctx;
+static OSSL_OP_cipher_freectx_fn chacha20_freectx;
+static OSSL_OP_cipher_get_params_fn chacha20_get_params;
+static OSSL_OP_cipher_get_ctx_params_fn chacha20_get_ctx_params;
+static OSSL_OP_cipher_set_ctx_params_fn chacha20_set_ctx_params;
+static OSSL_OP_cipher_gettable_ctx_params_fn chacha20_gettable_ctx_params;
+static OSSL_OP_cipher_settable_ctx_params_fn chacha20_settable_ctx_params;
+#define chacha20_cipher cipher_generic_cipher
+#define chacha20_update cipher_generic_stream_update
+#define chacha20_final cipher_generic_stream_final
+#define chacha20_gettable_params cipher_generic_gettable_params
+
+void chacha20_initctx(PROV_CHACHA20_CTX *ctx)
+{
+ cipher_generic_initkey(ctx, CHACHA20_KEYLEN * 8,
+ CHACHA20_BLKLEN * 8,
+ CHACHA20_IVLEN * 8,
+ 0, CHACHA20_FLAGS,
+ PROV_CIPHER_HW_chacha20(CHACHA20_KEYLEN * 8),
+ NULL);
+}
+
+static void *chacha20_newctx(void *provctx)
+{
+ PROV_CHACHA20_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
+
+ if (ctx != NULL)
+ chacha20_initctx(ctx);
+ return ctx;
+}
+
+static void chacha20_freectx(void *vctx)
+{
+ PROV_CHACHA20_CTX *ctx = (PROV_CHACHA20_CTX *)vctx;
+
+ if (ctx != NULL) {
+ OPENSSL_clear_free(ctx, sizeof(ctx));
+ }
+}
+
+static int chacha20_get_params(OSSL_PARAM params[])
+{
+ return cipher_generic_get_params(params, 0, CHACHA20_FLAGS,
+ CHACHA20_KEYLEN * 8,
+ CHACHA20_BLKLEN * 8,
+ CHACHA20_IVLEN * 8);
+}
+
+static int chacha20_get_ctx_params(void *vctx, OSSL_PARAM params[])
+{
+ OSSL_PARAM *p;
+
+ p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IVLEN);
+ if (p != NULL && !OSSL_PARAM_set_size_t(p, CHACHA20_IVLEN)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
+ return 0;
+ }
+ p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_KEYLEN);
+ if (p != NULL && !OSSL_PARAM_set_size_t(p, CHACHA20_KEYLEN)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
+ return 0;
+ }
+
+ return 1;
+}
+
+static const OSSL_PARAM chacha20_known_gettable_ctx_params[] = {
+ OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL),
+ OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_IVLEN, NULL),
+ OSSL_PARAM_END
+};
+const OSSL_PARAM *chacha20_gettable_ctx_params(void)
+{
+ return chacha20_known_gettable_ctx_params;
+}
+
+static int chacha20_set_ctx_params(void *vctx, const OSSL_PARAM params[])
+{
+ const OSSL_PARAM *p;
+ size_t len;
+
+ p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN);
+ if (p != NULL) {
+ if (!OSSL_PARAM_get_size_t(p, &len)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
+ return 0;
+ }
+ if (len != CHACHA20_KEYLEN) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);
+ return 0;
+ }
+ }
+ p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_IVLEN);
+ if (p != NULL) {
+ if (!OSSL_PARAM_get_size_t(p, &len)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
+ return 0;
+ }
+ if (len != CHACHA20_IVLEN) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static const OSSL_PARAM chacha20_known_settable_ctx_params[] = {
+ OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL),
+ OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_IVLEN, NULL),
+ OSSL_PARAM_END
+};
+const OSSL_PARAM *chacha20_settable_ctx_params(void)
+{
+ return chacha20_known_settable_ctx_params;
+}
+
+int chacha20_einit(void *vctx, const unsigned char *key, size_t keylen,
+ const unsigned char *iv, size_t ivlen)
+{
+ int ret;
+
+ ret= cipher_generic_einit(vctx, key, keylen, iv, ivlen);
+ if (ret && iv != NULL) {
+ PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx;
+ PROV_CIPHER_HW_CHACHA20 *hw = (PROV_CIPHER_HW_CHACHA20 *)ctx->hw;
+
+ hw->initiv(ctx);
+ }
+ return ret;
+}
+
+int chacha20_dinit(void *vctx, const unsigned char *key, size_t keylen,
+ const unsigned char *iv, size_t ivlen)
+{
+ int ret;
+
+ ret= cipher_generic_dinit(vctx, key, keylen, iv, ivlen);
+ if (ret && iv != NULL) {
+ PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx;
+ PROV_CIPHER_HW_CHACHA20 *hw = (PROV_CIPHER_HW_CHACHA20 *)ctx->hw;
+
+ hw->initiv(ctx);
+ }
+ return ret;
+}
+
+/* chacha20_functions */
+const OSSL_DISPATCH chacha20_functions[] = {
+ { OSSL_FUNC_CIPHER_NEWCTX, (void (*)(void))chacha20_newctx },
+ { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))chacha20_freectx },
+ { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))chacha20_einit },
+ { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))chacha20_dinit },
+ { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))chacha20_update },
+ { OSSL_FUNC_CIPHER_FINAL, (void (*)(void))chacha20_final },
+ { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))chacha20_cipher},
+ { OSSL_FUNC_CIPHER_GET_PARAMS, (void (*)(void))chacha20_get_params },
+ { OSSL_FUNC_CIPHER_GETTABLE_PARAMS,(void (*)(void))chacha20_gettable_params },
+ { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, (void (*)(void))chacha20_get_ctx_params },
+ { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS,
+ (void (*)(void))chacha20_gettable_ctx_params },
+ { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, (void (*)(void))chacha20_set_ctx_params },
+ { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS,
+ (void (*)(void))chacha20_settable_ctx_params },
+ { 0, NULL }
+};
+
diff --git a/providers/implementations/ciphers/cipher_chacha20.h b/providers/implementations/ciphers/cipher_chacha20.h
new file mode 100644
index 0000000000..f934c0033f
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_chacha20.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "include/crypto/chacha.h"
+#include "prov/ciphercommon.h"
+
+typedef struct {
+ PROV_CIPHER_CTX base; /* must be first */
+ union {
+ OSSL_UNION_ALIGN;
+ unsigned int d[CHACHA_KEY_SIZE / 4];
+ } key;
+ unsigned int counter[CHACHA_CTR_SIZE / 4];
+ unsigned char buf[CHACHA_BLK_SIZE];
+ unsigned int partial_len;
+} PROV_CHACHA20_CTX;
+
+typedef struct prov_cipher_hw_chacha20_st {
+ PROV_CIPHER_HW base; /* must be first */
+ int (*initiv)(PROV_CIPHER_CTX *ctx);
+
+} PROV_CIPHER_HW_CHACHA20;
+
+const PROV_CIPHER_HW *PROV_CIPHER_HW_chacha20(size_t keybits);
+
+OSSL_OP_cipher_encrypt_init_fn chacha20_einit;
+OSSL_OP_cipher_decrypt_init_fn chacha20_dinit;
+void chacha20_initctx(PROV_CHACHA20_CTX *ctx);
diff --git a/providers/implementations/ciphers/cipher_chacha20_hw.c b/providers/implementations/ciphers/cipher_chacha20_hw.c
new file mode 100644
index 0000000000..dce0a6c11c
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_chacha20_hw.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/* chacha20 cipher implementation */
+
+#include "cipher_chacha20.h"
+
+static int chacha20_initkey(PROV_CIPHER_CTX *bctx, const uint8_t *key,
+ size_t keylen)
+{
+ PROV_CHACHA20_CTX *ctx = (PROV_CHACHA20_CTX *)bctx;
+ unsigned int i;
+
+ if (key != NULL) {
+ for (i = 0; i < CHACHA_KEY_SIZE; i += 4)
+ ctx->key.d[i / 4] = CHACHA_U8TOU32(key + i);
+ }
+ ctx->partial_len = 0;
+ return 1;
+}
+
+static int chacha20_initiv(PROV_CIPHER_CTX *bctx)
+{
+ PROV_CHACHA20_CTX *ctx = (PROV_CHACHA20_CTX *)bctx;
+ unsigned int i;
+
+ if (bctx->iv_set) {
+ for (i = 0; i < CHACHA_CTR_SIZE; i += 4)
+ ctx->counter[i / 4] = CHACHA_U8TOU32(bctx->oiv + i);
+ }
+ return 1;
+}
+
+static int chacha20_cipher(PROV_CIPHER_CTX *bctx, unsigned char *out,
+ const unsigned char *in, size_t inl)
+{
+ PROV_CHACHA20_CTX *ctx = (PROV_CHACHA20_CTX *)bctx;
+ unsigned int n, rem, ctr32;
+
+ n = ctx->partial_len;
+ if (n > 0) {
+ while (inl > 0 && n < CHACHA_BLK_SIZE) {
+ *out++ = *in++ ^ ctx->buf[n++];
+ inl--;
+ }
+ ctx->partial_len = n;
+
+ if (inl == 0)
+ return 1;
+
+ if (n == CHACHA_BLK_SIZE) {
+ ctx->partial_len = 0;
+ ctx->counter[0]++;
+ if (ctx->counter[0] == 0)
+ ctx->counter[1]++;
+ }
+ }
+
+ rem = (unsigned int)(inl % CHACHA_BLK_SIZE);
+ inl -= rem;
+ ctr32 = ctx->counter[0];
+ while (inl >= CHACHA_BLK_SIZE) {
+ size_t blocks = inl / CHACHA_BLK_SIZE;
+
+ /*
+ * 1<<28 is just a not-so-small yet not-so-large number...
+ * Below condition is practically never met, but it has to
+ * be checked for code correctness.
+ */
+ if (sizeof(size_t) > sizeof(unsigned int) && blocks > (1U << 28))
+ blocks = (1U << 28);
+
+ /*
+ * As ChaCha20_ctr32 operates on 32-bit counter, caller
+ * has to handle overflow. 'if' below detects the
+ * overflow, which is then handled by limiting the
+ * amount of blocks to the exact overflow point...
+ */
+ ctr32 += (unsigned int)blocks;
+ if (ctr32 < blocks) {
+ blocks -= ctr32;
+ ctr32 = 0;
+ }
+ blocks *= CHACHA_BLK_SIZE;
+ ChaCha20_ctr32(out, in, blocks, ctx->key.d, ctx->counter);
+ inl -= blocks;
+ in += blocks;
+ out += blocks;
+
+ ctx->counter[0] = ctr32;
+ if (ctr32 == 0) ctx->counter[1]++;
+ }
+
+ if (rem > 0) {
+ memset(ctx->buf, 0, sizeof(ctx->buf));
+ ChaCha20_ctr32(ctx->buf, ctx->buf, CHACHA_BLK_SIZE,
+ ctx->key.d, ctx->counter);
+ for (n = 0; n < rem; n++)
+ out[n] = in[n] ^ ctx->buf[n];
+ ctx->partial_len = rem;
+ }
+
+ return 1;
+}
+
+static const PROV_CIPHER_HW_CHACHA20 chacha20_hw = {
+ { chacha20_initkey, chacha20_cipher },
+ chacha20_initiv
+};
+
+const PROV_CIPHER_HW *PROV_CIPHER_HW_chacha20(size_t keybits)
+{
+ return (PROV_CIPHER_HW *)&chacha20_hw;
+}
+
diff --git a/providers/implementations/ciphers/cipher_chacha20_poly1305.c b/providers/implementations/ciphers/cipher_chacha20_poly1305.c
new file mode 100644
index 0000000000..cc702cb8fc
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_chacha20_poly1305.c
@@ -0,0 +1,314 @@
+/*
+ * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/* Dispatch functions for chacha20_poly1305 cipher */
+
+#include "cipher_chacha20_poly1305.h"
+#include "prov/implementations.h"
+#include "prov/providercommonerr.h"
+
+
+#define CHACHA20_POLY1305_KEYLEN CHACHA_KEY_SIZE
+#define CHACHA20_POLY1305_BLKLEN 1
+#define CHACHA20_POLY1305_MAX_IVLEN 12
+#define CHACHA20_POLY1305_MODE 0
+/* TODO(3.0) Figure out what flags are required */
+#define CHACHA20_POLY1305_FLAGS (EVP_CIPH_FLAG_AEAD_CIPHER \
+ | EVP_CIPH_ALWAYS_CALL_INIT \
+ | EVP_CIPH_CTRL_INIT \
+ | EVP_CIPH_CUSTOM_COPY \
+ | EVP_CIPH_FLAG_CUSTOM_CIPHER \
+ | EVP_CIPH_CUSTOM_IV \
+ | EVP_CIPH_CUSTOM_IV_LENGTH)
+
+static OSSL_OP_cipher_newctx_fn chacha20_poly1305_newctx;
+static OSSL_OP_cipher_freectx_fn chacha20_poly1305_freectx;
+static OSSL_OP_cipher_encrypt_init_fn chacha20_poly1305_einit;
+static OSSL_OP_cipher_decrypt_init_fn chacha20_poly1305_dinit;
+static OSSL_OP_cipher_get_params_fn chacha20_poly1305_get_params;
+static OSSL_OP_cipher_get_ctx_params_fn chacha20_poly1305_get_ctx_params;
+static OSSL_OP_cipher_set_ctx_params_fn chacha20_poly1305_set_ctx_params;
+static OSSL_OP_cipher_cipher_fn chacha20_poly1305_cipher;
+static OSSL_OP_cipher_final_fn chacha20_poly1305_final;
+static OSSL_OP_cipher_gettable_ctx_params_fn chacha20_poly1305_gettable_ctx_params;
+#define chacha20_poly1305_settable_ctx_params cipher_aead_settable_ctx_params
+#define chacha20_poly1305_gettable_params cipher_generic_gettable_params
+#define chacha20_poly1305_update chacha20_poly1305_cipher
+
+static void *chacha20_poly1305_newctx(void *provctx)
+{
+ PROV_CHACHA20_POLY1305_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
+
+ if (ctx != NULL) {
+ cipher_generic_initkey(&ctx->base, CHACHA20_POLY1305_KEYLEN * 8,
+ CHACHA20_POLY1305_BLKLEN * 8,
+ CHACHA20_POLY1305_IVLEN * 8,
+ CHACHA20_POLY1305_MODE,
+ CHACHA20_POLY1305_FLAGS,
+ PROV_CIPHER_HW_chacha20_poly1305(
+ CHACHA20_POLY1305_KEYLEN * 8),
+ NULL);
+ ctx->nonce_len = CHACHA20_POLY1305_IVLEN;
+ ctx->tls_payload_length = NO_TLS_PAYLOAD_LENGTH;
+ chacha20_initctx(&ctx->chacha);
+ }
+ return ctx;
+}
+
+static void chacha20_poly1305_freectx(void *vctx)
+{
+ PROV_CHACHA20_POLY1305_CTX *ctx = (PROV_CHACHA20_POLY1305_CTX *)vctx;
+
+ if (ctx != NULL)
+ OPENSSL_clear_free(ctx, sizeof(ctx));
+}
+
+static int chacha20_poly1305_get_params(OSSL_PARAM params[])
+{
+ return cipher_generic_get_params(params, 0, CHACHA20_POLY1305_FLAGS,
+ CHACHA20_POLY1305_KEYLEN * 8,
+ CHACHA20_POLY1305_BLKLEN * 8,
+ CHACHA20_POLY1305_IVLEN * 8);
+}
+
+static int chacha20_poly1305_get_ctx_params(void *vctx, OSSL_PARAM params[])
+{
+ PROV_CHACHA20_POLY1305_CTX *ctx = (PROV_CHACHA20_POLY1305_CTX *)vctx;
+ OSSL_PARAM *p;
+
+ p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IVLEN);
+ if (p != NULL) {
+ if (!OSSL_PARAM_set_size_t(p, ctx->nonce_len)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
+ return 0;
+ }
+ }
+ p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_KEYLEN);
+ if (p != NULL && !OSSL_PARAM_set_size_t(p, CHACHA20_POLY1305_KEYLEN)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
+ return 0;
+ }
+ p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TAGLEN);
+ if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->tag_len)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
+ return 0;
+ }
+ p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD_PAD);
+ if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->tls_aad_pad_sz)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
+ return 0;
+ }
+
+ p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TAG);
+ if (p != NULL) {
+ if (p->data_type != OSSL_PARAM_OCTET_STRING) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
+ return 0;
+ }
+ if (!ctx->base.enc) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_TAG_NOTSET);
+ return 0;
+ }
+ if (p->data_size == 0 || p->data_size > POLY1305_BLOCK_SIZE) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_TAGLEN);
+ return 0;
+ }
+ memcpy(p->data, ctx->tag, p->data_size);
+ }
+
+ return 1;
+}
+
+static const OSSL_PARAM chacha20_poly1305_known_gettable_ctx_params[] = {
+ OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL),
+ OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_IVLEN, NULL),
+ OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_AEAD_TAGLEN, NULL),
+ OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, NULL, 0),
+ OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_AEAD_TLS1_AAD_PAD, NULL),
+ OSSL_PARAM_END
+};
+static const OSSL_PARAM *chacha20_poly1305_gettable_ctx_params(void)
+{
+ return chacha20_poly1305_known_gettable_ctx_params;
+}
+
+static int chacha20_poly1305_set_ctx_params(void *vctx,
+ const OSSL_PARAM params[])
+{
+ const OSSL_PARAM *p;
+ size_t len;
+ PROV_CHACHA20_POLY1305_CTX *ctx = (PROV_CHACHA20_POLY1305_CTX *)vctx;
+ PROV_CIPHER_HW_CHACHA20_POLY1305 *hw =
+ (PROV_CIPHER_HW_CHACHA20_POLY1305 *)ctx->base.hw;
+
+ p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN);
+ if (p != NULL) {
+ if (!OSSL_PARAM_get_size_t(p, &len)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
+ return 0;
+ }
+ if (len != CHACHA20_POLY1305_KEYLEN) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);
+ return 0;
+ }
+ }
+ p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_IVLEN);
+ if (p != NULL) {
+ if (!OSSL_PARAM_get_size_t(p, &len)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
+ return 0;
+ }
+ if (len == 0 || len > CHACHA20_POLY1305_MAX_IVLEN) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH);
+ return 0;
+ }
+ ctx->nonce_len = len;
+ }
+
+ p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TAG);
+ if (p != NULL) {
+ if (p->data_type != OSSL_PARAM_OCTET_STRING) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
+ return 0;
+ }
+ if (p->data_size == 0 || p->data_size > POLY1305_BLOCK_SIZE) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_TAGLEN);
+ return 0;
+ }
+ if (p->data != NULL) {
+ if (ctx->base.enc) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_TAG_NOT_NEEDED);
+ return 0;
+ }
+ memcpy(ctx->tag, p->data, p->data_size);
+ }
+ ctx->tag_len = p->data_size;
+ }
+
+ p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TLS1_AAD);
+ if (p != NULL) {
+ if (p->data_type != OSSL_PARAM_OCTET_STRING) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
+ return 0;
+ }
+ len = hw->tls_init(&ctx->base, p->data, p->data_size);
+ if (len == 0) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DATA);
+ return 0;
+ }
+ ctx->tls_aad_pad_sz = len;
+ }
+
+ p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TLS1_IV_FIXED);
+ if (p != NULL) {
+ if (p->data_type != OSSL_PARAM_OCTET_STRING) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
+ return 0;
+ }
+ if (hw->tls_iv_set_fixed(&ctx->base, p->data, p->data_size) == 0) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IVLEN);
+ return 0;
+ }
+ }
+ /* ignore OSSL_CIPHER_PARAM_AEAD_MAC_KEY */
+ return 1;
+}
+
+static int chacha20_poly1305_einit(void *vctx, const unsigned char *key,
+ size_t keylen, const unsigned char *iv,
+ size_t ivlen)
+{
+ int ret;
+
+ ret = cipher_generic_einit(vctx, key, keylen, iv, ivlen);
+ if (ret && iv != NULL) {
+ PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx;
+ PROV_CIPHER_HW_CHACHA20_POLY1305 *hw =
+ (PROV_CIPHER_HW_CHACHA20_POLY1305 *)ctx->hw;
+
+ hw->initiv(ctx);
+ }
+ return ret;
+}
+
+static int chacha20_poly1305_dinit(void *vctx, const unsigned char *key,
+ size_t keylen, const unsigned char *iv,
+ size_t ivlen)
+{
+ int ret;
+
+ ret = cipher_generic_dinit(vctx, key, keylen, iv, ivlen);
+ if (ret && iv != NULL) {
+ PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx;
+ PROV_CIPHER_HW_CHACHA20_POLY1305 *hw =
+ (PROV_CIPHER_HW_CHACHA20_POLY1305 *)ctx->hw;
+
+ hw->initiv(ctx);
+ }
+ return ret;
+}
+
+static int chacha20_poly1305_cipher(void *vctx, unsigned char *out,
+ size_t *outl, size_t outsize,
+ const unsigned char *in, size_t inl)
+{
+ PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx;