libressl/0051-evp-add-support-for-Magma-ctr-acpkm-omac-cipher.patch
Mikhail Novosyolov faac7d3eaa Add gost-new patches sponsored by ROSA Linux
TODO: add tests
2020-08-05 12:58:06 +03:00

251 lines
7.2 KiB
Diff

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