libressl/0058-evp-support-magma-kexp15-keywrap-algorithm.patch

211 lines
6.1 KiB
Diff
Raw Permalink Normal View History

From d621042e04e5f28f76720df8491c97f1a4307670 Mon Sep 17 00:00:00 2001
From: Dmitry Baryshkov <dbaryshkov@gmail.com>
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 <dbaryshkov@gmail.com>
---
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