mirror of
https://abf.rosa.ru/djam/libressl.git
synced 2025-02-23 16:12:53 +00:00
259 lines
7.8 KiB
Diff
259 lines
7.8 KiB
Diff
![]() |
From bdeea3d404c165fc266a1be7278db3865652b509 Mon Sep 17 00:00:00 2001
|
||
|
From: Dmitry Baryshkov <dbaryshkov@gmail.com>
|
||
|
Date: Wed, 25 Mar 2020 21:56:51 +0300
|
||
|
Subject: [PATCH 45/87] gost: add kuznyechik-mgm support
|
||
|
|
||
|
Add EVP_AEAD interface for supporting kuznyechik cipher in MGM mode.
|
||
|
|
||
|
Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
|
||
|
---
|
||
|
src/lib/libcrypto/Symbols.list | 1 +
|
||
|
src/lib/libcrypto/evp/e_kuznyechik.c | 161 +++++++++++++++++++
|
||
|
src/lib/libcrypto/evp/evp.h | 5 +
|
||
|
src/regress/lib/libcrypto/aead/aeadtest.c | 6 +
|
||
|
src/regress/lib/libcrypto/aead/aeadtests.txt | 9 ++
|
||
|
5 files changed, 182 insertions(+)
|
||
|
|
||
|
diff --git a/src/lib/libcrypto/Symbols.list b/src/lib/libcrypto/Symbols.list
|
||
|
index 287c86d2c..aff725bd4 100644
|
||
|
--- a/src/lib/libcrypto/Symbols.list
|
||
|
+++ b/src/lib/libcrypto/Symbols.list
|
||
|
@@ -1618,6 +1618,7 @@ EVP_add_digest
|
||
|
EVP_aead_aes_128_gcm
|
||
|
EVP_aead_aes_256_gcm
|
||
|
EVP_aead_chacha20_poly1305
|
||
|
+EVP_aead_kuznyechik_mgm
|
||
|
EVP_aead_xchacha20_poly1305
|
||
|
EVP_aes_128_cbc
|
||
|
EVP_aes_128_cbc_hmac_sha1
|
||
|
diff --git a/src/lib/libcrypto/evp/e_kuznyechik.c b/src/lib/libcrypto/evp/e_kuznyechik.c
|
||
|
index 5fd53aff6..88ecef8e5 100644
|
||
|
--- a/src/lib/libcrypto/evp/e_kuznyechik.c
|
||
|
+++ b/src/lib/libcrypto/evp/e_kuznyechik.c
|
||
|
@@ -26,6 +26,7 @@
|
||
|
#include <openssl/modes.h>
|
||
|
#include <openssl/gost.h>
|
||
|
#include "evp_locl.h"
|
||
|
+#include "modes_lcl.h"
|
||
|
|
||
|
typedef struct {
|
||
|
KUZNYECHIK_KEY ks;
|
||
|
@@ -199,4 +200,164 @@ BLOCK_CIPHER_def1(kuznyechik, ctr_acpkm, ctr_acpkm, CTR, EVP_KUZNYECHIK_CTX,
|
||
|
kuznyechik_ctr_acpkm_get_asn1_params,
|
||
|
kuznyechik_acpkm_ctl)
|
||
|
|
||
|
+#define EVP_AEAD_KUZNYECHIK_MGM_TAG_LEN 16
|
||
|
+
|
||
|
+struct aead_kuznyechik_mgm_ctx {
|
||
|
+ KUZNYECHIK_KEY ks;
|
||
|
+ MGM128_CONTEXT mgm;
|
||
|
+ unsigned char tag_len;
|
||
|
+};
|
||
|
+
|
||
|
+static void
|
||
|
+kuznyechik_mgm_set_key(KUZNYECHIK_KEY *kuznyechik_key, MGM128_CONTEXT *mgm_ctx,
|
||
|
+ const unsigned char *key, size_t key_len)
|
||
|
+{
|
||
|
+ Kuznyechik_set_key(kuznyechik_key, key, 1);
|
||
|
+ CRYPTO_mgm128_init(mgm_ctx, kuznyechik_key, (block128_f)Kuznyechik_encrypt);
|
||
|
+}
|
||
|
+
|
||
|
+static int
|
||
|
+aead_kuznyechik_mgm_init(EVP_AEAD_CTX *ctx, const unsigned char *key, size_t key_len,
|
||
|
+ size_t tag_len)
|
||
|
+{
|
||
|
+ struct aead_kuznyechik_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_KUZNYECHIK_MGM_TAG_LEN;
|
||
|
+
|
||
|
+ if (tag_len > EVP_AEAD_KUZNYECHIK_MGM_TAG_LEN) {
|
||
|
+ EVPerror(EVP_R_TAG_TOO_LARGE);
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ if ((mgm_ctx = calloc(1, sizeof(struct aead_kuznyechik_mgm_ctx))) == NULL)
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ kuznyechik_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_kuznyechik_mgm_cleanup(EVP_AEAD_CTX *ctx)
|
||
|
+{
|
||
|
+ struct aead_kuznyechik_mgm_ctx *mgm_ctx = ctx->aead_state;
|
||
|
+
|
||
|
+ freezero(mgm_ctx, sizeof(*mgm_ctx));
|
||
|
+}
|
||
|
+
|
||
|
+static int
|
||
|
+aead_kuznyechik_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_kuznyechik_mgm_ctx *mgm_ctx = ctx->aead_state;
|
||
|
+ MGM128_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 != MGM128_NONCE_LEN) {
|
||
|
+ EVPerror(EVP_R_IV_TOO_LARGE);
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ memcpy(&mgm, &mgm_ctx->mgm, sizeof(mgm));
|
||
|
+ CRYPTO_mgm128_setiv(&mgm, nonce);
|
||
|
+
|
||
|
+ if (ad_len > 0 && CRYPTO_mgm128_aad(&mgm, ad, ad_len))
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ if (CRYPTO_mgm128_encrypt(&mgm, in + bulk, out + bulk,
|
||
|
+ in_len - bulk))
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ CRYPTO_mgm128_tag(&mgm, out + in_len, mgm_ctx->tag_len);
|
||
|
+ *out_len = in_len + mgm_ctx->tag_len;
|
||
|
+
|
||
|
+ return 1;
|
||
|
+}
|
||
|
+
|
||
|
+static int
|
||
|
+aead_kuznyechik_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_kuznyechik_mgm_ctx *mgm_ctx = ctx->aead_state;
|
||
|
+ unsigned char tag[EVP_AEAD_KUZNYECHIK_MGM_TAG_LEN];
|
||
|
+ MGM128_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 != MGM128_NONCE_LEN) {
|
||
|
+ EVPerror(EVP_R_IV_TOO_LARGE);
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ memcpy(&mgm, &mgm_ctx->mgm, sizeof(mgm));
|
||
|
+ CRYPTO_mgm128_setiv(&mgm, nonce);
|
||
|
+
|
||
|
+ if (CRYPTO_mgm128_aad(&mgm, ad, ad_len))
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ if (CRYPTO_mgm128_decrypt(&mgm, in + bulk, out + bulk,
|
||
|
+ in_len - bulk - mgm_ctx->tag_len))
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ CRYPTO_mgm128_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_kuznyechik_mgm = {
|
||
|
+ .key_len = 32,
|
||
|
+ .nonce_len = 16,
|
||
|
+ .overhead = EVP_AEAD_KUZNYECHIK_MGM_TAG_LEN,
|
||
|
+ .max_tag_len = EVP_AEAD_KUZNYECHIK_MGM_TAG_LEN,
|
||
|
+
|
||
|
+ .init = aead_kuznyechik_mgm_init,
|
||
|
+ .cleanup = aead_kuznyechik_mgm_cleanup,
|
||
|
+ .seal = aead_kuznyechik_mgm_seal,
|
||
|
+ .open = aead_kuznyechik_mgm_open,
|
||
|
+};
|
||
|
+
|
||
|
+const EVP_AEAD *
|
||
|
+EVP_aead_kuznyechik_mgm(void)
|
||
|
+{
|
||
|
+ return &aead_kuznyechik_mgm;
|
||
|
+}
|
||
|
+
|
||
|
#endif
|
||
|
diff --git a/src/lib/libcrypto/evp/evp.h b/src/lib/libcrypto/evp/evp.h
|
||
|
index 1ef416041..3725dd17c 100644
|
||
|
--- a/src/lib/libcrypto/evp/evp.h
|
||
|
+++ b/src/lib/libcrypto/evp/evp.h
|
||
|
@@ -1289,6 +1289,11 @@ const EVP_AEAD *EVP_aead_chacha20_poly1305(void);
|
||
|
const EVP_AEAD *EVP_aead_xchacha20_poly1305(void);
|
||
|
#endif
|
||
|
|
||
|
+#if !defined(OPENSSL_NO_GOST)
|
||
|
+/* EVP_aead_kuznyechik_mgm is Kuznyechik in Multilinear Galois Mode. */
|
||
|
+const EVP_AEAD *EVP_aead_kuznyechik_mgm(void);
|
||
|
+#endif
|
||
|
+
|
||
|
/* EVP_AEAD_key_length returns the length of the keys used. */
|
||
|
size_t EVP_AEAD_key_length(const EVP_AEAD *aead);
|
||
|
|
||
|
diff --git a/src/regress/lib/libcrypto/aead/aeadtest.c b/src/regress/lib/libcrypto/aead/aeadtest.c
|
||
|
index 1b144c261..6f843e31c 100644
|
||
|
--- a/src/regress/lib/libcrypto/aead/aeadtest.c
|
||
|
+++ b/src/regress/lib/libcrypto/aead/aeadtest.c
|
||
|
@@ -143,6 +143,12 @@ aead_from_name(const EVP_AEAD **aead, const char *name)
|
||
|
*aead = EVP_aead_xchacha20_poly1305();
|
||
|
#else
|
||
|
fprintf(stderr, "No xchacha20-poly1305 support.\n");
|
||
|
+#endif
|
||
|
+ } else if (strcmp(name, "kuznyechik-mgm") == 0) {
|
||
|
+#ifndef OPENSSL_NO_GOST
|
||
|
+ *aead = EVP_aead_kuznyechik_mgm();
|
||
|
+#else
|
||
|
+ fprintf(stderr, "No kuznyechik-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 4ca47303b..d2d4e54f7 100644
|
||
|
--- a/src/regress/lib/libcrypto/aead/aeadtests.txt
|
||
|
+++ b/src/regress/lib/libcrypto/aead/aeadtests.txt
|
||
|
@@ -84,3 +84,12 @@ AD: 50515253c0c1c2c3c4c5c6c7
|
||
|
CT: bd6d179d3e83d43b9576579493c0e939572a1700252bfaccbed2902c21396cbb731c7f1b0b4aa6440bf3a82f4eda7e39ae64c6708c54c216cb96b72e1213b4522f8c9ba40db5d945b11b69b982c1bb9e3f3fac2bc369488f76b2383565d3fff921f9664c97637da9768812f615c68b13b52e
|
||
|
TAG: c0875924c1c7987947deafd8780acf49
|
||
|
|
||
|
+# draft-smyshlyaev-mgm-17
|
||
|
+AEAD: kuznyechik-mgm
|
||
|
+KEY: 8899aabbccddeeff0011223344556677fedcba98765432100123456789abcdef
|
||
|
+NONCE: 1122334455667700ffeeddccbbaa9988
|
||
|
+IN: 1122334455667700ffeeddccbbaa998800112233445566778899aabbcceeff0a112233445566778899aabbcceeff0a002233445566778899aabbcceeff0a0011aabbcc
|
||
|
+AD: 0202020202020202010101010101010104040404040404040303030303030303ea0505050505050505
|
||
|
+CT: a9757b8147956e9055b8a33de89f42fc8075d2212bf9fd5bd3f7069aadc16b39497ab15915a6ba85936b5d0ea9f6851cc60c14d4d3f883d0ab94420695c76deb2c7552
|
||
|
+TAG: cf5d656f40c34f5c46e8bb0e29fcdb4c
|
||
|
+
|
||
|
--
|
||
|
2.17.1
|
||
|
|