libressl/0044-modes-add-support-for-64-bit-MGM-mode.patch

379 lines
9.3 KiB
Diff
Raw Permalink Normal View History

From 2b03c9ee4c27cceda26c18eaa462e88e42014a3e Mon Sep 17 00:00:00 2001
From: Dmitry Baryshkov <dbaryshkov@gmail.com>
Date: Wed, 25 Mar 2020 21:54:20 +0300
Subject: [PATCH 44/87] modes: add support for 64-bit MGM mode
Add support for 64-bit MGM (Multilinear Galois Mode) defined in
draft-smyshlyaev-mgm.
Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
---
src/lib/libcrypto/modes/mgm64.c | 306 ++++++++++++++++++++++++++++
src/lib/libcrypto/modes/modes.h | 16 ++
src/lib/libcrypto/modes/modes_lcl.h | 11 +
3 files changed, 333 insertions(+)
create mode 100644 src/lib/libcrypto/modes/mgm64.c
diff --git a/src/lib/libcrypto/modes/mgm64.c b/src/lib/libcrypto/modes/mgm64.c
new file mode 100644
index 000000000..071ab19d2
--- /dev/null
+++ b/src/lib/libcrypto/modes/mgm64.c
@@ -0,0 +1,306 @@
+/* $OpenBSD: mgm64.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 MGM64_BLOCK_SIZE 8
+#define MGM64_POLYNOMIAL U64(0x1b)
+
+static u64
+mgm64_gf_shift (const u64 x)
+{
+ long mask;
+
+ /* Shift uses big-endian representation. */
+#if BYTE_ORDER != LITTLE_ENDIAN
+ mask = - ((x >> 63) & 1);
+ return (x << 1) ^ (mask & (MGM64_POLYNOMIAL));
+#else /* ! WORDS_BIGENDIAN */
+#define RSHIFT_WORD(x) \
+ ((((x) & UINT64_C(0x7f7f7f7f7f7f7f7f)) << 1) \
+ | (((x) & UINT64_C(0x8080808080808000)) >> 15))
+ mask = - ((x >> 7) & 1);
+ return RSHIFT_WORD(x) ^ (mask & (MGM64_POLYNOMIAL << 56));
+# undef RSHIFT_WORD
+#endif /* ! WORDS_BIGENDIAN */
+}
+
+static void
+mgm64_gf_mul_sum(MGM64_CONTEXT *ctx, u64 x, const uint8_t *y)
+{
+ u64 V, Z;
+ unsigned i;
+
+ V = x;
+ Z = 0;
+
+ for (i = 0; i < MGM64_BLOCK_SIZE; i++)
+ {
+ uint8_t b = y[MGM64_BLOCK_SIZE - i - 1];
+ unsigned j;
+ for (j = 0; j < 8; j++, b >>= 1)
+ {
+ if (b & 1) {
+ Z ^= V;
+ }
+
+ V = mgm64_gf_shift(V);
+ }
+ }
+
+ ctx->sum ^= Z;
+}
+
+static inline void mgm64_inc(unsigned char *counter, u32 n)
+{
+ u8 c;
+
+ do {
+ --n;
+ c = counter[n];
+ ++c;
+ counter[n] = c;
+ if (c) return;
+ } while (n);
+}
+
+void mgm64_hash_block(MGM64_CONTEXT *ctx, const u8 *data)
+{
+ union {u64 u; u8 c[MGM64_BLOCK_SIZE]; } tmp;
+
+ (*ctx->block)(ctx->z, tmp.c, ctx->key);
+ mgm64_gf_mul_sum(ctx, tmp.u, data);
+ mgm64_inc(ctx->z, MGM64_BLOCK_SIZE / 2);
+}
+
+void CRYPTO_mgm64_init(MGM64_CONTEXT *ctx, void *key, block64_f block)
+{
+ memset(ctx,0,sizeof(*ctx));
+ ctx->block = block;
+ ctx->key = key;
+}
+
+void CRYPTO_mgm64_setiv(MGM64_CONTEXT *ctx, const unsigned char *iv)
+{
+ memcpy(ctx->y, iv, MGM64_NONCE_LEN);
+ memcpy(ctx->z, iv, MGM64_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);
+
+ ctx->sum = 0;
+ memset(ctx->len, 0, MGM64_BLOCK_SIZE);
+}
+
+int CRYPTO_mgm64_aad(MGM64_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) % MGM64_BLOCK_SIZE;
+ }
+ if (n == 0) {
+ mgm64_hash_block(ctx, ctx->part);
+ } else {
+ ctx->a_remain = n;
+ return 0;
+ }
+ }
+
+ while (len >= MGM64_BLOCK_SIZE) {
+ mgm64_hash_block(ctx, aad);
+ aad += MGM64_BLOCK_SIZE;
+ len -= MGM64_BLOCK_SIZE;
+ }
+
+ if (len)
+ memcpy(ctx->part, aad, len);
+
+ ctx->a_remain = len;
+ return 0;
+}
+
+int CRYPTO_mgm64_encrypt(MGM64_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, MGM64_BLOCK_SIZE - ctx->a_remain);
+ mgm64_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) % MGM64_BLOCK_SIZE;
+ }
+ if (n == 0) {
+ mgm64_hash_block(ctx, ctx->part);
+ } else {
+ ctx->d_remain = n;
+ return 0;
+ }
+ }
+
+ while (len >= MGM64_BLOCK_SIZE) {
+ (*ctx->block)(ctx->y, ctx->part, ctx->key);
+ mgm64_inc(ctx->y + MGM64_BLOCK_SIZE / 2, MGM64_BLOCK_SIZE / 2);
+ for (n = 0; n < MGM64_BLOCK_SIZE; n++) {
+ out[n] = ctx->part[n] ^ in[n];
+ }
+ mgm64_hash_block(ctx, out);
+ in += MGM64_BLOCK_SIZE;
+ out += MGM64_BLOCK_SIZE;
+ len -= MGM64_BLOCK_SIZE;
+ }
+
+ if (len) {
+ (*ctx->block)(ctx->y, ctx->part, ctx->key);
+ mgm64_inc(ctx->y + MGM64_BLOCK_SIZE / 2, MGM64_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_mgm64_decrypt(MGM64_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, MGM64_BLOCK_SIZE - ctx->a_remain);
+ mgm64_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) % MGM64_BLOCK_SIZE;
+ }
+ if (n == 0) {
+ mgm64_hash_block(ctx, ctx->part);
+ } else {
+ ctx->d_remain = n;
+ return 0;
+ }
+ }
+
+ while (len >= MGM64_BLOCK_SIZE) {
+ mgm64_hash_block(ctx, in);
+ (*ctx->block)(ctx->y, ctx->part, ctx->key);
+ mgm64_inc(ctx->y + MGM64_BLOCK_SIZE / 2, MGM64_BLOCK_SIZE / 2);
+ for (n = 0; n < MGM64_BLOCK_SIZE; n++) {
+ out[n] = ctx->part[n] ^ in[n];
+ }
+ in += MGM64_BLOCK_SIZE;
+ out += MGM64_BLOCK_SIZE;
+ len -= MGM64_BLOCK_SIZE;
+ }
+
+ if (len) {
+ (*ctx->block)(ctx->y, ctx->part, ctx->key);
+ mgm64_inc(ctx->y + MGM64_BLOCK_SIZE / 2, MGM64_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_mgm64_finish(MGM64_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, MGM64_BLOCK_SIZE - ctx->a_remain);
+ mgm64_hash_block(ctx, ctx->part);
+ }
+
+ if (ctx->d_remain) {
+ memset(ctx->part + ctx->d_remain, 0, MGM64_BLOCK_SIZE - ctx->d_remain);
+ mgm64_hash_block(ctx, ctx->part);
+ }
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#ifdef BSWAP4
+ ctx->len[0] = BSWAP4(ctx->len[0]);
+ ctx->len[1] = BSWAP4(ctx->len[1]);
+#else
+ ctx->len[0] = GETU32((unsigned char *)&ctx->len[0]);
+ ctx->len[1] = GETU32((unsigned char *)&ctx->len[1]);
+#endif
+#endif
+ mgm64_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_mgm64_tag(MGM64_CONTEXT *ctx, unsigned char *tag, size_t len)
+{
+ CRYPTO_mgm64_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 477d5eb52..4d238bfeb 100644
--- a/src/lib/libcrypto/modes/modes.h
+++ b/src/lib/libcrypto/modes/modes.h
@@ -181,6 +181,22 @@ void CRYPTO_cfb64_encrypt(const unsigned char *in, unsigned char *out,
unsigned char ivec[8], int *num,
int enc, block64_f block);
+typedef struct mgm64_context MGM64_CONTEXT;
+
+void CRYPTO_mgm64_init(MGM64_CONTEXT *ctx,void *key,block64_f block);
+void CRYPTO_mgm64_setiv(MGM64_CONTEXT *ctx, const unsigned char *iv);
+int CRYPTO_mgm64_aad(MGM64_CONTEXT *ctx, const unsigned char *aad,
+ size_t len);
+int CRYPTO_mgm64_encrypt(MGM64_CONTEXT *ctx,
+ const unsigned char *in, unsigned char *out,
+ size_t len);
+int CRYPTO_mgm64_decrypt(MGM64_CONTEXT *ctx,
+ const unsigned char *in, unsigned char *out,
+ size_t len);
+int CRYPTO_mgm64_finish(MGM64_CONTEXT *ctx,const unsigned char *tag,
+ size_t len);
+void CRYPTO_mgm64_tag(MGM64_CONTEXT *ctx, unsigned char *tag, size_t len);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/lib/libcrypto/modes/modes_lcl.h b/src/lib/libcrypto/modes/modes_lcl.h
index e1bc05da5..cafcea167 100644
--- a/src/lib/libcrypto/modes/modes_lcl.h
+++ b/src/lib/libcrypto/modes/modes_lcl.h
@@ -119,4 +119,15 @@ struct mgm128_context {
#define MGM128_NONCE_LEN 16
+struct mgm64_context {
+ u32 len[2]; /* aad and data len */
+ u64 sum;
+ u8 y[8], z[8], part[8];
+ block64_f block;
+ void *key;
+ unsigned int a_remain, d_remain;
+};
+
+#define MGM64_NONCE_LEN 8
+
__END_HIDDEN_DECLS
--
2.17.1