From d621042e04e5f28f76720df8491c97f1a4307670 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 8 Apr 2020 18:09:14 +0300 Subject: [PATCH 58/87] evp: support magma kexp15 keywrap algorithm Add support for magma kexp15 key wrapping algorithm (draft-smyshlyaev-tls12-gost-suites, Section 8.2.1). Signed-off-by: Dmitry Baryshkov --- src/lib/libcrypto/evp/c_all.c | 1 + src/lib/libcrypto/evp/e_magma.c | 143 ++++++++++++++++++++++++++++++++ src/lib/libcrypto/evp/evp.h | 1 + 3 files changed, 145 insertions(+) diff --git a/src/lib/libcrypto/evp/c_all.c b/src/lib/libcrypto/evp/c_all.c index 482cc4e06..7afbb933e 100644 --- a/src/lib/libcrypto/evp/c_all.c +++ b/src/lib/libcrypto/evp/c_all.c @@ -236,6 +236,7 @@ OpenSSL_add_all_ciphers_internal(void) 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_kexp15_wrap()); 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 ffaeda505..c9e26deb5 100644 --- a/src/lib/libcrypto/evp/e_magma.c +++ b/src/lib/libcrypto/evp/e_magma.c @@ -42,6 +42,13 @@ typedef struct { unsigned char tag[8]; } EVP_MAGMA_CTR_ACPKM_OMAC_CTX; +typedef struct { + MAGMA_KEY ks; + CMAC_CTX *cmac; + int iv_set; + int key_set; +} EVP_MAGMA_KEXP15_WRAP_CTX; + static int magma_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, const unsigned char *iv, int enc) @@ -336,6 +343,131 @@ magma_ctr_acpkm_omac_get_asn1_params(EVP_CIPHER_CTX *ctx, ASN1_TYPE *params) return ret; } +#define KEXP15_IV_OFFSET 24 +#define KEXP15_MAGMA_IV_PART 4 + +static int +magma_kexp15_wrap_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, + const unsigned char *iv, int enc) +{ + EVP_MAGMA_KEXP15_WRAP_CTX *c = ctx->cipher_data; + + if (iv) { + memset(ctx->iv, 0, sizeof(ctx->iv)); + memcpy(ctx->iv, iv + KEXP15_IV_OFFSET, KEXP15_MAGMA_IV_PART); + c->iv_set = 1; + if (c->key_set) + CMAC_Update(c->cmac, iv, KEXP15_MAGMA_IV_PART); + } + + if (key) { + c->key_set = 1; + const EVP_CIPHER *ciph = EVP_magma_cbc(); + int kl = EVP_CIPHER_key_length(ciph); + + if (!CMAC_Init(c->cmac, key, kl, ciph, NULL)) + return 0; + + if (iv != NULL) + CMAC_Update(c->cmac, iv, KEXP15_MAGMA_IV_PART); + else if (c->iv_set) + CMAC_Update(c->cmac, ctx->iv, KEXP15_MAGMA_IV_PART); + + Magma_set_key(&c->ks, key + 32); + } + + return 1; +} + +static int +magma_kexp15_wrap_cleanup(EVP_CIPHER_CTX *ctx) +{ + EVP_MAGMA_KEXP15_WRAP_CTX *c = ctx->cipher_data; + + CMAC_CTX_free(c->cmac); + c->iv_set = 0; + c->key_set = 0; + + return 1; +} + +static int +magma_kexp15_wrap_ctl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr) +{ + EVP_MAGMA_KEXP15_WRAP_CTX *key = EVP_C_DATA(EVP_MAGMA_KEXP15_WRAP_CTX, ctx); + + switch (type) { + case EVP_CTRL_INIT: + key->cmac = CMAC_CTX_new(); + key->iv_set = 0; + key->key_set = 0; + return 1; + default: + return magma_ctl(ctx, type, arg, ptr); + } +} + +static int +magma_kexp15_wrap_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, + size_t len) +{ + EVP_MAGMA_KEXP15_WRAP_CTX *key = EVP_C_DATA(EVP_MAGMA_KEXP15_WRAP_CTX, ctx); + unsigned char tmp[EVP_MAX_BLOCK_LENGTH]; + size_t taglen = sizeof(tmp); + unsigned int bl = EVP_CIPHER_CTX_block_size(CMAC_CTX_get0_cipher_ctx(key->cmac)); + + if (in == NULL) + return 0; + + if (len % bl != 0) + return -1; + if (ctx->encrypt && len < bl) + return -1; + if (!ctx->encrypt && len < 2 *bl) + return -1; + if (out == NULL) { + if (ctx->encrypt) + return len + bl; + else + return len - bl; + } + + /* Do not reuse IV */ + key->iv_set = 0; + + 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_encrypt); + CMAC_Final(key->cmac, tmp, &taglen); + CRYPTO_ctr64_encrypt(tmp, out + len, taglen, &key->ks, ctx->iv, ctx->buf, + &ctx->num, (block64_f)Magma_encrypt); + return len + taglen; + } else { + CRYPTO_ctr64_encrypt(in, out, len - bl, &key->ks, ctx->iv, ctx->buf, + &ctx->num, (block64_f)Magma_encrypt); + CMAC_Update(key->cmac, out, len - bl); + CMAC_Final(key->cmac, tmp, &taglen); + CRYPTO_ctr64_encrypt(tmp, tmp, taglen, &key->ks, ctx->iv, ctx->buf, + &ctx->num, (block64_f)Magma_encrypt); + return timingsafe_memcmp(in + len - bl, tmp, bl) ? -1 : len - bl; + } +} + +static int +magma_kexp15_wrap_set_asn1_params(EVP_CIPHER_CTX *ctx, ASN1_TYPE *params) +{ + /* FIXME: set key agreement OID, we need to pass it from upper layer */ + return 1; +} + +static int +magma_kexp15_wrap_get_asn1_params(EVP_CIPHER_CTX *ctx, ASN1_TYPE *params) +{ + /* No useful information in ASN.1 params */ + return 1; +} + 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, @@ -369,6 +501,17 @@ BLOCK_CIPHER_def1(magma, ctr_acpkm_omac, ctr_acpkm_omac, CTR, EVP_MAGMA_CTR_ACPK magma_ctr_acpkm_omac_get_asn1_params, magma_ctr_acpkm_omac_ctl) +#define NID_magma_kexp15_wrap NID_id_tc26_wrap_gostr3412_2015_magma_kexp15 + +BLOCK_CIPHER_def1(magma, kexp15_wrap, kexp15_wrap, WRAP, EVP_MAGMA_KEXP15_WRAP_CTX, + NID_magma, 1, 64, 32, + EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER | EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT, + magma_kexp15_wrap_init_key, + magma_kexp15_wrap_cleanup, + magma_kexp15_wrap_set_asn1_params, + magma_kexp15_wrap_get_asn1_params, + magma_kexp15_wrap_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 79ddcebc2..d5b78d8bd 100644 --- a/src/lib/libcrypto/evp/evp.h +++ b/src/lib/libcrypto/evp/evp.h @@ -857,6 +857,7 @@ 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_kexp15_wrap(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