From 58d19972ccd8d8857633a578a3cfb10e6ae10d26 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov 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 --- 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 #include #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