From c797b2060c4a6bb2d7d9c3c9cb6aa6d4b6ed94c7 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 7 Apr 2020 16:34:52 +0300 Subject: [PATCH 51/87] evp: add support for Magma-ctr-acpkm-omac cipher Add support for AEAD cipher implemented using CTR-ACPKM as block cipher and CMAC as a MAC value. Sponsored by ROSA Linux Signed-off-by: Dmitry Baryshkov --- src/lib/libcrypto/evp/c_all.c | 1 + src/lib/libcrypto/evp/e_magma.c | 175 ++++++++++++++++++++++++++++++++ src/lib/libcrypto/evp/evp.h | 1 + 3 files changed, 177 insertions(+) diff --git a/src/lib/libcrypto/evp/c_all.c b/src/lib/libcrypto/evp/c_all.c index ef95d7d68..90d0f7e20 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_ctr_acpkm_omac()); EVP_add_cipher(EVP_magma_mgm()); EVP_add_cipher(EVP_kuznyechik_ecb()); EVP_add_cipher(EVP_kuznyechik_cbc()); diff --git a/src/lib/libcrypto/evp/e_magma.c b/src/lib/libcrypto/evp/e_magma.c index ae78824eb..ffaeda505 100644 --- a/src/lib/libcrypto/evp/e_magma.c +++ b/src/lib/libcrypto/evp/e_magma.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include "evp_locl.h" #include "modes_lcl.h" @@ -32,6 +34,14 @@ typedef struct { MAGMA_KEY ks; } EVP_MAGMA_CTX; +typedef struct { + MAGMA_KEY ks; + CMAC_CTX *cmac; + int iv_set; + int taglen; + unsigned char tag[8]; +} EVP_MAGMA_CTR_ACPKM_OMAC_CTX; + static int magma_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, const unsigned char *iv, int enc) @@ -172,6 +182,160 @@ magma_ctr_acpkm_get_asn1_params(EVP_CIPHER_CTX *ctx, ASN1_TYPE *params) return gost3412_ctr_acpkm_get_asn1_params(ctx, params, EVP_CIPHER_CTX_iv_length(ctx)); } +static int +magma_ctr_acpkm_omac_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, + const unsigned char *iv, int enc) +{ + EVP_MAGMA_CTR_ACPKM_OMAC_CTX *c = ctx->cipher_data; + unsigned char out[64]; + + c->taglen = -1; + if (iv) { + unsigned int il = EVP_CIPHER_CTX_iv_length(ctx) - 8; + memcpy(ctx->iv, iv, il); + memset(ctx->iv + il, 0, EVP_MAX_IV_LENGTH - il); + memcpy(ctx->oiv, iv + il, 8); + c->iv_set = 1; + ctx->num = 0; + } + + if (!key) + return 1; + + if (!c->iv_set) + return 0; + + if (!KDF_TREE(EVP_streebog256(), NULL, + key, EVP_CIPHER_CTX_key_length(ctx), + "kdf tree", 8, + ctx->oiv, 8, + 1, + out, sizeof(out))) + return 0; + + Magma_set_key(&c->ks, out); + + return CMAC_Init(c->cmac, out + 32, 32, EVP_magma_cbc(), NULL); +} + +static int +magma_ctr_acpkm_omac_cleanup(EVP_CIPHER_CTX *ctx) +{ + EVP_MAGMA_CTR_ACPKM_OMAC_CTX *c = ctx->cipher_data; + + CMAC_CTX_free(c->cmac); + + return 1; +} + +static int +magma_ctr_acpkm_omac_ctl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr) +{ + EVP_MAGMA_CTR_ACPKM_OMAC_CTX *key = EVP_C_DATA(EVP_MAGMA_CTR_ACPKM_OMAC_CTX, ctx); + + switch (type) { + case EVP_CTRL_GOST_SET_MESHING: + key->ks.key_meshing = arg; + return 1; + case EVP_CTRL_INIT: + /* deafult for tests */ + key->ks.key_meshing = 16; + key->iv_set = 0; + key->cmac = CMAC_CTX_new(); + return 1; + case EVP_CTRL_GCM_SET_TAG: + if (arg <= 0 || arg > sizeof(key->tag) || ctx->encrypt) + return 0; + + memcpy(key->tag, ptr, arg); + key->taglen = arg; + return 1; + case EVP_CTRL_GCM_GET_TAG: + if (arg <= 0 || arg > sizeof(key->tag) || !ctx->encrypt || key->taglen < 0) + return 0; + memcpy(ptr, key->tag, arg); + return 1; + default: + return magma_ctl(ctx, type, arg, ptr); + } +} + +static int +magma_ctr_acpkm_omac_final(EVP_CIPHER_CTX *ctx) +{ + EVP_MAGMA_CTR_ACPKM_OMAC_CTX *key = EVP_C_DATA(EVP_MAGMA_CTR_ACPKM_OMAC_CTX, ctx); + unsigned char tmp[EVP_MAX_BLOCK_LENGTH]; + size_t taglen = sizeof(tmp); + + /* Do not reuse IV */ + key->iv_set = 0; + + CMAC_Final(key->cmac, tmp, &taglen); + if (ctx->encrypt) { + CRYPTO_ctr64_encrypt(tmp, key->tag, taglen, &key->ks, ctx->iv, ctx->buf, + &ctx->num, (block64_f)Magma_acpkm_encrypt); + key->taglen = taglen; + } else { + CRYPTO_ctr64_encrypt(tmp, tmp, taglen, &key->ks, ctx->iv, ctx->buf, + &ctx->num, (block64_f)Magma_acpkm_encrypt); + if (key->taglen <= 0 || + key->taglen > taglen || + timingsafe_memcmp(tmp, key->tag, key->taglen)) + return -1; + } + + return 0; +} + +static int +magma_ctr_acpkm_omac_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, + size_t len) +{ + EVP_MAGMA_CTR_ACPKM_OMAC_CTX *key = EVP_C_DATA(EVP_MAGMA_CTR_ACPKM_OMAC_CTX, ctx); + + if (ctx->encrypt) + CMAC_Update(key->cmac, in, len); + + CRYPTO_ctr64_encrypt(in, out, len, &key->ks, ctx->iv, ctx->buf, + &ctx->num, (block64_f)Magma_acpkm_encrypt); + if (!ctx->encrypt) + CMAC_Update(key->cmac, out, len); + + if (!in) + return magma_ctr_acpkm_omac_final(ctx); + + return len; +} + +static int +magma_ctr_acpkm_omac_set_asn1_params(EVP_CIPHER_CTX *ctx, ASN1_TYPE *params) +{ + /* Also set meshing section size here. + * There is no other good place to enable meshing for CMS + */ + EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GOST_SET_MESHING, 8 * 1024, 0); + + return gost3412_ctr_acpkm_set_asn1_params(ctx, params, EVP_CIPHER_CTX_iv_length(ctx) - 8); +} + +static int +magma_ctr_acpkm_omac_get_asn1_params(EVP_CIPHER_CTX *ctx, ASN1_TYPE *params) +{ + int ret; + EVP_MAGMA_CTR_ACPKM_OMAC_CTX *key = EVP_C_DATA(EVP_MAGMA_CTR_ACPKM_OMAC_CTX, ctx); + + /* Also set meshing section size here. + * There is no other good place to enable meshing for CMS + */ + EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GOST_SET_MESHING, 8 * 1024, 0); + + ret = gost3412_ctr_acpkm_get_asn1_params(ctx, params, EVP_CIPHER_CTX_iv_length(ctx) - 8); + if (ret > 0) + key->iv_set = 1; + + return ret; +} + IMPLEMENT_BLOCK_CIPHER(magma, ks, Magma, EVP_MAGMA_CTX, NID_magma, 8, 32, 8, 64, 0, magma_init_key, NULL, EVP_CIPHER_set_asn1_iv, @@ -194,6 +358,17 @@ BLOCK_CIPHER_def1(magma, ctr_acpkm, ctr_acpkm, CTR, EVP_MAGMA_CTX, magma_ctr_acpkm_get_asn1_params, magma_acpkm_ctl) +#define NID_magma_ctr_acpkm_omac NID_id_tc26_cipher_gostr3412_2015_magma_ctracpkm_omac + +BLOCK_CIPHER_def1(magma, ctr_acpkm_omac, ctr_acpkm_omac, CTR, EVP_MAGMA_CTR_ACPKM_OMAC_CTX, + NID_magma, 1, 32, 12, + EVP_CIPH_FLAG_AEAD_CIPHER | EVP_CIPH_CTRL_INIT | EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV |EVP_CIPH_FLAG_CUSTOM_CIPHER, + magma_ctr_acpkm_omac_init_key, + magma_ctr_acpkm_omac_cleanup, + magma_ctr_acpkm_omac_set_asn1_params, + magma_ctr_acpkm_omac_get_asn1_params, + magma_ctr_acpkm_omac_ctl) + #define EVP_AEAD_MAGMA_MGM_TAG_LEN 16 typedef struct { diff --git a/src/lib/libcrypto/evp/evp.h b/src/lib/libcrypto/evp/evp.h index 9c618ddd5..981351d76 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_ctr_acpkm_omac(void); const EVP_CIPHER *EVP_magma_mgm(void); const EVP_CIPHER *EVP_kuznyechik_ecb(void); const EVP_CIPHER *EVP_kuznyechik_cbc(void); -- 2.17.1