libressl/0050-evp-add-support-for-Kuznyechik-ctr-acpkm-omac-cipher.patch

252 lines
7.4 KiB
Diff
Raw Permalink Normal View History

From f3348e4b61f6cef3c31a7a62ede2dcdcec2c6ab5 Mon Sep 17 00:00:00 2001
From: Dmitry Baryshkov <dbaryshkov@gmail.com>
Date: Tue, 7 Apr 2020 16:34:52 +0300
Subject: [PATCH 50/87] evp: add support for Kuznyechik-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 <dbaryshkov@gmail.com>
---
src/lib/libcrypto/evp/c_all.c | 1 +
src/lib/libcrypto/evp/e_kuznyechik.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 6a60624d3..ef95d7d68 100644
--- a/src/lib/libcrypto/evp/c_all.c
+++ b/src/lib/libcrypto/evp/c_all.c
@@ -242,6 +242,7 @@ OpenSSL_add_all_ciphers_internal(void)
EVP_add_cipher(EVP_kuznyechik_ofb());
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_mgm());
#endif
diff --git a/src/lib/libcrypto/evp/e_kuznyechik.c b/src/lib/libcrypto/evp/e_kuznyechik.c
index d022db39c..c6b09173e 100644
--- a/src/lib/libcrypto/evp/e_kuznyechik.c
+++ b/src/lib/libcrypto/evp/e_kuznyechik.c
@@ -25,6 +25,8 @@
#include <openssl/err.h>
#include <openssl/modes.h>
#include <openssl/gost.h>
+#include <openssl/cmac.h>
+#include <openssl/kdftree.h>
#include "evp_locl.h"
#include "modes_lcl.h"
@@ -32,6 +34,14 @@ typedef struct {
KUZNYECHIK_KEY ks;
} EVP_KUZNYECHIK_CTX;
+typedef struct {
+ KUZNYECHIK_KEY ks;
+ CMAC_CTX *cmac;
+ int iv_set;
+ int taglen;
+ unsigned char tag[16];
+} EVP_KUZNYECHIK_CTR_ACPKM_OMAC_CTX;
+
static int
kuznyechik_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
const unsigned char *iv, int enc)
@@ -178,6 +188,160 @@ kuznyechik_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
+kuznyechik_ctr_acpkm_omac_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
+ const unsigned char *iv, int enc)
+{
+ EVP_KUZNYECHIK_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;
+
+ Kuznyechik_set_key(&c->ks, out, 1);
+
+ return CMAC_Init(c->cmac, out + 32, 32, EVP_kuznyechik_cbc(), NULL);
+}
+
+static int
+kuznyechik_ctr_acpkm_omac_cleanup(EVP_CIPHER_CTX *ctx)
+{
+ EVP_KUZNYECHIK_CTR_ACPKM_OMAC_CTX *c = ctx->cipher_data;
+
+ CMAC_CTX_free(c->cmac);
+
+ return 1;
+}
+
+static int
+kuznyechik_ctr_acpkm_omac_ctl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr)
+{
+ EVP_KUZNYECHIK_CTR_ACPKM_OMAC_CTX *key = EVP_C_DATA(EVP_KUZNYECHIK_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 = 32;
+ 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 kuznyechik_ctl(ctx, type, arg, ptr);
+ }
+}
+
+static int
+kuznyechik_ctr_acpkm_omac_final(EVP_CIPHER_CTX *ctx)
+{
+ EVP_KUZNYECHIK_CTR_ACPKM_OMAC_CTX *key = EVP_C_DATA(EVP_KUZNYECHIK_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_ctr128_encrypt(tmp, key->tag, taglen, &key->ks, ctx->iv, ctx->buf,
+ &ctx->num, (block128_f)Kuznyechik_acpkm_encrypt);
+ key->taglen = taglen;
+ } else {
+ CRYPTO_ctr128_encrypt(tmp, tmp, taglen, &key->ks, ctx->iv, ctx->buf,
+ &ctx->num, (block128_f)Kuznyechik_acpkm_encrypt);
+ if (key->taglen <= 0 ||
+ key->taglen > taglen ||
+ timingsafe_memcmp(tmp, key->tag, key->taglen))
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+kuznyechik_ctr_acpkm_omac_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in,
+ size_t len)
+{
+ EVP_KUZNYECHIK_CTR_ACPKM_OMAC_CTX *key = EVP_C_DATA(EVP_KUZNYECHIK_CTR_ACPKM_OMAC_CTX, ctx);
+
+ 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_acpkm_encrypt);
+ if (!ctx->encrypt)
+ CMAC_Update(key->cmac, out, len);
+
+ if (!in)
+ return kuznyechik_ctr_acpkm_omac_final(ctx);
+
+ return len;
+}
+
+static int
+kuznyechik_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, 256 * 1024, 0);
+
+ return gost3412_ctr_acpkm_set_asn1_params(ctx, params, EVP_CIPHER_CTX_iv_length(ctx) - 8);
+}
+
+static int
+kuznyechik_ctr_acpkm_omac_get_asn1_params(EVP_CIPHER_CTX *ctx, ASN1_TYPE *params)
+{
+ int ret;
+ EVP_KUZNYECHIK_CTR_ACPKM_OMAC_CTX *key = EVP_C_DATA(EVP_KUZNYECHIK_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, 256 * 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(kuznyechik, ks, Kuznyechik, EVP_KUZNYECHIK_CTX,
NID_kuznyechik, 16, 32, 16, 128, 0, kuznyechik_init_key, NULL,
EVP_CIPHER_set_asn1_iv,
@@ -200,6 +364,17 @@ BLOCK_CIPHER_def1(kuznyechik, ctr_acpkm, ctr_acpkm, CTR, EVP_KUZNYECHIK_CTX,
kuznyechik_ctr_acpkm_get_asn1_params,
kuznyechik_acpkm_ctl)
+#define NID_kuznyechik_ctr_acpkm_omac NID_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm_omac
+
+BLOCK_CIPHER_def1(kuznyechik, ctr_acpkm_omac, ctr_acpkm_omac, CTR, EVP_KUZNYECHIK_CTR_ACPKM_OMAC_CTX,
+ NID_kuznyechik, 1, 32, 16,
+ EVP_CIPH_FLAG_AEAD_CIPHER | EVP_CIPH_CTRL_INIT | EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV |EVP_CIPH_FLAG_CUSTOM_CIPHER,
+ kuznyechik_ctr_acpkm_omac_init_key,
+ kuznyechik_ctr_acpkm_omac_cleanup,
+ kuznyechik_ctr_acpkm_omac_set_asn1_params,
+ kuznyechik_ctr_acpkm_omac_get_asn1_params,
+ kuznyechik_ctr_acpkm_omac_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 50b157525..9c618ddd5 100644
--- a/src/lib/libcrypto/evp/evp.h
+++ b/src/lib/libcrypto/evp/evp.h
@@ -863,6 +863,7 @@ const EVP_CIPHER *EVP_kuznyechik_cfb128(void);
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_mgm(void);
#endif
--
2.17.1