From 10686e4b5c14cbff10d40e5ae630c0aa35aaa8fe Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 25 Mar 2020 23:44:15 +0300 Subject: [PATCH 49/87] evp: add EVP_CIPHER interface for magma-mgm Signed-off-by: Dmitry Baryshkov --- src/lib/libcrypto/Symbols.list | 1 + src/lib/libcrypto/evp/c_all.c | 1 + src/lib/libcrypto/evp/e_magma.c | 153 ++++++++++++++++++ src/lib/libcrypto/evp/evp.h | 1 + .../lib/libcrypto/evp/evpaeadtests.txt | 3 + 5 files changed, 159 insertions(+) diff --git a/src/lib/libcrypto/Symbols.list b/src/lib/libcrypto/Symbols.list index d19720109..3eda9f3bd 100644 --- a/src/lib/libcrypto/Symbols.list +++ b/src/lib/libcrypto/Symbols.list @@ -1739,6 +1739,7 @@ EVP_magma_cfb64 EVP_magma_ctr EVP_magma_ctr_acpkm EVP_magma_ecb +EVP_magma_mgm EVP_magma_ofb EVP_md4 EVP_md5 diff --git a/src/lib/libcrypto/evp/c_all.c b/src/lib/libcrypto/evp/c_all.c index 586466eb6..6a60624d3 100644 --- a/src/lib/libcrypto/evp/c_all.c +++ b/src/lib/libcrypto/evp/c_all.c @@ -235,6 +235,7 @@ OpenSSL_add_all_ciphers_internal(void) EVP_add_cipher(EVP_magma_ofb()); EVP_add_cipher(EVP_magma_ctr()); EVP_add_cipher(EVP_magma_ctr_acpkm()); + EVP_add_cipher(EVP_magma_mgm()); EVP_add_cipher(EVP_kuznyechik_ecb()); EVP_add_cipher(EVP_kuznyechik_cbc()); EVP_add_cipher(EVP_kuznyechik_cfb128()); diff --git a/src/lib/libcrypto/evp/e_magma.c b/src/lib/libcrypto/evp/e_magma.c index 3d3083b95..ae78824eb 100644 --- a/src/lib/libcrypto/evp/e_magma.c +++ b/src/lib/libcrypto/evp/e_magma.c @@ -196,6 +196,14 @@ BLOCK_CIPHER_def1(magma, ctr_acpkm, ctr_acpkm, CTR, EVP_MAGMA_CTX, #define EVP_AEAD_MAGMA_MGM_TAG_LEN 16 +typedef struct { + MAGMA_KEY ks; /* MAGMA key schedule to use */ + MGM64_CONTEXT mgm; + int key_set; /* Set if key initialised */ + int iv_set; /* Set if an iv is set */ + int tag_len; +} EVP_MAGMA_MGM_CTX; + struct aead_magma_mgm_ctx { MAGMA_KEY ks; MGM64_CONTEXT mgm; @@ -210,6 +218,151 @@ magma_mgm_set_key(MAGMA_KEY *magma_key, MGM64_CONTEXT *mgm_ctx, CRYPTO_mgm64_init(mgm_ctx, magma_key, (block64_f)Magma_encrypt); } +static int +magma_mgm_cleanup(EVP_CIPHER_CTX *c) +{ + EVP_MAGMA_MGM_CTX *gctx = c->cipher_data; + + explicit_bzero(gctx, sizeof(*gctx)); + return 1; +} + +static int +magma_mgm_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr) +{ + EVP_MAGMA_MGM_CTX *gctx = c->cipher_data; + + switch (type) { + case EVP_CTRL_INIT: + gctx->key_set = 0; + gctx->iv_set = 0; + gctx->tag_len = -1; + return 1; + + case EVP_CTRL_MGM_SET_TAG: + if (arg <= 0 || arg > 8 || c->encrypt) + return 0; + memcpy(c->buf, ptr, arg); + gctx->tag_len = arg; + return 1; + + case EVP_CTRL_MGM_GET_TAG: + if (arg <= 0 || arg > 8 || !c->encrypt || gctx->tag_len < 0) + return 0; + memcpy(ptr, c->buf, arg); + return 1; + + case EVP_CTRL_COPY: + { + EVP_CIPHER_CTX *out = ptr; + EVP_MAGMA_MGM_CTX *gctx_out = out->cipher_data; + + if (gctx->mgm.key) { + if (gctx->mgm.key != &gctx->ks) + return 0; + gctx_out->mgm.key = &gctx_out->ks; + } + + return 1; + } + + default: + return -1; + + } +} + +static int +magma_mgm_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, + const unsigned char *iv, int enc) +{ + EVP_MAGMA_MGM_CTX *gctx = ctx->cipher_data; + + if (!iv && !key) + return 1; + if (key) { + magma_mgm_set_key(&gctx->ks, &gctx->mgm, key, ctx->key_len); + + /* If we have an iv can set it directly, otherwise use + * saved IV. + */ + if (gctx->iv_set) + iv = ctx->iv; + if (iv) { + CRYPTO_mgm64_setiv(&gctx->mgm, iv); + gctx->iv_set = 1; + } + gctx->key_set = 1; + } else { + /* If key set use IV, otherwise copy */ + if (gctx->key_set) + CRYPTO_mgm64_setiv(&gctx->mgm, iv); + else + memcpy(ctx->iv, iv, ctx->cipher->iv_len); + gctx->iv_set = 1; + } + return 1; +} + +static int +magma_mgm_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t len) +{ + EVP_MAGMA_MGM_CTX *gctx = ctx->cipher_data; + + /* If not set up, return error */ + if (!gctx->key_set) + return -1; + + if (!gctx->iv_set) + return -1; + + if (in) { + if (out == NULL) { + if (CRYPTO_mgm64_aad(&gctx->mgm, in, len)) + return -1; + } else if (ctx->encrypt) { + if (CRYPTO_mgm64_encrypt(&gctx->mgm, in, out, len)) + return -1; + } else { + if (CRYPTO_mgm64_decrypt(&gctx->mgm, in, out, len)) + return -1; + } + return len; + } else { + if (!ctx->encrypt) { + if (gctx->tag_len < 0) + return -1; + if (CRYPTO_mgm64_finish(&gctx->mgm, ctx->buf, gctx->tag_len) != 0) + return -1; + gctx->iv_set = 0; + return 0; + } + CRYPTO_mgm64_tag(&gctx->mgm, ctx->buf, 8); + gctx->tag_len = 8; + + /* Don't reuse the IV */ + gctx->iv_set = 0; + return 0; + } + +} + +#define CUSTOM_FLAGS \ + ( EVP_CIPH_FLAG_DEFAULT_ASN1 | EVP_CIPH_CUSTOM_IV | \ + EVP_CIPH_FLAG_CUSTOM_CIPHER | EVP_CIPH_ALWAYS_CALL_INIT | \ + EVP_CIPH_CTRL_INIT | EVP_CIPH_CUSTOM_COPY ) + +#define NID_magma_mgm NID_id_tc26_cipher_gostr3412_2015_magma_mgm + +BLOCK_CIPHER_def1(magma, mgm, mgm, GCM, EVP_MAGMA_MGM_CTX, + NID_magma, 1, 32, 8, + EVP_CIPH_FLAG_AEAD_CIPHER|CUSTOM_FLAGS, + magma_mgm_init_key, magma_mgm_cleanup, + EVP_CIPHER_set_asn1_iv, + EVP_CIPHER_get_asn1_iv, + magma_mgm_ctrl) + static int aead_magma_mgm_init(EVP_AEAD_CTX *ctx, const unsigned char *key, size_t key_len, size_t tag_len) diff --git a/src/lib/libcrypto/evp/evp.h b/src/lib/libcrypto/evp/evp.h index 334ce1cd3..50b157525 100644 --- a/src/lib/libcrypto/evp/evp.h +++ b/src/lib/libcrypto/evp/evp.h @@ -856,6 +856,7 @@ const EVP_CIPHER *EVP_magma_cfb64(void); const EVP_CIPHER *EVP_magma_ofb(void); const EVP_CIPHER *EVP_magma_ctr(void); const EVP_CIPHER *EVP_magma_ctr_acpkm(void); +const EVP_CIPHER *EVP_magma_mgm(void); const EVP_CIPHER *EVP_kuznyechik_ecb(void); const EVP_CIPHER *EVP_kuznyechik_cbc(void); const EVP_CIPHER *EVP_kuznyechik_cfb128(void); diff --git a/src/regress/lib/libcrypto/evp/evpaeadtests.txt b/src/regress/lib/libcrypto/evp/evpaeadtests.txt index 69ccd8c17..9c8dd7142 100644 --- a/src/regress/lib/libcrypto/evp/evpaeadtests.txt +++ b/src/regress/lib/libcrypto/evp/evpaeadtests.txt @@ -15,3 +15,6 @@ aes-256-gcm:4C973DBC7364621674F8B5B89E5C15511FCED9216490FB1C1A2CAA0FFE0407E5:7AE kuznyechik-mgm:8899aabbccddeeff0011223344556677fedcba98765432100123456789abcdef:1122334455667700ffeeddccbbaa9988:0202020202020202010101010101010104040404040404040303030303030303ea0505050505050505:1122334455667700ffeeddccbbaa998800112233445566778899aabbcceeff0a112233445566778899aabbcceeff0a002233445566778899aabbcceeff0a0011aabbcc:a9757b8147956e9055b8a33de89f42fc8075d2212bf9fd5bd3f7069aadc16b39497ab15915a6ba85936b5d0ea9f6851cc60c14d4d3f883d0ab94420695c76deb2c7552:cf5d656f40c34f5c46e8bb0e29fcdb4c:1 kuznyechik-mgm:8899aabbccddeeff0011223344556677fedcba98765432100123456789abcdef:1122334455667700ffeeddccbbaa9988:0202020202020202010101010101010104040404040404040303030303030303ea0505050505050505:1122334455667700ffeeddccbbaa998800112233445566778899aabbcceeff0a112233445566778899aabbcceeff0a002233445566778899aabbcceeff0a0011aabbcc:a9757b8147956e9055b8a33de89f42fc8075d2212bf9fd5bd3f7069aadc16b39497ab15915a6ba85936b5d0ea9f6851cc60c14d4d3f883d0ab94420695c76deb2c7552:cf5d656f40c34f5c46e8bb0e29fcdb4c:0 + +magma-mgm:ffeeddccbbaa99887766554433221100f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff:92def06b3c130a59:01010101010101010202020202020202030303030303030304040404040404040505050505050505EA:ffeeddccbbaa998811223344556677008899aabbcceeff0a001122334455667799aabbcceeff0a001122334455667788aabbcceeff0a00112233445566778899aabbcc:c795066c5f9ea03b85113342459185ae1f2e00d6bf2b785d940470b8bb9c8e7d9a5dd3731f7ddc70ec27cb0ace6fa57670f65c646abb75d547aa37c3bcb5c34e03bb9c:a7928069aa10fd10:1 +magma-mgm:ffeeddccbbaa99887766554433221100f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff:92def06b3c130a59:01010101010101010202020202020202030303030303030304040404040404040505050505050505EA:ffeeddccbbaa998811223344556677008899aabbcceeff0a001122334455667799aabbcceeff0a001122334455667788aabbcceeff0a00112233445566778899aabbcc:c795066c5f9ea03b85113342459185ae1f2e00d6bf2b785d940470b8bb9c8e7d9a5dd3731f7ddc70ec27cb0ace6fa57670f65c646abb75d547aa37c3bcb5c34e03bb9c:a7928069aa10fd10:0 -- 2.17.1