mirror of
https://abf.rosa.ru/djam/libressl.git
synced 2025-02-23 08:02:54 +00:00
380 lines
9.7 KiB
Diff
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
|
|
|