libressl/0043-modes-add-support-for-128-bit-MGM-mode.patch
Mikhail Novosyolov faac7d3eaa Add gost-new patches sponsored by ROSA Linux
TODO: add tests
2020-08-05 12:58:06 +03:00

380 lines
9.7 KiB
Diff

From cecf218cb638ba4776bce1f702e9ffe2c2e2db12 Mon Sep 17 00:00:00 2001
From: Dmitry Baryshkov <dbaryshkov@gmail.com>
Date: Wed, 25 Mar 2020 21:54:20 +0300
Subject: [PATCH 43/87] modes: add support for 128-bit MGM mode
Add support for 128-bit MGM (Multilinear Galois Mode) defined in
draft-smyshlyaev-mgm.
Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
---
src/lib/libcrypto/modes/mgm128.c | 308 ++++++++++++++++++++++++++++
src/lib/libcrypto/modes/modes.h | 16 ++
src/lib/libcrypto/modes/modes_lcl.h | 11 +
3 files changed, 335 insertions(+)
create mode 100644 src/lib/libcrypto/modes/mgm128.c
diff --git a/src/lib/libcrypto/modes/mgm128.c b/src/lib/libcrypto/modes/mgm128.c
new file mode 100644
index 000000000..dbd18b0a8
--- /dev/null
+++ b/src/lib/libcrypto/modes/mgm128.c
@@ -0,0 +1,308 @@
+/* $OpenBSD: mgm128.c,v 1.22 2018/01/24 23:03:37 kettenis Exp $ */
+/*
+ * Copyright (c) 2020 Dmitry Baryshkov <dbaryshkov@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <string.h>
+#include <machine/endian.h>
+
+#include <openssl/crypto.h>
+#include "modes_lcl.h"
+
+#define MGM128_BLOCK_SIZE 16
+#define MGM128_POLYNOMIAL U64(0x87)
+
+static void
+mgm128_gf_shift (u64 r[2], const u64 x[2])
+{
+ long mask;
+
+ /* Shift uses big-endian representation. */
+#if BYTE_ORDER != LITTLE_ENDIAN
+ mask = - ((x[0] >> 63) & 1);
+ r[0] = (x[0] << 1) | (x[1] >> 63);
+ r[1] = (x[1] << 1) ^ (mask & (MGM128_POLYNOMIAL));
+#else /* ! WORDS_BIGENDIAN */
+#define RSHIFT_WORD(x) \
+ ((((x) & UINT64_C(0x7f7f7f7f7f7f7f7f)) << 1) \
+ | (((x) & UINT64_C(0x8080808080808000)) >> 15))
+ mask = - ((x[0] >> 7) & 1);
+ r[0] = RSHIFT_WORD(x[0]) | ((x[1] & 0x80) << 49);
+ r[1] = RSHIFT_WORD(x[1]) ^ (mask & (MGM128_POLYNOMIAL << 56));
+# undef RSHIFT_WORD
+#endif /* ! WORDS_BIGENDIAN */
+}
+
+static void
+mgm128_gf_mul_sum(MGM128_CONTEXT *ctx, u64 *x, const uint8_t *y)
+{
+ u64 V[2], Z[2];
+ unsigned i;
+
+ memcpy(V, x, sizeof(V));
+ memset(Z, 0, sizeof(Z));
+
+ for (i = 0; i < MGM128_BLOCK_SIZE; i++)
+ {
+ uint8_t b = y[MGM128_BLOCK_SIZE - i - 1];
+ unsigned j;
+ for (j = 0; j < 8; j++, b >>= 1)
+ {
+ if (b & 1) {
+ Z[0] ^= V[0];
+ Z[1] ^= V[1];
+ }
+
+ mgm128_gf_shift(V, V);
+ }
+ }
+
+ ctx->sum[0] ^= Z[0];
+ ctx->sum[1] ^= Z[1];
+}
+
+static inline void mgm128_inc(unsigned char *counter, u32 n)
+{
+ u8 c;
+
+ do {
+ --n;
+ c = counter[n];
+ ++c;
+ counter[n] = c;
+ if (c) return;
+ } while (n);
+}
+
+void mgm128_hash_block(MGM128_CONTEXT *ctx, const u8 *data)
+{
+ union {u64 u[2]; u8 c[MGM128_BLOCK_SIZE]; } tmp;
+
+ (*ctx->block)(ctx->z, tmp.c, ctx->key);
+ mgm128_gf_mul_sum(ctx, tmp.u, data);
+ mgm128_inc(ctx->z, MGM128_BLOCK_SIZE / 2);
+}
+
+void CRYPTO_mgm128_init(MGM128_CONTEXT *ctx, void *key, block128_f block)
+{
+ memset(ctx,0,sizeof(*ctx));
+ ctx->block = block;
+ ctx->key = key;
+}
+
+void CRYPTO_mgm128_setiv(MGM128_CONTEXT *ctx, const unsigned char *iv)
+{
+ memcpy(ctx->y, iv, MGM128_NONCE_LEN);
+ memcpy(ctx->z, iv, MGM128_NONCE_LEN);
+
+ ctx->y[0] &= 0x7f;
+ ctx->z[0] |= 0x80;
+
+ (*ctx->block)(ctx->y, ctx->y, ctx->key);
+ (*ctx->block)(ctx->z, ctx->z, ctx->key);
+
+ memset(ctx->sum, 0, MGM128_BLOCK_SIZE);
+ memset(ctx->len, 0, MGM128_BLOCK_SIZE);
+}
+
+int CRYPTO_mgm128_aad(MGM128_CONTEXT *ctx, const unsigned char *aad,
+ size_t len)
+{
+ unsigned int n;
+
+ if (ctx->len[1])
+ return -2;
+
+ ctx->len[0] += len * 8;
+
+ n = ctx->a_remain;
+ if (n) {
+ while (n && len) {
+ ctx->part[n] = *(aad++);
+ --len;
+ n = (n + 1) % MGM128_BLOCK_SIZE;
+ }
+ if (n == 0) {
+ mgm128_hash_block(ctx, ctx->part);
+ } else {
+ ctx->a_remain = n;
+ return 0;
+ }
+ }
+
+ while (len >= MGM128_BLOCK_SIZE) {
+ mgm128_hash_block(ctx, aad);
+ aad += MGM128_BLOCK_SIZE;
+ len -= MGM128_BLOCK_SIZE;
+ }
+
+ if (len)
+ memcpy(ctx->part, aad, len);
+
+ ctx->a_remain = len;
+ return 0;
+}
+
+int CRYPTO_mgm128_encrypt(MGM128_CONTEXT *ctx,
+ const unsigned char *in, unsigned char *out,
+ size_t len)
+{
+ unsigned int n;
+
+ /* Handle AAD remainder */
+ if (ctx->a_remain) {
+ memset(ctx->part + ctx->a_remain, 0, MGM128_BLOCK_SIZE - ctx->a_remain);
+ mgm128_hash_block(ctx, ctx->part);
+ ctx->a_remain = 0;
+ }
+
+ ctx->len[1] += len * 8;
+
+ n = ctx->d_remain;
+ if (n) {
+ while (n && len) {
+ ctx->part[n] ^= *(in++);
+ *(out++) = ctx->part[n];
+ --len;
+ n = (n + 1) % MGM128_BLOCK_SIZE;
+ }
+ if (n == 0) {
+ mgm128_hash_block(ctx, ctx->part);
+ } else {
+ ctx->d_remain = n;
+ return 0;
+ }
+ }
+
+ while (len >= MGM128_BLOCK_SIZE) {
+ (*ctx->block)(ctx->y, ctx->part, ctx->key);
+ mgm128_inc(ctx->y + MGM128_BLOCK_SIZE / 2, MGM128_BLOCK_SIZE / 2);
+ for (n = 0; n < MGM128_BLOCK_SIZE; n++) {
+ out[n] = ctx->part[n] ^ in[n];
+ }
+ mgm128_hash_block(ctx, out);
+ in += MGM128_BLOCK_SIZE;
+ out += MGM128_BLOCK_SIZE;
+ len -= MGM128_BLOCK_SIZE;
+ }
+
+ if (len) {
+ (*ctx->block)(ctx->y, ctx->part, ctx->key);
+ mgm128_inc(ctx->y + MGM128_BLOCK_SIZE / 2, MGM128_BLOCK_SIZE / 2);
+ for (n = 0; n < len; n++) {
+ ctx->part[n] ^= *(in++);
+ *(out++) = ctx->part[n];
+ }
+ }
+
+ ctx->d_remain = len;
+
+ return 0;
+}
+
+int CRYPTO_mgm128_decrypt(MGM128_CONTEXT *ctx,
+ const unsigned char *in, unsigned char *out,
+ size_t len)
+{
+ unsigned int n;
+
+ /* Handle AAD remainder */
+ if (ctx->a_remain) {
+ memset(ctx->part + ctx->a_remain, 0, MGM128_BLOCK_SIZE - ctx->a_remain);
+ mgm128_hash_block(ctx, ctx->part);
+ ctx->a_remain = 0;
+ }
+
+ ctx->len[1] += len * 8;
+
+ n = ctx->d_remain;
+ if (n) {
+ while (n && len) {
+ u8 tmp = *(in++);
+ *(out++) = ctx->part[n] ^ tmp;
+ ctx->part[n] = tmp;
+ n = (n + 1) % MGM128_BLOCK_SIZE;
+ }
+ if (n == 0) {
+ mgm128_hash_block(ctx, ctx->part);
+ } else {
+ ctx->d_remain = n;
+ return 0;
+ }
+ }
+
+ while (len >= MGM128_BLOCK_SIZE) {
+ mgm128_hash_block(ctx, in);
+ (*ctx->block)(ctx->y, ctx->part, ctx->key);
+ mgm128_inc(ctx->y + MGM128_BLOCK_SIZE / 2, MGM128_BLOCK_SIZE / 2);
+ for (n = 0; n < MGM128_BLOCK_SIZE; n++) {
+ out[n] = ctx->part[n] ^ in[n];
+ }
+ in += MGM128_BLOCK_SIZE;
+ out += MGM128_BLOCK_SIZE;
+ len -= MGM128_BLOCK_SIZE;
+ }
+
+ if (len) {
+ (*ctx->block)(ctx->y, ctx->part, ctx->key);
+ mgm128_inc(ctx->y + MGM128_BLOCK_SIZE / 2, MGM128_BLOCK_SIZE / 2);
+ for (n = 0; n < len; n++) {
+ u8 tmp = *(in++);
+ *(out++) = ctx->part[n] ^ tmp;
+ ctx->part[n] = tmp;
+ }
+ }
+
+ ctx->d_remain = len;
+
+ return 0;
+}
+
+int CRYPTO_mgm128_finish(MGM128_CONTEXT *ctx,const unsigned char *tag,
+ size_t len)
+{
+ /* Handle AAD and data remainder */
+ if (ctx->a_remain) {
+ memset(ctx->part + ctx->a_remain, 0, MGM128_BLOCK_SIZE - ctx->a_remain);
+ mgm128_hash_block(ctx, ctx->part);
+ }
+
+ if (ctx->d_remain) {
+ memset(ctx->part + ctx->d_remain, 0, MGM128_BLOCK_SIZE - ctx->d_remain);
+ mgm128_hash_block(ctx, ctx->part);
+ }
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#ifndef BSWAP8
+#define BSWAP8(u) (u64)GETU32((unsigned char *)&u) << 32|GETU32(((unsigned char *)&u) + 4)
+#endif
+ ctx->len[0] = BSWAP8(ctx->len[0]);
+ ctx->len[1] = BSWAP8(ctx->len[1]);
+#endif
+ mgm128_hash_block(ctx, (unsigned char *)ctx->len);
+
+ (*ctx->block)((unsigned char *)ctx->sum, (unsigned char *)ctx->sum, ctx->key);
+
+ if (tag && len<=sizeof(ctx->sum))
+ return memcmp(ctx->sum, tag, len);
+ else
+ return -1;
+}
+
+void CRYPTO_mgm128_tag(MGM128_CONTEXT *ctx, unsigned char *tag, size_t len)
+{
+ CRYPTO_mgm128_finish(ctx, NULL, 0);
+ memcpy(tag, ctx->sum, len<=sizeof(ctx->sum)?len:sizeof(ctx->sum));
+}
diff --git a/src/lib/libcrypto/modes/modes.h b/src/lib/libcrypto/modes/modes.h
index 2344e944e..477d5eb52 100644
--- a/src/lib/libcrypto/modes/modes.h
+++ b/src/lib/libcrypto/modes/modes.h
@@ -139,6 +139,22 @@ typedef struct xts128_context XTS128_CONTEXT;
int CRYPTO_xts128_encrypt(const XTS128_CONTEXT *ctx, const unsigned char iv[16],
const unsigned char *inp, unsigned char *out, size_t len, int enc);
+typedef struct mgm128_context MGM128_CONTEXT;
+
+void CRYPTO_mgm128_init(MGM128_CONTEXT *ctx,void *key,block128_f block);
+void CRYPTO_mgm128_setiv(MGM128_CONTEXT *ctx, const unsigned char *iv);
+int CRYPTO_mgm128_aad(MGM128_CONTEXT *ctx, const unsigned char *aad,
+ size_t len);
+int CRYPTO_mgm128_encrypt(MGM128_CONTEXT *ctx,
+ const unsigned char *in, unsigned char *out,
+ size_t len);
+int CRYPTO_mgm128_decrypt(MGM128_CONTEXT *ctx,
+ const unsigned char *in, unsigned char *out,
+ size_t len);
+int CRYPTO_mgm128_finish(MGM128_CONTEXT *ctx,const unsigned char *tag,
+ size_t len);
+void CRYPTO_mgm128_tag(MGM128_CONTEXT *ctx, unsigned char *tag, size_t len);
+
typedef void (*block64_f)(const unsigned char in[8],
unsigned char out[8],
const void *key);
diff --git a/src/lib/libcrypto/modes/modes_lcl.h b/src/lib/libcrypto/modes/modes_lcl.h
index f8830e4de..e1bc05da5 100644
--- a/src/lib/libcrypto/modes/modes_lcl.h
+++ b/src/lib/libcrypto/modes/modes_lcl.h
@@ -108,4 +108,15 @@ struct ccm128_context {
void *key;
};
+struct mgm128_context {
+ u64 len[2]; /* aad and data len */
+ u64 sum[2];
+ u8 y[16], z[16], part[16];
+ block128_f block;
+ void *key;
+ unsigned int a_remain, d_remain;
+};
+
+#define MGM128_NONCE_LEN 16
+
__END_HIDDEN_DECLS
--
2.17.1