libressl/0046-gost-add-magma-mgm-support.patch

255 lines
7.5 KiB
Diff
Raw Permalink Normal View History

From 58d19972ccd8d8857633a578a3cfb10e6ae10d26 Mon Sep 17 00:00:00 2001
From: Dmitry Baryshkov <dbaryshkov@gmail.com>
Date: Wed, 25 Mar 2020 21:56:51 +0300
Subject: [PATCH 46/87] gost: add magma-mgm support
Add EVP_AEAD interface for supporting magma cipher in MGM mode.
Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
---
src/lib/libcrypto/Symbols.list | 1 +
src/lib/libcrypto/evp/e_magma.c | 160 +++++++++++++++++++
src/lib/libcrypto/evp/evp.h | 2 +
src/regress/lib/libcrypto/aead/aeadtest.c | 6 +
src/regress/lib/libcrypto/aead/aeadtests.txt | 9 ++
5 files changed, 178 insertions(+)
diff --git a/src/lib/libcrypto/Symbols.list b/src/lib/libcrypto/Symbols.list
index aff725bd4..56169f990 100644
--- a/src/lib/libcrypto/Symbols.list
+++ b/src/lib/libcrypto/Symbols.list
@@ -1619,6 +1619,7 @@ EVP_aead_aes_128_gcm
EVP_aead_aes_256_gcm
EVP_aead_chacha20_poly1305
EVP_aead_kuznyechik_mgm
+EVP_aead_magma_mgm
EVP_aead_xchacha20_poly1305
EVP_aes_128_cbc
EVP_aes_128_cbc_hmac_sha1
diff --git a/src/lib/libcrypto/evp/e_magma.c b/src/lib/libcrypto/evp/e_magma.c
index 0311e04b1..3d3083b95 100644
--- a/src/lib/libcrypto/evp/e_magma.c
+++ b/src/lib/libcrypto/evp/e_magma.c
@@ -26,6 +26,7 @@
#include <openssl/modes.h>
#include <openssl/gost.h>
#include "evp_locl.h"
+#include "modes_lcl.h"
typedef struct {
MAGMA_KEY ks;
@@ -193,4 +194,163 @@ BLOCK_CIPHER_def1(magma, ctr_acpkm, ctr_acpkm, CTR, EVP_MAGMA_CTX,
magma_ctr_acpkm_get_asn1_params,
magma_acpkm_ctl)
+#define EVP_AEAD_MAGMA_MGM_TAG_LEN 16
+
+struct aead_magma_mgm_ctx {
+ MAGMA_KEY ks;
+ MGM64_CONTEXT mgm;
+ unsigned char tag_len;
+};
+
+static void
+magma_mgm_set_key(MAGMA_KEY *magma_key, MGM64_CONTEXT *mgm_ctx,
+ const unsigned char *key, size_t key_len)
+{
+ Magma_set_key(magma_key, key);
+ CRYPTO_mgm64_init(mgm_ctx, magma_key, (block64_f)Magma_encrypt);
+}
+
+static int
+aead_magma_mgm_init(EVP_AEAD_CTX *ctx, const unsigned char *key, size_t key_len,
+ size_t tag_len)
+{
+ struct aead_magma_mgm_ctx *mgm_ctx;
+ const size_t key_bits = key_len * 8;
+
+ /* EVP_AEAD_CTX_init should catch this. */
+ if (key_bits != 256) {
+ EVPerror(EVP_R_BAD_KEY_LENGTH);
+ return 0;
+ }
+
+ if (tag_len == EVP_AEAD_DEFAULT_TAG_LENGTH)
+ tag_len = EVP_AEAD_MAGMA_MGM_TAG_LEN;
+
+ if (tag_len > EVP_AEAD_MAGMA_MGM_TAG_LEN) {
+ EVPerror(EVP_R_TAG_TOO_LARGE);
+ return 0;
+ }
+
+ if ((mgm_ctx = calloc(1, sizeof(struct aead_magma_mgm_ctx))) == NULL)
+ return 0;
+
+ magma_mgm_set_key(&mgm_ctx->ks, &mgm_ctx->mgm, key, key_len);
+
+ mgm_ctx->tag_len = tag_len;
+ ctx->aead_state = mgm_ctx;
+
+ return 1;
+}
+
+static void
+aead_magma_mgm_cleanup(EVP_AEAD_CTX *ctx)
+{
+ struct aead_magma_mgm_ctx *mgm_ctx = ctx->aead_state;
+
+ freezero(mgm_ctx, sizeof(*mgm_ctx));
+}
+
+static int
+aead_magma_mgm_seal(const EVP_AEAD_CTX *ctx, unsigned char *out, size_t *out_len,
+ size_t max_out_len, const unsigned char *nonce, size_t nonce_len,
+ const unsigned char *in, size_t in_len, const unsigned char *ad,
+ size_t ad_len)
+{
+ const struct aead_magma_mgm_ctx *mgm_ctx = ctx->aead_state;
+ MGM64_CONTEXT mgm;
+ size_t bulk = 0;
+
+ if (max_out_len < in_len + mgm_ctx->tag_len) {
+ EVPerror(EVP_R_BUFFER_TOO_SMALL);
+ return 0;
+ }
+
+ if (nonce_len != MGM64_NONCE_LEN) {
+ EVPerror(EVP_R_IV_TOO_LARGE);
+ return 0;
+ }
+
+ memcpy(&mgm, &mgm_ctx->mgm, sizeof(mgm));
+ CRYPTO_mgm64_setiv(&mgm, nonce);
+
+ if (ad_len > 0 && CRYPTO_mgm64_aad(&mgm, ad, ad_len))
+ return 0;
+
+ if (CRYPTO_mgm64_encrypt(&mgm, in + bulk, out + bulk,
+ in_len - bulk))
+ return 0;
+
+ CRYPTO_mgm64_tag(&mgm, out + in_len, mgm_ctx->tag_len);
+ *out_len = in_len + mgm_ctx->tag_len;
+
+ return 1;
+}
+
+static int
+aead_magma_mgm_open(const EVP_AEAD_CTX *ctx, unsigned char *out, size_t *out_len,
+ size_t max_out_len, const unsigned char *nonce, size_t nonce_len,
+ const unsigned char *in, size_t in_len, const unsigned char *ad,
+ size_t ad_len)
+{
+ const struct aead_magma_mgm_ctx *mgm_ctx = ctx->aead_state;
+ unsigned char tag[EVP_AEAD_MAGMA_MGM_TAG_LEN];
+ MGM64_CONTEXT mgm;
+ size_t plaintext_len;
+ size_t bulk = 0;
+
+ if (in_len < mgm_ctx->tag_len) {
+ EVPerror(EVP_R_BAD_DECRYPT);
+ return 0;
+ }
+
+ plaintext_len = in_len - mgm_ctx->tag_len;
+
+ if (max_out_len < plaintext_len) {
+ EVPerror(EVP_R_BUFFER_TOO_SMALL);
+ return 0;
+ }
+
+ if (nonce_len != MGM64_NONCE_LEN) {
+ EVPerror(EVP_R_IV_TOO_LARGE);
+ return 0;
+ }
+
+ memcpy(&mgm, &mgm_ctx->mgm, sizeof(mgm));
+ CRYPTO_mgm64_setiv(&mgm, nonce);
+
+ if (CRYPTO_mgm64_aad(&mgm, ad, ad_len))
+ return 0;
+
+ if (CRYPTO_mgm64_decrypt(&mgm, in + bulk, out + bulk,
+ in_len - bulk - mgm_ctx->tag_len))
+ return 0;
+
+ CRYPTO_mgm64_tag(&mgm, tag, mgm_ctx->tag_len);
+ if (timingsafe_memcmp(tag, in + plaintext_len, mgm_ctx->tag_len) != 0) {
+ EVPerror(EVP_R_BAD_DECRYPT);
+ return 0;
+ }
+
+ *out_len = plaintext_len;
+
+ return 1;
+}
+
+static const EVP_AEAD aead_magma_mgm = {
+ .key_len = 32,
+ .nonce_len = 8,
+ .overhead = EVP_AEAD_MAGMA_MGM_TAG_LEN,
+ .max_tag_len = EVP_AEAD_MAGMA_MGM_TAG_LEN,
+
+ .init = aead_magma_mgm_init,
+ .cleanup = aead_magma_mgm_cleanup,
+ .seal = aead_magma_mgm_seal,
+ .open = aead_magma_mgm_open,
+};
+
+const EVP_AEAD *
+EVP_aead_magma_mgm(void)
+{
+ return &aead_magma_mgm;
+}
#endif
diff --git a/src/lib/libcrypto/evp/evp.h b/src/lib/libcrypto/evp/evp.h
index 3725dd17c..88d9b1989 100644
--- a/src/lib/libcrypto/evp/evp.h
+++ b/src/lib/libcrypto/evp/evp.h
@@ -1292,6 +1292,8 @@ const EVP_AEAD *EVP_aead_xchacha20_poly1305(void);
#if !defined(OPENSSL_NO_GOST)
/* EVP_aead_kuznyechik_mgm is Kuznyechik in Multilinear Galois Mode. */
const EVP_AEAD *EVP_aead_kuznyechik_mgm(void);
+/* EVP_aead_magma_mgm is Magma in Multilinear Galois Mode. */
+const EVP_AEAD *EVP_aead_magma_mgm(void);
#endif
/* EVP_AEAD_key_length returns the length of the keys used. */
diff --git a/src/regress/lib/libcrypto/aead/aeadtest.c b/src/regress/lib/libcrypto/aead/aeadtest.c
index 6f843e31c..37244931f 100644
--- a/src/regress/lib/libcrypto/aead/aeadtest.c
+++ b/src/regress/lib/libcrypto/aead/aeadtest.c
@@ -149,6 +149,12 @@ aead_from_name(const EVP_AEAD **aead, const char *name)
*aead = EVP_aead_kuznyechik_mgm();
#else
fprintf(stderr, "No kuznyechik-MGM support.\n");
+#endif
+ } else if (strcmp(name, "magma-mgm") == 0) {
+#ifndef OPENSSL_NO_GOST
+ *aead = EVP_aead_magma_mgm();
+#else
+ fprintf(stderr, "No magma-MGM support.\n");
#endif
} else {
fprintf(stderr, "Unknown AEAD: %s\n", name);
diff --git a/src/regress/lib/libcrypto/aead/aeadtests.txt b/src/regress/lib/libcrypto/aead/aeadtests.txt
index d2d4e54f7..86f5dac7e 100644
--- a/src/regress/lib/libcrypto/aead/aeadtests.txt
+++ b/src/regress/lib/libcrypto/aead/aeadtests.txt
@@ -93,3 +93,12 @@ AD: 0202020202020202010101010101010104040404040404040303030303030303ea0505050505
CT: a9757b8147956e9055b8a33de89f42fc8075d2212bf9fd5bd3f7069aadc16b39497ab15915a6ba85936b5d0ea9f6851cc60c14d4d3f883d0ab94420695c76deb2c7552
TAG: cf5d656f40c34f5c46e8bb0e29fcdb4c
+# Not defined in a draft, only in original R 1323565.1.026-2019
+AEAD: magma-mgm
+KEY: ffeeddccbbaa99887766554433221100f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff
+NONCE: 92def06b3c130a59
+IN: ffeeddccbbaa998811223344556677008899aabbcceeff0a001122334455667799aabbcceeff0a001122334455667788aabbcceeff0a00112233445566778899aabbcc
+AD: 01010101010101010202020202020202030303030303030304040404040404040505050505050505EA
+CT: c795066c5f9ea03b85113342459185ae1f2e00d6bf2b785d940470b8bb9c8e7d9a5dd3731f7ddc70ec27cb0ace6fa57670f65c646abb75d547aa37c3bcb5c34e03bb9c
+TAG: a7928069aa10fd10
+
--
2.17.1