libressl/0057-evp-support-kuznyechik-kexp15-keywrap-algorithm.patch
Mikhail Novosyolov faac7d3eaa Add gost-new patches sponsored by ROSA Linux
TODO: add tests
2020-08-05 12:58:06 +03:00

210 lines
6.3 KiB
Diff

From 4d039c645d00d539a40cf52ff3e7e776b8ae792a Mon Sep 17 00:00:00 2001
From: Dmitry Baryshkov <dbaryshkov@gmail.com>
Date: Wed, 8 Apr 2020 18:09:14 +0300
Subject: [PATCH 57/87] evp: support kuznyechik kexp15 keywrap algorithm
Add support for kuznyechik 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_kuznyechik.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 90d0f7e20..482cc4e06 100644
--- a/src/lib/libcrypto/evp/c_all.c
+++ b/src/lib/libcrypto/evp/c_all.c
@@ -244,6 +244,7 @@ OpenSSL_add_all_ciphers_internal(void)
EVP_add_cipher(EVP_kuznyechik_ctr());
EVP_add_cipher(EVP_kuznyechik_ctr_acpkm());
EVP_add_cipher(EVP_kuznyechik_ctr_acpkm_omac());
+ EVP_add_cipher(EVP_kuznyechik_kexp15_wrap());
EVP_add_cipher(EVP_kuznyechik_mgm());
#endif
diff --git a/src/lib/libcrypto/evp/e_kuznyechik.c b/src/lib/libcrypto/evp/e_kuznyechik.c
index c6b09173e..3c2a70aeb 100644
--- a/src/lib/libcrypto/evp/e_kuznyechik.c
+++ b/src/lib/libcrypto/evp/e_kuznyechik.c
@@ -42,6 +42,13 @@ typedef struct {
unsigned char tag[16];
} EVP_KUZNYECHIK_CTR_ACPKM_OMAC_CTX;
+typedef struct {
+ KUZNYECHIK_KEY ks;
+ CMAC_CTX *cmac;
+ int iv_set;
+ int key_set;
+} EVP_KUZNYECHIK_KEXP15_WRAP_CTX;
+
static int
kuznyechik_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
const unsigned char *iv, int enc)
@@ -342,6 +349,131 @@ kuznyechik_ctr_acpkm_omac_get_asn1_params(EVP_CIPHER_CTX *ctx, ASN1_TYPE *params
return ret;
}
+#define KEXP15_IV_OFFSET 24
+#define KEXP15_KUZNYECHIK_IV_PART 8
+
+static int
+kuznyechik_kexp15_wrap_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
+ const unsigned char *iv, int enc)
+{
+ EVP_KUZNYECHIK_KEXP15_WRAP_CTX *c = ctx->cipher_data;
+
+ if (iv) {
+ memset(ctx->iv, 0, sizeof(ctx->iv));
+ memcpy(ctx->iv, iv + KEXP15_IV_OFFSET, KEXP15_KUZNYECHIK_IV_PART);
+ c->iv_set = 1;
+ if (c->key_set)
+ CMAC_Update(c->cmac, iv, KEXP15_KUZNYECHIK_IV_PART);
+ }
+
+ if (key) {
+ c->key_set = 1;
+ const EVP_CIPHER *ciph = EVP_kuznyechik_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_KUZNYECHIK_IV_PART);
+ else if (c->iv_set)
+ CMAC_Update(c->cmac, ctx->iv, KEXP15_KUZNYECHIK_IV_PART);
+
+ Kuznyechik_set_key(&c->ks, key + kl, 1);
+ }
+
+ return 1;
+}
+
+static int
+kuznyechik_kexp15_wrap_cleanup(EVP_CIPHER_CTX *ctx)
+{
+ EVP_KUZNYECHIK_KEXP15_WRAP_CTX *c = ctx->cipher_data;
+
+ CMAC_CTX_free(c->cmac);
+ c->iv_set = 0;
+ c->key_set = 0;
+
+ return 1;
+}
+
+static int
+kuznyechik_kexp15_wrap_ctl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr)
+{
+ EVP_KUZNYECHIK_KEXP15_WRAP_CTX *key = EVP_C_DATA(EVP_KUZNYECHIK_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 kuznyechik_ctl(ctx, type, arg, ptr);
+ }
+}
+
+static int
+kuznyechik_kexp15_wrap_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in,
+ size_t len)
+{
+ EVP_KUZNYECHIK_KEXP15_WRAP_CTX *key = EVP_C_DATA(EVP_KUZNYECHIK_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_ctr128_encrypt(in, out, len, &key->ks, ctx->iv, ctx->buf,
+ &ctx->num, (block128_f)Kuznyechik_encrypt);
+ CMAC_Final(key->cmac, tmp, &taglen);
+ CRYPTO_ctr128_encrypt(tmp, out + len, taglen, &key->ks, ctx->iv, ctx->buf,
+ &ctx->num, (block128_f)Kuznyechik_encrypt);
+ return len + taglen;
+ } else {
+ CRYPTO_ctr128_encrypt(in, out, len - bl, &key->ks, ctx->iv, ctx->buf,
+ &ctx->num, (block128_f)Kuznyechik_encrypt);
+ CMAC_Update(key->cmac, out, len - bl);
+ CMAC_Final(key->cmac, tmp, &taglen);
+ CRYPTO_ctr128_encrypt(tmp, tmp, taglen, &key->ks, ctx->iv, ctx->buf,
+ &ctx->num, (block128_f)Kuznyechik_encrypt);
+ return timingsafe_memcmp(in + len - bl, tmp, bl) ? -1 : len - bl;
+ }
+}
+
+static int
+kuznyechik_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
+kuznyechik_kexp15_wrap_get_asn1_params(EVP_CIPHER_CTX *ctx, ASN1_TYPE *params)
+{
+ /* No useful information in ASN.1 params */
+ return 1;
+}
+
IMPLEMENT_BLOCK_CIPHER(kuznyechik, ks, Kuznyechik, EVP_KUZNYECHIK_CTX,
NID_kuznyechik, 16, 32, 16, 128, 0, kuznyechik_init_key, NULL,
EVP_CIPHER_set_asn1_iv,
@@ -375,6 +507,17 @@ BLOCK_CIPHER_def1(kuznyechik, ctr_acpkm_omac, ctr_acpkm_omac, CTR, EVP_KUZNYECHI
kuznyechik_ctr_acpkm_omac_get_asn1_params,
kuznyechik_ctr_acpkm_omac_ctl)
+#define NID_kuznyechik_kexp15_wrap NID_id_tc26_wrap_gostr3412_2015_kuznyechik_kexp15
+
+BLOCK_CIPHER_def1(kuznyechik, kexp15_wrap, kexp15_wrap, WRAP, EVP_KUZNYECHIK_KEXP15_WRAP_CTX,
+ NID_kuznyechik, 1, 64, 32,
+ EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER | EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT,
+ kuznyechik_kexp15_wrap_init_key,
+ kuznyechik_kexp15_wrap_cleanup,
+ kuznyechik_kexp15_wrap_set_asn1_params,
+ kuznyechik_kexp15_wrap_get_asn1_params,
+ kuznyechik_kexp15_wrap_ctl)
+
#define EVP_AEAD_KUZNYECHIK_MGM_TAG_LEN 16
typedef struct {
diff --git a/src/lib/libcrypto/evp/evp.h b/src/lib/libcrypto/evp/evp.h
index 48c7e7360..79ddcebc2 100644
--- a/src/lib/libcrypto/evp/evp.h
+++ b/src/lib/libcrypto/evp/evp.h
@@ -865,6 +865,7 @@ const EVP_CIPHER *EVP_kuznyechik_ofb(void);
const EVP_CIPHER *EVP_kuznyechik_ctr(void);
const EVP_CIPHER *EVP_kuznyechik_ctr_acpkm(void);
const EVP_CIPHER *EVP_kuznyechik_ctr_acpkm_omac(void);
+const EVP_CIPHER *EVP_kuznyechik_kexp15_wrap(void);
const EVP_CIPHER *EVP_kuznyechik_mgm(void);
#endif
--
2.17.1