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

258 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