summaryrefslogtreecommitdiff
path: root/providers/implementations/ciphers
diff options
context:
space:
mode:
authorRichard Levitte <levitte@openssl.org>2019-10-04 14:44:42 +0200
committerRichard Levitte <levitte@openssl.org>2019-10-10 14:12:15 +0200
commit604e884bb8aba9b549c7e5effe01e406ccab3bcd (patch)
tree9ef1f699e8376854b11ea237191c264d408b3c2b /providers/implementations/ciphers
parent7c214f1092f7622a1c2fdc5cfe70ddc94918daa3 (diff)
downloadopenssl-new-604e884bb8aba9b549c7e5effe01e406ccab3bcd.tar.gz
Providers: move all ciphers
From providers/{common,default}/ to providers/implementations/ Except for common code, which remains in providers/common/ciphers/. However, we do move providers/common/include/internal/ciphers/*.h to providers/common/include/prov/, and adjust all source including any of those header files. Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/10088)
Diffstat (limited to 'providers/implementations/ciphers')
-rw-r--r--providers/implementations/ciphers/build.info102
-rw-r--r--providers/implementations/ciphers/cipher_aes.c80
-rw-r--r--providers/implementations/ciphers/cipher_aes.h62
-rw-r--r--providers/implementations/ciphers/cipher_aes_ccm.c38
-rw-r--r--providers/implementations/ciphers/cipher_aes_ccm_hw.c64
-rw-r--r--providers/implementations/ciphers/cipher_aes_ccm_hw_aesni.inc38
-rw-r--r--providers/implementations/ciphers/cipher_aes_ccm_hw_s390x.inc268
-rw-r--r--providers/implementations/ciphers/cipher_aes_ccm_hw_t4.inc36
-rw-r--r--providers/implementations/ciphers/cipher_aes_gcm.c38
-rw-r--r--providers/implementations/ciphers/cipher_aes_gcm_hw.c78
-rw-r--r--providers/implementations/ciphers/cipher_aes_gcm_hw_aesni.inc38
-rw-r--r--providers/implementations/ciphers/cipher_aes_gcm_hw_s390x.inc300
-rw-r--r--providers/implementations/ciphers/cipher_aes_gcm_hw_t4.inc52
-rw-r--r--providers/implementations/ciphers/cipher_aes_hw.c139
-rw-r--r--providers/implementations/ciphers/cipher_aes_hw_aesni.inc83
-rw-r--r--providers/implementations/ciphers/cipher_aes_hw_s390x.inc203
-rw-r--r--providers/implementations/ciphers/cipher_aes_hw_t4.inc95
-rw-r--r--providers/implementations/ciphers/cipher_aes_ocb.c495
-rw-r--r--providers/implementations/ciphers/cipher_aes_ocb.h38
-rw-r--r--providers/implementations/ciphers/cipher_aes_ocb_hw.c115
-rw-r--r--providers/implementations/ciphers/cipher_aes_wrp.c242
-rw-r--r--providers/implementations/ciphers/cipher_aes_xts.c275
-rw-r--r--providers/implementations/ciphers/cipher_aes_xts.h34
-rw-r--r--providers/implementations/ciphers/cipher_aes_xts_fips.c16
-rw-r--r--providers/implementations/ciphers/cipher_aes_xts_hw.c153
-rw-r--r--providers/implementations/ciphers/cipher_aria.c80
-rw-r--r--providers/implementations/ciphers/cipher_aria.h30
-rw-r--r--providers/implementations/ciphers/cipher_aria_ccm.c39
-rw-r--r--providers/implementations/ciphers/cipher_aria_ccm.h22
-rw-r--r--providers/implementations/ciphers/cipher_aria_ccm_hw.c40
-rw-r--r--providers/implementations/ciphers/cipher_aria_gcm.c38
-rw-r--r--providers/implementations/ciphers/cipher_aria_gcm.h22
-rw-r--r--providers/implementations/ciphers/cipher_aria_gcm_hw.c50
-rw-r--r--providers/implementations/ciphers/cipher_aria_hw.c48
-rw-r--r--providers/implementations/ciphers/cipher_blowfish.c48
-rw-r--r--providers/implementations/ciphers/cipher_blowfish.h24
-rw-r--r--providers/implementations/ciphers/cipher_blowfish_hw.c36
-rw-r--r--providers/implementations/ciphers/cipher_camellia.c81
-rw-r--r--providers/implementations/ciphers/cipher_camellia.h29
-rw-r--r--providers/implementations/ciphers/cipher_camellia_hw.c64
-rw-r--r--providers/implementations/ciphers/cipher_camellia_hw_t4.inc83
-rw-r--r--providers/implementations/ciphers/cipher_cast.h24
-rw-r--r--providers/implementations/ciphers/cipher_cast5.c48
-rw-r--r--providers/implementations/ciphers/cipher_cast5_hw.c36
-rw-r--r--providers/implementations/ciphers/cipher_des.c160
-rw-r--r--providers/implementations/ciphers/cipher_des.h33
-rw-r--r--providers/implementations/ciphers/cipher_des_hw.c173
-rw-r--r--providers/implementations/ciphers/cipher_desx.c15
-rw-r--r--providers/implementations/ciphers/cipher_desx_hw.c62
-rw-r--r--providers/implementations/ciphers/cipher_idea.c46
-rw-r--r--providers/implementations/ciphers/cipher_idea.h24
-rw-r--r--providers/implementations/ciphers/cipher_idea_hw.c56
-rw-r--r--providers/implementations/ciphers/cipher_rc2.c239
-rw-r--r--providers/implementations/ciphers/cipher_rc2.h28
-rw-r--r--providers/implementations/ciphers/cipher_rc2_hw.c37
-rw-r--r--providers/implementations/ciphers/cipher_rc4.c87
-rw-r--r--providers/implementations/ciphers/cipher_rc4.h21
-rw-r--r--providers/implementations/ciphers/cipher_rc4_hw.c38
-rw-r--r--providers/implementations/ciphers/cipher_rc5.c145
-rw-r--r--providers/implementations/ciphers/cipher_rc5.h25
-rw-r--r--providers/implementations/ciphers/cipher_rc5_hw.c35
-rw-r--r--providers/implementations/ciphers/cipher_seed.c46
-rw-r--r--providers/implementations/ciphers/cipher_seed.h24
-rw-r--r--providers/implementations/ciphers/cipher_seed_hw.c36
-rw-r--r--providers/implementations/ciphers/cipher_sm4.c48
-rw-r--r--providers/implementations/ciphers/cipher_sm4.h25
-rw-r--r--providers/implementations/ciphers/cipher_sm4_hw.c43
-rw-r--r--providers/implementations/ciphers/cipher_tdes.c114
-rw-r--r--providers/implementations/ciphers/cipher_tdes.h96
-rw-r--r--providers/implementations/ciphers/cipher_tdes_default.c29
-rw-r--r--providers/implementations/ciphers/cipher_tdes_default.h25
-rw-r--r--providers/implementations/ciphers/cipher_tdes_default_hw.c140
-rw-r--r--providers/implementations/ciphers/cipher_tdes_hw.c82
-rw-r--r--providers/implementations/ciphers/cipher_tdes_wrap.c199
-rw-r--r--providers/implementations/ciphers/cipher_tdes_wrap_hw.c14
75 files changed, 6069 insertions, 0 deletions
diff --git a/providers/implementations/ciphers/build.info b/providers/implementations/ciphers/build.info
new file mode 100644
index 0000000000..fb2b53e58a
--- /dev/null
+++ b/providers/implementations/ciphers/build.info
@@ -0,0 +1,102 @@
+# We make separate GOAL variables for each algorithm, to make it easy to
+# switch each to the Legacy provider when needed.
+#
+# $TDES_1_GOAL and $TDES_2_GOAL separate FIPSable and non-FIPSable TDES.
+# The latter may become legacy sooner, so it's comfortable to have two
+# variables already now, to switch the non-FIPSable TDES to legacy if needed.
+
+$AES_GOAL=../../libimplementations.a
+$TDES_1_GOAL=../../libimplementations.a
+$TDES_2_GOAL=../../libimplementations.a
+$DES_GOAL=../../libimplementations.a
+$ARIA_GOAL=../../libimplementations.a
+$CAMELLIA_GOAL=../../libimplementations.a
+$BLOWFISH_GOAL=../../libimplementations.a
+$IDEA_GOAL=../../libimplementations.a
+$CAST5_GOAL=../../libimplementations.a
+$SEED_GOAL=../../libimplementations.a
+$SM4_GOAL=../../libimplementations.a
+$RC4_GOAL=../../libimplementations.a
+$RC5_GOAL=../../libimplementations.a
+$RC2_GOAL=../../libimplementations.a
+
+IF[{- !$disabled{des} -}]
+ SOURCE[$TDES_1_GOAL]=cipher_tdes.c cipher_tdes_hw.c
+ENDIF
+
+SOURCE[$AES_GOAL]=\
+ cipher_aes.c cipher_aes_hw.c \
+ cipher_aes_xts.c cipher_aes_xts_hw.c \
+ cipher_aes_gcm.c cipher_aes_gcm_hw.c \
+ cipher_aes_ccm.c cipher_aes_ccm_hw.c \
+ cipher_aes_wrp.c
+# Extra code to satisfy the FIPS and non-FIPS separation.
+# When the AES-xxx-XTS moves to legacy, this can be removed.
+SOURCE[../../libfips.a]=cipher_aes_xts_fips.c
+SOURCE[../../libnonfips.a]=cipher_aes_xts_fips.c
+
+IF[{- !$disabled{des} -}]
+ SOURCE[$TDES_2_GOAL]=\
+ cipher_tdes_default.c cipher_tdes_default_hw.c \
+ cipher_tdes_wrap.c cipher_tdes_wrap_hw.c
+ SOURCE[$DES_GOAL]=\
+ cipher_desx.c cipher_desx_hw.c \
+ cipher_des.c cipher_des_hw.c
+ENDIF
+
+IF[{- !$disabled{aria} -}]
+ SOURCE[$ARIA_GOAL]=\
+ cipher_aria.c cipher_aria_hw.c \
+ cipher_aria_gcm.c cipher_aria_gcm_hw.c \
+ cipher_aria_ccm.c cipher_aria_ccm_hw.c
+ENDIF
+
+IF[{- !$disabled{camellia} -}]
+ SOURCE[$CAMELLIA_GOAL]=\
+ cipher_camellia.c cipher_camellia_hw.c
+ENDIF
+
+IF[{- !$disabled{bf} -}]
+ SOURCE[$BLOWFISH_GOAL]=\
+ cipher_blowfish.c cipher_blowfish_hw.c
+ENDIF
+
+IF[{- !$disabled{idea} -}]
+ SOURCE[$IDEA_GOAL]=\
+ cipher_idea.c cipher_idea_hw.c
+ENDIF
+
+IF[{- !$disabled{cast} -}]
+ SOURCE[$CAST5_GOAL]=\
+ cipher_cast5.c cipher_cast5_hw.c
+ENDIF
+
+IF[{- !$disabled{seed} -}]
+ SOURCE[$SEED_GOAL]=\
+ cipher_seed.c cipher_seed_hw.c
+ENDIF
+
+IF[{- !$disabled{sm4} -}]
+ SOURCE[$SM4_GOAL]=\
+ cipher_sm4.c cipher_sm4_hw.c
+ENDIF
+
+IF[{- !$disabled{ocb} -}]
+ SOURCE[$AES_GOAL]=\
+ cipher_aes_ocb.c cipher_aes_ocb_hw.c
+ENDIF
+
+IF[{- !$disabled{rc4} -}]
+ SOURCE[$RC4_GOAL]=\
+ cipher_rc4.c cipher_rc4_hw.c
+ENDIF
+
+IF[{- !$disabled{rc5} -}]
+ SOURCE[$RC5_GOAL]=\
+ cipher_rc5.c cipher_rc5_hw.c
+ENDIF
+
+IF[{- !$disabled{rc2} -}]
+ SOURCE[$RC2_GOAL]=\
+ cipher_rc2.c cipher_rc2_hw.c
+ENDIF
diff --git a/providers/implementations/ciphers/cipher_aes.c b/providers/implementations/ciphers/cipher_aes.c
new file mode 100644
index 0000000000..46880e0bf7
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aes.c
@@ -0,0 +1,80 @@
+/*
+ * 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 AES cipher modes ecb, cbc, ofb, cfb, ctr */
+
+#include "cipher_aes.h"
+#include "internal/provider_algs.h"
+
+static OSSL_OP_cipher_freectx_fn aes_freectx;
+static OSSL_OP_cipher_dupctx_fn aes_dupctx;
+
+static void aes_freectx(void *vctx)
+{
+ PROV_AES_CTX *ctx = (PROV_AES_CTX *)vctx;
+
+ OPENSSL_clear_free(ctx, sizeof(*ctx));
+}
+
+static void *aes_dupctx(void *ctx)
+{
+ PROV_AES_CTX *in = (PROV_AES_CTX *)ctx;
+ PROV_AES_CTX *ret = OPENSSL_malloc(sizeof(*ret));
+
+ if (ret == NULL) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ *ret = *in;
+
+ return ret;
+}
+
+/* aes256ecb_functions */
+IMPLEMENT_generic_cipher(aes, AES, ecb, ECB, 0, 256, 128, 0, block)
+/* aes192ecb_functions */
+IMPLEMENT_generic_cipher(aes, AES, ecb, ECB, 0, 192, 128, 0, block)
+/* aes128ecb_functions */
+IMPLEMENT_generic_cipher(aes, AES, ecb, ECB, 0, 128, 128, 0, block)
+/* aes256cbc_functions */
+IMPLEMENT_generic_cipher(aes, AES, cbc, CBC, 0, 256, 128, 128, block)
+/* aes192cbc_functions */
+IMPLEMENT_generic_cipher(aes, AES, cbc, CBC, 0, 192, 128, 128, block)
+/* aes128cbc_functions */
+IMPLEMENT_generic_cipher(aes, AES, cbc, CBC, 0, 128, 128, 128, block)
+/* aes256ofb_functions */
+IMPLEMENT_generic_cipher(aes, AES, ofb, OFB, 0, 256, 8, 128, stream)
+/* aes192ofb_functions */
+IMPLEMENT_generic_cipher(aes, AES, ofb, OFB, 0, 192, 8, 128, stream)
+/* aes128ofb_functions */
+IMPLEMENT_generic_cipher(aes, AES, ofb, OFB, 0, 128, 8, 128, stream)
+/* aes256cfb_functions */
+IMPLEMENT_generic_cipher(aes, AES, cfb, CFB, 0, 256, 8, 128, stream)
+/* aes192cfb_functions */
+IMPLEMENT_generic_cipher(aes, AES, cfb, CFB, 0, 192, 8, 128, stream)
+/* aes128cfb_functions */
+IMPLEMENT_generic_cipher(aes, AES, cfb, CFB, 0, 128, 8, 128, stream)
+/* aes256cfb1_functions */
+IMPLEMENT_generic_cipher(aes, AES, cfb1, CFB, 0, 256, 8, 128, stream)
+/* aes192cfb1_functions */
+IMPLEMENT_generic_cipher(aes, AES, cfb1, CFB, 0, 192, 8, 128, stream)
+/* aes128cfb1_functions */
+IMPLEMENT_generic_cipher(aes, AES, cfb1, CFB, 0, 128, 8, 128, stream)
+/* aes256cfb8_functions */
+IMPLEMENT_generic_cipher(aes, AES, cfb8, CFB, 0, 256, 8, 128, stream)
+/* aes192cfb8_functions */
+IMPLEMENT_generic_cipher(aes, AES, cfb8, CFB, 0, 192, 8, 128, stream)
+/* aes128cfb8_functions */
+IMPLEMENT_generic_cipher(aes, AES, cfb8, CFB, 0, 128, 8, 128, stream)
+/* aes256ctr_functions */
+IMPLEMENT_generic_cipher(aes, AES, ctr, CTR, 0, 256, 8, 128, stream)
+/* aes192ctr_functions */
+IMPLEMENT_generic_cipher(aes, AES, ctr, CTR, 0, 192, 8, 128, stream)
+/* aes128ctr_functions */
+IMPLEMENT_generic_cipher(aes, AES, ctr, CTR, 0, 128, 8, 128, stream)
diff --git a/providers/implementations/ciphers/cipher_aes.h b/providers/implementations/ciphers/cipher_aes.h
new file mode 100644
index 0000000000..d00fab13ef
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aes.h
@@ -0,0 +1,62 @@
+/*
+ * 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 <openssl/aes.h>
+#include "prov/ciphercommon.h"
+
+typedef struct prov_aes_ctx_st {
+ PROV_CIPHER_CTX base; /* Must be first */
+ union {
+ OSSL_UNION_ALIGN;
+ AES_KEY ks;
+ } ks;
+
+ /* Platform specific data */
+ union {
+ int dummy;
+#if defined(OPENSSL_CPUID_OBJ) && defined(__s390__)
+ struct {
+ union {
+ OSSL_UNION_ALIGN;
+ /*-
+ * KM-AES parameter block - begin
+ * (see z/Architecture Principles of Operation >= SA22-7832-06)
+ */
+ struct {
+ unsigned char k[32];
+ } km;
+ /* KM-AES parameter block - end */
+ /*-
+ * KMO-AES/KMF-AES parameter block - begin
+ * (see z/Architecture Principles of Operation >= SA22-7832-08)
+ */
+ struct {
+ unsigned char cv[16];
+ unsigned char k[32];
+ } kmo_kmf;
+ /* KMO-AES/KMF-AES parameter block - end */
+ } param;
+ unsigned int fc;
+ int res;
+ } s390x;
+#endif /* defined(OPENSSL_CPUID_OBJ) && defined(__s390__) */
+ } plat;
+
+} PROV_AES_CTX;
+
+#define PROV_CIPHER_HW_aes_ofb PROV_CIPHER_HW_aes_ofb128
+#define PROV_CIPHER_HW_aes_cfb PROV_CIPHER_HW_aes_cfb128
+const PROV_CIPHER_HW *PROV_CIPHER_HW_aes_ecb(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_aes_cbc(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_aes_ofb128(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_aes_cfb128(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_aes_cfb1(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_aes_cfb8(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_aes_ctr(size_t keybits);
+
diff --git a/providers/implementations/ciphers/cipher_aes_ccm.c b/providers/implementations/ciphers/cipher_aes_ccm.c
new file mode 100644
index 0000000000..59fc7274c9
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aes_ccm.c
@@ -0,0 +1,38 @@
+/*
+ * 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 AES CCM mode */
+
+#include "prov/ciphercommon.h"
+#include "prov/cipher_ccm.h"
+#include "internal/provider_algs.h"
+
+static void *aes_ccm_newctx(void *provctx, size_t keybits)
+{
+ PROV_AES_CCM_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
+
+ if (ctx != NULL)
+ ccm_initctx(&ctx->base, keybits, PROV_AES_HW_ccm(keybits));
+ return ctx;
+}
+
+static OSSL_OP_cipher_freectx_fn aes_ccm_freectx;
+static void aes_ccm_freectx(void *vctx)
+{
+ PROV_AES_CCM_CTX *ctx = (PROV_AES_CCM_CTX *)vctx;
+
+ OPENSSL_clear_free(ctx, sizeof(*ctx));
+}
+
+/* aes128ccm_functions */
+IMPLEMENT_aead_cipher(aes, ccm, CCM, AEAD_FLAGS, 128, 8, 96);
+/* aes192ccm_functions */
+IMPLEMENT_aead_cipher(aes, ccm, CCM, AEAD_FLAGS, 192, 8, 96);
+/* aes256ccm_functions */
+IMPLEMENT_aead_cipher(aes, ccm, CCM, AEAD_FLAGS, 256, 8, 96);
diff --git a/providers/implementations/ciphers/cipher_aes_ccm_hw.c b/providers/implementations/ciphers/cipher_aes_ccm_hw.c
new file mode 100644
index 0000000000..ae200ebada
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aes_ccm_hw.c
@@ -0,0 +1,64 @@
+/*
+ * 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
+ */
+
+/* AES CCM mode */
+
+#include "prov/ciphercommon.h"
+#include "prov/cipher_ccm.h"
+
+#define AES_HW_CCM_SET_KEY_FN(fn_set_enc_key, fn_blk, fn_ccm_enc, fn_ccm_dec) \
+ fn_set_enc_key(key, keylen * 8, &actx->ccm.ks.ks); \
+ CRYPTO_ccm128_init(&ctx->ccm_ctx, ctx->m, ctx->l, &actx->ccm.ks.ks, \
+ (block128_f)fn_blk); \
+ ctx->str = ctx->enc ? (ccm128_f)fn_ccm_enc : (ccm128_f)fn_ccm_dec; \
+ ctx->key_set = 1;
+
+static int ccm_generic_aes_initkey(PROV_CCM_CTX *ctx, const unsigned char *key,
+ size_t keylen)
+{
+ PROV_AES_CCM_CTX *actx = (PROV_AES_CCM_CTX *)ctx;
+
+#ifdef HWAES_CAPABLE
+ if (HWAES_CAPABLE) {
+ AES_HW_CCM_SET_KEY_FN(HWAES_set_encrypt_key, HWAES_encrypt, NULL, NULL);
+ } else
+#endif /* HWAES_CAPABLE */
+
+#ifdef VPAES_CAPABLE
+ if (VPAES_CAPABLE) {
+ AES_HW_CCM_SET_KEY_FN(vpaes_set_encrypt_key, vpaes_encrypt, NULL, NULL);
+ } else
+#endif
+ {
+ AES_HW_CCM_SET_KEY_FN(AES_set_encrypt_key, AES_encrypt, NULL, NULL)
+ }
+ return 1;
+}
+
+static const PROV_CCM_HW aes_ccm = {
+ ccm_generic_aes_initkey,
+ ccm_generic_setiv,
+ ccm_generic_setaad,
+ ccm_generic_auth_encrypt,
+ ccm_generic_auth_decrypt,
+ ccm_generic_gettag
+};
+
+#if defined(S390X_aes_128_CAPABLE)
+# include "cipher_aes_ccm_hw_s390x.inc"
+#elif defined(AESNI_CAPABLE)
+# include "cipher_aes_ccm_hw_aesni.inc"
+#elif defined(SPARC_AES_CAPABLE)
+# include "cipher_aes_ccm_hw_t4.inc"
+#else
+const PROV_CCM_HW *PROV_AES_HW_ccm(size_t keybits)
+{
+ return &aes_ccm;
+}
+#endif
diff --git a/providers/implementations/ciphers/cipher_aes_ccm_hw_aesni.inc b/providers/implementations/ciphers/cipher_aes_ccm_hw_aesni.inc
new file mode 100644
index 0000000000..3a5e4a740d
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aes_ccm_hw_aesni.inc
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2001-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
+ */
+
+/*-
+ * AES-NI support for AES CCM.
+ * This file is included by cipher_ccm_hw.c
+ */
+
+static int ccm_aesni_initkey(PROV_CCM_CTX *ctx, const unsigned char *key,
+ size_t keylen)
+{
+ PROV_AES_CCM_CTX *actx = (PROV_AES_CCM_CTX *)ctx;
+
+ AES_HW_CCM_SET_KEY_FN(aesni_set_encrypt_key, aesni_encrypt,
+ aesni_ccm64_encrypt_blocks,
+ aesni_ccm64_decrypt_blocks);
+ return 1;
+}
+
+static const PROV_CCM_HW aesni_ccm = {
+ ccm_aesni_initkey,
+ ccm_generic_setiv,
+ ccm_generic_setaad,
+ ccm_generic_auth_encrypt,
+ ccm_generic_auth_decrypt,
+ ccm_generic_gettag
+};
+
+const PROV_CCM_HW *PROV_AES_HW_ccm(size_t keybits)
+{
+ return AESNI_CAPABLE ? &aesni_ccm : &aes_ccm;
+}
diff --git a/providers/implementations/ciphers/cipher_aes_ccm_hw_s390x.inc b/providers/implementations/ciphers/cipher_aes_ccm_hw_s390x.inc
new file mode 100644
index 0000000000..a5025e5960
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aes_ccm_hw_s390x.inc
@@ -0,0 +1,268 @@
+/*
+ * Copyright 2001-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
+ */
+
+/*-
+ * S390X support for AES CCM.
+ * This file is included by cipher_ccm_hw.c
+ */
+
+#define S390X_CCM_AAD_FLAG 0x40
+
+static int s390x_aes_ccm_initkey(PROV_CCM_CTX *ctx,
+ const unsigned char *key, size_t keylen)
+{
+ PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx;
+
+ sctx->ccm.s390x.fc = S390X_AES_FC(keylen);
+ memcpy(&sctx->ccm.s390x.kmac.k, key, keylen);
+ /* Store encoded m and l. */
+ sctx->ccm.s390x.nonce.b[0] = ((ctx->l - 1) & 0x7)
+ | (((ctx->m - 2) >> 1) & 0x7) << 3;
+ memset(sctx->ccm.s390x.nonce.b + 1, 0, sizeof(sctx->ccm.s390x.nonce.b));
+ sctx->ccm.s390x.blocks = 0;
+ ctx->key_set = 1;
+ return 1;
+}
+
+static int s390x_aes_ccm_setiv(PROV_CCM_CTX *ctx,
+ const unsigned char *nonce, size_t noncelen,
+ size_t mlen)
+{
+ PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx;
+
+ sctx->ccm.s390x.nonce.b[0] &= ~S390X_CCM_AAD_FLAG;
+ sctx->ccm.s390x.nonce.g[1] = mlen;
+ memcpy(sctx->ccm.s390x.nonce.b + 1, nonce, 15 - ctx->l);
+ return 1;
+}
+
+/*-
+ * Process additional authenticated data. Code is big-endian.
+ */
+static int s390x_aes_ccm_setaad(PROV_CCM_CTX *ctx,
+ const unsigned char *aad, size_t alen)
+{
+ PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx;
+ unsigned char *ptr;
+ int i, rem;
+
+ if (!alen)
+ return 1;
+
+ sctx->ccm.s390x.nonce.b[0] |= S390X_CCM_AAD_FLAG;
+
+ /* Suppress 'type-punned pointer dereference' warning. */
+ ptr = sctx->ccm.s390x.buf.b;
+
+ if (alen < ((1 << 16) - (1 << 8))) {
+ *(uint16_t *)ptr = alen;
+ i = 2;
+ } else if (sizeof(alen) == 8
+ && alen >= (size_t)1 << (32 % (sizeof(alen) * 8))) {
+ *(uint16_t *)ptr = 0xffff;
+ *(uint64_t *)(ptr + 2) = alen;
+ i = 10;
+ } else {
+ *(uint16_t *)ptr = 0xfffe;
+ *(uint32_t *)(ptr + 2) = alen;
+ i = 6;
+ }
+
+ while (i < 16 && alen) {
+ sctx->ccm.s390x.buf.b[i] = *aad;
+ ++aad;
+ --alen;
+ ++i;
+ }
+ while (i < 16) {
+ sctx->ccm.s390x.buf.b[i] = 0;
+ ++i;
+ }
+
+ sctx->ccm.s390x.kmac.icv.g[0] = 0;
+ sctx->ccm.s390x.kmac.icv.g[1] = 0;
+ s390x_kmac(sctx->ccm.s390x.nonce.b, 32, sctx->ccm.s390x.fc,
+ &sctx->ccm.s390x.kmac);
+ sctx->ccm.s390x.blocks += 2;
+
+ rem = alen & 0xf;
+ alen &= ~(size_t)0xf;
+ if (alen) {
+ s390x_kmac(aad, alen, sctx->ccm.s390x.fc, &sctx->ccm.s390x.kmac);
+ sctx->ccm.s390x.blocks += alen >> 4;
+ aad += alen;
+ }
+ if (rem) {
+ for (i = 0; i < rem; i++)
+ sctx->ccm.s390x.kmac.icv.b[i] ^= aad[i];
+
+ s390x_km(sctx->ccm.s390x.kmac.icv.b, 16,
+ sctx->ccm.s390x.kmac.icv.b, sctx->ccm.s390x.fc,
+ sctx->ccm.s390x.kmac.k);
+ sctx->ccm.s390x.blocks++;
+ }
+ return 1;
+}
+
+/*-
+ * En/de-crypt plain/cipher-text. Compute tag from plaintext. Returns 1 for
+ * success.
+ */
+static int s390x_aes_ccm_auth_encdec(PROV_CCM_CTX *ctx,
+ const unsigned char *in,
+ unsigned char *out, size_t len, int enc)
+{
+ PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx;
+ size_t n, rem;
+ unsigned int i, l, num;
+ unsigned char flags;
+
+ flags = sctx->ccm.s390x.nonce.b[0];
+ if (!(flags & S390X_CCM_AAD_FLAG)) {
+ s390x_km(sctx->ccm.s390x.nonce.b, 16, sctx->ccm.s390x.kmac.icv.b,
+ sctx->ccm.s390x.fc, sctx->ccm.s390x.kmac.k);
+ sctx->ccm.s390x.blocks++;
+ }
+ l = flags & 0x7;
+ sctx->ccm.s390x.nonce.b[0] = l;
+
+ /*-
+ * Reconstruct length from encoded length field
+ * and initialize it with counter value.
+ */
+ n = 0;
+ for (i = 15 - l; i < 15; i++) {
+ n |= sctx->ccm.s390x.nonce.b[i];
+ sctx->ccm.s390x.nonce.b[i] = 0;
+ n <<= 8;
+ }
+ n |= sctx->ccm.s390x.nonce.b[15];
+ sctx->ccm.s390x.nonce.b[15] = 1;
+
+ if (n != len)
+ return 0; /* length mismatch */
+
+ if (enc) {
+ /* Two operations per block plus one for tag encryption */
+ sctx->ccm.s390x.blocks += (((len + 15) >> 4) << 1) + 1;
+ if (sctx->ccm.s390x.blocks > (1ULL << 61))
+ return 0; /* too much data */
+ }
+
+ num = 0;
+ rem = len & 0xf;
+ len &= ~(size_t)0xf;
+
+ if (enc) {
+ /* mac-then-encrypt */
+ if (len)
+ s390x_kmac(in, len, sctx->ccm.s390x.fc, &sctx->ccm.s390x.kmac);
+ if (rem) {
+ for (i = 0; i < rem; i++)
+ sctx->ccm.s390x.kmac.icv.b[i] ^= in[len + i];
+
+ s390x_km(sctx->ccm.s390x.kmac.icv.b, 16,
+ sctx->ccm.s390x.kmac.icv.b,
+ sctx->ccm.s390x.fc, sctx->ccm.s390x.kmac.k);
+ }
+
+ CRYPTO_ctr128_encrypt_ctr32(in, out, len + rem, &sctx->ccm.ks.ks,
+ sctx->ccm.s390x.nonce.b, sctx->ccm.s390x.buf.b,
+ &num, (ctr128_f)AES_ctr32_encrypt);
+ } else {
+ /* decrypt-then-mac */
+ CRYPTO_ctr128_encrypt_ctr32(in, out, len + rem, &sctx->ccm.ks.ks,
+ sctx->ccm.s390x.nonce.b, sctx->ccm.s390x.buf.b,
+ &num, (ctr128_f)AES_ctr32_encrypt);
+
+ if (len)
+ s390x_kmac(out, len, sctx->ccm.s390x.fc, &sctx->ccm.s390x.kmac);
+ if (rem) {
+ for (i = 0; i < rem; i++)
+ sctx->ccm.s390x.kmac.icv.b[i] ^= out[len + i];
+
+ s390x_km(sctx->ccm.s390x.kmac.icv.b, 16,
+ sctx->ccm.s390x.kmac.icv.b,
+ sctx->ccm.s390x.fc, sctx->ccm.s390x.kmac.k);
+ }
+ }
+ /* encrypt tag */
+ for (i = 15 - l; i < 16; i++)
+ sctx->ccm.s390x.nonce.b[i] = 0;
+
+ s390x_km(sctx->ccm.s390x.nonce.b, 16, sctx->ccm.s390x.buf.b,
+ sctx->ccm.s390x.fc, sctx->ccm.s390x.kmac.k);
+ sctx->ccm.s390x.kmac.icv.g[0] ^= sctx->ccm.s390x.buf.g[0];
+ sctx->ccm.s390x.kmac.icv.g[1] ^= sctx->ccm.s390x.buf.g[1];
+
+ sctx->ccm.s390x.nonce.b[0] = flags; /* restore flags field */
+ return 1;
+}
+
+
+static int s390x_aes_ccm_gettag(PROV_CCM_CTX *ctx,
+ unsigned char *tag, size_t tlen)
+{
+ PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx;
+
+ if (tlen > ctx->m)
+ return 0;
+ memcpy(tag, sctx->ccm.s390x.kmac.icv.b, tlen);
+ return 1;
+}
+
+static int s390x_aes_ccm_auth_encrypt(PROV_CCM_CTX *ctx,
+ const unsigned char *in,
+ unsigned char *out, size_t len,
+ unsigned char *tag, size_t taglen)
+{
+ int rv;
+
+ rv = s390x_aes_ccm_auth_encdec(ctx, in, out, len, 1);
+ if (rv && tag != NULL)
+ rv = s390x_aes_ccm_gettag(ctx, tag, taglen);
+ return rv;
+}
+
+static int s390x_aes_ccm_auth_decrypt(PROV_CCM_CTX *ctx,
+ const unsigned char *in,
+ unsigned char *out, size_t len,
+ unsigned char *expected_tag,
+ size_t taglen)
+{
+ int rv = 0;
+ PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx;
+
+ rv = s390x_aes_ccm_auth_encdec(ctx, in, out, len, 0);
+ if (rv) {
+ if (CRYPTO_memcmp(sctx->ccm.s390x.kmac.icv.b, expected_tag, ctx->m) != 0)
+ rv = 0;
+ }
+ if (rv == 0)
+ OPENSSL_cleanse(out, len);
+ return rv;
+}
+
+static const PROV_CCM_HW s390x_aes_ccm = {
+ s390x_aes_ccm_initkey,
+ s390x_aes_ccm_setiv,
+ s390x_aes_ccm_setaad,
+ s390x_aes_ccm_auth_encrypt,
+ s390x_aes_ccm_auth_decrypt,
+ s390x_aes_ccm_gettag
+};
+
+const PROV_CCM_HW *PROV_AES_HW_ccm(size_t keybits)
+{
+ if ((keybits == 128 && S390X_aes_128_ccm_CAPABLE)
+ || (keybits == 192 && S390X_aes_192_ccm_CAPABLE)
+ || (keybits == 256 && S390X_aes_256_ccm_CAPABLE))
+ return &s390x_aes_ccm;
+ return &aes_ccm;
+}
diff --git a/providers/implementations/ciphers/cipher_aes_ccm_hw_t4.inc b/providers/implementations/ciphers/cipher_aes_ccm_hw_t4.inc
new file mode 100644
index 0000000000..21bf6861e0
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aes_ccm_hw_t4.inc
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2001-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
+ */
+
+/*-
+ * Fujitsu SPARC64 X support for AES CCM.
+ * This file is included by cipher_ccm_hw.c
+ */
+
+static int ccm_t4_aes_initkey(PROV_CCM_CTX *ctx, const unsigned char *key,
+ size_t keylen)
+{
+ PROV_AES_CCM_CTX *actx = (PROV_AES_CCM_CTX *)ctx;
+
+ AES_HW_CCM_SET_KEY_FN(aes_t4_set_encrypt_key, aes_t4_encrypt, NULL, NULL);
+ return 1;
+}
+
+static const PROV_CCM_HW t4_aes_ccm = {
+ ccm_t4_aes_initkey,
+ ccm_generic_setiv,
+ ccm_generic_setaad,
+ ccm_generic_auth_encrypt,
+ ccm_generic_auth_decrypt,
+ ccm_generic_gettag
+};
+
+const PROV_CCM_HW *PROV_AES_HW_ccm(size_t keybits)
+{
+ return SPARC_AES_CAPABLE ? &t4_aes_ccm : &aes_ccm;
+}
diff --git a/providers/implementations/ciphers/cipher_aes_gcm.c b/providers/implementations/ciphers/cipher_aes_gcm.c
new file mode 100644
index 0000000000..1df1c1dba9
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aes_gcm.c
@@ -0,0 +1,38 @@
+/*
+ * 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 AES GCM mode */
+
+#include "prov/ciphercommon.h"
+#include "prov/cipher_gcm.h"
+#include "internal/provider_algs.h"
+
+static void *aes_gcm_newctx(void *provctx, size_t keybits)
+{
+ PROV_AES_GCM_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
+
+ if (ctx != NULL)
+ gcm_initctx(provctx, &ctx->base, keybits, PROV_AES_HW_gcm(keybits), 8);
+ return ctx;
+}
+
+static OSSL_OP_cipher_freectx_fn aes_gcm_freectx;
+static void aes_gcm_freectx(void *vctx)
+{
+ PROV_AES_GCM_CTX *ctx = (PROV_AES_GCM_CTX *)vctx;
+
+ OPENSSL_clear_free(ctx, sizeof(*ctx));
+}
+
+/* aes128gcm_functions */
+IMPLEMENT_aead_cipher(aes, gcm, GCM, AEAD_FLAGS, 128, 8, 96);
+/* aes192gcm_functions */
+IMPLEMENT_aead_cipher(aes, gcm, GCM, AEAD_FLAGS, 192, 8, 96);
+/* aes256gcm_functions */
+IMPLEMENT_aead_cipher(aes, gcm, GCM, AEAD_FLAGS, 256, 8, 96);
diff --git a/providers/implementations/ciphers/cipher_aes_gcm_hw.c b/providers/implementations/ciphers/cipher_aes_gcm_hw.c
new file mode 100644
index 0000000000..f5dc0c4eed
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aes_gcm_hw.c
@@ -0,0 +1,78 @@
+/*
+ * 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 AES GCM mode */
+
+#include "prov/ciphercommon.h"
+#include "prov/cipher_gcm.h"
+
+static int generic_aes_gcm_initkey(PROV_GCM_CTX *ctx, const unsigned char *key,
+ size_t keylen)
+{
+ PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx;
+ AES_KEY *ks = &actx->ks.ks;
+
+# ifdef HWAES_CAPABLE
+ if (HWAES_CAPABLE) {
+# ifdef HWAES_ctr32_encrypt_blocks
+ GCM_HW_SET_KEY_CTR_FN(ks, HWAES_set_encrypt_key, HWAES_encrypt,
+ HWAES_ctr32_encrypt_blocks);
+# else
+ GCM_HW_SET_KEY_CTR_FN(ks, HWAES_set_encrypt_key, HWAES_encrypt, NULL);
+# endif /* HWAES_ctr32_encrypt_blocks */
+ } else
+# endif /* HWAES_CAPABLE */
+
+# ifdef BSAES_CAPABLE
+ if (BSAES_CAPABLE) {
+ GCM_HW_SET_KEY_CTR_FN(ks, AES_set_encrypt_key, AES_encrypt,
+ bsaes_ctr32_encrypt_blocks);
+ } else
+# endif /* BSAES_CAPABLE */
+
+# ifdef VPAES_CAPABLE
+ if (VPAES_CAPABLE) {
+ GCM_HW_SET_KEY_CTR_FN(ks, vpaes_set_encrypt_key, vpaes_encrypt, NULL);
+ } else
+# endif /* VPAES_CAPABLE */
+
+ {
+# ifdef AES_CTR_ASM
+ GCM_HW_SET_KEY_CTR_FN(ks, AES_set_encrypt_key, AES_encrypt,
+ AES_ctr32_encrypt);
+# else
+ GCM_HW_SET_KEY_CTR_FN(ks, AES_set_encrypt_key, AES_encrypt, NULL);
+# endif /* AES_CTR_ASM */
+ }
+ ctx->key_set = 1;
+ return 1;
+}
+
+static const PROV_GCM_HW aes_gcm = {
+ generic_aes_gcm_initkey,
+ gcm_setiv,
+ gcm_aad_update,
+ gcm_cipher_update,
+ gcm_cipher_final,
+ gcm_one_shot
+};
+
+#if defined(S390X_aes_128_CAPABLE)
+# include "cipher_aes_gcm_hw_s390x.inc"
+#elif defined(AESNI_CAPABLE)
+# include "cipher_aes_gcm_hw_aesni.inc"
+#elif defined(SPARC_AES_CAPABLE)
+# include "cipher_aes_gcm_hw_t4.inc"
+#else
+const PROV_GCM_HW *PROV_AES_HW_gcm(size_t keybits)
+{
+ return &aes_gcm;
+}
+#endif
+
diff --git a/providers/implementations/ciphers/cipher_aes_gcm_hw_aesni.inc b/providers/implementations/ciphers/cipher_aes_gcm_hw_aesni.inc
new file mode 100644
index 0000000000..eb2a3f343a
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aes_gcm_hw_aesni.inc
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2001-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
+ */
+
+/*-
+ * AES-NI support for AES GCM.
+ * This file is included by cipher_gcm_hw.c
+ */
+
+static int aesni_gcm_initkey(PROV_GCM_CTX *ctx, const unsigned char *key,
+ size_t keylen)
+{
+ PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx;
+ AES_KEY *ks = &actx->ks.ks;
+ GCM_HW_SET_KEY_CTR_FN(ks, aesni_set_encrypt_key, aesni_encrypt,
+ aesni_ctr32_encrypt_blocks);
+ return 1;
+}
+
+static const PROV_GCM_HW aesni_gcm = {
+ aesni_gcm_initkey,
+ gcm_setiv,
+ gcm_aad_update,
+ gcm_cipher_update,
+ gcm_cipher_final,
+ gcm_one_shot
+};
+
+const PROV_GCM_HW *PROV_AES_HW_gcm(size_t keybits)
+{
+ return AESNI_CAPABLE ? &aesni_gcm : &aes_gcm;
+}
+
diff --git a/providers/implementations/ciphers/cipher_aes_gcm_hw_s390x.inc b/providers/implementations/ciphers/cipher_aes_gcm_hw_s390x.inc
new file mode 100644
index 0000000000..44c3bf332d
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aes_gcm_hw_s390x.inc
@@ -0,0 +1,300 @@
+/*
+ * Copyright 2001-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
+ */
+
+/*-
+ * IBM S390X support for AES GCM.
+ * This file is included by cipher_gcm_hw.c
+ */
+
+/* iv + padding length for iv lengths != 12 */
+#define S390X_gcm_ivpadlen(i) ((((i) + 15) >> 4 << 4) + 16)
+
+static int s390x_aes_gcm_initkey(PROV_GCM_CTX *ctx,
+ const unsigned char *key, size_t keylen)
+{
+ PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx;
+
+ ctx->key_set = 1;
+ memcpy(&actx->plat.s390x.param.kma.k, key, keylen);
+ actx->plat.s390x.fc = S390X_AES_FC(keylen);
+ if (!ctx->enc)
+ actx->plat.s390x.fc |= S390X_DECRYPT;
+ return 1;
+}
+
+static int s390x_aes_gcm_setiv(PROV_GCM_CTX *ctx, const unsigned char *iv,
+ size_t ivlen)
+{
+ PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx;
+ S390X_KMA_PARAMS *kma = &actx->plat.s390x.param.kma;
+
+ kma->t.g[0] = 0;
+ kma->t.g[1] = 0;
+ kma->tpcl = 0;
+ kma->taadl = 0;
+ actx->plat.s390x.mreslen = 0;
+ actx->plat.s390x.areslen = 0;
+ actx->plat.s390x.kreslen = 0;
+
+ if (ivlen == GCM_IV_DEFAULT_SIZE) {
+ memcpy(&kma->j0, iv, ivlen);
+ kma->j0.w[3] = 1;
+ kma->cv.w = 1;
+ } else {
+ unsigned long long ivbits = ivlen << 3;
+ size_t len = S390X_gcm_ivpadlen(ivlen);
+ unsigned char iv_zero_pad[S390X_gcm_ivpadlen(GCM_IV_MAX_SIZE)];
+ /*
+ * The IV length needs to be zero padded to be a multiple of 16 bytes
+ * followed by 8 bytes of zeros and 8 bytes for the IV length.
+ * The GHASH of this value can then be calculated.
+ */
+ memcpy(iv_zero_pad, iv, ivlen);
+ memset(iv_zero_pad + ivlen, 0, len - ivlen);
+ memcpy(iv_zero_pad + len - sizeof(ivbits), &ivbits, sizeof(ivbits));
+ /*
+ * Calculate the ghash of the iv - the result is stored into the tag
+ * param.
+ */
+ s390x_kma(iv_zero_pad, len, NULL, 0, NULL, actx->plat.s390x.fc, kma);
+ actx->plat.s390x.fc |= S390X_KMA_HS; /* The hash subkey is set */
+
+ /* Copy the 128 bit GHASH result into J0 and clear the tag */
+ kma->j0.g[0] = kma->t.g[0];
+ kma->j0.g[1] = kma->t.g[1];
+ kma->t.g[0] = 0;
+ kma->t.g[1] = 0;
+ /* Set the 32 bit counter */
+ kma->cv.w = kma->j0.w[3];
+ }
+ return 1;
+}
+
+static int s390x_aes_gcm_cipher_final(PROV_GCM_CTX *ctx, unsigned char *tag)
+{
+ PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx;
+ S390X_KMA_PARAMS *kma = &actx->plat.s390x.param.kma;
+ unsigned char out[AES_BLOCK_SIZE];
+ int rc;
+
+ kma->taadl <<= 3;
+ kma->tpcl <<= 3;
+ s390x_kma(actx->plat.s390x.ares, actx->plat.s390x.areslen,
+ actx->plat.s390x.mres, actx->plat.s390x.mreslen, out,
+ actx->plat.s390x.fc | S390X_KMA_LAAD | S390X_KMA_LPC, kma);
+
+ /* gctx->mres already returned to the caller */
+ OPENSSL_cleanse(out, actx->plat.s390x.mreslen);
+
+ if (ctx->enc) {
+ ctx->taglen = GCM_TAG_MAX_SIZE;
+ memcpy(tag, kma->t.b, ctx->taglen);
+ rc = 1;
+ } else {
+ rc = (CRYPTO_memcmp(tag, kma->t.b, ctx->taglen) == 0);
+ }
+ return rc;
+}
+
+static int s390x_aes_gcm_one_shot(PROV_GCM_CTX *ctx,
+ unsigned char *aad, size_t aad_len,
+ const unsigned char *in, size_t in_len,
+ unsigned char *out,
+ unsigned char *tag, size_t taglen)
+{
+ PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx;
+ S390X_KMA_PARAMS *kma = &actx->plat.s390x.param.kma;
+ int rc;
+
+ kma->taadl = aad_len << 3;
+ kma->tpcl = in_len << 3;
+ s390x_kma(aad, aad_len, in, in_len, out,
+ actx->plat.s390x.fc | S390X_KMA_LAAD | S390X_KMA_LPC, kma);
+
+ if (ctx->enc) {
+ memcpy(tag, kma->t.b, taglen);
+ rc = 1;
+ } else {
+ rc = (CRYPTO_memcmp(tag, kma->t.b, taglen) == 0);
+ }
+ return rc;
+}
+
+/*
+ * Process additional authenticated data. Returns 1 on success. Code is
+ * big-endian.
+ */
+static int s390x_aes_gcm_aad_update(PROV_GCM_CTX *ctx,
+ const unsigned char *aad, size_t len)
+{
+ PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx;
+ S390X_KMA_PARAMS *kma = &actx->plat.s390x.param.kma;
+ unsigned long long alen;
+ int n, rem;
+
+ /* If already processed pt/ct then error */
+ if (kma->tpcl != 0)
+ return 0;
+
+ /* update the total aad length */
+ alen = kma->taadl + len;
+ if (alen > (U64(1) << 61) || (sizeof(len) == 8 && alen < len))
+ return 0;
+ kma->taadl = alen;
+
+ /* check if there is any existing aad data from a previous add */
+ n = actx->plat.s390x.areslen;
+ if (n) {
+ /* add additional data to a buffer until it has 16 bytes */
+ while (n && len) {
+ actx->plat.s390x.ares[n] = *aad;
+ ++aad;
+ --len;
+ n = (n + 1) & 0xf;
+ }
+ /* ctx->ares contains a complete block if offset has wrapped around */
+ if (!n) {
+ s390x_kma(actx->plat.s390x.ares, 16, NULL, 0, NULL,
+ actx->plat.s390x.fc, kma);
+ actx->plat.s390x.fc |= S390X_KMA_HS;
+ }
+ actx->plat.s390x.areslen = n;
+ }
+
+ /* If there are leftover bytes (< 128 bits) save them for next time */
+ rem = len & 0xf;
+ /* Add any remaining 16 byte blocks (128 bit each) */
+ len &= ~(size_t)0xf;
+ if (len) {
+ s390x_kma(aad, len, NULL, 0, NULL, actx->plat.s390x.fc, kma);
+ actx->plat.s390x.fc |= S390X_KMA_HS;
+ aad += len;
+ }
+
+ if (rem) {
+ actx->plat.s390x.areslen = rem;
+
+ do {
+ --rem;
+ actx->plat.s390x.ares[rem] = aad[rem];
+ } while (rem);
+ }
+ return 1;
+}
+
+/*-
+ * En/de-crypt plain/cipher-text and authenticate ciphertext. Returns 1 for
+ * success. Code is big-endian.
+ */
+static int s390x_aes_gcm_cipher_update(PROV_GCM_CTX *ctx,
+ const unsigned char *in, size_t len,
+ unsigned char *out)
+{
+ PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx;
+ S390X_KMA_PARAMS *kma = &actx->plat.s390x.param.kma;
+ const unsigned char *inptr;
+ unsigned long long mlen;
+ union {
+ unsigned int w[4];
+ unsigned char b[16];
+ } buf;
+ size_t inlen;
+ int n, rem, i;
+
+ mlen = kma->tpcl + len;
+ if (mlen > ((U64(1) << 36) - 32) || (sizeof(len) == 8 && mlen < len))
+ return 0;
+ kma->tpcl = mlen;
+
+ n = actx->plat.s390x.mreslen;
+ if (n) {
+ inptr = in;
+ inlen = len;
+ while (n && inlen) {
+ actx->plat.s390x.mres[n] = *inptr;
+ n = (n + 1) & 0xf;
+ ++inptr;
+ --inlen;
+ }
+ /* ctx->mres contains a complete block if offset has wrapped around */
+ if (!n) {
+ s390x_kma(actx->plat.s390x.ares, actx->plat.s390x.areslen,
+ actx->plat.s390x.mres, 16, buf.b,
+ actx->plat.s390x.fc | S390X_KMA_LAAD, kma);
+ actx->plat.s390x.fc |= S390X_KMA_HS;
+ actx->plat.s390x.areslen = 0;
+
+ /* previous call already encrypted/decrypted its remainder,
+ * see comment below */
+ n = actx->plat.s390x.mreslen;
+ while (n) {
+ *out = buf.b[n];
+ n = (n + 1) & 0xf;
+ ++out;
+ ++in;
+ --len;
+ }
+ actx->plat.s390x.mreslen = 0;
+ }
+ }
+
+ rem = len & 0xf;
+
+ len &= ~(size_t)0xf;
+ if (len) {
+ s390x_kma(actx->plat.s390x.ares, actx->plat.s390x.areslen, in, len, out,
+ actx->plat.s390x.fc | S390X_KMA_LAAD, kma);
+ in += len;
+ out += len;
+ actx->plat.s390x.fc |= S390X_KMA_HS;
+ actx->plat.s390x.areslen = 0;
+ }
+
+ /*-
+ * If there is a remainder, it has to be saved such that it can be
+ * processed by kma later. However, we also have to do the for-now
+ * unauthenticated encryption/decryption part here and now...
+ */
+ if (rem) {
+ if (!actx->plat.s390x.mreslen) {
+ buf.w[0] = kma->j0.w[0];
+ buf.w[1] = kma->j0.w[1];
+ buf.w[2] = kma->j0.w[2];
+ buf.w[3] = kma->cv.w + 1;
+ s390x_km(buf.b, 16, actx->plat.s390x.kres,
+ actx->plat.s390x.fc & 0x1f, &kma->k);
+ }
+
+ n = actx->plat.s390x.mreslen;
+ for (i = 0; i < rem; i++) {
+ actx->plat.s390x.mres[n + i] = in[i];
+ out[i] = in[i] ^ actx->plat.s390x.kres[n + i];
+ }
+ actx->plat.s390x.mreslen += rem;
+ }
+ return 1;
+}
+
+static const PROV_GCM_HW s390x_aes_gcm = {
+ s390x_aes_gcm_initkey,
+ s390x_aes_gcm_setiv,
+ s390x_aes_gcm_aad_update,
+ s390x_aes_gcm_cipher_update,
+ s390x_aes_gcm_cipher_final,
+ s390x_aes_gcm_one_shot
+};
+
+const PROV_GCM_HW *PROV_AES_HW_gcm(size_t keybits)
+{
+ if ((keybits == 128 && S390X_aes_128_gcm_CAPABLE)
+ || (keybits == 192 && S390X_aes_192_gcm_CAPABLE)
+ || (keybits == 256 && S390X_aes_256_gcm_CAPABLE))
+ return &s390x_aes_gcm;
+ return &aes_gcm;
+}
diff --git a/providers/implementations/ciphers/cipher_aes_gcm_hw_t4.inc b/providers/implementations/ciphers/cipher_aes_gcm_hw_t4.inc
new file mode 100644
index 0000000000..19e9ccb760
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aes_gcm_hw_t4.inc
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2001-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
+ */
+
+/*-
+ * Fujitsu SPARC64 X support for AES GCM.
+ * This file is included by cipher_gcm_hw.c
+ */
+
+static int t4_aes_gcm_initkey(PROV_GCM_CTX *ctx, const unsigned char *key,
+ size_t keylen)
+{
+ ctr128_f ctr;
+ PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx;
+ AES_KEY *ks = &actx->ks.ks;
+
+
+ switch (keylen) {
+ case 16:
+ ctr = (ctr128_f)aes128_t4_ctr32_encrypt;
+ break;
+ case 24:
+ ctr = (ctr128_f)aes192_t4_ctr32_encrypt;
+ break;
+ case 32:
+ ctr = (ctr128_f)aes256_t4_ctr32_encrypt;
+ break;
+ default:
+ return 0;
+ }
+
+ GCM_HW_SET_KEY_CTR_FN(ks, aes_t4_set_encrypt_key, aes_t4_encrypt, ctr);
+ return 1;
+}
+
+static const PROV_GCM_HW t4_aes_gcm = {
+ t4_aes_gcm_initkey,
+ gcm_setiv,
+ gcm_aad_update,
+ gcm_cipher_update,
+ gcm_cipher_final,
+ gcm_one_shot
+};
+const PROV_GCM_HW *PROV_AES_HW_gcm(size_t keybits)
+{
+ return SPARC_AES_CAPABLE ? &t4_aes_gcm : &aes_gcm;
+}
diff --git a/providers/implementations/ciphers/cipher_aes_hw.c b/providers/implementations/ciphers/cipher_aes_hw.c
new file mode 100644
index 0000000000..e9b6388300
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aes_hw.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2001-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 "cipher_aes.h"
+#include "internal/providercommonerr.h"
+
+static int cipher_hw_aes_initkey(PROV_CIPHER_CTX *dat,
+ const unsigned char *key, size_t keylen)
+{
+ int ret;
+ PROV_AES_CTX *adat = (PROV_AES_CTX *)dat;
+ AES_KEY *ks = &adat->ks.ks;
+
+ dat->ks = ks;
+
+ if ((dat->mode == EVP_CIPH_ECB_MODE || dat->mode == EVP_CIPH_CBC_MODE)
+ && !dat->enc) {
+#ifdef HWAES_CAPABLE
+ if (HWAES_CAPABLE) {
+ ret = HWAES_set_decrypt_key(key, keylen * 8, ks);
+ dat->block = (block128_f)HWAES_decrypt;
+ dat->stream.cbc = NULL;
+# ifdef HWAES_cbc_encrypt
+ if (dat->mode == EVP_CIPH_CBC_MODE)
+ dat->stream.cbc = (cbc128_f)HWAES_cbc_encrypt;
+# endif
+ } else
+#endif
+#ifdef BSAES_CAPABLE
+ if (BSAES_CAPABLE && dat->mode == EVP_CIPH_CBC_MODE) {
+ ret = AES_set_decrypt_key(key, keylen * 8, ks);
+ dat->block = (block128_f)AES_decrypt;
+ dat->stream.cbc = (cbc128_f)bsaes_cbc_encrypt;
+ } else
+#endif
+#ifdef VPAES_CAPABLE
+ if (VPAES_CAPABLE) {
+ ret = vpaes_set_decrypt_key(key, keylen * 8, ks);
+ dat->block = (block128_f)vpaes_decrypt;
+ dat->stream.cbc = (dat->mode == EVP_CIPH_CBC_MODE)
+ ?(cbc128_f)vpaes_cbc_encrypt : NULL;
+ } else
+#endif
+ {
+ ret = AES_set_decrypt_key(key, keylen * 8, ks);
+ dat->block = (block128_f)AES_decrypt;
+ dat->stream.cbc = (dat->mode == EVP_CIPH_CBC_MODE)
+ ? (cbc128_f)AES_cbc_encrypt : NULL;
+ }
+ } else
+#ifdef HWAES_CAPABLE
+ if (HWAES_CAPABLE) {
+ ret = HWAES_set_encrypt_key(key, keylen * 8, ks);
+ dat->block = (block128_f)HWAES_encrypt;
+ dat->stream.cbc = NULL;
+# ifdef HWAES_cbc_encrypt
+ if (dat->mode == EVP_CIPH_CBC_MODE)
+ dat->stream.cbc = (cbc128_f)HWAES_cbc_encrypt;
+ else
+# endif
+# ifdef HWAES_ctr32_encrypt_blocks
+ if (dat->mode == EVP_CIPH_CTR_MODE)
+ dat->stream.ctr = (ctr128_f)HWAES_ctr32_encrypt_blocks;
+ else
+# endif
+ (void)0; /* terminate potentially open 'else' */
+ } else
+#endif
+#ifdef BSAES_CAPABLE
+ if (BSAES_CAPABLE && dat->mode == EVP_CIPH_CTR_MODE) {
+ ret = AES_set_encrypt_key(key, keylen * 8, ks);
+ dat->block = (block128_f)AES_encrypt;
+ dat->stream.ctr = (ctr128_f)bsaes_ctr32_encrypt_blocks;
+ } else
+#endif
+#ifdef VPAES_CAPABLE
+ if (VPAES_CAPABLE) {
+ ret = vpaes_set_encrypt_key(key, keylen * 8, ks);
+ dat->block = (block128_f)vpaes_encrypt;
+ dat->stream.cbc = (dat->mode == EVP_CIPH_CBC_MODE)
+ ? (cbc128_f)vpaes_cbc_encrypt : NULL;
+ } else
+#endif
+ {
+ ret = AES_set_encrypt_key(key, keylen * 8, ks);
+ dat->block = (block128_f)AES_encrypt;
+ dat->stream.cbc = (dat->mode == EVP_CIPH_CBC_MODE)
+ ? (cbc128_f)AES_cbc_encrypt : NULL;
+#ifdef AES_CTR_ASM
+ if (dat->mode == EVP_CIPH_CTR_MODE)
+ dat->stream.ctr = (ctr128_f)AES_ctr32_encrypt;
+#endif
+ }
+
+ if (ret < 0) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_AES_KEY_SETUP_FAILED);
+ return 0;
+ }
+
+ return 1;
+}
+
+#define PROV_CIPHER_HW_aes_mode(mode) \
+static const PROV_CIPHER_HW aes_##mode = { \
+ cipher_hw_aes_initkey, \
+ cipher_hw_generic_##mode \
+}; \
+PROV_CIPHER_HW_declare(mode) \
+const PROV_CIPHER_HW *PROV_CIPHER_HW_aes_##mode(size_t keybits) \
+{ \
+ PROV_CIPHER_HW_select(mode) \
+ return &aes_##mode; \
+}
+
+#if defined(AESNI_CAPABLE)
+# include "cipher_aes_hw_aesni.inc"
+#elif defined(SPARC_AES_CAPABLE)
+# include "cipher_aes_hw_t4.inc"
+#elif defined(S390X_aes_128_CAPABLE)
+# include "cipher_aes_hw_s390x.inc"
+#else
+/* The generic case */
+# define PROV_CIPHER_HW_declare(mode)
+# define PROV_CIPHER_HW_select(mode)
+#endif
+
+PROV_CIPHER_HW_aes_mode(cbc)
+PROV_CIPHER_HW_aes_mode(ecb)
+PROV_CIPHER_HW_aes_mode(ofb128)
+PROV_CIPHER_HW_aes_mode(cfb128)
+PROV_CIPHER_HW_aes_mode(cfb1)
+PROV_CIPHER_HW_aes_mode(cfb8)
+PROV_CIPHER_HW_aes_mode(ctr)
diff --git a/providers/implementations/ciphers/cipher_aes_hw_aesni.inc b/providers/implementations/ciphers/cipher_aes_hw_aesni.inc
new file mode 100644
index 0000000000..6070939dee
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aes_hw_aesni.inc
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2001-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
+ */
+
+/*-
+ * AES-NI support for AES modes ecb, cbc, ofb, cfb, ctr.
+ * This file is included by cipher_aes_hw.c
+ */
+
+#define cipher_hw_aesni_ofb128 cipher_hw_generic_ofb128
+#define cipher_hw_aesni_cfb128 cipher_hw_generic_cfb128
+#define cipher_hw_aesni_cfb8 cipher_hw_generic_cfb8
+#define cipher_hw_aesni_cfb1 cipher_hw_generic_cfb1
+#define cipher_hw_aesni_ctr cipher_hw_generic_ctr
+
+static int cipher_hw_aesni_initkey(PROV_CIPHER_CTX *dat,
+ const unsigned char *key, size_t keylen)
+{
+ int ret;
+ PROV_AES_CTX *adat = (PROV_AES_CTX *)dat;
+ AES_KEY *ks = &adat->ks.ks;
+
+ dat->ks = ks;
+
+ if ((dat->mode == EVP_CIPH_ECB_MODE || dat->mode == EVP_CIPH_CBC_MODE)
+ && !dat->enc) {
+ ret = aesni_set_decrypt_key(key, keylen * 8, ks);
+ dat->block = (block128_f) aesni_decrypt;
+ dat->stream.cbc = dat->mode == EVP_CIPH_CBC_MODE ?
+ (cbc128_f) aesni_cbc_encrypt : NULL;
+ } else {
+ ret = aesni_set_encrypt_key(key, keylen * 8, ks);
+ dat->block = (block128_f) aesni_encrypt;
+ if (dat->mode == EVP_CIPH_CBC_MODE)
+ dat->stream.cbc = (cbc128_f) aesni_cbc_encrypt;
+ else if (dat->mode == EVP_CIPH_CTR_MODE)
+ dat->stream.ctr = (ctr128_f) aesni_ctr32_encrypt_blocks;
+ else
+ dat->stream.cbc = NULL;
+ }
+
+ if (ret < 0) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_AES_KEY_SETUP_FAILED);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int cipher_hw_aesni_cbc(PROV_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, size_t len)
+{
+ const AES_KEY *ks = ctx->ks;
+
+ aesni_cbc_encrypt(in, out, len, ks, ctx->iv, ctx->enc);
+
+ return 1;
+}
+
+static int cipher_hw_aesni_ecb(PROV_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, size_t len)
+{
+ if (len < ctx->blocksize)
+ return 1;
+
+ aesni_ecb_encrypt(in, out, len, ctx->ks, ctx->enc);
+
+ return 1;
+}
+
+#define PROV_CIPHER_HW_declare(mode) \
+static const PROV_CIPHER_HW aesni_##mode = { \
+ cipher_hw_aesni_initkey, \
+ cipher_hw_aesni_##mode \
+};
+#define PROV_CIPHER_HW_select(mode) \
+if (AESNI_CAPABLE) \
+ return &aesni_##mode;
diff --git a/providers/implementations/ciphers/cipher_aes_hw_s390x.inc b/providers/implementations/ciphers/cipher_aes_hw_s390x.inc
new file mode 100644
index 0000000000..805fa91e5f
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aes_hw_s390x.inc
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2001-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
+ */
+
+/*
+ * IBM S390X support for AES modes ecb, cbc, ofb, cfb, ctr.
+ * This file is included by cipher_aes_hw.c
+ */
+
+#include "s390x_arch.h"
+
+#define s390x_aes_cbc_initkey cipher_hw_aes_initkey
+#define s390x_aes_cfb1_initkey cipher_hw_aes_initkey
+#define s390x_aes_ctr_initkey cipher_hw_aes_initkey
+#define s390x_aes_cbc_cipher_hw cipher_hw_generic_cbc
+#define s390x_aes_cfb1_cipher_hw cipher_hw_generic_cfb1
+#define s390x_aes_ctr_cipher_hw cipher_hw_generic_ctr
+
+#define S390X_aes_128_ofb128_CAPABLE S390X_aes_128_ofb_CAPABLE
+#define S390X_aes_192_ofb128_CAPABLE S390X_aes_192_ofb_CAPABLE
+#define S390X_aes_256_ofb128_CAPABLE S390X_aes_256_ofb_CAPABLE
+#define S390X_aes_128_cfb128_CAPABLE S390X_aes_128_cfb_CAPABLE
+#define S390X_aes_192_cfb128_CAPABLE S390X_aes_192_cfb_CAPABLE
+#define S390X_aes_256_cfb128_CAPABLE S390X_aes_256_cfb_CAPABLE
+
+static int s390x_aes_ecb_initkey(PROV_CIPHER_CTX *dat,
+ const unsigned char *key, size_t keylen)
+{
+ PROV_AES_CTX *adat = (PROV_AES_CTX *)dat;
+
+ adat->plat.s390x.fc = S390X_AES_FC(keylen);
+ if (!dat->enc)
+ adat->plat.s390x.fc |= S390X_DECRYPT;
+
+ memcpy(adat->plat.s390x.param.km.k, key, keylen);
+ return 1;
+}
+
+static int s390x_aes_ecb_cipher_hw(PROV_CIPHER_CTX *dat, unsigned char *out,
+ const unsigned char *in, size_t len)
+{
+ PROV_AES_CTX *adat = (PROV_AES_CTX *)dat;
+
+ s390x_km(in, len, out, adat->plat.s390x.fc, &adat->plat.s390x.param.km);
+ return 1;
+}
+
+static int s390x_aes_ofb128_initkey(PROV_CIPHER_CTX *dat,
+ const unsigned char *key, size_t keylen)
+{
+ PROV_AES_CTX *adat = (PROV_AES_CTX *)dat;
+
+ memcpy(adat->plat.s390x.param.kmo_kmf.cv, dat->iv, dat->ivlen);
+ memcpy(adat->plat.s390x.param.kmo_kmf.k, key, keylen);
+ adat->plat.s390x.fc = S390X_AES_FC(keylen);
+ adat->plat.s390x.res = 0;
+ return 1;
+}
+
+static int s390x_aes_ofb128_cipher_hw(PROV_CIPHER_CTX *dat, unsigned char *out,
+ const unsigned char *in, size_t len)
+{
+ PROV_AES_CTX *adat = (PROV_AES_CTX *)dat;
+ int n = adat->plat.s390x.res;
+ int rem;
+
+ while (n && len) {
+ *out = *in ^ adat->plat.s390x.param.kmo_kmf.cv[n];
+ n = (n + 1) & 0xf;
+ --len;
+ ++in;
+ ++out;
+ }
+
+ rem = len & 0xf;
+
+ len &= ~(size_t)0xf;
+ if (len) {
+ s390x_kmo(in, len, out, adat->plat.s390x.fc,
+ &adat->plat.s390x.param.kmo_kmf);
+
+ out += len;
+ in += len;
+ }
+
+ if (rem) {
+ s390x_km(adat->plat.s390x.param.kmo_kmf.cv, 16,
+ adat->plat.s390x.param.kmo_kmf.cv, adat->plat.s390x.fc,
+ adat->plat.s390x.param.kmo_kmf.k);
+
+ while (rem--) {
+ out[n] = in[n] ^ adat->plat.s390x.param.kmo_kmf.cv[n];
+ ++n;
+ }
+ }
+
+ adat->plat.s390x.res = n;
+ return 1;
+}
+
+static int s390x_aes_cfb128_initkey(PROV_CIPHER_CTX *dat,
+ const unsigned char *key, size_t keylen)
+{
+ PROV_AES_CTX *adat = (PROV_AES_CTX *)dat;
+
+ adat->plat.s390x.fc = S390X_AES_FC(keylen);
+ adat->plat.s390x.fc |= 16 << 24; /* 16 bytes cipher feedback */
+ if (!dat->enc)
+ adat->plat.s390x.fc |= S390X_DECRYPT;
+
+ adat->plat.s390x.res = 0;
+ memcpy(adat->plat.s390x.param.kmo_kmf.cv, dat->iv, dat->ivlen);
+ memcpy(adat->plat.s390x.param.kmo_kmf.k, key, keylen);
+ return 1;
+}
+
+static int s390x_aes_cfb128_cipher_hw(PROV_CIPHER_CTX *dat, unsigned char *out,
+ const unsigned char *in, size_t len)
+{
+ PROV_AES_CTX *adat = (PROV_AES_CTX *)dat;
+ int n = adat->plat.s390x.res;
+ int rem;
+ unsigned char tmp;
+
+ while (n && len) {
+ tmp = *in;
+ *out = adat->plat.s390x.param.kmo_kmf.cv[n] ^ tmp;
+ adat->plat.s390x.param.kmo_kmf.cv[n] = dat->enc ? *out : tmp;
+ n = (n + 1) & 0xf;
+ --len;
+ ++in;
+ ++out;
+ }
+
+ rem = len & 0xf;
+
+ len &= ~(size_t)0xf;
+ if (len) {
+ s390x_kmf(in, len, out, adat->plat.s390x.fc,
+ &adat->plat.s390x.param.kmo_kmf);
+
+ out += len;
+ in += len;
+ }
+
+ if (rem) {
+ s390x_km(adat->plat.s390x.param.kmo_kmf.cv, 16,
+ adat->plat.s390x.param.kmo_kmf.cv,
+ S390X_AES_FC(dat->keylen), adat->plat.s390x.param.kmo_kmf.k);
+
+ while (rem--) {
+ tmp = in[n];
+ out[n] = adat->plat.s390x.param.kmo_kmf.cv[n] ^ tmp;
+ adat->plat.s390x.param.kmo_kmf.cv[n] = dat->enc ? out[n] : tmp;
+ ++n;
+ }
+ }
+
+ adat->plat.s390x.res = n;
+ return 1;
+}
+
+static int s390x_aes_cfb8_initkey(PROV_CIPHER_CTX *dat,
+ const unsigned char *key, size_t keylen)
+{
+ PROV_AES_CTX *adat = (PROV_AES_CTX *)dat;
+
+ adat->plat.s390x.fc = S390X_AES_FC(keylen);
+ adat->plat.s390x.fc |= 1 << 24; /* 1 byte cipher feedback */
+ if (!dat->enc)
+ adat->plat.s390x.fc |= S390X_DECRYPT;
+
+ memcpy(adat->plat.s390x.param.kmo_kmf.cv, dat->iv, dat->ivlen);
+ memcpy(adat->plat.s390x.param.kmo_kmf.k, key, keylen);
+ return 1;
+}
+
+static int s390x_aes_cfb8_cipher_hw(PROV_CIPHER_CTX *dat, unsigned char *out,
+ const unsigned char *in, size_t len)
+{
+ PROV_AES_CTX *adat = (PROV_AES_CTX *)dat;
+
+ s390x_kmf(in, len, out, adat->plat.s390x.fc,
+ &adat->plat.s390x.param.kmo_kmf);
+ return 1;
+}
+
+#define PROV_CIPHER_HW_declare(mode) \
+static const PROV_CIPHER_HW s390x_aes_##mode = { \
+ s390x_aes_##mode##_initkey, \
+ s390x_aes_##mode##_cipher_hw \
+};
+#define PROV_CIPHER_HW_select(mode) \
+if ((keybits == 128 && S390X_aes_128_##mode##_CAPABLE) \
+ || (keybits == 192 && S390X_aes_192_##mode##_CAPABLE) \
+ || (keybits == 256 && S390X_aes_256_##mode##_CAPABLE)) \
+ return &s390x_aes_##mode;
+
diff --git a/providers/implementations/ciphers/cipher_aes_hw_t4.inc b/providers/implementations/ciphers/cipher_aes_hw_t4.inc
new file mode 100644
index 0000000000..21b672710a
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aes_hw_t4.inc
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2001-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
+ */
+
+/*-
+ * Sparc t4 support for AES modes ecb, cbc, ofb, cfb, ctr.
+ * This file is included by cipher_aes_hw.c
+ */
+
+static int cipher_hw_aes_t4_initkey(PROV_CIPHER_CTX *dat,
+ const unsigned char *key, size_t keylen)
+{
+ int ret, bits;
+ PROV_AES_CTX *adat = (PROV_AES_CTX *)dat;
+ AES_KEY *ks = &adat->ks.ks;
+
+ dat->ks = (const void *)ks; /* used by cipher_hw_generic_XXX */
+
+ bits = keylen * 8;
+ if ((dat->mode == EVP_CIPH_ECB_MODE || dat->mode == EVP_CIPH_CBC_MODE)
+ && !dat->enc) {
+ ret = 0;
+ aes_t4_set_decrypt_key(key, bits, ks);
+ dat->block = (block128_f)aes_t4_decrypt;
+ switch (bits) {
+ case 128:
+ dat->stream.cbc = dat->mode == EVP_CIPH_CBC_MODE ?
+ (cbc128_f)aes128_t4_cbc_decrypt : NULL;
+ break;
+ case 192:
+ dat->stream.cbc = dat->mode == EVP_CIPH_CBC_MODE ?
+ (cbc128_f)aes192_t4_cbc_decrypt : NULL;
+ break;
+ case 256:
+ dat->stream.cbc = dat->mode == EVP_CIPH_CBC_MODE ?
+ (cbc128_f)aes256_t4_cbc_decrypt : NULL;
+ break;
+ default:
+ ret = -1;
+ }
+ } else {
+ ret = 0;
+ aes_t4_set_encrypt_key(key, bits, ks);
+ dat->block = (block128_f)aes_t4_encrypt;
+ switch (bits) {
+ case 128:
+ if (dat->mode == EVP_CIPH_CBC_MODE)
+ dat->stream.cbc = (cbc128_f)aes128_t4_cbc_encrypt;
+ else if (dat->mode == EVP_CIPH_CTR_MODE)
+ dat->stream.ctr = (ctr128_f)aes128_t4_ctr32_encrypt;
+ else
+ dat->stream.cbc = NULL;
+ break;
+ case 192:
+ if (dat->mode == EVP_CIPH_CBC_MODE)
+ dat->stream.cbc = (cbc128_f)aes192_t4_cbc_encrypt;
+ else if (dat->mode == EVP_CIPH_CTR_MODE)
+ dat->stream.ctr = (ctr128_f)aes192_t4_ctr32_encrypt;
+ else
+ dat->stream.cbc = NULL;
+ break;
+ case 256:
+ if (dat->mode == EVP_CIPH_CBC_MODE)
+ dat->stream.cbc = (cbc128_f)aes256_t4_cbc_encrypt;
+ else if (dat->mode == EVP_CIPH_CTR_MODE)
+ dat->stream.ctr = (ctr128_f)aes256_t4_ctr32_encrypt;
+ else
+ dat->stream.cbc = NULL;
+ break;
+ default:
+ ret = -1;
+ }
+ }
+
+ if (ret < 0) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_AES_KEY_SETUP_FAILED);
+ return 0;
+ }
+
+ return 1;
+}
+
+#define PROV_CIPHER_HW_declare(mode) \
+static const PROV_CIPHER_HW aes_t4_##mode = { \
+ cipher_hw_aes_t4_initkey, \
+ cipher_hw_generic_##mode \
+};
+#define PROV_CIPHER_HW_select(mode) \
+ if (SPARC_AES_CAPABLE) \
+ return &aes_t4_##mode;
diff --git a/providers/implementations/ciphers/cipher_aes_ocb.c b/providers/implementations/ciphers/cipher_aes_ocb.c
new file mode 100644
index 0000000000..5ab0b8fd15
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aes_ocb.c
@@ -0,0 +1,495 @@
+/*
+ * 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 "cipher_aes_ocb.h"
+#include "internal/providercommonerr.h"
+#include "prov/cipher_aead.h"
+#include "internal/provider_algs.h"
+
+#define AES_OCB_FLAGS AEAD_FLAGS
+
+#define OCB_DEFAULT_TAG_LEN 16
+#define OCB_DEFAULT_IV_LEN 12
+#define OCB_MIN_IV_LEN 1
+#define OCB_MAX_IV_LEN 15
+
+PROV_CIPHER_FUNC(int, ocb_cipher, (PROV_AES_OCB_CTX *ctx,
+ const unsigned char *in, unsigned char *out,
+ size_t nextblock));
+/* forward declarations */
+static OSSL_OP_cipher_encrypt_init_fn aes_ocb_einit;
+static OSSL_OP_cipher_decrypt_init_fn aes_ocb_dinit;
+static OSSL_OP_cipher_update_fn aes_ocb_block_update;
+static OSSL_OP_cipher_final_fn aes_ocb_block_final;
+static OSSL_OP_cipher_cipher_fn aes_ocb_cipher;
+static OSSL_OP_cipher_freectx_fn aes_ocb_freectx;
+static OSSL_OP_cipher_dupctx_fn aes_ocb_dupctx;
+static OSSL_OP_cipher_get_ctx_params_fn aes_ocb_get_ctx_params;
+static OSSL_OP_cipher_set_ctx_params_fn aes_ocb_set_ctx_params;
+
+/*
+ * The following methods could be moved into PROV_AES_OCB_HW if
+ * multiple hardware implementations are ever needed.
+ */
+static ossl_inline int aes_generic_ocb_setiv(PROV_AES_OCB_CTX *ctx,
+ const unsigned char *iv,
+ size_t ivlen, size_t taglen)
+{
+ return (CRYPTO_ocb128_setiv(&ctx->ocb, iv, ivlen, taglen) == 1);
+}
+
+static ossl_inline int aes_generic_ocb_setaad(PROV_AES_OCB_CTX *ctx,
+ const unsigned char *aad,
+ size_t alen)
+{
+ return CRYPTO_ocb128_aad(&ctx->ocb, aad, alen) == 1;
+}
+
+static ossl_inline int aes_generic_ocb_gettag(PROV_AES_OCB_CTX *ctx,
+ unsigned char *tag, size_t tlen)
+{
+ return CRYPTO_ocb128_tag(&ctx->ocb, tag, tlen) > 0;
+}
+
+static ossl_inline int aes_generic_ocb_final(PROV_AES_OCB_CTX *ctx)
+{
+ return (CRYPTO_ocb128_finish(&ctx->ocb, ctx->tag, ctx->taglen) == 0);
+}
+
+static ossl_inline void aes_generic_ocb_cleanup(PROV_AES_OCB_CTX *ctx)
+{
+ CRYPTO_ocb128_cleanup(&ctx->ocb);
+}
+
+static ossl_inline int aes_generic_ocb_cipher(PROV_AES_OCB_CTX *ctx,
+ const unsigned char *in,
+ unsigned char *out, size_t len)
+{
+ if (ctx->base.enc) {
+ if (!CRYPTO_ocb128_encrypt(&ctx->ocb, in, out, len))
+ return 0;
+ } else {
+ if (!CRYPTO_ocb128_decrypt(&ctx->ocb, in, out, len))
+ return 0;
+ }
+ return 1;
+}
+
+static ossl_inline int aes_generic_ocb_copy_ctx(PROV_AES_OCB_CTX *dst,
+ PROV_AES_OCB_CTX *src)
+{
+ return (!CRYPTO_ocb128_copy_ctx(&dst->ocb, &src->ocb,
+ &src->ksenc.ks, &src->ksdec.ks));
+}
+
+/*-
+ * Provider dispatch functions
+ */
+static int aes_ocb_init(void *vctx, const unsigned char *key, size_t keylen,
+ const unsigned char *iv, size_t ivlen, int enc)
+{
+ PROV_AES_OCB_CTX *ctx = (PROV_AES_OCB_CTX *)vctx;
+
+ ctx->base.enc = enc;
+
+ if (iv != NULL) {
+ if (ivlen != ctx->base.ivlen) {
+ /* IV len must be 1 to 15 */
+ if (ivlen < OCB_MIN_IV_LEN || ivlen > OCB_MAX_IV_LEN) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH);
+ return 0;
+ }
+ ctx->base.ivlen = ivlen;
+ }
+ if (!cipher_generic_initiv(&ctx->base, iv, ivlen))
+ return 0;
+ ctx->iv_state = IV_STATE_BUFFERED;
+ }
+ if (key != NULL) {
+ if (keylen != ctx->base.keylen) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);
+ return 0;
+ }
+ return ctx->base.hw->init(&ctx->base, key, keylen);
+ }
+ return 1;
+}
+
+static int aes_ocb_einit(void *vctx, const unsigned char *key, size_t keylen,
+ const unsigned char *iv, size_t ivlen)
+{
+ return aes_ocb_init(vctx, key, keylen, iv, ivlen, 1);
+}
+
+static int aes_ocb_dinit(void *vctx, const unsigned char *key, size_t keylen,
+ const unsigned char *iv, size_t ivlen)
+{
+ return aes_ocb_init(vctx, key, keylen, iv, ivlen, 0);
+}
+
+/*
+ * Because of the way OCB works, both the AAD and data are buffered in the
+ * same way. Only the last block can be a partial block.
+ */
+static int aes_ocb_block_update_internal(PROV_AES_OCB_CTX *ctx,
+ unsigned char *buf, size_t *bufsz,
+ unsigned char *out, size_t *outl,
+ size_t outsize, const unsigned char *in,
+ size_t inl, OSSL_ocb_cipher_fn ciph)
+{
+ size_t nextblocks = fillblock(buf, bufsz, AES_BLOCK_SIZE, &in, &inl);
+ size_t outlint = 0;
+
+ if (*bufsz == AES_BLOCK_SIZE) {
+ if (outsize < AES_BLOCK_SIZE) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
+ return 0;
+ }
+ if (!ciph(ctx, buf, out, AES_BLOCK_SIZE)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED);
+ return 0;
+ }
+ *bufsz = 0;
+ outlint = AES_BLOCK_SIZE;
+ out += AES_BLOCK_SIZE;
+ }
+ if (nextblocks > 0) {
+ outlint += nextblocks;
+ if (outsize < outlint) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
+ return 0;
+ }
+ if (!ciph(ctx, in, out, nextblocks)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED);
+ return 0;
+ }
+ in += nextblocks;
+ inl -= nextblocks;
+ }
+ if (!trailingdata(buf, bufsz, AES_BLOCK_SIZE, &in, &inl)) {
+ /* PROVerr already called */
+ return 0;
+ }
+
+ *outl = outlint;
+ return inl == 0;
+}
+
+/* A wrapper function that has the same signature as cipher */
+static int cipher_updateaad(PROV_AES_OCB_CTX *ctx, const unsigned char *in,
+ unsigned char *out, size_t len)
+{
+ return aes_generic_ocb_setaad(ctx, in, len);
+}
+
+static int update_iv(PROV_AES_OCB_CTX *ctx)
+{
+ if (ctx->iv_state == IV_STATE_FINISHED
+ || ctx->iv_state == IV_STATE_UNINITIALISED)
+ return 0;
+ if (ctx->iv_state == IV_STATE_BUFFERED) {
+ if (!aes_generic_ocb_setiv(ctx, ctx->base.iv, ctx->base.ivlen,
+ ctx->taglen))
+ return 0;
+ ctx->iv_state = IV_STATE_COPIED;
+ }
+ return 1;
+}
+
+static int aes_ocb_block_update(void *vctx, unsigned char *out, size_t *outl,
+ size_t outsize, const unsigned char *in,
+ size_t inl)
+{
+ PROV_AES_OCB_CTX *ctx = (PROV_AES_OCB_CTX *)vctx;
+ unsigned char *buf;
+ size_t *buflen;
+ OSSL_ocb_cipher_fn fn;
+
+ if (!ctx->key_set || !update_iv(ctx))
+ return 0;
+
+ /* Are we dealing with AAD or normal data here? */
+ if (out == NULL) {
+ buf = ctx->aad_buf;
+ buflen = &ctx->aad_buf_len;
+ fn = cipher_updateaad;
+ } else {
+ buf = ctx->data_buf;
+ buflen = &ctx->data_buf_len;
+ fn = aes_generic_ocb_cipher;
+ }
+ return aes_ocb_block_update_internal(ctx, buf, buflen, out, outl, outsize,
+ in, inl, fn);
+}
+
+static int aes_ocb_block_final(void *vctx, unsigned char *out, size_t *outl,
+ size_t outsize)
+{
+ PROV_AES_OCB_CTX *ctx = (PROV_AES_OCB_CTX *)vctx;
+
+ /* If no block_update has run then the iv still needs to be set */
+ if (!ctx->key_set || !update_iv(ctx))
+ return 0;
+
+ /*
+ * Empty the buffer of any partial block that we might have been provided,
+ * both for data and AAD
+ */
+ *outl = 0;
+ if (ctx->data_buf_len > 0) {
+ if (!aes_generic_ocb_cipher(ctx, ctx->data_buf, out, ctx->data_buf_len))
+ return 0;
+ *outl = ctx->data_buf_len;
+ ctx->data_buf_len = 0;
+ }
+ if (ctx->aad_buf_len > 0) {
+ if (!aes_generic_ocb_setaad(ctx, ctx->aad_buf, ctx->aad_buf_len))
+ return 0;
+ ctx->aad_buf_len = 0;
+ }
+ if (ctx->base.enc) {
+ /* If encrypting then just get the tag */
+ if (!aes_generic_ocb_gettag(ctx, ctx->tag, ctx->taglen))
+ return 0;
+ } else {
+ /* If decrypting then verify */
+ if (ctx->taglen == 0)
+ return 0;
+ if (!aes_generic_ocb_final(ctx))
+ return 0;
+ }
+ /* Don't reuse the IV */
+ ctx->iv_state = IV_STATE_FINISHED;
+ return 1;
+}
+
+static void *aes_ocb_newctx(void *provctx, size_t kbits, size_t blkbits,
+ size_t ivbits, unsigned int mode, uint64_t flags)
+{
+ PROV_AES_OCB_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
+
+ if (ctx != NULL) {
+ cipher_generic_initkey(ctx, kbits, blkbits, ivbits, mode, flags,
+ PROV_CIPHER_HW_aes_ocb(kbits), NULL);
+ ctx->taglen = OCB_DEFAULT_TAG_LEN;
+ }
+ return ctx;
+}
+
+static void aes_ocb_freectx(void *vctx)
+{
+ PROV_AES_OCB_CTX *ctx = (PROV_AES_OCB_CTX *)vctx;
+
+ if (ctx != NULL) {
+ aes_generic_ocb_cleanup(ctx);
+ OPENSSL_clear_free(ctx, sizeof(*ctx));
+ }
+}
+
+static void *aes_ocb_dupctx(void *vctx)
+{
+ PROV_AES_OCB_CTX *in = (PROV_AES_OCB_CTX *)vctx;
+ PROV_AES_OCB_CTX *ret = OPENSSL_malloc(sizeof(*ret));
+
+ if (ret == NULL) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ *ret = *in;
+ if (!aes_generic_ocb_copy_ctx(ret, in)) {
+ OPENSSL_free(ret);
+ ret = NULL;
+ }
+ return ret;
+}
+
+static int aes_ocb_set_ctx_params(void *vctx, const OSSL_PARAM params[])
+{
+ PROV_AES_OCB_CTX *ctx = (PROV_AES_OCB_CTX *)vctx;
+ const OSSL_PARAM *p;
+ size_t sz;
+
+ 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 == NULL) {
+ /* Tag len must be 0 to 16 */
+ if (p->data_size > OCB_MAX_TAG_LEN)
+ return 0;
+ ctx->taglen = p->data_size;
+ } else {
+ if (p->data_size != ctx->taglen || ctx->base.enc)
+ return 0;
+ memcpy(ctx->tag, p->data, p->data_size);
+ }
+ }
+ p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_IVLEN);
+ if (p != NULL) {
+ if (!OSSL_PARAM_get_size_t(p, &sz)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
+ return 0;
+ }
+ /* IV len must be 1 to 15 */
+ if (sz < OCB_MIN_IV_LEN || sz > OCB_MAX_IV_LEN)
+ return 0;
+ ctx->base.ivlen = sz;
+ }
+ p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN);
+ if (p != NULL) {
+ size_t keylen;
+
+ if (!OSSL_PARAM_get_size_t(p, &keylen)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
+ return 0;
+ }
+ if (ctx->base.keylen != keylen) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int aes_ocb_get_ctx_params(void *vctx, OSSL_PARAM params[])
+{
+ PROV_AES_OCB_CTX *ctx = (PROV_AES_OCB_CTX *)vctx;
+ OSSL_PARAM *p;
+
+ p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IVLEN);
+ if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->base.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, ctx->base.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) {
+ if (!OSSL_PARAM_set_size_t(p, ctx->taglen)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
+ return 0;
+ }
+ }
+
+ p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IV);
+ if (p != NULL) {
+ if (ctx->base.ivlen != p->data_size) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH);
+ return 0;
+ }
+ if (!OSSL_PARAM_set_octet_string(p, ctx->base.oiv, ctx->base.ivlen)) {
+ 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_GET_PARAMETER);
+ return 0;
+ }
+ if (!ctx->base.enc || p->data_size != ctx->taglen) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_TAGLEN);
+ return 0;
+ }
+ memcpy(p->data, ctx->tag, ctx->taglen);
+ }
+ return 1;
+}
+
+static const OSSL_PARAM cipher_ocb_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_IV, NULL, 0),
+ OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, NULL, 0),
+ OSSL_PARAM_END
+};
+static const OSSL_PARAM *cipher_ocb_gettable_ctx_params(void)
+{
+ return cipher_ocb_known_gettable_ctx_params;
+}
+
+static const OSSL_PARAM cipher_ocb_known_settable_ctx_params[] = {
+ OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL),
+ OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_AEAD_IVLEN, NULL),
+ OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, NULL, 0),
+ OSSL_PARAM_END
+};
+static const OSSL_PARAM *cipher_ocb_settable_ctx_params(void)
+{
+ return cipher_ocb_known_settable_ctx_params;
+}
+
+static int aes_ocb_cipher(void *vctx, unsigned char *out, size_t *outl,
+ size_t outsize, const unsigned char *in, size_t inl)
+{
+ PROV_AES_OCB_CTX *ctx = (PROV_AES_OCB_CTX *)vctx;
+
+ if (outsize < inl) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
+ return 0;
+ }
+
+ if (!aes_generic_ocb_cipher(ctx, in, out, inl)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED);
+ return 0;
+ }
+
+ *outl = inl;
+ return 1;
+}
+
+#define IMPLEMENT_cipher(mode, UCMODE, flags, kbits, blkbits, ivbits) \
+static OSSL_OP_cipher_get_params_fn aes_##kbits##_##mode##_get_params; \
+static int aes_##kbits##_##mode##_get_params(OSSL_PARAM params[]) \
+{ \
+ return cipher_generic_get_params(params, EVP_CIPH_##UCMODE##_MODE, \
+ flags, kbits, blkbits, ivbits); \
+} \
+static OSSL_OP_cipher_newctx_fn aes_##kbits##_##mode##_newctx; \
+static void *aes_##kbits##_##mode##_newctx(void *provctx) \
+{ \
+ return aes_##mode##_newctx(provctx, kbits, blkbits, ivbits, \
+ EVP_CIPH_##UCMODE##_MODE, flags); \
+} \
+const OSSL_DISPATCH aes##kbits##mode##_functions[] = { \
+ { OSSL_FUNC_CIPHER_NEWCTX, \
+ (void (*)(void))aes_##kbits##_##mode##_newctx }, \
+ { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))aes_##mode##_einit }, \
+ { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))aes_##mode##_dinit }, \
+ { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))aes_##mode##_block_update }, \
+ { OSSL_FUNC_CIPHER_FINAL, (void (*)(void))aes_##mode##_block_final }, \
+ { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))aes_ocb_cipher }, \
+ { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))aes_##mode##_freectx }, \
+ { OSSL_FUNC_CIPHER_DUPCTX, (void (*)(void))aes_##mode##_dupctx }, \
+ { OSSL_FUNC_CIPHER_GET_PARAMS, \
+ (void (*)(void))aes_##kbits##_##mode##_get_params }, \
+ { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, \
+ (void (*)(void))aes_##mode##_get_ctx_params }, \
+ { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \
+ (void (*)(void))aes_##mode##_set_ctx_params }, \
+ { OSSL_FUNC_CIPHER_GETTABLE_PARAMS, \
+ (void (*)(void))cipher_generic_gettable_params }, \
+ { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \
+ (void (*)(void))cipher_ocb_gettable_ctx_params }, \
+ { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \
+ (void (*)(void))cipher_ocb_settable_ctx_params }, \
+ { 0, NULL } \
+}
+
+IMPLEMENT_cipher(ocb, OCB, AES_OCB_FLAGS, 256, 128, OCB_DEFAULT_IV_LEN * 8);
+IMPLEMENT_cipher(ocb, OCB, AES_OCB_FLAGS, 192, 128, OCB_DEFAULT_IV_LEN * 8);
+IMPLEMENT_cipher(ocb, OCB, AES_OCB_FLAGS, 128, 128, OCB_DEFAULT_IV_LEN * 8);
+
diff --git a/providers/implementations/ciphers/cipher_aes_ocb.h b/providers/implementations/ciphers/cipher_aes_ocb.h
new file mode 100644
index 0000000000..ba515241e2
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aes_ocb.h
@@ -0,0 +1,38 @@
+/*
+ * 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 <openssl/aes.h>
+#include "prov/ciphercommon.h"
+
+#define OCB_MAX_TAG_LEN AES_BLOCK_SIZE
+#define OCB_MAX_DATA_LEN AES_BLOCK_SIZE
+#define OCB_MAX_AAD_LEN AES_BLOCK_SIZE
+
+typedef struct prov_aes_ocb_ctx_st {
+ PROV_CIPHER_CTX base; /* Must be first */
+ union {
+ OSSL_UNION_ALIGN;
+ AES_KEY ks;
+ } ksenc; /* AES key schedule to use for encryption/aad */
+ union {
+ OSSL_UNION_ALIGN;
+ AES_KEY ks;
+ } ksdec; /* AES key schedule to use for decryption */
+ OCB128_CONTEXT ocb;
+ unsigned int iv_state; /* set to one of IV_STATE_XXX */
+ unsigned int key_set : 1;
+ size_t taglen;
+ size_t data_buf_len;
+ size_t aad_buf_len;
+ unsigned char tag[OCB_MAX_TAG_LEN];
+ unsigned char data_buf[OCB_MAX_DATA_LEN]; /* Store partial data blocks */
+ unsigned char aad_buf[OCB_MAX_AAD_LEN]; /* Store partial AAD blocks */
+} PROV_AES_OCB_CTX;
+
+const PROV_CIPHER_HW *PROV_CIPHER_HW_aes_ocb(size_t keybits);
diff --git a/providers/implementations/ciphers/cipher_aes_ocb_hw.c b/providers/implementations/ciphers/cipher_aes_ocb_hw.c
new file mode 100644
index 0000000000..49f387b5ba
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aes_ocb_hw.c
@@ -0,0 +1,115 @@
+/*
+ * 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 "cipher_aes_ocb.h"
+
+#define OCB_SET_KEY_FN(fn_set_enc_key, fn_set_dec_key, \
+ fn_block_enc, fn_block_dec, \
+ fn_stream_enc, fn_stream_dec) \
+fn_set_enc_key(key, keylen * 8, &ctx->ksenc.ks); \
+fn_set_dec_key(key, keylen * 8, &ctx->ksdec.ks); \
+if (!CRYPTO_ocb128_init(&ctx->ocb, &ctx->ksenc.ks, &ctx->ksdec.ks, \
+ (block128_f)fn_block_enc, (block128_f)fn_block_dec, \
+ ctx->base.enc ? (ocb128_f)fn_stream_enc : \
+ (ocb128_f)fn_stream_dec)) \
+ return 0; \
+ctx->key_set = 1
+
+
+static int cipher_hw_aes_ocb_generic_initkey(PROV_CIPHER_CTX *vctx,
+ const unsigned char *key,
+ size_t keylen)
+{
+ PROV_AES_OCB_CTX *ctx = (PROV_AES_OCB_CTX *)vctx;
+
+/*
+ * We set both the encrypt and decrypt key here because decrypt
+ * needs both. (i.e- AAD uses encrypt).
+ */
+# ifdef HWAES_CAPABLE
+ if (HWAES_CAPABLE) {
+ OCB_SET_KEY_FN(HWAES_set_encrypt_key, HWAES_set_decrypt_key,
+ HWAES_encrypt, HWAES_decrypt,
+ HWAES_ocb_encrypt, HWAES_ocb_decrypt);
+ } else
+# endif
+# ifdef VPAES_CAPABLE
+ if (VPAES_CAPABLE) {
+ OCB_SET_KEY_FN(vpaes_set_encrypt_key, vpaes_set_decrypt_key,
+ vpaes_encrypt, vpaes_decrypt, NULL, NULL);
+ } else
+# endif
+ {
+ OCB_SET_KEY_FN(AES_set_encrypt_key, AES_set_decrypt_key,
+ AES_encrypt, AES_decrypt, NULL, NULL);
+ }
+ return 1;
+}
+
+# if defined(AESNI_CAPABLE)
+
+static int cipher_hw_aes_ocb_aesni_initkey(PROV_CIPHER_CTX *vctx,
+ const unsigned char *key,
+ size_t keylen)
+{
+ PROV_AES_OCB_CTX *ctx = (PROV_AES_OCB_CTX *)vctx;
+
+ OCB_SET_KEY_FN(aesni_set_encrypt_key, aesni_set_decrypt_key,
+ aesni_encrypt, aesni_decrypt,
+ aesni_ocb_encrypt, aesni_ocb_decrypt);
+ return 1;
+}
+
+# define PROV_CIPHER_HW_declare() \
+static const PROV_CIPHER_HW aesni_ocb = { \
+ cipher_hw_aes_ocb_aesni_initkey, \
+ NULL \
+};
+# define PROV_CIPHER_HW_select() \
+ if (AESNI_CAPABLE) \
+ return &aesni_ocb;
+
+#elif defined(SPARC_AES_CAPABLE)
+
+static int cipher_hw_aes_ocb_t4_initkey(PROV_CIPHER_CTX *vctx,
+ const unsigned char *key,
+ size_t keylen)
+{
+ PROV_AES_OCB_CTX *ctx = (PROV_AES_OCB_CTX *)vctx;
+
+ OCB_SET_KEY_FN(aes_t4_set_encrypt_key, aes_t4_set_decrypt_key,
+ aes_t4_encrypt, aes_t4_decrypt, NULL, NULL);
+ return 1;
+}
+
+# define PROV_CIPHER_HW_declare() \
+static const PROV_CIPHER_HW aes_t4_ocb = { \
+ cipher_hw_aes_ocb_t4_initkey, \
+ NULL \
+};
+# define PROV_CIPHER_HW_select() \
+ if (SPARC_AES_CAPABLE) \
+ return &aes_t4_ocb;
+#else
+# define PROV_CIPHER_HW_declare()
+# define PROV_CIPHER_HW_select()
+# endif
+
+static const PROV_CIPHER_HW aes_generic_ocb = {
+ cipher_hw_aes_ocb_generic_initkey,
+ NULL
+};
+PROV_CIPHER_HW_declare()
+const PROV_CIPHER_HW *PROV_CIPHER_HW_aes_ocb(size_t keybits)
+{
+ PROV_CIPHER_HW_select()
+ return &aes_generic_ocb;
+}
+
+
diff --git a/providers/implementations/ciphers/cipher_aes_wrp.c b/providers/implementations/ciphers/cipher_aes_wrp.c
new file mode 100644
index 0000000000..1bf4c1793a
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aes_wrp.c
@@ -0,0 +1,242 @@
+/*
+ * 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 "cipher_aes.h"
+#include "internal/providercommonerr.h"
+#include "internal/provider_algs.h"
+
+/* AES wrap with padding has IV length of 4, without padding 8 */
+#define AES_WRAP_PAD_IVLEN 4
+#define AES_WRAP_NOPAD_IVLEN 8
+
+/* TODO(3.0) Figure out what flags need to be passed */
+#define WRAP_FLAGS (EVP_CIPH_WRAP_MODE \
+ | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER \
+ | EVP_CIPH_ALWAYS_CALL_INIT)
+
+typedef size_t (*aeswrap_fn)(void *key, const unsigned char *iv,
+ unsigned char *out, const unsigned char *in,
+ size_t inlen, block128_f block);
+
+static OSSL_OP_cipher_encrypt_init_fn aes_wrap_einit;
+static OSSL_OP_cipher_decrypt_init_fn aes_wrap_dinit;
+static OSSL_OP_cipher_update_fn aes_wrap_cipher;
+static OSSL_OP_cipher_final_fn aes_wrap_final;
+static OSSL_OP_cipher_freectx_fn aes_wrap_freectx;
+
+typedef struct prov_aes_wrap_ctx_st {
+ PROV_CIPHER_CTX base;
+ union {
+ OSSL_UNION_ALIGN;
+ AES_KEY ks;
+ } ks;
+ aeswrap_fn wrapfn;
+
+} PROV_AES_WRAP_CTX;
+
+
+static void *aes_wrap_newctx(size_t kbits, size_t blkbits,
+ size_t ivbits, unsigned int mode, uint64_t flags)
+{
+ PROV_AES_WRAP_CTX *wctx = OPENSSL_zalloc(sizeof(*wctx));
+ PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)wctx;
+
+ if (ctx != NULL) {
+ cipher_generic_initkey(ctx, kbits, blkbits, ivbits, mode, flags,
+ NULL, NULL);
+ ctx->pad = (ctx->ivlen == AES_WRAP_PAD_IVLEN);
+ }
+ return wctx;
+}
+
+static void aes_wrap_freectx(void *vctx)
+{
+ PROV_AES_WRAP_CTX *wctx = (PROV_AES_WRAP_CTX *)vctx;
+
+ OPENSSL_clear_free(wctx, sizeof(*wctx));
+}
+
+static int aes_wrap_init(void *vctx, const unsigned char *key,
+ size_t keylen, const unsigned char *iv,
+ size_t ivlen, int enc)
+{
+ PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx;
+ PROV_AES_WRAP_CTX *wctx = (PROV_AES_WRAP_CTX *)vctx;
+
+ ctx->enc = enc;
+ ctx->block = enc ? (block128_f)AES_encrypt : (block128_f)AES_decrypt;
+ if (ctx->pad)
+ wctx->wrapfn = enc ? CRYPTO_128_wrap_pad : CRYPTO_128_unwrap_pad;
+ else
+ wctx->wrapfn = enc ? CRYPTO_128_wrap : CRYPTO_128_unwrap;
+
+ if (iv != NULL) {
+ if (!cipher_generic_initiv(ctx, iv, ivlen))
+ return 0;
+ }
+ if (key != NULL) {
+ if (keylen != ctx->keylen) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);
+ return 0;
+ }
+ if (ctx->enc)
+ AES_set_encrypt_key(key, keylen * 8, &wctx->ks.ks);
+ else
+ AES_set_decrypt_key(key, keylen * 8, &wctx->ks.ks);
+ }
+ return 1;
+}
+
+static int aes_wrap_einit(void *ctx, const unsigned char *key, size_t keylen,
+ const unsigned char *iv, size_t ivlen)
+{
+ return aes_wrap_init(ctx, key, keylen, iv, ivlen, 1);
+}
+
+static int aes_wrap_dinit(void *ctx, const unsigned char *key, size_t keylen,
+ const unsigned char *iv, size_t ivlen)
+{
+ return aes_wrap_init(ctx, key, keylen, iv, ivlen, 0);
+}
+
+static int aes_wrap_cipher_internal(void *vctx, unsigned char *out,
+ const unsigned char *in, size_t inlen)
+{
+ PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx;
+ PROV_AES_WRAP_CTX *wctx = (PROV_AES_WRAP_CTX *)vctx;
+ size_t rv;
+ int pad = ctx->pad;
+
+ /* No final operation so always return zero length */
+ if (in == NULL)
+ return 0;
+
+ /* Input length must always be non-zero */
+ if (inlen == 0)
+ return -1;
+
+ /* If decrypting need at least 16 bytes and multiple of 8 */
+ if (!ctx->enc && (inlen < 16 || inlen & 0x7))
+ return -1;
+
+ /* If not padding input must be multiple of 8 */
+ if (!pad && inlen & 0x7)
+ return -1;
+
+ if (out == NULL) {
+ if (ctx->enc) {
+ /* If padding round up to multiple of 8 */
+ if (pad)
+ inlen = (inlen + 7) / 8 * 8;
+ /* 8 byte prefix */
+ return inlen + 8;
+ } else {
+ /*
+ * If not padding output will be exactly 8 bytes smaller than
+ * input. If padding it will be at least 8 bytes smaller but we
+ * don't know how much.
+ */
+ return inlen - 8;
+ }
+ }
+
+ rv = wctx->wrapfn(&wctx->ks.ks, ctx->iv_set ? ctx->iv : NULL, out, in,
+ inlen, ctx->block);
+ return rv ? (int)rv : -1;
+}
+
+static int aes_wrap_final(void *vctx, unsigned char *out, size_t *outl,
+ size_t outsize)
+{
+ *outl = 0;
+ return 1;
+}
+
+static int aes_wrap_cipher(void *vctx,
+ unsigned char *out, size_t *outl, size_t outsize,
+ const unsigned char *in, size_t inl)
+{
+ PROV_AES_WRAP_CTX *ctx = (PROV_AES_WRAP_CTX *)vctx;
+ size_t len;
+
+ if (outsize < inl) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
+ return -1;
+ }
+
+ len = aes_wrap_cipher_internal(ctx, out, in, inl);
+ if (len == 0)
+ return -1;
+
+ *outl = len;
+ return 1;
+}
+
+static int aes_wrap_set_ctx_params(void *vctx, const OSSL_PARAM params[])
+{
+ PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx;
+ const OSSL_PARAM *p;
+ size_t keylen = 0;
+
+ p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN);
+ if (p != NULL) {
+ if (!OSSL_PARAM_get_size_t(p, &keylen)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
+ return 0;
+ }
+ if (ctx->keylen != keylen) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+#define IMPLEMENT_cipher(mode, fname, UCMODE, flags, kbits, blkbits, ivbits) \
+ static OSSL_OP_cipher_get_params_fn aes_##kbits##_##fname##_get_params; \
+ static int aes_##kbits##_##fname##_get_params(OSSL_PARAM params[]) \
+ { \
+ return cipher_generic_get_params(params, EVP_CIPH_##UCMODE##_MODE, \
+ flags, kbits, blkbits, ivbits); \
+ } \
+ static OSSL_OP_cipher_newctx_fn aes_##kbits##fname##_newctx; \
+ static void *aes_##kbits##fname##_newctx(void *provctx) \
+ { \
+ return aes_##mode##_newctx(kbits, blkbits, ivbits, \
+ EVP_CIPH_##UCMODE##_MODE, flags); \
+ } \
+ const OSSL_DISPATCH aes##kbits##fname##_functions[] = { \
+ { OSSL_FUNC_CIPHER_NEWCTX, \
+ (void (*)(void))aes_##kbits##fname##_newctx }, \
+ { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))aes_##mode##_einit }, \
+ { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))aes_##mode##_dinit }, \
+ { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))aes_##mode##_cipher }, \
+ { OSSL_FUNC_CIPHER_FINAL, (void (*)(void))aes_##mode##_final }, \
+ { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))aes_##mode##_freectx }, \
+ { OSSL_FUNC_CIPHER_GET_PARAMS, \
+ (void (*)(void))aes_##kbits##_##fname##_get_params }, \
+ { OSSL_FUNC_CIPHER_GETTABLE_PARAMS, \
+ (void (*)(void))cipher_generic_gettable_params }, \
+ { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, \
+ (void (*)(void))cipher_generic_get_ctx_params }, \
+ { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \
+ (void (*)(void))aes_wrap_set_ctx_params }, \
+ { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \
+ (void (*)(void))cipher_generic_gettable_ctx_params }, \
+ { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \
+ (void (*)(void))cipher_generic_settable_ctx_params }, \
+ { 0, NULL } \
+ }
+
+IMPLEMENT_cipher(wrap, wrap, WRAP, WRAP_FLAGS, 256, 64, AES_WRAP_NOPAD_IVLEN * 8);
+IMPLEMENT_cipher(wrap, wrap, WRAP, WRAP_FLAGS, 192, 64, AES_WRAP_NOPAD_IVLEN * 8);
+IMPLEMENT_cipher(wrap, wrap, WRAP, WRAP_FLAGS, 128, 64, AES_WRAP_NOPAD_IVLEN * 8);
+IMPLEMENT_cipher(wrap, wrappad, WRAP, WRAP_FLAGS, 256, 64, AES_WRAP_PAD_IVLEN * 8);
+IMPLEMENT_cipher(wrap, wrappad, WRAP, WRAP_FLAGS, 192, 64, AES_WRAP_PAD_IVLEN * 8);
+IMPLEMENT_cipher(wrap, wrappad, WRAP, WRAP_FLAGS, 128, 64, AES_WRAP_PAD_IVLEN * 8);
diff --git a/providers/implementations/ciphers/cipher_aes_xts.c b/providers/implementations/ciphers/cipher_aes_xts.c
new file mode 100644
index 0000000000..d0b999081e
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aes_xts.c
@@ -0,0 +1,275 @@
+/*
+ * 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 "cipher_aes_xts.h"
+#include "internal/provider_algs.h"
+#include "internal/providercommonerr.h"
+
+/* TODO (3.0) Figure out what flags need to be set */
+#define AES_XTS_FLAGS (EVP_CIPH_CUSTOM_IV \
+ | EVP_CIPH_ALWAYS_CALL_INIT \
+ | EVP_CIPH_CTRL_INIT \
+ | EVP_CIPH_CUSTOM_COPY)
+
+#define AES_XTS_IV_BITS 128
+#define AES_XTS_BLOCK_BITS 8
+
+/* forward declarations */
+static OSSL_OP_cipher_encrypt_init_fn aes_xts_einit;
+static OSSL_OP_cipher_decrypt_init_fn aes_xts_dinit;
+static OSSL_OP_cipher_update_fn aes_xts_stream_update;
+static OSSL_OP_cipher_final_fn aes_xts_stream_final;
+static OSSL_OP_cipher_cipher_fn aes_xts_cipher;
+static OSSL_OP_cipher_freectx_fn aes_xts_freectx;
+static OSSL_OP_cipher_dupctx_fn aes_xts_dupctx;
+static OSSL_OP_cipher_set_ctx_params_fn aes_xts_set_ctx_params;
+static OSSL_OP_cipher_settable_ctx_params_fn aes_xts_settable_ctx_params;
+
+/*
+ * Verify that the two keys are different.
+ *
+ * This addresses the vulnerability described in Rogaway's
+ * September 2004 paper:
+ *
+ * "Efficient Instantiations of Tweakable Blockciphers and
+ * Refinements to Modes OCB and PMAC".
+ * (http://web.cs.ucdavis.edu/~rogaway/papers/offsets.pdf)
+ *
+ * FIPS 140-2 IG A.9 XTS-AES Key Generation Requirements states
+ * that:
+ * "The check for Key_1 != Key_2 shall be done at any place
+ * BEFORE using the keys in the XTS-AES algorithm to process
+ * data with them."
+ */
+static int aes_xts_check_keys_differ(const unsigned char *key, size_t bytes,
+ int enc)
+{
+ if ((!allow_insecure_decrypt || enc)
+ && CRYPTO_memcmp(key, key + bytes, bytes) == 0) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_XTS_DUPLICATED_KEYS);
+ return 0;
+ }
+ return 1;
+}
+
+/*-
+ * Provider dispatch functions
+ */
+static int aes_xts_init(void *vctx, const unsigned char *key, size_t keylen,
+ const unsigned char *iv, size_t ivlen, int enc)
+{
+ PROV_AES_XTS_CTX *xctx = (PROV_AES_XTS_CTX *)vctx;
+ PROV_CIPHER_CTX *ctx = &xctx->base;
+
+ ctx->enc = enc;
+
+ if (iv != NULL) {
+ if (!cipher_generic_initiv(vctx, iv, ivlen))
+ return 0;
+ }
+ if (key != NULL) {
+ if (keylen != ctx->keylen) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);
+ return 0;
+ }
+ if (!aes_xts_check_keys_differ(key, keylen / 2, enc))
+ return 0;
+ return ctx->hw->init(ctx, key, keylen);
+ }
+ return 1;
+}
+
+static int aes_xts_einit(void *vctx, const unsigned char *key, size_t keylen,
+ const unsigned char *iv, size_t ivlen)
+{
+ return aes_xts_init(vctx, key, keylen, iv, ivlen, 1);
+}
+
+static int aes_xts_dinit(void *vctx, const unsigned char *key, size_t keylen,
+ const unsigned char *iv, size_t ivlen)
+{
+ return aes_xts_init(vctx, key, keylen, iv, ivlen, 0);
+}
+
+static void *aes_xts_newctx(void *provctx, unsigned int mode, uint64_t flags,
+ size_t kbits, size_t blkbits, size_t ivbits)
+{
+ PROV_AES_XTS_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
+
+ if (ctx != NULL) {
+ cipher_generic_initkey(&ctx->base, kbits, blkbits, ivbits, mode, flags,
+ PROV_CIPHER_HW_aes_xts(kbits), NULL);
+ }
+ return ctx;
+}
+
+static void aes_xts_freectx(void *vctx)
+{
+ PROV_AES_XTS_CTX *ctx = (PROV_AES_XTS_CTX *)vctx;
+
+ OPENSSL_clear_free(ctx, sizeof(*ctx));
+}
+
+static void *aes_xts_dupctx(void *vctx)
+{
+ PROV_AES_XTS_CTX *in = (PROV_AES_XTS_CTX *)vctx;
+ PROV_AES_XTS_CTX *ret = NULL;
+
+ if (in->xts.key1 != NULL) {
+ if (in->xts.key1 != &in->ks1)
+ return NULL;
+ }
+ if (in->xts.key2 != NULL) {
+ if (in->xts.key2 != &in->ks2)
+ return NULL;
+ }
+ ret = OPENSSL_malloc(sizeof(*ret));
+ if (ret == NULL) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ *ret = *in;
+ return ret;
+}
+
+static int aes_xts_cipher(void *vctx, unsigned char *out, size_t *outl,
+ size_t outsize, const unsigned char *in, size_t inl)
+{
+ PROV_AES_XTS_CTX *ctx = (PROV_AES_XTS_CTX *)vctx;
+
+ if (ctx->xts.key1 == NULL
+ || ctx->xts.key2 == NULL
+ || !ctx->base.iv_set
+ || out == NULL
+ || in == NULL
+ || inl < AES_BLOCK_SIZE)
+ return 0;
+
+ /*
+ * Impose a limit of 2^20 blocks per data unit as specifed by
+ * IEEE Std 1619-2018. The earlier and obsolete IEEE Std 1619-2007
+ * indicated that this was a SHOULD NOT rather than a MUST NOT.
+ * NIST SP 800-38E mandates the same limit.
+ */
+ if (inl > XTS_MAX_BLOCKS_PER_DATA_UNIT * AES_BLOCK_SIZE) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_XTS_DATA_UNIT_IS_TOO_LARGE);
+ return 0;
+ }
+
+ if (ctx->stream != NULL)
+ (*ctx->stream)(in, out, inl, ctx->xts.key1, ctx->xts.key2, ctx->base.iv);
+ else if (CRYPTO_xts128_encrypt(&ctx->xts, ctx->base.iv, in, out, inl,
+ ctx->base.enc))
+ return 0;
+
+ *outl = inl;
+ return 1;
+}
+
+static int aes_xts_stream_update(void *vctx, unsigned char *out, size_t *outl,
+ size_t outsize, const unsigned char *in,
+ size_t inl)
+{
+ PROV_AES_XTS_CTX *ctx = (PROV_AES_XTS_CTX *)vctx;
+
+ if (outsize < inl) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
+ return 0;
+ }
+
+ if (!aes_xts_cipher(ctx, out, outl, outsize, in, inl)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int aes_xts_stream_final(void *vctx, unsigned char *out, size_t *outl,
+ size_t outsize)
+{
+ *outl = 0;
+ return 1;
+}
+
+static const OSSL_PARAM aes_xts_known_settable_ctx_params[] = {
+ OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL),
+ OSSL_PARAM_END
+};
+
+static const OSSL_PARAM *aes_xts_settable_ctx_params(void)
+{
+ return aes_xts_known_settable_ctx_params;
+}
+
+static int aes_xts_set_ctx_params(void *vctx, const OSSL_PARAM params[])
+{
+ PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx;
+ const OSSL_PARAM *p;
+
+ /*
+ * TODO(3.0) We need a general solution for handling missing parameters
+ * inside set_params and get_params methods.
+ */
+ p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN);
+ if (p != NULL) {
+ size_t keylen;
+
+ if (!OSSL_PARAM_get_size_t(p, &keylen)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
+ return 0;
+ }
+ /* The key length can not be modified for xts mode */
+ if (keylen != ctx->keylen)
+ return 0;
+ }
+
+ return 1;
+}
+
+#define IMPLEMENT_cipher(lcmode, UCMODE, kbits, flags) \
+static OSSL_OP_cipher_get_params_fn aes_##kbits##_##lcmode##_get_params; \
+static int aes_##kbits##_##lcmode##_get_params(OSSL_PARAM params[]) \
+{ \
+ return cipher_generic_get_params(params, EVP_CIPH_##UCMODE##_MODE, \
+ flags, 2 * kbits, AES_XTS_BLOCK_BITS, \
+ AES_XTS_IV_BITS); \
+} \
+static OSSL_OP_cipher_newctx_fn aes_##kbits##_xts_newctx; \
+static void *aes_##kbits##_xts_newctx(void *provctx) \
+{ \
+ return aes_xts_newctx(provctx, EVP_CIPH_##UCMODE##_MODE, flags, 2 * kbits, \
+ AES_XTS_BLOCK_BITS, AES_XTS_IV_BITS); \
+} \
+const OSSL_DISPATCH aes##kbits##xts_functions[] = { \
+ { OSSL_FUNC_CIPHER_NEWCTX, (void (*)(void))aes_##kbits##_xts_newctx }, \
+ { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))aes_xts_einit }, \
+ { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))aes_xts_dinit }, \
+ { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))aes_xts_stream_update }, \
+ { OSSL_FUNC_CIPHER_FINAL, (void (*)(void))aes_xts_stream_final }, \
+ { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))aes_xts_cipher }, \
+ { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))aes_xts_freectx }, \
+ { OSSL_FUNC_CIPHER_DUPCTX, (void (*)(void))aes_xts_dupctx }, \
+ { OSSL_FUNC_CIPHER_GET_PARAMS, \
+ (void (*)(void))aes_##kbits##_##lcmode##_get_params }, \
+ { OSSL_FUNC_CIPHER_GETTABLE_PARAMS, \
+ (void (*)(void))cipher_generic_gettable_params }, \
+ { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, \
+ (void (*)(void))cipher_generic_get_ctx_params }, \
+ { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \
+ (void (*)(void))cipher_generic_gettable_ctx_params }, \
+ { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \
+ (void (*)(void))aes_xts_set_ctx_params }, \
+ { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \
+ (void (*)(void))aes_xts_settable_ctx_params }, \
+ { 0, NULL } \
+}
+
+IMPLEMENT_cipher(xts, XTS, 256, AES_XTS_FLAGS);
+IMPLEMENT_cipher(xts, XTS, 128, AES_XTS_FLAGS);
diff --git a/providers/implementations/ciphers/cipher_aes_xts.h b/providers/implementations/ciphers/cipher_aes_xts.h
new file mode 100644
index 0000000000..615ee61905
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aes_xts.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 <openssl/aes.h>
+#include "prov/ciphercommon.h"
+
+/*
+ * Available in cipher_fips.c, and compiled with different values depending
+ * on we're in the FIPS module or not.
+ */
+extern const int allow_insecure_decrypt;
+
+PROV_CIPHER_FUNC(void, xts_stream,
+ (const unsigned char *in, unsigned char *out, size_t len,
+ const AES_KEY *key1, const AES_KEY *key2,
+ const unsigned char iv[16]));
+
+typedef struct prov_aes_xts_ctx_st {
+ PROV_CIPHER_CTX base; /* Must be first */
+ union {
+ OSSL_UNION_ALIGN;
+ AES_KEY ks;
+ } ks1, ks2; /* AES key schedules to use */
+ XTS128_CONTEXT xts;
+ OSSL_xts_stream_fn stream;
+} PROV_AES_XTS_CTX;
+
+const PROV_CIPHER_HW *PROV_CIPHER_HW_aes_xts(size_t keybits);
diff --git a/providers/implementations/ciphers/cipher_aes_xts_fips.c b/providers/implementations/ciphers/cipher_aes_xts_fips.c
new file mode 100644
index 0000000000..c99d6ed2f4
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aes_xts_fips.c
@@ -0,0 +1,16 @@
+/*
+ * 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 "cipher_aes_xts.h"
+
+#ifdef FIPS_MODE
+const int allow_insecure_decrypt = 0;
+#else
+const int allow_insecure_decrypt = 1;
+#endif /* FIPS_MODE */
diff --git a/providers/implementations/ciphers/cipher_aes_xts_hw.c b/providers/implementations/ciphers/cipher_aes_xts_hw.c
new file mode 100644
index 0000000000..9ac70c4fa8
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aes_xts_hw.c
@@ -0,0 +1,153 @@
+/*
+ * 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 "cipher_aes_xts.h"
+
+#define XTS_SET_KEY_FN(fn_set_enc_key, fn_set_dec_key, \
+ fn_block_enc, fn_block_dec, \
+ fn_stream_enc, fn_stream_dec) { \
+ size_t bytes = keylen / 2; \
+ size_t bits = bytes * 8; \
+ \
+ if (ctx->enc) { \
+ fn_set_enc_key(key, bits, &xctx->ks1.ks); \
+ xctx->xts.block1 = (block128_f)fn_block_enc; \
+ } else { \
+ fn_set_dec_key(key, bits, &xctx->ks1.ks); \
+ xctx->xts.block1 = (block128_f)fn_block_dec; \
+ } \
+ fn_set_enc_key(key + bytes, bits, &xctx->ks2.ks); \
+ xctx->xts.block2 = (block128_f)fn_block_enc; \
+ xctx->xts.key1 = &xctx->ks1; \
+ xctx->xts.key2 = &xctx->ks2; \
+ xctx->stream = ctx->enc ? fn_stream_enc : fn_stream_dec; \
+}
+
+static int cipher_hw_aes_xts_generic_initkey(PROV_CIPHER_CTX *ctx,
+ const unsigned char *key,
+ size_t keylen)
+{
+ PROV_AES_XTS_CTX *xctx = (PROV_AES_XTS_CTX *)ctx;
+ OSSL_xts_stream_fn stream_enc = NULL;
+ OSSL_xts_stream_fn stream_dec = NULL;
+
+#ifdef AES_XTS_ASM
+ stream_enc = AES_xts_encrypt;
+ stream_dec = AES_xts_decrypt;
+#endif /* AES_XTS_ASM */
+
+#ifdef HWAES_CAPABLE
+ if (HWAES_CAPABLE) {
+# ifdef HWAES_xts_encrypt
+ stream_enc = HWAES_xts_encrypt;
+# endif /* HWAES_xts_encrypt */
+# ifdef HWAES_xts_decrypt
+ stream_dec = HWAES_xts_decrypt;
+# endif /* HWAES_xts_decrypt */
+ XTS_SET_KEY_FN(HWAES_set_encrypt_key, HWAES_set_decrypt_key,
+ HWAES_encrypt, HWAES_decrypt,
+ stream_enc, stream_dec);
+ } else
+#endif /* HWAES_CAPABLE */
+
+#ifdef BSAES_CAPABLE
+ if (BSAES_CAPABLE) {
+ stream_enc = bsaes_xts_encrypt;
+ stream_dec = bsaes_xts_decrypt;
+ }
+#endif /* BSAES_CAPABLE */
+
+#ifdef VPAES_CAPABLE
+ if (VPAES_CAPABLE) {
+ XTS_SET_KEY_FN(vpaes_set_encrypt_key, vpaes_set_decrypt_key,
+ vpaes_encrypt, vpaes_decrypt, stream_enc, stream_dec);
+ } else
+#endif /* VPAES_CAPABLE */
+ {
+ XTS_SET_KEY_FN(AES_set_encrypt_key, AES_set_decrypt_key,
+ AES_encrypt, AES_decrypt, stream_enc, stream_dec);
+ }
+ return 1;
+}
+
+#if defined(AESNI_CAPABLE)
+
+static int cipher_hw_aesni_xts_initkey(PROV_CIPHER_CTX *ctx,
+ const unsigned char *key, size_t keylen)
+{
+ PROV_AES_XTS_CTX *xctx = (PROV_AES_XTS_CTX *)ctx;
+
+ XTS_SET_KEY_FN(aesni_set_encrypt_key, aesni_set_decrypt_key,
+ aesni_encrypt, aesni_decrypt,
+ aesni_xts_encrypt, aesni_xts_decrypt);
+ return 1;
+}
+
+# define PROV_CIPHER_HW_declare_xts() \
+static const PROV_CIPHER_HW aesni_xts = { \
+ cipher_hw_aesni_xts_initkey, \
+ NULL \
+};
+# define PROV_CIPHER_HW_select_xts() \
+if (AESNI_CAPABLE) \
+ return &aesni_xts;
+
+# elif defined(SPARC_AES_CAPABLE)
+
+static int cipher_hw_aes_xts_t4_initkey(PROV_CIPHER_CTX *ctx,
+ const unsigned char *key, size_t keylen)
+{
+ PROV_AES_XTS_CTX *xctx = (PROV_AES_XTS_CTX *)ctx;
+ OSSL_xts_stream_fn stream_enc = NULL;
+ OSSL_xts_stream_fn stream_dec = NULL;
+
+ /* Note: keylen is the size of 2 keys */
+ switch (keylen) {
+ case 32:
+ stream_enc = aes128_t4_xts_encrypt;
+ stream_dec = aes128_t4_xts_decrypt;
+ break;
+ case 64:
+ stream_enc = aes256_t4_xts_encrypt;
+ stream_dec = aes256_t4_xts_decrypt;
+ break;
+ default:
+ return 0;
+ }
+
+ XTS_SET_KEY_FN(aes_t4_set_encrypt_key, aes_t4_set_decrypt_key,
+ aes_t4_encrypt, aes_t4_decrypt,
+ stream_enc, stream_dec);
+ return 1;
+}
+
+# define PROV_CIPHER_HW_declare_xts() \
+static const PROV_CIPHER_HW aes_xts_t4 = { \
+ cipher_hw_aes_xts_t4_initkey, \
+ NULL \
+};
+# define PROV_CIPHER_HW_select_xts() \
+if (SPARC_AES_CAPABLE) \
+ return &aes_xts_t4;
+# else
+/* The generic case */
+# define PROV_CIPHER_HW_declare_xts()
+# define PROV_CIPHER_HW_select_xts()
+#endif
+
+static const PROV_CIPHER_HW aes_generic_xts = {
+ cipher_hw_aes_xts_generic_initkey,
+ NULL
+};
+PROV_CIPHER_HW_declare_xts()
+const PROV_CIPHER_HW *PROV_CIPHER_HW_aes_xts(size_t keybits)
+{
+ PROV_CIPHER_HW_select_xts()
+ return &aes_generic_xts;
+}
diff --git a/providers/implementations/ciphers/cipher_aria.c b/providers/implementations/ciphers/cipher_aria.c
new file mode 100644
index 0000000000..861b28268b
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aria.c
@@ -0,0 +1,80 @@
+/*
+ * 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 ARIA cipher modes ecb, cbc, ofb, cfb, ctr */
+
+#include "cipher_aria.h"
+#include "internal/provider_algs.h"
+
+static OSSL_OP_cipher_freectx_fn aria_freectx;
+static OSSL_OP_cipher_dupctx_fn aria_dupctx;
+
+static void aria_freectx(void *vctx)
+{
+ PROV_ARIA_CTX *ctx = (PROV_ARIA_CTX *)vctx;
+
+ OPENSSL_clear_free(ctx, sizeof(*ctx));
+}
+
+static void *aria_dupctx(void *ctx)
+{
+ PROV_ARIA_CTX *in = (PROV_ARIA_CTX *)ctx;
+ PROV_ARIA_CTX *ret = OPENSSL_malloc(sizeof(*ret));
+
+ if (ret == NULL) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ *ret = *in;
+
+ return ret;
+}
+
+/* aria256ecb_functions */
+IMPLEMENT_generic_cipher(aria, ARIA, ecb, ECB, 0, 256, 128, 0, block)
+/* aria192ecb_functions */
+IMPLEMENT_generic_cipher(aria, ARIA, ecb, ECB, 0, 192, 128, 0, block)
+/* aria128ecb_functions */
+IMPLEMENT_generic_cipher(aria, ARIA, ecb, ECB, 0, 128, 128, 0, block)
+/* aria256cbc_functions */
+IMPLEMENT_generic_cipher(aria, ARIA, cbc, CBC, 0, 256, 128, 128, block)
+/* aria192cbc_functions */
+IMPLEMENT_generic_cipher(aria, ARIA, cbc, CBC, 0, 192, 128, 128, block)
+/* aria128cbc_functions */
+IMPLEMENT_generic_cipher(aria, ARIA, cbc, CBC, 0, 128, 128, 128, block)
+/* aria256ofb_functions */
+IMPLEMENT_generic_cipher(aria, ARIA, ofb, OFB, 0, 256, 8, 128, stream)
+/* aria192ofb_functions */
+IMPLEMENT_generic_cipher(aria, ARIA, ofb, OFB, 0, 192, 8, 128, stream)
+/* aria128ofb_functions */
+IMPLEMENT_generic_cipher(aria, ARIA, ofb, OFB, 0, 128, 8, 128, stream)
+/* aria256cfb_functions */
+IMPLEMENT_generic_cipher(aria, ARIA, cfb, CFB, 0, 256, 8, 128, stream)
+/* aria192cfb_functions */
+IMPLEMENT_generic_cipher(aria, ARIA, cfb, CFB, 0, 192, 8, 128, stream)
+/* aria128cfb_functions */
+IMPLEMENT_generic_cipher(aria, ARIA, cfb, CFB, 0, 128, 8, 128, stream)
+/* aria256cfb1_functions */
+IMPLEMENT_generic_cipher(aria, ARIA, cfb1, CFB, 0, 256, 8, 128, stream)
+/* aria192cfb1_functions */
+IMPLEMENT_generic_cipher(aria, ARIA, cfb1, CFB, 0, 192, 8, 128, stream)
+/* aria128cfb1_functions */
+IMPLEMENT_generic_cipher(aria, ARIA, cfb1, CFB, 0, 128, 8, 128, stream)
+/* aria256cfb8_functions */
+IMPLEMENT_generic_cipher(aria, ARIA, cfb8, CFB, 0, 256, 8, 128, stream)
+/* aria192cfb8_functions */
+IMPLEMENT_generic_cipher(aria, ARIA, cfb8, CFB, 0, 192, 8, 128, stream)
+/* aria128cfb8_functions */
+IMPLEMENT_generic_cipher(aria, ARIA, cfb8, CFB, 0, 128, 8, 128, stream)
+/* aria256ctr_functions */
+IMPLEMENT_generic_cipher(aria, ARIA, ctr, CTR, 0, 256, 8, 128, stream)
+/* aria192ctr_functions */
+IMPLEMENT_generic_cipher(aria, ARIA, ctr, CTR, 0, 192, 8, 128, stream)
+/* aria128ctr_functions */
+IMPLEMENT_generic_cipher(aria, ARIA, ctr, CTR, 0, 128, 8, 128, stream)
diff --git a/providers/implementations/ciphers/cipher_aria.h b/providers/implementations/ciphers/cipher_aria.h
new file mode 100644
index 0000000000..282408c58e
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aria.h
@@ -0,0 +1,30 @@
+/*
+ * 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 "crypto/aria.h"
+#include "prov/ciphercommon.h"
+
+typedef struct prov_aria_ctx_st {
+ PROV_CIPHER_CTX base; /* Must be first */
+ union {
+ OSSL_UNION_ALIGN;
+ ARIA_KEY ks;
+ } ks;
+} PROV_ARIA_CTX;
+
+
+# define PROV_CIPHER_HW_aria_ofb PROV_CIPHER_HW_aria_ofb128
+# define PROV_CIPHER_HW_aria_cfb PROV_CIPHER_HW_aria_cfb128
+const PROV_CIPHER_HW *PROV_CIPHER_HW_aria_ecb(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_aria_cbc(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_aria_ofb128(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_aria_cfb128(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_aria_cfb1(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_aria_cfb8(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_aria_ctr(size_t keybits);
diff --git a/providers/implementations/ciphers/cipher_aria_ccm.c b/providers/implementations/ciphers/cipher_aria_ccm.c
new file mode 100644
index 0000000000..97e8137db8
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aria_ccm.c
@@ -0,0 +1,39 @@
+/*
+ * 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 ARIA CCM mode */
+
+#include "cipher_aria_ccm.h"
+#include "internal/provider_algs.h"
+
+static OSSL_OP_cipher_freectx_fn aria_ccm_freectx;
+
+static void *aria_ccm_newctx(void *provctx, size_t keybits)
+{
+ PROV_ARIA_CCM_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
+
+ if (ctx != NULL)
+ ccm_initctx(&ctx->base, keybits, PROV_ARIA_HW_ccm(keybits));
+ return ctx;
+}
+
+static void aria_ccm_freectx(void *vctx)
+{
+ PROV_ARIA_CCM_CTX *ctx = (PROV_ARIA_CCM_CTX *)vctx;
+
+ OPENSSL_clear_free(ctx, sizeof(*ctx));
+}
+
+/* aria128ccm functions */
+IMPLEMENT_aead_cipher(aria, ccm, CCM, AEAD_FLAGS, 128, 8, 96);
+/* aria192ccm functions */
+IMPLEMENT_aead_cipher(aria, ccm, CCM, AEAD_FLAGS, 192, 8, 96);
+/* aria256ccm functions */
+IMPLEMENT_aead_cipher(aria, ccm, CCM, AEAD_FLAGS, 256, 8, 96);
+
diff --git a/providers/implementations/ciphers/cipher_aria_ccm.h b/providers/implementations/ciphers/cipher_aria_ccm.h
new file mode 100644
index 0000000000..301ce14306
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aria_ccm.h
@@ -0,0 +1,22 @@
+/*
+ * 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 "crypto/aria.h"
+#include "prov/ciphercommon.h"
+#include "prov/cipher_ccm.h"
+
+typedef struct prov_aria_ccm_ctx_st {
+ PROV_CCM_CTX base; /* Must be first */
+ union {
+ OSSL_UNION_ALIGN;
+ ARIA_KEY ks;
+ } ks; /* ARIA key schedule to use */
+} PROV_ARIA_CCM_CTX;
+
+const PROV_CCM_HW *PROV_ARIA_HW_ccm(size_t keylen);
diff --git a/providers/implementations/ciphers/cipher_aria_ccm_hw.c b/providers/implementations/ciphers/cipher_aria_ccm_hw.c
new file mode 100644
index 0000000000..db3a9c8ea8
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aria_ccm_hw.c
@@ -0,0 +1,40 @@
+/*
+ * 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
+ */
+
+/*-
+ * Generic support for ARIA CCM.
+ */
+
+#include "cipher_aria_ccm.h"
+
+static int ccm_aria_initkey(PROV_CCM_CTX *ctx,
+ const unsigned char *key, size_t keylen)
+{
+ PROV_ARIA_CCM_CTX *actx = (PROV_ARIA_CCM_CTX *)ctx;
+
+ aria_set_encrypt_key(key, keylen * 8, &actx->ks.ks);
+ CRYPTO_ccm128_init(&ctx->ccm_ctx, ctx->m, ctx->l, &actx->ks.ks,
+ (block128_f)aria_encrypt);
+ ctx->str = NULL;
+ ctx->key_set = 1;
+ return 1;
+}
+
+static const PROV_CCM_HW ccm_aria = {
+ ccm_aria_initkey,
+ ccm_generic_setiv,
+ ccm_generic_setaad,
+ ccm_generic_auth_encrypt,
+ ccm_generic_auth_decrypt,
+ ccm_generic_gettag
+};
+const PROV_CCM_HW *PROV_ARIA_HW_ccm(size_t keybits)
+{
+ return &ccm_aria;
+}
diff --git a/providers/implementations/ciphers/cipher_aria_gcm.c b/providers/implementations/ciphers/cipher_aria_gcm.c
new file mode 100644
index 0000000000..7c9fa3d211
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aria_gcm.c
@@ -0,0 +1,38 @@
+/*
+ * 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 ARIA GCM mode */
+
+#include "cipher_aria_gcm.h"
+#include "internal/provider_algs.h"
+
+static void *aria_gcm_newctx(void *provctx, size_t keybits)
+{
+ PROV_ARIA_GCM_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
+
+ if (ctx != NULL)
+ gcm_initctx(provctx, &ctx->base, keybits, PROV_ARIA_HW_gcm(keybits), 4);
+ return ctx;
+}
+
+static OSSL_OP_cipher_freectx_fn aria_gcm_freectx;
+static void aria_gcm_freectx(void *vctx)
+{
+ PROV_ARIA_GCM_CTX *ctx = (PROV_ARIA_GCM_CTX *)vctx;
+
+ OPENSSL_clear_free(ctx, sizeof(*ctx));
+}
+
+/* aria128gcm_functions */
+IMPLEMENT_aead_cipher(aria, gcm, GCM, AEAD_FLAGS, 128, 8, 96);
+/* aria192gcm_functions */
+IMPLEMENT_aead_cipher(aria, gcm, GCM, AEAD_FLAGS, 192, 8, 96);
+/* aria256gcm_functions */
+IMPLEMENT_aead_cipher(aria, gcm, GCM, AEAD_FLAGS, 256, 8, 96);
+
diff --git a/providers/implementations/ciphers/cipher_aria_gcm.h b/providers/implementations/ciphers/cipher_aria_gcm.h
new file mode 100644
index 0000000000..13fbe175d9
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aria_gcm.h
@@ -0,0 +1,22 @@
+/*
+ * 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 "crypto/aria.h"
+#include "prov/ciphercommon.h"
+#include "prov/cipher_gcm.h"
+
+typedef struct prov_aria_gcm_ctx_st {
+ PROV_GCM_CTX base; /* must be first entry in struct */
+ union {
+ OSSL_UNION_ALIGN;
+ ARIA_KEY ks;
+ } ks;
+} PROV_ARIA_GCM_CTX;
+
+const PROV_GCM_HW *PROV_ARIA_HW_gcm(size_t keybits);
diff --git a/providers/implementations/ciphers/cipher_aria_gcm_hw.c b/providers/implementations/ciphers/cipher_aria_gcm_hw.c
new file mode 100644
index 0000000000..ed1e1851dc
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aria_gcm_hw.c
@@ -0,0 +1,50 @@
+/*
+ * 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
+ */
+
+/*-
+ * Generic support for ARIA GCM.
+ */
+
+#include "cipher_aria_gcm.h"
+
+static int aria_gcm_initkey(PROV_GCM_CTX *ctx, const unsigned char *key,
+ size_t keylen)
+{
+ PROV_ARIA_GCM_CTX *actx = (PROV_ARIA_GCM_CTX *)ctx;
+ ARIA_KEY *ks = &actx->ks.ks;
+
+ GCM_HW_SET_KEY_CTR_FN(ks, aria_set_encrypt_key, aria_encrypt, NULL);
+ return 1;
+}
+
+static int aria_cipher_update(PROV_GCM_CTX *ctx, const unsigned char *in,
+ size_t len, unsigned char *out)
+{
+ if (ctx->enc) {
+ if (CRYPTO_gcm128_encrypt(&ctx->gcm, in, out, len))
+ return 0;
+ } else {
+ if (CRYPTO_gcm128_decrypt(&ctx->gcm, in, out, len))
+ return 0;
+ }
+ return 1;
+}
+
+static const PROV_GCM_HW aria_gcm = {
+ aria_gcm_initkey,
+ gcm_setiv,
+ gcm_aad_update,
+ aria_cipher_update,
+ gcm_cipher_final,
+ gcm_one_shot
+};
+const PROV_GCM_HW *PROV_ARIA_HW_gcm(size_t keybits)
+{
+ return &aria_gcm;
+}
diff --git a/providers/implementations/ciphers/cipher_aria_hw.c b/providers/implementations/ciphers/cipher_aria_hw.c
new file mode 100644
index 0000000000..b644be8dda
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aria_hw.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2001-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 "cipher_aria.h"
+
+static int cipher_hw_aria_initkey(PROV_CIPHER_CTX *dat,
+ const unsigned char *key, size_t keylen)
+{
+ int ret, mode = dat->mode;
+ PROV_ARIA_CTX *adat = (PROV_ARIA_CTX *)dat;
+ ARIA_KEY *ks = &adat->ks.ks;
+
+ if (dat->enc || (mode != EVP_CIPH_ECB_MODE && mode != EVP_CIPH_CBC_MODE))
+ ret = aria_set_encrypt_key(key, keylen * 8, ks);
+ else
+ ret = aria_set_decrypt_key(key, keylen * 8, ks);
+ if (ret < 0) {
+ ERR_raise(ERR_LIB_PROV, EVP_R_ARIA_KEY_SETUP_FAILED);
+ return 0;
+ }
+ dat->ks = ks;
+ dat->block = (block128_f)aria_encrypt;
+ return 1;
+}
+
+# define PROV_CIPHER_HW_aria_mode(mode) \
+static const PROV_CIPHER_HW aria_##mode = { \
+ cipher_hw_aria_initkey, \
+ cipher_hw_chunked_##mode \
+}; \
+const PROV_CIPHER_HW *PROV_CIPHER_HW_aria_##mode(size_t keybits) \
+{ \
+ return &aria_##mode; \
+}
+
+PROV_CIPHER_HW_aria_mode(cbc)
+PROV_CIPHER_HW_aria_mode(ecb)
+PROV_CIPHER_HW_aria_mode(ofb128)
+PROV_CIPHER_HW_aria_mode(cfb128)
+PROV_CIPHER_HW_aria_mode(cfb1)
+PROV_CIPHER_HW_aria_mode(cfb8)
+PROV_CIPHER_HW_aria_mode(ctr)
diff --git a/providers/implementations/ciphers/cipher_blowfish.c b/providers/implementations/ciphers/cipher_blowfish.c
new file mode 100644
index 0000000000..4730f1fd40
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_blowfish.c
@@ -0,0 +1,48 @@
+/*
+ * 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 Blowfish cipher modes ecb, cbc, ofb, cfb */
+
+#include "cipher_blowfish.h"
+#include "internal/provider_algs.h"
+
+#define BF_FLAGS (EVP_CIPH_VARIABLE_LENGTH)
+
+static OSSL_OP_cipher_freectx_fn blowfish_freectx;
+static OSSL_OP_cipher_dupctx_fn blowfish_dupctx;
+
+static void blowfish_freectx(void *vctx)
+{
+ PROV_BLOWFISH_CTX *ctx = (PROV_BLOWFISH_CTX *)vctx;
+
+ OPENSSL_clear_free(ctx, sizeof(*ctx));
+}
+
+static void *blowfish_dupctx(void *ctx)
+{
+ PROV_BLOWFISH_CTX *in = (PROV_BLOWFISH_CTX *)ctx;
+ PROV_BLOWFISH_CTX *ret = OPENSSL_malloc(sizeof(*ret));
+
+ if (ret == NULL) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ *ret = *in;
+
+ return ret;
+}
+
+/* bf_ecb_functions */
+IMPLEMENT_generic_cipher(blowfish, BLOWFISH, ecb, ECB, BF_FLAGS, 128, 64, 0, block)
+/* bf_cbc_functions */
+IMPLEMENT_generic_cipher(blowfish, BLOWFISH, cbc, CBC, BF_FLAGS, 128, 64, 64, block)
+/* bf_ofb_functions */
+IMPLEMENT_generic_cipher(blowfish, BLOWFISH, ofb64, OFB, BF_FLAGS, 64, 8, 64, stream)
+/* bf_cfb_functions */
+IMPLEMENT_generic_cipher(blowfish, BLOWFISH, cfb64, CFB, BF_FLAGS, 64, 8, 64, stream)
diff --git a/providers/implementations/ciphers/cipher_blowfish.h b/providers/implementations/ciphers/cipher_blowfish.h
new file mode 100644
index 0000000000..2d66d1bc0e
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_blowfish.h
@@ -0,0 +1,24 @@
+/*
+ * 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 <openssl/blowfish.h>
+#include "prov/ciphercommon.h"
+
+typedef struct prov_blowfish_ctx_st {
+ PROV_CIPHER_CTX base; /* Must be first */
+ union {
+ OSSL_UNION_ALIGN;
+ BF_KEY ks;
+ } ks;
+} PROV_BLOWFISH_CTX;
+
+const PROV_CIPHER_HW *PROV_CIPHER_HW_blowfish_cbc(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_blowfish_ecb(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_blowfish_ofb64(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_blowfish_cfb64(size_t keybits);
diff --git a/providers/implementations/ciphers/cipher_blowfish_hw.c b/providers/implementations/ciphers/cipher_blowfish_hw.c
new file mode 100644
index 0000000000..137aeef5ca
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_blowfish_hw.c
@@ -0,0 +1,36 @@
+/*
+ * 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 "cipher_blowfish.h"
+
+static int cipher_hw_blowfish_initkey(PROV_CIPHER_CTX *ctx,
+ const unsigned char *key, size_t keylen)
+{
+ PROV_BLOWFISH_CTX *bctx = (PROV_BLOWFISH_CTX *)ctx;
+
+ BF_set_key(&bctx->ks.ks, keylen, key);
+ return 1;
+}
+
+# define PROV_CIPHER_HW_blowfish_mode(mode, UCMODE) \
+IMPLEMENT_CIPHER_HW_##UCMODE(mode, blowfish, PROV_BLOWFISH_CTX, BF_KEY, \
+ BF_##mode) \
+static const PROV_CIPHER_HW bf_##mode = { \
+ cipher_hw_blowfish_initkey, \
+ cipher_hw_blowfish_##mode##_cipher \
+}; \
+const PROV_CIPHER_HW *PROV_CIPHER_HW_blowfish_##mode(size_t keybits) \
+{ \
+ return &bf_##mode; \
+}
+
+PROV_CIPHER_HW_blowfish_mode(cbc, CBC)
+PROV_CIPHER_HW_blowfish_mode(ecb, ECB)
+PROV_CIPHER_HW_blowfish_mode(ofb64, OFB)
+PROV_CIPHER_HW_blowfish_mode(cfb64, CFB)
diff --git a/providers/implementations/ciphers/cipher_camellia.c b/providers/implementations/ciphers/cipher_camellia.c
new file mode 100644
index 0000000000..68c0e91355
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_camellia.c
@@ -0,0 +1,81 @@
+/*
+ * 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 CAMELLIA cipher modes ecb, cbc, ofb, cfb, ctr */
+
+#include "cipher_camellia.h"
+#include "internal/provider_algs.h"
+
+static OSSL_OP_cipher_freectx_fn camellia_freectx;
+static OSSL_OP_cipher_dupctx_fn camellia_dupctx;
+
+static void camellia_freectx(void *vctx)
+{
+ PROV_CAMELLIA_CTX *ctx = (PROV_CAMELLIA_CTX *)vctx;
+
+ OPENSSL_clear_free(ctx, sizeof(*ctx));
+}
+
+static void *camellia_dupctx(void *ctx)
+{
+ PROV_CAMELLIA_CTX *in = (PROV_CAMELLIA_CTX *)ctx;
+ PROV_CAMELLIA_CTX *ret = OPENSSL_malloc(sizeof(*ret));
+
+ if (ret == NULL) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ *ret = *in;
+
+ return ret;
+}
+
+/* camellia256ecb_functions */
+IMPLEMENT_generic_cipher(camellia, CAMELLIA, ecb, ECB, 0, 256, 128, 0, block)
+/* camellia192ecb_functions */
+IMPLEMENT_generic_cipher(camellia, CAMELLIA, ecb, ECB, 0, 192, 128, 0, block)
+/* camellia128ecb_functions */
+IMPLEMENT_generic_cipher(camellia, CAMELLIA, ecb, ECB, 0, 128, 128, 0, block)
+/* camellia256cbc_functions */
+IMPLEMENT_generic_cipher(camellia, CAMELLIA, cbc, CBC, 0, 256, 128, 128, block)
+/* camellia192cbc_functions */
+IMPLEMENT_generic_cipher(camellia, CAMELLIA, cbc, CBC, 0, 192, 128, 128, block)
+/* camellia128cbc_functions */
+IMPLEMENT_generic_cipher(camellia, CAMELLIA, cbc, CBC, 0, 128, 128, 128, block)
+/* camellia256ofb_functions */
+IMPLEMENT_generic_cipher(camellia, CAMELLIA, ofb, OFB, 0, 256, 8, 128, stream)
+/* camellia192ofb_functions */
+IMPLEMENT_generic_cipher(camellia, CAMELLIA, ofb, OFB, 0, 192, 8, 128, stream)
+/* camellia128ofb_functions */
+IMPLEMENT_generic_cipher(camellia, CAMELLIA, ofb, OFB, 0, 128, 8, 128, stream)
+/* camellia256cfb_functions */
+IMPLEMENT_generic_cipher(camellia, CAMELLIA, cfb, CFB, 0, 256, 8, 128, stream)
+/* camellia192cfb_functions */
+IMPLEMENT_generic_cipher(camellia, CAMELLIA, cfb, CFB, 0, 192, 8, 128, stream)
+/* camellia128cfb_functions */
+IMPLEMENT_generic_cipher(camellia, CAMELLIA, cfb, CFB, 0, 128, 8, 128, stream)
+/* camellia256cfb1_functions */
+IMPLEMENT_generic_cipher(camellia, CAMELLIA, cfb1, CFB, 0, 256, 8, 128, stream)
+/* camellia192cfb1_functions */
+IMPLEMENT_generic_cipher(camellia, CAMELLIA, cfb1, CFB, 0, 192, 8, 128, stream)
+/* camellia128cfb1_functions */
+IMPLEMENT_generic_cipher(camellia, CAMELLIA, cfb1, CFB, 0, 128, 8, 128, stream)
+/* camellia256cfb8_functions */
+IMPLEMENT_generic_cipher(camellia, CAMELLIA, cfb8, CFB, 0, 256, 8, 128, stream)
+/* camellia192cfb8_functions */
+IMPLEMENT_generic_cipher(camellia, CAMELLIA, cfb8, CFB, 0, 192, 8, 128, stream)
+/* camellia128cfb8_functions */
+IMPLEMENT_generic_cipher(camellia, CAMELLIA, cfb8, CFB, 0, 128, 8, 128, stream)
+/* camellia256ctr_functions */
+IMPLEMENT_generic_cipher(camellia, CAMELLIA, ctr, CTR, 0, 256, 8, 128, stream)
+/* camellia192ctr_functions */
+IMPLEMENT_generic_cipher(camellia, CAMELLIA, ctr, CTR, 0, 192, 8, 128, stream)
+/* camellia128ctr_functions */
+IMPLEMENT_generic_cipher(camellia, CAMELLIA, ctr, CTR, 0, 128, 8, 128, stream)
+
diff --git a/providers/implementations/ciphers/cipher_camellia.h b/providers/implementations/ciphers/cipher_camellia.h
new file mode 100644
index 0000000000..58636f1d32
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_camellia.h
@@ -0,0 +1,29 @@
+/*
+ * 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 "openssl/camellia.h"
+#include "prov/ciphercommon.h"
+
+typedef struct prov_camellia_ctx_st {
+ PROV_CIPHER_CTX base; /* Must be first */
+ union {
+ OSSL_UNION_ALIGN;
+ CAMELLIA_KEY ks;
+ } ks;
+} PROV_CAMELLIA_CTX;
+
+#define PROV_CIPHER_HW_camellia_ofb PROV_CIPHER_HW_camellia_ofb128
+#define PROV_CIPHER_HW_camellia_cfb PROV_CIPHER_HW_camellia_cfb128
+const PROV_CIPHER_HW *PROV_CIPHER_HW_camellia_ecb(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_camellia_cbc(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_camellia_ofb128(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_camellia_cfb128(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_camellia_cfb1(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_camellia_cfb8(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_camellia_ctr(size_t keybits);
diff --git a/providers/implementations/ciphers/cipher_camellia_hw.c b/providers/implementations/ciphers/cipher_camellia_hw.c
new file mode 100644
index 0000000000..39ba4bd0ac
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_camellia_hw.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2001-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 "cipher_camellia.h"
+#include <openssl/camellia.h>
+
+static int cipher_hw_camellia_initkey(PROV_CIPHER_CTX *dat,
+ const unsigned char *key, size_t keylen)
+{
+ int ret, mode = dat->mode;
+ PROV_CAMELLIA_CTX *adat = (PROV_CAMELLIA_CTX *)dat;
+ CAMELLIA_KEY *ks = &adat->ks.ks;
+
+ dat->ks = ks;
+ ret = Camellia_set_key(key, keylen * 8, ks);
+ if (ret < 0) {
+ ERR_raise(ERR_LIB_PROV, EVP_R_ARIA_KEY_SETUP_FAILED);
+ return 0;
+ }
+ if (dat->enc || (mode != EVP_CIPH_ECB_MODE && mode != EVP_CIPH_CBC_MODE)) {
+ dat->block = (block128_f) Camellia_encrypt;
+ dat->stream.cbc = mode == EVP_CIPH_CBC_MODE ?
+ (cbc128_f) Camellia_cbc_encrypt : NULL;
+ } else {
+ dat->block = (block128_f) Camellia_decrypt;
+ dat->stream.cbc = mode == EVP_CIPH_CBC_MODE ?
+ (cbc128_f) Camellia_cbc_encrypt : NULL;
+ }
+ return 1;
+}
+
+# if defined(SPARC_CMLL_CAPABLE)
+# include "cipher_camellia_hw_t4.inc"
+# else
+/* The generic case */
+# define PROV_CIPHER_HW_declare(mode)
+# define PROV_CIPHER_HW_select(mode)
+# endif /* SPARC_CMLL_CAPABLE */
+
+#define PROV_CIPHER_HW_camellia_mode(mode) \
+static const PROV_CIPHER_HW camellia_##mode = { \
+ cipher_hw_camellia_initkey, \
+ cipher_hw_generic_##mode \
+}; \
+PROV_CIPHER_HW_declare(mode) \
+const PROV_CIPHER_HW *PROV_CIPHER_HW_camellia_##mode(size_t keybits) \
+{ \
+ PROV_CIPHER_HW_select(mode) \
+ return &camellia_##mode; \
+}
+
+PROV_CIPHER_HW_camellia_mode(cbc)
+PROV_CIPHER_HW_camellia_mode(ecb)
+PROV_CIPHER_HW_camellia_mode(ofb128)
+PROV_CIPHER_HW_camellia_mode(cfb128)
+PROV_CIPHER_HW_camellia_mode(cfb1)
+PROV_CIPHER_HW_camellia_mode(cfb8)
+PROV_CIPHER_HW_camellia_mode(ctr)
diff --git a/providers/implementations/ciphers/cipher_camellia_hw_t4.inc b/providers/implementations/ciphers/cipher_camellia_hw_t4.inc
new file mode 100644
index 0000000000..24e104646b
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_camellia_hw_t4.inc
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2001-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
+ */
+
+/*-
+ * Fujitsu SPARC64 X support for camellia modes.
+ * This file is included by cipher_camellia_hw.c
+ */
+
+static int cipher_hw_camellia_t4_initkey(PROV_CIPHER_CTX *dat,
+ const unsigned char *key,
+ size_t keylen)
+{
+ int ret = 0, bits, mode = dat->mode;
+ PROV_CAMELLIA_CTX *adat = (PROV_CAMELLIA_CTX *)dat;
+ CAMELLIA_KEY *ks = &adat->ks.ks;
+
+ dat->ks = ks;
+ bits = keylen * 8;
+
+ cmll_t4_set_key(key, bits, ks);
+
+ if (dat->enc || (mode != EVP_CIPH_ECB_MODE && mode != EVP_CIPH_CBC_MODE)) {
+ dat->block = (block128_f) cmll_t4_encrypt;
+ switch (bits) {
+ case 128:
+ if (mode == EVP_CIPH_CBC_MODE)
+ dat->stream.cbc = (cbc128_f) cmll128_t4_cbc_encrypt;
+ else if (mode == EVP_CIPH_CTR_MODE)
+ dat->stream.ctr = (ctr128_f) cmll128_t4_ctr32_encrypt;
+ else
+ dat->stream.cbc = NULL;
+ break;
+ case 192:
+ case 256:
+ if (mode == EVP_CIPH_CBC_MODE)
+ dat->stream.cbc = (cbc128_f) cmll256_t4_cbc_encrypt;
+ else if (mode == EVP_CIPH_CTR_MODE)
+ dat->stream.ctr = (ctr128_f) cmll256_t4_ctr32_encrypt;
+ else
+ dat->stream.cbc = NULL;
+ break;
+ default:
+ ret = -1;
+ break;
+ }
+ } else {
+ dat->block = (block128_f) cmll_t4_decrypt;
+ switch (bits) {
+ case 128:
+ dat->stream.cbc = mode == EVP_CIPH_CBC_MODE ?
+ (cbc128_f) cmll128_t4_cbc_decrypt : NULL;
+ break;
+ case 192:
+ case 256:
+ dat->stream.cbc = mode == EVP_CIPH_CBC_MODE ?
+ (cbc128_f) cmll256_t4_cbc_decrypt : NULL;
+ break;
+ default:
+ ret = -1;
+ break;
+ }
+ }
+ if (ret < 0) {
+ ERR_raise(ERR_LIB_PROV, EVP_R_CAMELLIA_KEY_SETUP_FAILED);
+ return 0;
+ }
+ return 1;
+}
+
+#define PROV_CIPHER_HW_declare(mode) \
+static const PROV_CIPHER_HW t4_camellia_##mode = { \
+ cipher_hw_camellia_t4_initkey, \
+ cipher_hw_generic_##mode \
+};
+#define PROV_CIPHER_HW_select(mode) \
+if (SPARC_CMLL_CAPABLE) \
+ return &t4_camellia_##mode;
diff --git a/providers/implementations/ciphers/cipher_cast.h b/providers/implementations/ciphers/cipher_cast.h
new file mode 100644
index 0000000000..218f5c4fb5
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_cast.h
@@ -0,0 +1,24 @@
+/*
+ * 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 <openssl/cast.h>
+#include "prov/ciphercommon.h"
+
+typedef struct prov_cast_ctx_st {
+ PROV_CIPHER_CTX base; /* Must be first */
+ union {
+ OSSL_UNION_ALIGN;
+ CAST_KEY ks;
+ } ks;
+} PROV_CAST_CTX;
+
+const PROV_CIPHER_HW *PROV_CIPHER_HW_cast5_cbc(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_cast5_ecb(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_cast5_ofb64(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_cast5_cfb64(size_t keybits);
diff --git a/providers/implementations/ciphers/cipher_cast5.c b/providers/implementations/ciphers/cipher_cast5.c
new file mode 100644
index 0000000000..eb79aad820
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_cast5.c
@@ -0,0 +1,48 @@
+/*
+ * 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 cast cipher modes ecb, cbc, ofb, cfb */
+
+#include "cipher_cast.h"
+#include "internal/provider_algs.h"
+
+#define CAST5_FLAGS (EVP_CIPH_VARIABLE_LENGTH)
+
+static OSSL_OP_cipher_freectx_fn cast5_freectx;
+static OSSL_OP_cipher_dupctx_fn cast5_dupctx;
+
+static void cast5_freectx(void *vctx)
+{
+ PROV_CAST_CTX *ctx = (PROV_CAST_CTX *)vctx;
+
+ OPENSSL_clear_free(ctx, sizeof(*ctx));
+}
+
+static void *cast5_dupctx(void *ctx)
+{
+ PROV_CAST_CTX *in = (PROV_CAST_CTX *)ctx;
+ PROV_CAST_CTX *ret = OPENSSL_malloc(sizeof(*ret));
+
+ if (ret == NULL) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ *ret = *in;
+
+ return ret;
+}
+
+/* cast5128ecb_functions */
+IMPLEMENT_generic_cipher(cast5, CAST, ecb, ECB, CAST5_FLAGS, 128, 64, 0, block)
+/* cast5128cbc_functions */
+IMPLEMENT_generic_cipher(cast5, CAST, cbc, CBC, CAST5_FLAGS, 128, 64, 64, block)
+/* cast564ofb64_functions */
+IMPLEMENT_generic_cipher(cast5, CAST, ofb64, OFB, CAST5_FLAGS, 64, 8, 64, stream)
+/* cast564cfb64_functions */
+IMPLEMENT_generic_cipher(cast5, CAST, cfb64, CFB, CAST5_FLAGS, 64, 8, 64, stream)
diff --git a/providers/implementations/ciphers/cipher_cast5_hw.c b/providers/implementations/ciphers/cipher_cast5_hw.c
new file mode 100644
index 0000000000..227e90d7a7
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_cast5_hw.c
@@ -0,0 +1,36 @@
+/*
+ * 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 "cipher_cast.h"
+
+static int cipher_hw_cast5_initkey(PROV_CIPHER_CTX *ctx,
+ const unsigned char *key, size_t keylen)
+{
+ PROV_CAST_CTX *bctx = (PROV_CAST_CTX *)ctx;
+
+ CAST_set_key(&(bctx->ks.ks), keylen, key);
+ return 1;
+}
+
+# define PROV_CIPHER_HW_cast_mode(mode, UCMODE) \
+IMPLEMENT_CIPHER_HW_##UCMODE(mode, cast5, PROV_CAST_CTX, CAST_KEY, \
+ CAST_##mode) \
+static const PROV_CIPHER_HW cast5_##mode = { \
+ cipher_hw_cast5_initkey, \
+ cipher_hw_cast5_##mode##_cipher \
+}; \
+const PROV_CIPHER_HW *PROV_CIPHER_HW_cast5_##mode(size_t keybits) \
+{ \
+ return &cast5_##mode; \
+}
+
+PROV_CIPHER_HW_cast_mode(cbc, CBC)
+PROV_CIPHER_HW_cast_mode(ecb, ECB)
+PROV_CIPHER_HW_cast_mode(ofb64, OFB)
+PROV_CIPHER_HW_cast_mode(cfb64, CFB)
diff --git a/providers/implementations/ciphers/cipher_des.c b/providers/implementations/ciphers/cipher_des.c
new file mode 100644
index 0000000000..5781aa4706
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_des.c
@@ -0,0 +1,160 @@
+/*
+ * 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 "prov/ciphercommon.h"
+#include "cipher_des.h"
+#include "crypto/rand.h"
+#include "internal/provider_algs.h"
+#include "internal/providercommonerr.h"
+
+/* TODO(3.0) Figure out what flags need to be here */
+#define DES_FLAGS (EVP_CIPH_RAND_KEY)
+
+static OSSL_OP_cipher_freectx_fn des_freectx;
+static OSSL_OP_cipher_encrypt_init_fn des_einit;
+static OSSL_OP_cipher_decrypt_init_fn des_dinit;
+static OSSL_OP_cipher_get_ctx_params_fn des_get_ctx_params;
+static OSSL_OP_cipher_gettable_ctx_params_fn des_gettable_ctx_params;
+
+static void *des_newctx(void *provctx, size_t kbits, size_t blkbits,
+ size_t ivbits, unsigned int mode, uint64_t flags,
+ const PROV_CIPHER_HW *hw)
+{
+ PROV_DES_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
+
+ if (ctx != NULL)
+ cipher_generic_initkey(ctx, kbits, blkbits, ivbits, mode, flags, hw,
+ provctx);
+ return ctx;
+}
+
+static void des_freectx(void *vctx)
+{
+ PROV_DES_CTX *ctx = (PROV_DES_CTX *)vctx;
+
+ OPENSSL_clear_free(ctx, sizeof(*ctx));
+}
+
+static int des_init(void *vctx, const unsigned char *key, size_t keylen,
+ const unsigned char *iv, size_t ivlen, int enc)
+{
+ PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx;
+
+ ctx->enc = enc;
+
+ if (iv != NULL) {
+ if (!cipher_generic_initiv(ctx, iv, ivlen))
+ return 0;
+ }
+
+ if (key != NULL) {
+ if (keylen != ctx->keylen) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEYLEN);
+ return 0;
+ }
+ return ctx->hw->init(ctx, key, keylen);
+ }
+ return 1;
+}
+
+static int des_einit(void *vctx, const unsigned char *key, size_t keylen,
+ const unsigned char *iv, size_t ivlen)
+{
+ return des_init(vctx, key, keylen, iv, ivlen, 1);
+}
+
+static int des_dinit(void *vctx, const unsigned char *key, size_t keylen,
+ const unsigned char *iv, size_t ivlen)
+{
+ return des_init(vctx, key, keylen, iv, ivlen, 0);
+}
+
+static int des_generatekey(PROV_CIPHER_CTX *ctx, void *ptr)
+{
+
+ DES_cblock *deskey = ptr;
+ size_t kl = ctx->keylen;
+
+ if (kl == 0 || rand_priv_bytes_ex(ctx->libctx, ptr, kl) <= 0)
+ return 0;
+ DES_set_odd_parity(deskey);
+ return 1;
+}
+
+CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_START(des)
+ OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_RANDOM_KEY, NULL, 0),
+CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_END(des)
+
+static int des_get_ctx_params(void *vctx, OSSL_PARAM params[])
+{
+ PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx;
+ OSSL_PARAM *p;
+
+ if (!cipher_generic_get_ctx_params(vctx, params))
+ return 0;
+
+ p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_RANDOM_KEY);
+ if (p != NULL && !des_generatekey(ctx, p->data)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GENERATE_KEY);
+ return 0;
+ }
+ return 1;
+}
+
+#define IMPLEMENT_des_cipher(type, lcmode, UCMODE, flags, \
+ kbits, blkbits, ivbits, block) \
+static OSSL_OP_cipher_newctx_fn type##_##lcmode##_newctx; \
+static void *des_##lcmode##_newctx(void *provctx) \
+{ \
+ return des_newctx(provctx, kbits, blkbits, ivbits, \
+ EVP_CIPH_##UCMODE##_MODE, flags, \
+ PROV_CIPHER_HW_des_##lcmode()); \
+} \
+static OSSL_OP_cipher_get_params_fn des_##lcmode##_get_params; \
+static int des_##lcmode##_get_params(OSSL_PARAM params[]) \
+{ \
+ return cipher_generic_get_params(params, EVP_CIPH_##UCMODE##_MODE, flags, \
+ kbits, blkbits, ivbits); \
+} \
+const OSSL_DISPATCH des_##lcmode##_functions[] = { \
+ { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))des_einit }, \
+ { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))des_dinit }, \
+ { OSSL_FUNC_CIPHER_UPDATE, \
+ (void (*)(void))cipher_generic_##block##_update }, \
+ { OSSL_FUNC_CIPHER_FINAL, (void (*)(void))cipher_generic_##block##_final },\
+ { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))cipher_generic_cipher }, \
+ { OSSL_FUNC_CIPHER_NEWCTX, \
+ (void (*)(void))des_##lcmode##_newctx }, \
+ { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))des_freectx }, \
+ { OSSL_FUNC_CIPHER_GET_PARAMS, \
+ (void (*)(void))des_##lcmode##_get_params }, \
+ { OSSL_FUNC_CIPHER_GETTABLE_PARAMS, \
+ (void (*)(void))cipher_generic_gettable_params }, \
+ { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, (void (*)(void))des_get_ctx_params }, \
+ { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \
+ (void (*)(void))des_gettable_ctx_params }, \
+ { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \
+ (void (*)(void))cipher_generic_set_ctx_params }, \
+ { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \
+ (void (*)(void))cipher_generic_settable_ctx_params }, \
+ { 0, NULL } \
+}
+
+/* des_ecb_functions */
+IMPLEMENT_des_cipher(des, ecb, ECB, DES_FLAGS, 64, 64, 0, block);
+/* des_cbc_functions */
+IMPLEMENT_des_cipher(des, cbc, CBC, DES_FLAGS, 64, 64, 64, block);
+/* des_ofb64_functions */
+IMPLEMENT_des_cipher(des, ofb64, OFB, DES_FLAGS, 64, 8, 64, stream);
+/* des_cfb64_functions */
+IMPLEMENT_des_cipher(des, cfb64, CFB, DES_FLAGS, 64, 8, 64, stream);
+/* des_cfb1_functions */
+IMPLEMENT_des_cipher(des, cfb1, CFB, DES_FLAGS, 64, 8, 64, stream);
+/* des_cfb8_functions */
+IMPLEMENT_des_cipher(des, cfb8, CFB, DES_FLAGS, 64, 8, 64, stream);
diff --git a/providers/implementations/ciphers/cipher_des.h b/providers/implementations/ciphers/cipher_des.h
new file mode 100644
index 0000000000..92dcfa11e9
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_des.h
@@ -0,0 +1,33 @@
+/*
+ * 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 <openssl/des.h>
+
+/* TODO(3.0) Figure out what flags need to be here */
+#define TDES_FLAGS (EVP_CIPH_RAND_KEY)
+
+typedef struct prov_des_ctx_st {
+ PROV_CIPHER_CTX base; /* Must be first */
+ union {
+ OSSL_UNION_ALIGN;
+ DES_key_schedule ks;
+ } dks;
+ union {
+ void (*cbc) (const void *, void *, size_t,
+ const DES_key_schedule *, unsigned char *);
+ } dstream;
+
+} PROV_DES_CTX;
+
+const PROV_CIPHER_HW *PROV_CIPHER_HW_des_cbc(void);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_des_ecb(void);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_des_ofb64(void);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_des_cfb64(void);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_des_cfb1(void);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_des_cfb8(void);
diff --git a/providers/implementations/ciphers/cipher_des_hw.c b/providers/implementations/ciphers/cipher_des_hw.c
new file mode 100644
index 0000000000..c3a67080fd
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_des_hw.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright 1995-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 "prov/ciphercommon.h"
+#include "cipher_des.h"
+
+static int cipher_hw_des_initkey(PROV_CIPHER_CTX *ctx,
+ const unsigned char *key, size_t keylen)
+{
+ PROV_DES_CTX *dctx = (PROV_DES_CTX *)ctx;
+ DES_cblock *deskey = (DES_cblock *)key;
+ DES_key_schedule *ks = &dctx->dks.ks;
+
+ dctx->dstream.cbc = NULL;
+#if defined(SPARC_DES_CAPABLE)
+ if (SPARC_DES_CAPABLE) {
+ if (ctx->mode == EVP_CIPH_CBC_MODE) {
+ des_t4_key_expand(&deskey[0], ks);
+ dctx->dstream.cbc = ctx->enc ? des_t4_cbc_encrypt :
+ des_t4_cbc_decrypt;
+ return 1;
+ }
+ }
+#endif
+ DES_set_key_unchecked(deskey, ks);
+ return 1;
+}
+
+static int cipher_hw_des_ecb_cipher(PROV_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, size_t len)
+{
+ size_t i, bl = ctx->blocksize;
+ DES_key_schedule *key = &(((PROV_DES_CTX *)ctx)->dks.ks);
+
+ if (len < bl)
+ return 1;
+ for (i = 0, len -= bl; i <= len; i += bl)
+ DES_ecb_encrypt((const_DES_cblock *)(in + i),
+ (const_DES_cblock *)(out + i), key, ctx->enc);
+ return 1;
+}
+
+static int cipher_hw_des_cbc_cipher(PROV_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, size_t len)
+{
+ DES_key_schedule *key = &(((PROV_DES_CTX *)ctx)->dks.ks);
+
+ while (len >= MAXCHUNK) {
+ DES_ncbc_encrypt(in, out, MAXCHUNK, key, (DES_cblock *)ctx->iv,
+ ctx->enc);
+ len -= MAXCHUNK;
+ in += MAXCHUNK;
+ out += MAXCHUNK;
+ }
+ if (len > 0)
+ DES_ncbc_encrypt(in, out, (long)len, key, (DES_cblock *)ctx->iv,
+ ctx->enc);
+ return 1;
+}
+
+static int cipher_hw_des_ofb64_cipher(PROV_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, size_t len)
+{
+ int num = ctx->num;
+ DES_key_schedule *key = &(((PROV_DES_CTX *)ctx)->dks.ks);
+
+ while (len >= MAXCHUNK) {
+ DES_ofb64_encrypt(in, out, MAXCHUNK, key, (DES_cblock *)ctx->iv, &num);
+ len -= MAXCHUNK;
+ in += MAXCHUNK;
+ out += MAXCHUNK;
+ }
+ if (len > 0) {
+ DES_ofb64_encrypt(in, out, (long)len, key, (DES_cblock *)ctx->iv, &num);
+ }
+ ctx->num = num;
+ return 1;
+}
+
+static int cipher_hw_des_cfb64_cipher(PROV_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, size_t len)
+{
+ size_t chunk = MAXCHUNK;
+ DES_key_schedule *key = &(((PROV_DES_CTX *)ctx)->dks.ks);
+ int num = ctx->num;
+
+ if (len < chunk)
+ chunk = len;
+ while (len > 0 && len >= chunk) {
+ DES_cfb64_encrypt(in, out, (long)chunk, key, (DES_cblock *)ctx->iv,
+ &num, ctx->enc);
+ len -= chunk;
+ in += chunk;
+ out += chunk;
+ if (len < chunk)
+ chunk = len;
+ }
+ ctx->num = num;
+ return 1;
+}
+
+/*
+ * Although we have a CFB-r implementation for DES, it doesn't pack the right
+ * way, so wrap it here
+ */
+static int cipher_hw_des_cfb1_cipher(PROV_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, size_t inl)
+{
+ size_t n, chunk = MAXCHUNK / 8;
+ DES_key_schedule *key = &(((PROV_DES_CTX *)ctx)->dks.ks);
+ unsigned char c[1], d[1];
+
+ if (inl < chunk)
+ chunk = inl;
+
+ while (inl && inl >= chunk) {
+ for (n = 0; n < chunk * 8; ++n) {
+ c[0] = (in[n / 8] & (1 << (7 - n % 8))) ? 0x80 : 0;
+ DES_cfb_encrypt(c, d, 1, 1, key, (DES_cblock *)ctx->iv, ctx->enc);
+ out[n / 8] =
+ (out[n / 8] & ~(0x80 >> (unsigned int)(n % 8))) |
+ ((d[0] & 0x80) >> (unsigned int)(n % 8));
+ }
+ inl -= chunk;
+ in += chunk;
+ out += chunk;
+ if (inl < chunk)
+ chunk = inl;
+ }
+
+ return 1;
+}
+
+static int cipher_hw_des_cfb8_cipher(PROV_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, size_t inl)
+{
+ DES_key_schedule *key = &(((PROV_DES_CTX *)ctx)->dks.ks);
+
+ while (inl >= MAXCHUNK) {
+ DES_cfb_encrypt(in, out, 8, (long)MAXCHUNK, key,
+ (DES_cblock *)ctx->iv, ctx->enc);
+ inl -= MAXCHUNK;
+ in += MAXCHUNK;
+ out += MAXCHUNK;
+ }
+ if (inl > 0)
+ DES_cfb_encrypt(in, out, 8, (long)inl, key,
+ (DES_cblock *)ctx->iv, ctx->enc);
+ return 1;
+}
+
+#define PROV_CIPHER_HW_des_mode(mode) \
+static const PROV_CIPHER_HW des_##mode = { \
+ cipher_hw_des_initkey, \
+ cipher_hw_des_##mode##_cipher \
+}; \
+const PROV_CIPHER_HW *PROV_CIPHER_HW_des_##mode(void) \
+{ \
+ return &des_##mode; \
+}
+
+PROV_CIPHER_HW_des_mode(ecb)
+PROV_CIPHER_HW_des_mode(cbc)
+PROV_CIPHER_HW_des_mode(ofb64)
+PROV_CIPHER_HW_des_mode(cfb64)
+PROV_CIPHER_HW_des_mode(cfb1)
+PROV_CIPHER_HW_des_mode(cfb8)
diff --git a/providers/implementations/ciphers/cipher_desx.c b/providers/implementations/ciphers/cipher_desx.c
new file mode 100644
index 0000000000..4a232cd080
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_desx.c
@@ -0,0 +1,15 @@
+/*
+ * 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 "cipher_tdes_default.h"
+#include "internal/provider_algs.h"
+
+/* desx_cbc_functions */
+IMPLEMENT_tdes_cipher(desx, DESX, cbc, CBC, TDES_FLAGS, 64*3, 64, 64, block);
+
diff --git a/providers/implementations/ciphers/cipher_desx_hw.c b/providers/implementations/ciphers/cipher_desx_hw.c
new file mode 100644
index 0000000000..ef1b3b0694
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_desx_hw.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright 1995-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 <openssl/des.h>
+#include "cipher_tdes_default.h"
+
+/*
+ * Note the PROV_TDES_CTX has been used for the DESX cipher, just to reduce
+ * code size.
+ */
+#define ks1 tks.ks[0]
+#define ks2 tks.ks[1].ks[0].cblock
+#define ks3 tks.ks[2].ks[0].cblock
+
+static int cipher_hw_desx_cbc_initkey(PROV_CIPHER_CTX *ctx,
+ const unsigned char *key, size_t keylen)
+{
+ PROV_TDES_CTX *tctx = (PROV_TDES_CTX *)ctx;
+ DES_cblock *deskey = (DES_cblock *)key;
+
+ DES_set_key_unchecked(deskey, &tctx->ks1);
+ memcpy(&tctx->ks2, &key[8], 8);
+ memcpy(&tctx->ks3, &key[16], 8);
+
+ return 1;
+}
+
+static int cipher_hw_desx_cbc(PROV_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, size_t inl)
+{
+ PROV_TDES_CTX *tctx = (PROV_TDES_CTX *)ctx;
+
+ while (inl >= MAXCHUNK) {
+ DES_xcbc_encrypt(in, out, (long)MAXCHUNK, &tctx->ks1,
+ (DES_cblock *)ctx->iv, &tctx->ks2, &tctx->ks3,
+ ctx->enc);
+ inl -= MAXCHUNK;
+ in += MAXCHUNK;
+ out += MAXCHUNK;
+ }
+ if (inl > 0)
+ DES_xcbc_encrypt(in, out, (long)inl, &tctx->ks1,
+ (DES_cblock *)ctx->iv, &tctx->ks2, &tctx->ks3,
+ ctx->enc);
+ return 1;
+}
+
+static const PROV_CIPHER_HW desx_cbc =
+{
+ cipher_hw_desx_cbc_initkey,
+ cipher_hw_desx_cbc
+};
+const PROV_CIPHER_HW *PROV_CIPHER_HW_tdes_desx_cbc(void)
+{
+ return &desx_cbc;
+}
diff --git a/providers/implementations/ciphers/cipher_idea.c b/providers/implementations/ciphers/cipher_idea.c
new file mode 100644
index 0000000000..6bb5419b6d
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_idea.c
@@ -0,0 +1,46 @@
+/*
+ * 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 Idea cipher modes ecb, cbc, ofb, cfb */
+
+#include "cipher_idea.h"
+#include "internal/provider_algs.h"
+
+static OSSL_OP_cipher_freectx_fn idea_freectx;
+static OSSL_OP_cipher_dupctx_fn idea_dupctx;
+
+static void idea_freectx(void *vctx)
+{
+ PROV_IDEA_CTX *ctx = (PROV_IDEA_CTX *)vctx;
+
+ OPENSSL_clear_free(ctx, sizeof(*ctx));
+}
+
+static void *idea_dupctx(void *ctx)
+{
+ PROV_IDEA_CTX *in = (PROV_IDEA_CTX *)ctx;
+ PROV_IDEA_CTX *ret = OPENSSL_malloc(sizeof(*ret));
+
+ if (ret == NULL) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ *ret = *in;
+
+ return ret;
+}
+
+/* idea128ecb_functions */
+IMPLEMENT_generic_cipher(idea, IDEA, ecb, ECB, 0, 128, 64, 0, block)
+/* idea128cbc_functions */
+IMPLEMENT_generic_cipher(idea, IDEA, cbc, CBC, 0, 128, 64, 64, block)
+/* idea128ofb64_functions */
+IMPLEMENT_generic_cipher(idea, IDEA, ofb64, OFB, 0, 128, 8, 64, stream)
+/* idea128cfb64_functions */
+IMPLEMENT_generic_cipher(idea, IDEA, cfb64, CFB, 0, 128, 8, 64, stream)
diff --git a/providers/implementations/ciphers/cipher_idea.h b/providers/implementations/ciphers/cipher_idea.h
new file mode 100644
index 0000000000..ebe590b93c
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_idea.h
@@ -0,0 +1,24 @@
+/*
+ * 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 <openssl/idea.h>
+#include "prov/ciphercommon.h"
+
+typedef struct prov_idea_ctx_st {
+ PROV_CIPHER_CTX base; /* Must be first */
+ union {
+ OSSL_UNION_ALIGN;
+ IDEA_KEY_SCHEDULE ks;
+ } ks;
+} PROV_IDEA_CTX;
+
+const PROV_CIPHER_HW *PROV_CIPHER_HW_idea_cbc(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_idea_ecb(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_idea_ofb64(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_idea_cfb64(size_t keybits);
diff --git a/providers/implementations/ciphers/cipher_idea_hw.c b/providers/implementations/ciphers/cipher_idea_hw.c
new file mode 100644
index 0000000000..d722cc7a27
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_idea_hw.c
@@ -0,0 +1,56 @@
+/*
+ * 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 "cipher_idea.h"
+
+static int cipher_hw_idea_initkey(PROV_CIPHER_CTX *ctx,
+ const unsigned char *key, size_t keylen)
+{
+ PROV_IDEA_CTX *ictx = (PROV_IDEA_CTX *)ctx;
+ IDEA_KEY_SCHEDULE *ks = &(ictx->ks.ks);
+
+ if (ctx->enc
+ || ctx->mode == EVP_CIPH_OFB_MODE
+ || ctx->mode == EVP_CIPH_CFB_MODE) {
+ IDEA_set_encrypt_key(key, ks);
+ } else {
+ IDEA_KEY_SCHEDULE tmp;
+
+ IDEA_set_encrypt_key(key, &tmp);
+ IDEA_set_decrypt_key(&tmp, ks);
+ OPENSSL_cleanse((unsigned char *)&tmp, sizeof(IDEA_KEY_SCHEDULE));
+ }
+ return 1;
+}
+
+# define PROV_CIPHER_HW_idea_mode_ex(mode, UCMODE, fname) \
+IMPLEMENT_CIPHER_HW_##UCMODE(mode, idea, PROV_IDEA_CTX, IDEA_KEY_SCHEDULE, \
+ fname) \
+static const PROV_CIPHER_HW idea_##mode = { \
+ cipher_hw_idea_initkey, \
+ cipher_hw_idea_##mode##_cipher \
+}; \
+const PROV_CIPHER_HW *PROV_CIPHER_HW_idea_##mode(size_t keybits) \
+{ \
+ return &idea_##mode; \
+}
+
+# define PROV_CIPHER_HW_idea_mode(mode, UCMODE) \
+ PROV_CIPHER_HW_idea_mode_ex(mode, UCMODE, IDEA_##mode)
+
+PROV_CIPHER_HW_idea_mode(cbc, CBC)
+PROV_CIPHER_HW_idea_mode(ofb64, OFB)
+PROV_CIPHER_HW_idea_mode(cfb64, CFB)
+/*
+ * IDEA_ecb_encrypt() does not have a enc parameter - so we create a macro
+ * that ignores this parameter when IMPLEMENT_CIPHER_HW_ecb() is called.
+ */
+#define IDEA2_ecb_encrypt(in, out, ks, enc) IDEA_ecb_encrypt(in, out, ks)
+
+PROV_CIPHER_HW_idea_mode_ex(ecb, ECB, IDEA2_ecb)
diff --git a/providers/implementations/ciphers/cipher_rc2.c b/providers/implementations/ciphers/cipher_rc2.c
new file mode 100644
index 0000000000..f7ee268276
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_rc2.c
@@ -0,0 +1,239 @@
+/*
+ * 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 RC2 cipher modes ecb, cbc, ofb, cfb */
+
+#include "cipher_rc2.h"
+#include "internal/provider_algs.h"
+#include "internal/providercommonerr.h"
+
+#define RC2_40_MAGIC 0xa0
+#define RC2_64_MAGIC 0x78
+#define RC2_128_MAGIC 0x3a
+
+static OSSL_OP_cipher_freectx_fn rc2_freectx;
+static OSSL_OP_cipher_dupctx_fn rc2_dupctx;
+static OSSL_OP_cipher_gettable_ctx_params_fn rc2_gettable_ctx_params;
+static OSSL_OP_cipher_settable_ctx_params_fn rc2_settable_ctx_params;
+
+static void rc2_freectx(void *vctx)
+{
+ PROV_RC2_CTX *ctx = (PROV_RC2_CTX *)vctx;
+
+ OPENSSL_clear_free(ctx, sizeof(*ctx));
+}
+
+static void *rc2_dupctx(void *ctx)
+{
+ PROV_RC2_CTX *in = (PROV_RC2_CTX *)ctx;
+ PROV_RC2_CTX *ret = OPENSSL_malloc(sizeof(*ret));
+
+ if (ret == NULL) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ *ret = *in;
+
+ return ret;
+}
+
+static int rc2_keybits_to_magic(int keybits)
+{
+ switch (keybits) {
+ case 128:
+ return RC2_128_MAGIC;
+ case 64:
+ return RC2_64_MAGIC;
+ case 40:
+ return RC2_40_MAGIC;
+ }
+ ERR_raise(ERR_LIB_PROV, PROV_R_UNSUPPORTED_KEY_SIZE);
+ return 0;
+}
+
+static int rc2_magic_to_keybits(int magic)
+{
+ switch (magic) {
+ case RC2_128_MAGIC:
+ return 128;
+ case RC2_64_MAGIC:
+ return 64;
+ case RC2_40_MAGIC:
+ return 40;
+ }
+ ERR_raise(ERR_LIB_PROV, PROV_R_UNSUPPORTED_KEY_SIZE);
+ return 0;
+}
+
+static int rc2_get_ctx_params(void *vctx, OSSL_PARAM params[])
+{
+ PROV_RC2_CTX *ctx = (PROV_RC2_CTX *)vctx;
+ OSSL_PARAM *p;
+
+ if (!cipher_generic_get_ctx_params(vctx, params))
+ return 0;
+ p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_RC2_KEYBITS);
+ if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->key_bits)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
+ return 0;
+ }
+ p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_ALG_ID);
+ if (p != NULL) {
+ long num;
+ int i;
+ ASN1_TYPE *type;
+ unsigned char *d = p->data;
+ unsigned char **dd = d == NULL ? NULL : &d;
+
+ if (p->data_type != OSSL_PARAM_OCTET_STRING) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
+ return 0;
+ }
+ if ((type = ASN1_TYPE_new()) == NULL) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ /* Is this the original IV or the running IV? */
+ num = rc2_keybits_to_magic(ctx->key_bits);
+ if (!ASN1_TYPE_set_int_octetstring(type, num,
+ ctx->base.iv, ctx->base.ivlen)) {
+ ASN1_TYPE_free(type);
+ ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ /*
+ * IF the caller has a buffer, we pray to the gods they got the
+ * size right. There's no way to tell the i2d functions...
+ */
+ i = i2d_ASN1_TYPE(type, dd);
+ if (i >= 0)
+ p->return_size = (size_t)i;
+
+ ASN1_TYPE_free(type);
+ if (i < 0) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int rc2_set_ctx_params(void *vctx, OSSL_PARAM params[])
+{
+ PROV_RC2_CTX *ctx = (PROV_RC2_CTX *)vctx;
+ const OSSL_PARAM *p;
+
+ if (!cipher_generic_set_ctx_params(vctx, params))
+ return 0;
+ p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_RC2_KEYBITS);
+ if (p != NULL) {
+ if (!OSSL_PARAM_get_size_t(p, &ctx->key_bits)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
+ return 0;
+ }
+ }
+ p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_ALG_ID);
+ if (p != NULL) {
+ ASN1_TYPE *type = NULL;
+ long num = 0;
+ const unsigned char *d = p->data;
+ int ret = 1;
+ unsigned char iv[16];
+
+ if (p->data_type != OSSL_PARAM_OCTET_STRING
+ || ctx->base.ivlen > sizeof(iv)
+ || (type = d2i_ASN1_TYPE(NULL, &d, p->data_size)) == NULL
+ || ((size_t)ASN1_TYPE_get_int_octetstring(type, &num, iv,
+ ctx->base.ivlen)
+ != ctx->base.ivlen)
+ || !cipher_generic_initiv(&ctx->base, iv, ctx->base.ivlen)
+ || (ctx->key_bits = rc2_magic_to_keybits(num)) == 0) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
+ ret = 0;
+ }
+ ASN1_TYPE_free(type);
+ if (ret == 0)
+ return 0;
+ /*
+ * This code assumes that the caller will call
+ * EVP_CipherInit_ex() with a non NULL key in order to setup a key that
+ * uses the keylen and keybits that were set here.
+ */
+ ctx->base.keylen = ctx->key_bits / 8;
+ }
+ return 1;
+}
+
+CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_START(rc2)
+OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_RC2_KEYBITS, NULL),
+CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_END(rc2)
+
+CIPHER_DEFAULT_SETTABLE_CTX_PARAMS_START(rc2)
+OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_RC2_KEYBITS, NULL),
+CIPHER_DEFAULT_SETTABLE_CTX_PARAMS_END(rc2)
+
+#define IMPLEMENT_cipher(alg, UCALG, lcmode, UCMODE, flags, kbits, blkbits, \
+ ivbits, typ) \
+static OSSL_OP_cipher_get_params_fn alg##_##kbits##_##lcmode##_get_params; \
+static int alg##_##kbits##_##lcmode##_get_params(OSSL_PARAM params[]) \
+{ \
+ return cipher_generic_get_params(params, EVP_CIPH_##UCMODE##_MODE, flags, \
+ kbits, blkbits, ivbits); \
+} \
+static OSSL_OP_cipher_newctx_fn alg##_##kbits##_##lcmode##_newctx; \
+static void * alg##_##kbits##_##lcmode##_newctx(void *provctx) \
+{ \
+ PROV_##UCALG##_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx)); \
+ if (ctx != NULL) { \
+ cipher_generic_initkey(ctx, kbits, blkbits, ivbits, \
+ EVP_CIPH_##UCMODE##_MODE, flags, \
+ PROV_CIPHER_HW_##alg##_##lcmode(kbits), NULL); \
+ ctx->key_bits = kbits; \
+ } \
+ return ctx; \
+} \
+const OSSL_DISPATCH alg##kbits##lcmode##_functions[] = { \
+ { OSSL_FUNC_CIPHER_NEWCTX, \
+ (void (*)(void)) alg##_##kbits##_##lcmode##_newctx }, \
+ { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void)) alg##_freectx }, \
+ { OSSL_FUNC_CIPHER_DUPCTX, (void (*)(void)) alg##_dupctx }, \
+ { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))cipher_generic_einit }, \
+ { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))cipher_generic_dinit }, \
+ { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))cipher_generic_##typ##_update },\
+ { OSSL_FUNC_CIPHER_FINAL, (void (*)(void))cipher_generic_##typ##_final }, \
+ { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))cipher_generic_cipher }, \
+ { OSSL_FUNC_CIPHER_GET_PARAMS, \
+ (void (*)(void)) alg##_##kbits##_##lcmode##_get_params }, \
+ { OSSL_FUNC_CIPHER_GETTABLE_PARAMS, \
+ (void (*)(void))cipher_generic_gettable_params }, \
+ { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, \
+ (void (*)(void))rc2_get_ctx_params }, \
+ { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \
+ (void (*)(void))rc2_gettable_ctx_params }, \
+ { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \
+ (void (*)(void))rc2_set_ctx_params }, \
+ { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \
+ (void (*)(void))rc2_settable_ctx_params }, \
+ { 0, NULL } \
+};
+
+/* rc2128ecb_functions */
+IMPLEMENT_cipher(rc2, RC2, ecb, ECB, EVP_CIPH_VARIABLE_LENGTH, 128, 64, 0, block)
+/* rc2128cbc_functions */
+IMPLEMENT_cipher(rc2, RC2, cbc, CBC, EVP_CIPH_VARIABLE_LENGTH, 128, 64, 64, block)
+/* rc240cbc_functions */
+IMPLEMENT_cipher(rc2, RC2, cbc, CBC, EVP_CIPH_VARIABLE_LENGTH, 40, 64, 64, block)
+/* rc264cbc_functions */
+IMPLEMENT_cipher(rc2, RC2, cbc, CBC, EVP_CIPH_VARIABLE_LENGTH, 64, 64, 64, block)
+
+/* rc2128ofb128_functions */
+IMPLEMENT_cipher(rc2, RC2, ofb128, OFB, EVP_CIPH_VARIABLE_LENGTH, 128, 8, 64, stream)
+/* rc2128cfb128_functions */
+IMPLEMENT_cipher(rc2, RC2, cfb128, CFB, EVP_CIPH_VARIABLE_LENGTH, 128, 8, 64, stream)
diff --git a/providers/implementations/ciphers/cipher_rc2.h b/providers/implementations/ciphers/cipher_rc2.h
new file mode 100644
index 0000000000..82f0f6ca74
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_rc2.h
@@ -0,0 +1,28 @@
+/*
+ * 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 <openssl/rc2.h>
+#include "prov/ciphercommon.h"
+
+typedef struct prov_rc2_ctx_st {
+ PROV_CIPHER_CTX base; /* Must be first */
+ union {
+ OSSL_UNION_ALIGN;
+ RC2_KEY ks;
+ } ks;
+ size_t key_bits;
+} PROV_RC2_CTX;
+
+#define PROV_CIPHER_HW_rc2_ofb128 PROV_CIPHER_HW_rc2_ofb64
+#define PROV_CIPHER_HW_rc2_cfb128 PROV_CIPHER_HW_rc2_cfb64
+
+const PROV_CIPHER_HW *PROV_CIPHER_HW_rc2_cbc(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_rc2_ecb(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_rc2_ofb64(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_rc2_cfb64(size_t keybits);
diff --git a/providers/implementations/ciphers/cipher_rc2_hw.c b/providers/implementations/ciphers/cipher_rc2_hw.c
new file mode 100644
index 0000000000..83d7560d41
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_rc2_hw.c
@@ -0,0 +1,37 @@
+/*
+ * 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 "cipher_rc2.h"
+
+static int cipher_hw_rc2_initkey(PROV_CIPHER_CTX *ctx,
+ const unsigned char *key, size_t keylen)
+{
+ PROV_RC2_CTX *rctx = (PROV_RC2_CTX *)ctx;
+ RC2_KEY *ks = &(rctx->ks.ks);
+
+ RC2_set_key(ks, (int)ctx->keylen, key, (int)rctx->key_bits);
+ return 1;
+}
+
+# define PROV_CIPHER_HW_rc2_mode(mode, UCMODE) \
+IMPLEMENT_CIPHER_HW_##UCMODE(mode, rc2, PROV_RC2_CTX, RC2_KEY, \
+ RC2_##mode) \
+static const PROV_CIPHER_HW rc2_##mode = { \
+ cipher_hw_rc2_initkey, \
+ cipher_hw_rc2_##mode##_cipher \
+}; \
+const PROV_CIPHER_HW *PROV_CIPHER_HW_rc2_##mode(size_t keybits) \
+{ \
+ return &rc2_##mode; \
+}
+
+PROV_CIPHER_HW_rc2_mode(cbc, CBC)
+PROV_CIPHER_HW_rc2_mode(ecb, ECB)
+PROV_CIPHER_HW_rc2_mode(ofb64, OFB)
+PROV_CIPHER_HW_rc2_mode(cfb64, CFB)
diff --git a/providers/implementations/ciphers/cipher_rc4.c b/providers/implementations/ciphers/cipher_rc4.c
new file mode 100644
index 0000000000..d81b776bc2
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_rc4.c
@@ -0,0 +1,87 @@
+/*
+ * 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 RC4 ciphers */
+
+#include "cipher_rc4.h"
+#include "internal/provider_algs.h"
+
+/* TODO (3.0) Figure out what flags are required */
+#define RC4_FLAGS EVP_CIPH_FLAG_DEFAULT_ASN1
+
+static OSSL_OP_cipher_freectx_fn rc4_freectx;
+static OSSL_OP_cipher_dupctx_fn rc4_dupctx;
+
+static void rc4_freectx(void *vctx)
+{
+ PROV_RC4_CTX *ctx = (PROV_RC4_CTX *)vctx;
+
+ OPENSSL_clear_free(ctx, sizeof(*ctx));
+}
+
+static void *rc4_dupctx(void *ctx)
+{
+ PROV_RC4_CTX *in = (PROV_RC4_CTX *)ctx;
+ PROV_RC4_CTX *ret = OPENSSL_malloc(sizeof(*ret));
+
+ if (ret == NULL) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ *ret = *in;
+
+ return ret;
+}
+
+#define IMPLEMENT_cipher(alg, UCALG, flags, kbits, blkbits, ivbits, typ) \
+static OSSL_OP_cipher_get_params_fn alg##_##kbits##_get_params; \
+static int alg##_##kbits##_get_params(OSSL_PARAM params[]) \
+{ \
+ return cipher_generic_get_params(params, 0, flags, \
+ kbits, blkbits, ivbits); \
+} \
+static OSSL_OP_cipher_newctx_fn alg##_##kbits##_newctx; \
+static void * alg##_##kbits##_newctx(void *provctx) \
+{ \
+ PROV_##UCALG##_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx)); \
+ if (ctx != NULL) { \
+ cipher_generic_initkey(ctx, kbits, blkbits, ivbits, 0, flags, \
+ PROV_CIPHER_HW_##alg(kbits), NULL); \
+ } \
+ return ctx; \
+} \
+const OSSL_DISPATCH alg##kbits##_functions[] = { \
+ { OSSL_FUNC_CIPHER_NEWCTX, \
+ (void (*)(void)) alg##_##kbits##_newctx }, \
+ { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void)) alg##_freectx }, \
+ { OSSL_FUNC_CIPHER_DUPCTX, (void (*)(void)) alg##_dupctx }, \
+ { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))cipher_generic_einit }, \
+ { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))cipher_generic_dinit }, \
+ { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))cipher_generic_##typ##_update },\
+ { OSSL_FUNC_CIPHER_FINAL, (void (*)(void))cipher_generic_##typ##_final }, \
+ { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))cipher_generic_cipher }, \
+ { OSSL_FUNC_CIPHER_GET_PARAMS, \
+ (void (*)(void)) alg##_##kbits##_get_params }, \
+ { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, \
+ (void (*)(void))cipher_generic_get_ctx_params }, \
+ { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \
+ (void (*)(void))cipher_generic_set_ctx_params }, \
+ { OSSL_FUNC_CIPHER_GETTABLE_PARAMS, \
+ (void (*)(void))cipher_generic_gettable_params }, \
+ { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \
+ (void (*)(void))cipher_generic_gettable_ctx_params }, \
+ { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \
+ (void (*)(void))cipher_generic_settable_ctx_params }, \
+ { 0, NULL } \
+};
+
+/* rc440_functions */
+IMPLEMENT_cipher(rc4, RC4, EVP_CIPH_VARIABLE_LENGTH, 40, 8, 0, stream)
+/* rc4128_functions */
+IMPLEMENT_cipher(rc4, RC4, EVP_CIPH_VARIABLE_LENGTH, 128, 8, 0, stream)
diff --git a/providers/implementations/ciphers/cipher_rc4.h b/providers/implementations/ciphers/cipher_rc4.h
new file mode 100644
index 0000000000..a2d0a50f21
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_rc4.h
@@ -0,0 +1,21 @@
+/*
+ * 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 <openssl/rc4.h>
+#include "prov/ciphercommon.h"
+
+typedef struct prov_rc4_ctx_st {
+ PROV_CIPHER_CTX base; /* Must be first */
+ union {
+ OSSL_UNION_ALIGN;
+ RC4_KEY ks;
+ } ks;
+} PROV_RC4_CTX;
+
+const PROV_CIPHER_HW *PROV_CIPHER_HW_rc4(size_t keybits);
diff --git a/providers/implementations/ciphers/cipher_rc4_hw.c b/providers/implementations/ciphers/cipher_rc4_hw.c
new file mode 100644
index 0000000000..503a618914
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_rc4_hw.c
@@ -0,0 +1,38 @@
+/*
+ * 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 "cipher_rc4.h"
+
+static int cipher_hw_rc4_initkey(PROV_CIPHER_CTX *ctx,
+ const unsigned char *key, size_t keylen)
+{
+ PROV_RC4_CTX *rctx = (PROV_RC4_CTX *)ctx;
+
+ RC4_set_key(&rctx->ks.ks, keylen, key);
+ return 1;
+}
+
+static int cipher_hw_rc4_cipher(PROV_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, size_t len)
+{
+ PROV_RC4_CTX *rctx = (PROV_RC4_CTX *)ctx;
+
+ RC4(&rctx->ks.ks, len, in, out);
+ return 1;
+}
+
+static const PROV_CIPHER_HW rc4_hw = {
+ cipher_hw_rc4_initkey,
+ cipher_hw_rc4_cipher
+};
+const PROV_CIPHER_HW *PROV_CIPHER_HW_rc4(size_t keybits)
+{
+ return &rc4_hw;
+}
+
diff --git a/providers/implementations/ciphers/cipher_rc5.c b/providers/implementations/ciphers/cipher_rc5.c
new file mode 100644
index 0000000000..645a6b8b64
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_rc5.c
@@ -0,0 +1,145 @@
+/*
+ * 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 RC5 cipher modes ecb, cbc, ofb, cfb */
+
+#include "cipher_rc5.h"
+#include "internal/provider_algs.h"
+#include "internal/providercommonerr.h"
+
+static OSSL_OP_cipher_freectx_fn rc5_freectx;
+static OSSL_OP_cipher_dupctx_fn rc5_dupctx;
+OSSL_OP_cipher_gettable_ctx_params_fn rc5_gettable_ctx_params;
+OSSL_OP_cipher_settable_ctx_params_fn rc5_settable_ctx_params;
+
+static void rc5_freectx(void *vctx)
+{
+ PROV_RC5_CTX *ctx = (PROV_RC5_CTX *)vctx;
+
+ OPENSSL_clear_free(ctx, sizeof(*ctx));
+}
+
+static void *rc5_dupctx(void *ctx)
+{
+ PROV_RC5_CTX *in = (PROV_RC5_CTX *)ctx;
+ PROV_RC5_CTX *ret = OPENSSL_malloc(sizeof(*ret));
+
+ if (ret == NULL) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ *ret = *in;
+
+ return ret;
+}
+
+static int rc5_set_ctx_params(void *vctx, const OSSL_PARAM params[])
+{
+ PROV_RC5_CTX *ctx = (PROV_RC5_CTX *)vctx;
+ const OSSL_PARAM *p;
+
+ if (!cipher_generic_set_ctx_params(vctx, params))
+ return 0;
+
+ p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_ROUNDS);
+ if (p != NULL) {
+ unsigned int rounds;
+
+ if (!OSSL_PARAM_get_uint(p, &rounds)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
+ return 0;
+ }
+ if (rounds != RC5_8_ROUNDS
+ && rounds != RC5_12_ROUNDS
+ && rounds != RC5_16_ROUNDS) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_UNSUPPORTED_NUMBER_OF_ROUNDS);
+ return 0;
+ }
+ ctx->rounds = rounds;
+ }
+ return 1;
+}
+
+CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_START(rc5)
+ OSSL_PARAM_uint(OSSL_CIPHER_PARAM_ROUNDS, NULL),
+CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_END(rc5)
+
+CIPHER_DEFAULT_SETTABLE_CTX_PARAMS_START(rc5)
+ OSSL_PARAM_uint(OSSL_CIPHER_PARAM_ROUNDS, NULL),
+CIPHER_DEFAULT_SETTABLE_CTX_PARAMS_END(rc5)
+
+
+static int rc5_get_ctx_params(void *vctx, OSSL_PARAM params[])
+{
+ PROV_RC5_CTX *ctx = (PROV_RC5_CTX *)vctx;
+ OSSL_PARAM *p;
+
+ if (!cipher_generic_get_ctx_params(vctx, params))
+ return 0;
+ p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_ROUNDS);
+ if (p != NULL && !OSSL_PARAM_set_uint(p, ctx->rounds)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
+ return 0;
+ }
+ return 1;
+}
+
+#define IMPLEMENT_cipher(alg, UCALG, lcmode, UCMODE, flags, kbits, \
+ blkbits, ivbits, typ) \
+static OSSL_OP_cipher_get_params_fn alg##_##kbits##_##lcmode##_get_params; \
+static int alg##_##kbits##_##lcmode##_get_params(OSSL_PARAM params[]) \
+{ \
+ return cipher_generic_get_params(params, EVP_CIPH_##UCMODE##_MODE, flags, \
+ kbits, blkbits, ivbits); \
+} \
+static OSSL_OP_cipher_newctx_fn alg##_##kbits##_##lcmode##_newctx; \
+static void * alg##_##kbits##_##lcmode##_newctx(void *provctx) \
+{ \
+ PROV_##UCALG##_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx)); \
+ if (ctx != NULL) { \
+ cipher_generic_initkey(ctx, kbits, blkbits, ivbits, \
+ EVP_CIPH_##UCMODE##_MODE, flags, \
+ PROV_CIPHER_HW_##alg##_##lcmode(kbits), NULL); \
+ ctx->rounds = RC5_12_ROUNDS; \
+ } \
+ return ctx; \
+} \
+const OSSL_DISPATCH alg##kbits##lcmode##_functions[] = { \
+ { OSSL_FUNC_CIPHER_NEWCTX, \
+ (void (*)(void)) alg##_##kbits##_##lcmode##_newctx }, \
+ { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void)) alg##_freectx }, \
+ { OSSL_FUNC_CIPHER_DUPCTX, (void (*)(void)) alg##_dupctx }, \
+ { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))cipher_generic_einit }, \
+ { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))cipher_generic_dinit }, \
+ { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))cipher_generic_##typ##_update },\
+ { OSSL_FUNC_CIPHER_FINAL, (void (*)(void))cipher_generic_##typ##_final }, \
+ { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))cipher_generic_cipher }, \
+ { OSSL_FUNC_CIPHER_GET_PARAMS, \
+ (void (*)(void)) alg##_##kbits##_##lcmode##_get_params }, \
+ { OSSL_FUNC_CIPHER_GETTABLE_PARAMS, \
+ (void (*)(void))cipher_generic_gettable_params }, \
+ { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, \
+ (void (*)(void))rc5_get_ctx_params }, \
+ { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \
+ (void (*)(void))rc5_gettable_ctx_params }, \
+ { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \
+ (void (*)(void))rc5_set_ctx_params }, \
+ { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \
+ (void (*)(void))rc5_settable_ctx_params }, \
+ { 0, NULL } \
+};
+
+/* rc5128ecb_functions */
+IMPLEMENT_cipher(rc5, RC5, ecb, ECB, EVP_CIPH_VARIABLE_LENGTH, 128, 64, 0, block)
+/* rc5128cbc_functions */
+IMPLEMENT_cipher(rc5, RC5, cbc, CBC, EVP_CIPH_VARIABLE_LENGTH, 128, 64, 64, block)
+/* rc5128ofb64_functions */
+IMPLEMENT_cipher(rc5, RC5, ofb64, OFB, EVP_CIPH_VARIABLE_LENGTH, 128, 8, 64, stream)
+/* rc5128cfb64_functions */
+IMPLEMENT_cipher(rc5, RC5, cfb64, CFB, EVP_CIPH_VARIABLE_LENGTH, 128, 8, 64, stream)
diff --git a/providers/implementations/ciphers/cipher_rc5.h b/providers/implementations/ciphers/cipher_rc5.h
new file mode 100644
index 0000000000..fe0d09f710
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_rc5.h
@@ -0,0 +1,25 @@
+/*
+ * 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 <openssl/rc5.h>
+#include "prov/ciphercommon.h"
+
+typedef struct prov_blowfish_ctx_st {
+ PROV_CIPHER_CTX base; /* Must be first */
+ union {
+ OSSL_UNION_ALIGN;
+ RC5_32_KEY ks; /* key schedule */
+ } ks;
+ unsigned int rounds; /* number of rounds */
+} PROV_RC5_CTX;
+
+const PROV_CIPHER_HW *PROV_CIPHER_HW_rc5_cbc(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_rc5_ecb(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_rc5_ofb64(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_rc5_cfb64(size_t keybits);
diff --git a/providers/implementations/ciphers/cipher_rc5_hw.c b/providers/implementations/ciphers/cipher_rc5_hw.c
new file mode 100644
index 0000000000..a9a05ba32f
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_rc5_hw.c
@@ -0,0 +1,35 @@
+/*
+ * 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 "cipher_rc5.h"
+
+static int cipher_hw_rc5_initkey(PROV_CIPHER_CTX *ctx,
+ const unsigned char *key, size_t keylen)
+{
+ PROV_RC5_CTX *rctx = (PROV_RC5_CTX *)ctx;
+
+ return RC5_32_set_key(&rctx->ks.ks, keylen, key, rctx->rounds);
+}
+
+# define PROV_CIPHER_HW_rc5_mode(mode, UCMODE) \
+IMPLEMENT_CIPHER_HW_##UCMODE(mode, rc5, PROV_RC5_CTX, RC5_32_KEY, \
+ RC5_32_##mode) \
+static const PROV_CIPHER_HW rc5_##mode = { \
+ cipher_hw_rc5_initkey, \
+ cipher_hw_rc5_##mode##_cipher \
+}; \
+const PROV_CIPHER_HW *PROV_CIPHER_HW_rc5_##mode(size_t keybits) \
+{ \
+ return &rc5_##mode; \
+}
+
+PROV_CIPHER_HW_rc5_mode(cbc, CBC)
+PROV_CIPHER_HW_rc5_mode(ecb, ECB)
+PROV_CIPHER_HW_rc5_mode(ofb64, OFB)
+PROV_CIPHER_HW_rc5_mode(cfb64, CFB)
diff --git a/providers/implementations/ciphers/cipher_seed.c b/providers/implementations/ciphers/cipher_seed.c
new file mode 100644
index 0000000000..397671dd06
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_seed.c
@@ -0,0 +1,46 @@
+/*
+ * 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 Seed cipher modes ecb, cbc, ofb, cfb */
+
+#include "cipher_seed.h"
+#include "internal/provider_algs.h"
+
+static OSSL_OP_cipher_freectx_fn seed_freectx;
+static OSSL_OP_cipher_dupctx_fn seed_dupctx;
+
+static void seed_freectx(void *vctx)
+{
+ PROV_SEED_CTX *ctx = (PROV_SEED_CTX *)vctx;
+
+ OPENSSL_clear_free(ctx, sizeof(*ctx));
+}
+
+static void *seed_dupctx(void *ctx)
+{
+ PROV_SEED_CTX *in = (PROV_SEED_CTX *)ctx;
+ PROV_SEED_CTX *ret = OPENSSL_malloc(sizeof(*ret));
+
+ if (ret == NULL) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ *ret = *in;
+
+ return ret;
+}
+
+/* seed128ecb_functions */
+IMPLEMENT_generic_cipher(seed, SEED, ecb, ECB, 0, 128, 128, 0, block)
+/* seed128cbc_functions */
+IMPLEMENT_generic_cipher(seed, SEED, cbc, CBC, 0, 128, 128, 128, block)
+/* seed128ofb128_functions */
+IMPLEMENT_generic_cipher(seed, SEED, ofb128, OFB, 0, 128, 8, 128, stream)
+/* seed128cfb128_functions */
+IMPLEMENT_generic_cipher(seed, SEED, cfb128, CFB, 0, 128, 8, 128, stream)
diff --git a/providers/implementations/ciphers/cipher_seed.h b/providers/implementations/ciphers/cipher_seed.h
new file mode 100644
index 0000000000..976af35005
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_seed.h
@@ -0,0 +1,24 @@
+/*
+ * 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 <openssl/seed.h>
+#include "prov/ciphercommon.h"
+
+typedef struct prov_seed_ctx_st {
+ PROV_CIPHER_CTX base; /* Must be first */
+ union {
+ OSSL_UNION_ALIGN;
+ SEED_KEY_SCHEDULE ks;
+ } ks;
+} PROV_SEED_CTX;
+
+const PROV_CIPHER_HW *PROV_CIPHER_HW_seed_cbc(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_seed_ecb(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_seed_ofb128(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_seed_cfb128(size_t keybits);
diff --git a/providers/implementations/ciphers/cipher_seed_hw.c b/providers/implementations/ciphers/cipher_seed_hw.c
new file mode 100644
index 0000000000..3bd3323dc0
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_seed_hw.c
@@ -0,0 +1,36 @@
+/*
+ * 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 "cipher_seed.h"
+
+static int cipher_hw_seed_initkey(PROV_CIPHER_CTX *ctx,
+ const unsigned char *key, size_t keylen)
+{
+ PROV_SEED_CTX *sctx = (PROV_SEED_CTX *)ctx;
+
+ SEED_set_key(key, &(sctx->ks.ks));
+ return 1;
+}
+
+# define PROV_CIPHER_HW_seed_mode(mode, UCMODE) \
+IMPLEMENT_CIPHER_HW_##UCMODE(mode, seed, PROV_SEED_CTX, SEED_KEY_SCHEDULE, \
+ SEED_##mode) \
+static const PROV_CIPHER_HW seed_##mode = { \
+ cipher_hw_seed_initkey, \
+ cipher_hw_seed_##mode##_cipher \
+}; \
+const PROV_CIPHER_HW *PROV_CIPHER_HW_seed_##mode(size_t keybits) \
+{ \
+ return &seed_##mode; \
+}
+
+PROV_CIPHER_HW_seed_mode(cbc, CBC)
+PROV_CIPHER_HW_seed_mode(ecb, ECB)
+PROV_CIPHER_HW_seed_mode(ofb128, OFB)
+PROV_CIPHER_HW_seed_mode(cfb128, CFB)
diff --git a/providers/implementations/ciphers/cipher_sm4.c b/providers/implementations/ciphers/cipher_sm4.c
new file mode 100644
index 0000000000..2c1e587863
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_sm4.c
@@ -0,0 +1,48 @@
+/*
+ * 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 cast cipher modes ecb, cbc, ofb, cfb */
+
+#include "cipher_sm4.h"
+#include "internal/provider_algs.h"
+
+static OSSL_OP_cipher_freectx_fn sm4_freectx;
+static OSSL_OP_cipher_dupctx_fn sm4_dupctx;
+
+static void sm4_freectx(void *vctx)
+{
+ PROV_SM4_CTX *ctx = (PROV_SM4_CTX *)vctx;
+
+ OPENSSL_clear_free(ctx, sizeof(*ctx));
+}
+
+static void *sm4_dupctx(void *ctx)
+{
+ PROV_SM4_CTX *in = (PROV_SM4_CTX *)ctx;
+ PROV_SM4_CTX *ret = OPENSSL_malloc(sizeof(*ret));
+
+ if (ret == NULL) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ *ret = *in;
+
+ return ret;
+}
+
+/* sm4128ecb_functions */
+IMPLEMENT_generic_cipher(sm4, SM4, ecb, ECB, 0, 128, 128, 0, block)
+/* sm4128cbc_functions */
+IMPLEMENT_generic_cipher(sm4, SM4, cbc, CBC, 0, 128, 128, 128, block)
+/* sm4128ctr_functions */
+IMPLEMENT_generic_cipher(sm4, SM4, ctr, CTR, 0, 128, 8, 128, stream)
+/* sm4128ofb128_functions */
+IMPLEMENT_generic_cipher(sm4, SM4, ofb128, OFB, 0, 128, 8, 128, stream)
+/* sm4128cfb128_functions */
+IMPLEMENT_generic_cipher(sm4, SM4, cfb128, CFB, 0, 128, 8, 128, stream)
diff --git a/providers/implementations/ciphers/cipher_sm4.h b/providers/implementations/ciphers/cipher_sm4.h
new file mode 100644
index 0000000000..d5c9633552
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_sm4.h
@@ -0,0 +1,25 @@
+/*
+ * 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 "prov/ciphercommon.h"
+#include "crypto/sm4.h"
+
+typedef struct prov_cast_ctx_st {
+ PROV_CIPHER_CTX base; /* Must be first */
+ union {
+ OSSL_UNION_ALIGN;
+ SM4_KEY ks;
+ } ks;
+} PROV_SM4_CTX;
+
+const PROV_CIPHER_HW *PROV_CIPHER_HW_sm4_cbc(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_sm4_ecb(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_sm4_ctr(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_sm4_ofb128(size_t keybits);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_sm4_cfb128(size_t keybits);
diff --git a/providers/implementations/ciphers/cipher_sm4_hw.c b/providers/implementations/ciphers/cipher_sm4_hw.c
new file mode 100644
index 0000000000..9ecaf0b997
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_sm4_hw.c
@@ -0,0 +1,43 @@
+/*
+ * 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 "cipher_sm4.h"
+
+static int cipher_hw_sm4_initkey(PROV_CIPHER_CTX *ctx,
+ const unsigned char *key, size_t keylen)
+{
+ PROV_SM4_CTX *sctx = (PROV_SM4_CTX *)ctx;
+ SM4_KEY *ks = &sctx->ks.ks;
+
+ SM4_set_key(key, ks);
+ ctx->ks = ks;
+ if (ctx->enc
+ || (ctx->mode != EVP_CIPH_ECB_MODE
+ && ctx->mode != EVP_CIPH_CBC_MODE))
+ ctx->block = (block128_f)SM4_encrypt;
+ else
+ ctx->block = (block128_f)SM4_decrypt;
+ return 1;
+}
+
+# define PROV_CIPHER_HW_sm4_mode(mode) \
+static const PROV_CIPHER_HW sm4_##mode = { \
+ cipher_hw_sm4_initkey, \
+ cipher_hw_chunked_##mode \
+}; \
+const PROV_CIPHER_HW *PROV_CIPHER_HW_sm4_##mode(size_t keybits) \
+{ \
+ return &sm4_##mode; \
+}
+
+PROV_CIPHER_HW_sm4_mode(cbc)
+PROV_CIPHER_HW_sm4_mode(ecb)
+PROV_CIPHER_HW_sm4_mode(ofb128)
+PROV_CIPHER_HW_sm4_mode(cfb128)
+PROV_CIPHER_HW_sm4_mode(ctr)
diff --git a/providers/implementations/ciphers/cipher_tdes.c b/providers/implementations/ciphers/cipher_tdes.c
new file mode 100644
index 0000000000..9c032902e9
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_tdes.c
@@ -0,0 +1,114 @@
+/*
+ * 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 "prov/ciphercommon.h"
+#include "cipher_tdes.h"
+#include "crypto/rand.h"
+#include "internal/provider_algs.h"
+#include "internal/providercommonerr.h"
+
+void *tdes_newctx(void *provctx, int mode, size_t kbits, size_t blkbits,
+ size_t ivbits, uint64_t flags, const PROV_CIPHER_HW *hw)
+{
+ PROV_TDES_CTX *tctx = OPENSSL_zalloc(sizeof(*tctx));
+
+ if (tctx != NULL)
+ cipher_generic_initkey(tctx, kbits, blkbits, ivbits, mode, flags, hw,
+ provctx);
+ return tctx;
+}
+
+void tdes_freectx(void *vctx)
+{
+ PROV_TDES_CTX *ctx = (PROV_TDES_CTX *)vctx;
+
+ OPENSSL_clear_free(ctx, sizeof(*ctx));
+}
+
+static int tdes_init(void *vctx, const unsigned char *key, size_t keylen,
+ const unsigned char *iv, size_t ivlen, int enc)
+{
+ PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx;
+
+ ctx->enc = enc;
+
+ if (iv != NULL) {
+ if (!cipher_generic_initiv(ctx, iv, ivlen))
+ return 0;
+ }
+
+ if (key != NULL) {
+ if (keylen != ctx->keylen) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEYLEN);
+ return 0;
+ }
+ return ctx->hw->init(ctx, key, ctx->keylen);
+ }
+ return 1;
+}
+
+int tdes_einit(void *vctx, const unsigned char *key, size_t keylen,
+ const unsigned char *iv, size_t ivlen)
+{
+ return tdes_init(vctx, key, keylen, iv, ivlen, 1);
+}
+
+int tdes_dinit(void *vctx, const unsigned char *key, size_t keylen,
+ const unsigned char *iv, size_t ivlen)
+{
+ return tdes_init(vctx, key, keylen, iv, ivlen, 0);
+}
+
+static int tdes_generatekey(PROV_CIPHER_CTX *ctx, void *ptr)
+{
+
+ DES_cblock *deskey = ptr;
+ size_t kl = ctx->keylen;
+
+ if (kl == 0 || rand_priv_bytes_ex(ctx->libctx, ptr, kl) <= 0)
+ return 0;
+ DES_set_odd_parity(deskey);
+ if (kl >= 16)
+ DES_set_odd_parity(deskey + 1);
+ if (kl >= 24) {
+ DES_set_odd_parity(deskey + 2);
+ return 1;
+ }
+ return 0;
+}
+
+CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_START(tdes)
+ OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_RANDOM_KEY, NULL, 0),
+CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_END(tdes)
+
+int tdes_get_ctx_params(void *vctx, OSSL_PARAM params[])
+{
+ PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx;
+ OSSL_PARAM *p;
+
+ if (!cipher_generic_get_ctx_params(vctx, params))
+ return 0;
+
+ p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_RANDOM_KEY);
+ if (p != NULL && !tdes_generatekey(ctx, p->data)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GENERATE_KEY);
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * TODO(3.0) - ECB mode does not use an IV - but existing test code is setting
+ * an IV. Fixing this could potentially make applications break.
+ */
+
+/* tdes_ede3_ecb_functions */
+IMPLEMENT_tdes_cipher(ede3, EDE3, ecb, ECB, TDES_FLAGS, 64*3, 64, 64, block);
+/* tdes_ede3_cbc_functions */
+IMPLEMENT_tdes_cipher(ede3, EDE3, cbc, CBC, TDES_FLAGS, 64*3, 64, 64, block);
diff --git a/providers/implementations/ciphers/cipher_tdes.h b/providers/implementations/ciphers/cipher_tdes.h
new file mode 100644
index 0000000000..7bb879fb4f
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_tdes.h
@@ -0,0 +1,96 @@
+/*
+ * 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 <openssl/des.h>
+#include <openssl/core_numbers.h>
+
+#define DES_BLOCK_SIZE 8
+#define TDES_IVLEN 8
+
+/* TODO(3.0) Figure out what flags need to be here */
+#define TDES_FLAGS (EVP_CIPH_RAND_KEY)
+
+typedef struct prov_tdes_ctx_st {
+ PROV_CIPHER_CTX base; /* Must be first */
+ union {
+ OSSL_UNION_ALIGN;
+ DES_key_schedule ks[3];
+ } tks;
+ union {
+ void (*cbc) (const void *, void *, size_t,
+ const DES_key_schedule *, unsigned char *);
+ } tstream;
+
+} PROV_TDES_CTX;
+
+#define IMPLEMENT_tdes_cipher(type, UCTYPE, lcmode, UCMODE, flags, \
+ kbits, blkbits, ivbits, block) \
+static OSSL_OP_cipher_newctx_fn tdes_##type##_##lcmode##_newctx; \
+static void *tdes_##type##_##lcmode##_newctx(void *provctx) \
+{ \
+ return tdes_newctx(provctx, EVP_CIPH_##UCMODE##_MODE, kbits, blkbits, \
+ ivbits, flags, PROV_CIPHER_HW_tdes_##type##_##lcmode());\
+} \
+static OSSL_OP_cipher_get_params_fn tdes_##type##_##lcmode##_get_params; \
+static int tdes_##type##_##lcmode##_get_params(OSSL_PARAM params[]) \
+{ \
+ return cipher_generic_get_params(params, EVP_CIPH_##UCMODE##_MODE, flags, \
+ kbits, blkbits, ivbits); \
+} \
+const OSSL_DISPATCH tdes_##type##_##lcmode##_functions[] = { \
+ { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))tdes_einit }, \
+ { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))tdes_dinit }, \
+ { OSSL_FUNC_CIPHER_UPDATE, \
+ (void (*)(void))cipher_generic_##block##_update }, \
+ { OSSL_FUNC_CIPHER_FINAL, (void (*)(void))cipher_generic_##block##_final },\
+ { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))cipher_generic_cipher }, \
+ { OSSL_FUNC_CIPHER_NEWCTX, \
+ (void (*)(void))tdes_##type##_##lcmode##_newctx }, \
+ { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))tdes_freectx }, \
+ { OSSL_FUNC_CIPHER_GET_PARAMS, \
+ (void (*)(void))tdes_##type##_##lcmode##_get_params }, \
+ { OSSL_FUNC_CIPHER_GETTABLE_PARAMS, \
+ (void (*)(void))cipher_generic_gettable_params }, \
+ { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, (void (*)(void))tdes_get_ctx_params }, \
+ { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \
+ (void (*)(void))tdes_gettable_ctx_params }, \
+ { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \
+ (void (*)(void))cipher_generic_set_ctx_params }, \
+ { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \
+ (void (*)(void))cipher_generic_settable_ctx_params }, \
+ { 0, NULL } \
+}
+
+void *tdes_newctx(void *provctx, int mode, size_t kbits, size_t blkbits,
+ size_t ivbits, uint64_t flags, const PROV_CIPHER_HW *hw);
+OSSL_OP_cipher_freectx_fn tdes_freectx;
+OSSL_OP_cipher_encrypt_init_fn tdes_einit;
+OSSL_OP_cipher_decrypt_init_fn tdes_dinit;
+OSSL_OP_cipher_get_ctx_params_fn tdes_get_ctx_params;
+OSSL_OP_cipher_gettable_ctx_params_fn tdes_gettable_ctx_params;
+
+#define PROV_CIPHER_HW_tdes_mode(type, mode) \
+static const PROV_CIPHER_HW type##_##mode = { \
+ cipher_hw_tdes_##type##_initkey, \
+ cipher_hw_tdes_##mode \
+}; \
+const PROV_CIPHER_HW *PROV_CIPHER_HW_tdes_##type##_##mode(void) \
+{ \
+ return &type##_##mode; \
+}
+
+int cipher_hw_tdes_ede3_initkey(PROV_CIPHER_CTX *ctx, const unsigned char *key,
+ size_t keylen);
+int cipher_hw_tdes_cbc(PROV_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, size_t inl);
+int cipher_hw_tdes_ecb(PROV_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, size_t len);
+
+const PROV_CIPHER_HW *PROV_CIPHER_HW_tdes_ede3_cbc(void);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_tdes_ede3_ecb(void);
diff --git a/providers/implementations/ciphers/cipher_tdes_default.c b/providers/implementations/ciphers/cipher_tdes_default.c
new file mode 100644
index 0000000000..73a78e8089
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_tdes_default.c
@@ -0,0 +1,29 @@
+/*
+ * 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 "cipher_tdes_default.h"
+#include "internal/provider_algs.h"
+
+/* tdes_ede3_ofb_functions */
+IMPLEMENT_tdes_cipher(ede3, EDE3, ofb, OFB, TDES_FLAGS, 64*3, 8, 64, stream);
+/* tdes_ede3_cfb_functions */
+IMPLEMENT_tdes_cipher(ede3, EDE3, cfb, CFB, TDES_FLAGS, 64*3, 8, 64, stream);
+/* tdes_ede3_cfb1_functions */
+IMPLEMENT_tdes_cipher(ede3, EDE3, cfb1, CFB, TDES_FLAGS, 64*3, 8, 64, stream);
+/* tdes_ede3_cfb8_functions */
+IMPLEMENT_tdes_cipher(ede3, EDE3, cfb8, CFB, TDES_FLAGS, 64*3, 8, 64, stream);
+
+/* tdes_ede2_ecb_functions */
+IMPLEMENT_tdes_cipher(ede2, EDE2, ecb, ECB, TDES_FLAGS, 64*2, 64, 64, block);
+/* tdes_ede2_cbc_functions */
+IMPLEMENT_tdes_cipher(ede2, EDE2, cbc, CBC, TDES_FLAGS, 64*2, 64, 64, block);
+/* tdes_ede2_ofb_functions */
+IMPLEMENT_tdes_cipher(ede2, EDE2, ofb, OFB, TDES_FLAGS, 64*2, 8, 64, stream);
+/* tdes_ede2_cfb_functions */
+IMPLEMENT_tdes_cipher(ede2, EDE2, cfb, CFB, TDES_FLAGS, 64*2, 8, 64, stream);
diff --git a/providers/implementations/ciphers/cipher_tdes_default.h b/providers/implementations/ciphers/cipher_tdes_default.h
new file mode 100644
index 0000000000..0bc499fc86
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_tdes_default.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright 1995-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 "prov/ciphercommon.h"
+#include "cipher_tdes.h"
+
+const PROV_CIPHER_HW *PROV_CIPHER_HW_tdes_ede3_ofb(void);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_tdes_ede3_cfb(void);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_tdes_ede3_cfb1(void);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_tdes_ede3_cfb8(void);
+
+const PROV_CIPHER_HW *PROV_CIPHER_HW_tdes_ede2_cbc(void);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_tdes_ede2_ecb(void);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_tdes_ede2_ofb(void);
+const PROV_CIPHER_HW *PROV_CIPHER_HW_tdes_ede2_cfb(void);
+
+const PROV_CIPHER_HW *PROV_CIPHER_HW_tdes_desx_cbc(void);
+
+const PROV_CIPHER_HW *PROV_CIPHER_HW_tdes_wrap_cbc(void);
diff --git a/providers/implementations/ciphers/cipher_tdes_default_hw.c b/providers/implementations/ciphers/cipher_tdes_default_hw.c
new file mode 100644
index 0000000000..73169a0e56
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_tdes_default_hw.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright 1995-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 "cipher_tdes_default.h"
+
+#define ks1 tks.ks[0]
+#define ks2 tks.ks[1]
+#define ks3 tks.ks[2]
+
+static int cipher_hw_tdes_ede2_initkey(PROV_CIPHER_CTX *ctx,
+ const unsigned char *key, size_t keylen)
+{
+ PROV_TDES_CTX *tctx = (PROV_TDES_CTX *)ctx;
+ DES_cblock *deskey = (DES_cblock *)key;
+
+ tctx->tstream.cbc = NULL;
+# if defined(SPARC_DES_CAPABLE)
+ if (SPARC_DES_CAPABLE) {
+ if (ctx->mode == EVP_CIPH_CBC_MODE) {
+ des_t4_key_expand(&deskey[0], &tctx->ks1);
+ des_t4_key_expand(&deskey[1], &tctx->ks2);
+ memcpy(&tctx->ks3, &tctx->ks1, sizeof(tctx->ks1));
+ tctx->tstream.cbc = ctx->enc ? des_t4_ede3_cbc_encrypt :
+ des_t4_ede3_cbc_decrypt;
+ return 1;
+ }
+ }
+# endif
+ DES_set_key_unchecked(&deskey[0], &tctx->ks1);
+ DES_set_key_unchecked(&deskey[1], &tctx->ks2);
+ memcpy(&tctx->ks3, &tctx->ks1, sizeof(tctx->ks1));
+ return 1;
+}
+
+static int cipher_hw_tdes_ofb(PROV_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, size_t inl)
+{
+ PROV_TDES_CTX *tctx = (PROV_TDES_CTX *)ctx;
+ int num = ctx->num;
+
+ while (inl >= MAXCHUNK) {
+ DES_ede3_ofb64_encrypt(in, out, (long)MAXCHUNK, &tctx->ks1, &tctx->ks2,
+ &tctx->ks3, (DES_cblock *)ctx->iv, &num);
+ inl -= MAXCHUNK;
+ in += MAXCHUNK;
+ out += MAXCHUNK;
+ }
+ if (inl > 0) {
+ DES_ede3_ofb64_encrypt(in, out, (long)inl, &tctx->ks1, &tctx->ks2,
+ &tctx->ks3, (DES_cblock *)ctx->iv, &num);
+ }
+ ctx->num = num;
+ return 1;
+}
+
+static int cipher_hw_tdes_cfb(PROV_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, size_t inl)
+{
+ PROV_TDES_CTX *tctx = (PROV_TDES_CTX *)ctx;
+ int num = ctx->num;
+
+ while (inl >= MAXCHUNK) {
+
+ DES_ede3_cfb64_encrypt(in, out, (long)MAXCHUNK,
+ &tctx->ks1, &tctx->ks2, &tctx->ks3,
+ (DES_cblock *)ctx->iv, &num, ctx->enc);
+ inl -= MAXCHUNK;
+ in += MAXCHUNK;
+ out += MAXCHUNK;
+ }
+ if (inl > 0) {
+ DES_ede3_cfb64_encrypt(in, out, (long)inl,
+ &tctx->ks1, &tctx->ks2, &tctx->ks3,
+ (DES_cblock *)ctx->iv, &num, ctx->enc);
+ }
+ ctx->num = num;
+ return 1;
+}
+
+/*
+ * Although we have a CFB-r implementation for 3-DES, it doesn't pack the
+ * right way, so wrap it here
+ */
+static int cipher_hw_tdes_cfb1(PROV_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, size_t inl)
+{
+ PROV_TDES_CTX *tctx = (PROV_TDES_CTX *)ctx;
+ size_t n;
+ unsigned char c[1], d[1];
+
+ if ((ctx->flags & EVP_CIPH_FLAG_LENGTH_BITS) == 0)
+ inl *= 8;
+ for (n = 0; n < inl; ++n) {
+ c[0] = (in[n / 8] & (1 << (7 - n % 8))) ? 0x80 : 0;
+ DES_ede3_cfb_encrypt(c, d, 1, 1,
+ &tctx->ks1, &tctx->ks2, &tctx->ks3,
+ (DES_cblock *)ctx->iv, ctx->enc);
+ out[n / 8] = (out[n / 8] & ~(0x80 >> (unsigned int)(n % 8)))
+ | ((d[0] & 0x80) >> (unsigned int)(n % 8));
+ }
+
+ return 1;
+}
+
+static int cipher_hw_tdes_cfb8(PROV_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, size_t inl)
+{
+ PROV_TDES_CTX *tctx = (PROV_TDES_CTX *)ctx;
+
+ while (inl >= MAXCHUNK) {
+ DES_ede3_cfb_encrypt(in, out, 8, (long)MAXCHUNK,
+ &tctx->ks1, &tctx->ks2, &tctx->ks3,
+ (DES_cblock *)ctx->iv, ctx->enc);
+ inl -= MAXCHUNK;
+ in += MAXCHUNK;
+ out += MAXCHUNK;
+ }
+ if (inl > 0)
+ DES_ede3_cfb_encrypt(in, out, 8, (long)inl,
+ &tctx->ks1, &tctx->ks2, &tctx->ks3,
+ (DES_cblock *)ctx->iv, ctx->enc);
+ return 1;
+}
+
+PROV_CIPHER_HW_tdes_mode(ede3, ofb)
+PROV_CIPHER_HW_tdes_mode(ede3, cfb)
+PROV_CIPHER_HW_tdes_mode(ede3, cfb1)
+PROV_CIPHER_HW_tdes_mode(ede3, cfb8)
+
+PROV_CIPHER_HW_tdes_mode(ede2, ecb)
+PROV_CIPHER_HW_tdes_mode(ede2, cbc)
+PROV_CIPHER_HW_tdes_mode(ede2, ofb)
+PROV_CIPHER_HW_tdes_mode(ede2, cfb)
+
diff --git a/providers/implementations/ciphers/cipher_tdes_hw.c b/providers/implementations/ciphers/cipher_tdes_hw.c
new file mode 100644
index 0000000000..208e83df0f
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_tdes_hw.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright 1995-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 "prov/ciphercommon.h"
+#include "cipher_tdes.h"
+
+#define ks1 tks.ks[0]
+#define ks2 tks.ks[1]
+#define ks3 tks.ks[2]
+
+int cipher_hw_tdes_ede3_initkey(PROV_CIPHER_CTX *ctx, const unsigned char *key,
+ size_t keylen)
+{
+ PROV_TDES_CTX *tctx = (PROV_TDES_CTX *)ctx;
+ DES_cblock *deskey = (DES_cblock *)key;
+
+ tctx->tstream.cbc = NULL;
+# if defined(SPARC_DES_CAPABLE)
+ if (SPARC_DES_CAPABLE) {
+ if (ctx->mode == EVP_CIPH_CBC_MODE) {
+ des_t4_key_expand(&deskey[0], &tctx->ks1);
+ des_t4_key_expand(&deskey[1], &tctx->ks2);
+ des_t4_key_expand(&deskey[2], &tctx->ks3);
+ tctx->tstream.cbc = ctx->enc ? des_t4_ede3_cbc_encrypt :
+ des_t4_ede3_cbc_decrypt;
+ return 1;
+ }
+ }
+# endif
+ DES_set_key_unchecked(&deskey[0], &tctx->ks1);
+ DES_set_key_unchecked(&deskey[1], &tctx->ks2);
+ DES_set_key_unchecked(&deskey[2], &tctx->ks3);
+ return 1;
+}
+
+int cipher_hw_tdes_cbc(PROV_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, size_t inl)
+{
+ PROV_TDES_CTX *tctx = (PROV_TDES_CTX *)ctx;
+
+ if (tctx->tstream.cbc != NULL) {
+ (*tctx->tstream.cbc) (in, out, inl, tctx->tks.ks, ctx->iv);
+ return 1;
+ }
+
+ while (inl >= MAXCHUNK) {
+ DES_ede3_cbc_encrypt(in, out, (long)MAXCHUNK, &tctx->ks1, &tctx->ks2,
+ &tctx->ks3, (DES_cblock *)ctx->iv, ctx->enc);
+ inl -= MAXCHUNK;
+ in += MAXCHUNK;
+ out += MAXCHUNK;
+ }
+ if (inl > 0)
+ DES_ede3_cbc_encrypt(in, out, (long)inl, &tctx->ks1, &tctx->ks2,
+ &tctx->ks3, (DES_cblock *)ctx->iv, ctx->enc);
+ return 1;
+}
+
+int cipher_hw_tdes_ecb(PROV_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, size_t len)
+{
+ size_t i;
+ PROV_TDES_CTX *tctx = (PROV_TDES_CTX *)ctx;
+
+ if (len < DES_BLOCK_SIZE)
+ return 1;
+
+ for (i = 0, len -= DES_BLOCK_SIZE; i <= len; i += DES_BLOCK_SIZE) {
+ DES_ecb3_encrypt((const_DES_cblock *)(in + i), (DES_cblock *)(out + i),
+ &tctx->ks1, &tctx->ks2, &tctx->ks3, ctx->enc);
+ }
+ return 1;
+}
+
+PROV_CIPHER_HW_tdes_mode(ede3, ecb)
+PROV_CIPHER_HW_tdes_mode(ede3, cbc)
diff --git a/providers/implementations/ciphers/cipher_tdes_wrap.c b/providers/implementations/ciphers/cipher_tdes_wrap.c
new file mode 100644
index 0000000000..1ee0044489
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_tdes_wrap.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright 1995-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 <openssl/sha.h>
+#include "cipher_tdes_default.h"
+#include "crypto/evp.h"
+#include "crypto/rand.h"
+#include "internal/provider_algs.h"
+#include "internal/providercommonerr.h"
+
+/* TODO (3.0) Figure out what flags are requred */
+#define TDES_WRAP_FLAGS (EVP_CIPH_WRAP_MODE \
+ | EVP_CIPH_CUSTOM_IV \
+ | EVP_CIPH_FLAG_CUSTOM_CIPHER)
+
+
+static OSSL_OP_cipher_update_fn tdes_wrap_update;
+static OSSL_OP_cipher_cipher_fn tdes_wrap_cipher;
+
+static const unsigned char wrap_iv[8] =
+{
+ 0x4a, 0xdd, 0xa2, 0x2c, 0x79, 0xe8, 0x21, 0x05
+};
+
+static int des_ede3_unwrap(PROV_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, size_t inl)
+{
+ unsigned char icv[8], iv[TDES_IVLEN], sha1tmp[SHA_DIGEST_LENGTH];
+ int rv = -1;
+
+ if (inl < 24)
+ return -1;
+ if (out == NULL)
+ return inl - 16;
+
+ memcpy(ctx->iv, wrap_iv, 8);
+ /* Decrypt first block which will end up as icv */
+ ctx->hw->cipher(ctx, icv, in, 8);
+ /* Decrypt central blocks */
+ /*
+ * If decrypting in place move whole output along a block so the next
+ * des_ede_cbc_cipher is in place.
+ */
+ if (out == in) {
+ memmove(out, out + 8, inl - 8);
+ in -= 8;
+ }
+ ctx->hw->cipher(ctx, out, in + 8, inl - 16);
+ /* Decrypt final block which will be IV */
+ ctx->hw->cipher(ctx, iv, in + inl - 8, 8);
+ /* Reverse order of everything */
+ BUF_reverse(icv, NULL, 8);
+ BUF_reverse(out, NULL, inl - 16);
+ BUF_reverse(ctx->iv, iv, 8);
+ /* Decrypt again using new IV */
+ ctx->hw->cipher(ctx, out, out, inl - 16);
+ ctx->hw->cipher(ctx, icv, icv, 8);
+ /* Work out SHA1 hash of first portion */
+ SHA1(out, inl - 16, sha1tmp);
+
+ if (!CRYPTO_memcmp(sha1tmp, icv, 8))
+ rv = inl - 16;
+ OPENSSL_cleanse(icv, 8);
+ OPENSSL_cleanse(sha1tmp, SHA_DIGEST_LENGTH);
+ OPENSSL_cleanse(iv, 8);
+ OPENSSL_cleanse(ctx->iv, sizeof(ctx->iv));
+ if (rv == -1)
+ OPENSSL_cleanse(out, inl - 16);
+
+ return rv;
+}
+
+static int des_ede3_wrap(PROV_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, size_t inl)
+{
+ unsigned char sha1tmp[SHA_DIGEST_LENGTH];
+ size_t ivlen = TDES_IVLEN;
+ size_t icvlen = TDES_IVLEN;
+ size_t len = inl + ivlen + icvlen;
+
+ if (out == NULL)
+ return len;
+
+ /* Copy input to output buffer + 8 so we have space for IV */
+ memmove(out + ivlen, in, inl);
+ /* Work out ICV */
+ SHA1(in, inl, sha1tmp);
+ memcpy(out + inl + ivlen, sha1tmp, icvlen);
+ OPENSSL_cleanse(sha1tmp, SHA_DIGEST_LENGTH);
+ /* Generate random IV */
+ if (rand_bytes_ex(ctx->libctx, ctx->iv, ivlen) <= 0)
+ return 0;
+ memcpy(out, ctx->iv, ivlen);
+ /* Encrypt everything after IV in place */
+ ctx->hw->cipher(ctx, out + ivlen, out + ivlen, inl + ivlen);
+ BUF_reverse(out, NULL, len);
+ memcpy(ctx->iv, wrap_iv, ivlen);
+ ctx->hw->cipher(ctx, out, out, len);
+ return len;
+}
+
+static int tdes_wrap_cipher_internal(PROV_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, size_t inl)
+{
+ /*
+ * Sanity check input length: we typically only wrap keys so EVP_MAXCHUNK
+ * is more than will ever be needed. Also input length must be a multiple
+ * of 8 bits.
+ */
+ if (inl >= EVP_MAXCHUNK || inl % 8)
+ return -1;
+ if (ctx->enc)
+ return des_ede3_wrap(ctx, out, in, inl);
+ else
+ return des_ede3_unwrap(ctx, out, in, inl);
+}
+
+static int tdes_wrap_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;
+ int ret;
+
+ *outl = 0;
+ if (outsize < inl) {
+ PROVerr(0, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
+ return -1;
+ }
+
+ ret = tdes_wrap_cipher_internal(ctx, out, in, inl);
+ if (ret <= 0)
+ return 0;
+
+ *outl = ret;
+ return 1;
+}
+
+static int tdes_wrap_update(void *vctx, unsigned char *out, size_t *outl,
+ size_t outsize, const unsigned char *in,
+ size_t inl)
+{
+ *outl = 0;
+ if (outsize < inl) {
+ PROVerr(0, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
+ return 0;
+ }
+
+ if (!tdes_wrap_cipher(vctx, out, outl, outsize, in, inl)) {
+ PROVerr(0, PROV_R_CIPHER_OPERATION_FAILED);
+ return 0;
+ }
+ return 1;
+}
+
+
+# define IMPLEMENT_WRAP_CIPHER(flags, kbits, blkbits, ivbits) \
+static OSSL_OP_cipher_newctx_fn tdes_wrap_newctx; \
+static void *tdes_wrap_newctx(void *provctx) \
+{ \
+ return tdes_newctx(provctx, EVP_CIPH_WRAP_MODE, kbits, blkbits, ivbits, \
+ flags, PROV_CIPHER_HW_tdes_wrap_cbc()); \
+} \
+static OSSL_OP_cipher_get_params_fn tdes_wrap_get_params; \
+static int tdes_wrap_get_params(OSSL_PARAM params[]) \
+{ \
+ return cipher_generic_get_params(params, EVP_CIPH_WRAP_MODE, flags, \
+ kbits, blkbits, ivbits); \
+} \
+const OSSL_DISPATCH tdes_wrap_cbc_functions[] = \
+{ \
+ { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void)) tdes_einit }, \
+ { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void)) tdes_dinit }, \
+ { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))tdes_wrap_cipher }, \
+ { OSSL_FUNC_CIPHER_NEWCTX, (void (*)(void))tdes_wrap_newctx }, \
+ { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))tdes_freectx }, \
+ { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))tdes_wrap_update }, \
+ { OSSL_FUNC_CIPHER_FINAL, (void (*)(void))cipher_generic_stream_final }, \
+ { OSSL_FUNC_CIPHER_GET_PARAMS, (void (*)(void))tdes_wrap_get_params }, \
+ { OSSL_FUNC_CIPHER_GETTABLE_PARAMS, \
+ (void (*)(void))cipher_generic_gettable_params }, \
+ { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, (void (*)(void))tdes_get_ctx_params }, \
+ { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \
+ (void (*)(void))tdes_gettable_ctx_params }, \
+ { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \
+ (void (*)(void))cipher_generic_set_ctx_params }, \
+ { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \
+ (void (*)(void))cipher_generic_settable_ctx_params }, \
+ { 0, NULL } \
+}
+
+/* tdes_wrap_cbc_functions */
+IMPLEMENT_WRAP_CIPHER(TDES_WRAP_FLAGS, 64*3, 64, 0);
diff --git a/providers/implementations/ciphers/cipher_tdes_wrap_hw.c b/providers/implementations/ciphers/cipher_tdes_wrap_hw.c
new file mode 100644
index 0000000000..09155b6f48
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_tdes_wrap_hw.c
@@ -0,0 +1,14 @@
+/*
+ * Copyright 1995-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 "cipher_tdes_default.h"
+
+#define cipher_hw_tdes_wrap_initkey cipher_hw_tdes_ede3_initkey
+
+PROV_CIPHER_HW_tdes_mode(wrap, cbc)