Signed-off-by: Dmitry Baryshkov <[email protected]>
---
Makefile.in | 2 +-
gost28147-params.c | 11 +++++
gost28147.c | 86 ++++++++++++++++++++++++++++++++++++++
gost28147.h | 85 +++++++++++++++++++++++++++++++++++++
testsuite/Makefile.in | 2 +-
testsuite/gost28147-test.c | 77 ++++++++++++++++++++++++++++++++++
6 files changed, 261 insertions(+), 2 deletions(-)
create mode 100644 gost28147.h
create mode 100644 testsuite/gost28147-test.c
diff --git a/Makefile.in b/Makefile.in
index 41e0389f2979..d4bec88615ed 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -211,7 +211,7 @@ HEADERS = aes.h arcfour.h arctwo.h asn1.h blowfish.h \
cbc.h ccm.h cfb.h chacha.h chacha-poly1305.h ctr.h \
curve25519.h curve448.h des.h dsa.h dsa-compat.h eax.h \
ecc-curve.h ecc.h ecdsa.h eddsa.h \
- gcm.h gostdsa.h gosthash94.h hmac.h \
+ gcm.h gost28147.h gostdsa.h gosthash94.h hmac.h \
knuth-lfib.h hkdf.h \
macros.h \
cmac.h siv-cmac.h \
diff --git a/gost28147-params.c b/gost28147-params.c
index 6addec31f170..7489641ba5a1 100644
--- a/gost28147-params.c
+++ b/gost28147-params.c
@@ -33,6 +33,7 @@
#endif
#include "macros.h"
+#include "gost28147.h"
#include "gost28147-internal.h"
/* pre-initialized GOST lookup tables based on rotated S-Box */
@@ -569,3 +570,13 @@ const struct gost28147_param
_gost28147_param_CryptoPro_3411 =
}
}
};
+
+const struct gost28147_param * gost28147_get_param_test_3411 (void)
+{
+ return &_gost28147_param_test_3411;
+}
+
+const struct gost28147_param * gost28147_get_param_CryptoPro_3411 (void)
+{
+ return &_gost28147_param_CryptoPro_3411;
+}
diff --git a/gost28147.c b/gost28147.c
index 669fc85d2083..9525b41b148b 100644
--- a/gost28147.c
+++ b/gost28147.c
@@ -32,7 +32,10 @@
#include "config.h"
#endif
+#include <assert.h>
+
#include "macros.h"
+#include "gost28147.h"
#include "gost28147-internal.h"
/*
@@ -79,3 +82,86 @@ void _gost28147_encrypt_block (const uint32_t *key, const
uint32_t sbox[4][256],
GOST_ENCRYPT_ROUND(l, r, key[1], key[0], sbox);
*out = l, *(out + 1) = r;
}
+
+static
+void _gost28147_decrypt_block (const uint32_t *key, const uint32_t
sbox[4][256],
+ const uint32_t *in, uint32_t *out)
+{
+ uint32_t l, r;
+
+ r = in[0], l = in[1];
+ GOST_ENCRYPT_ROUND(l, r, key[0], key[1], sbox);
+ GOST_ENCRYPT_ROUND(l, r, key[2], key[3], sbox);
+ GOST_ENCRYPT_ROUND(l, r, key[4], key[5], sbox);
+ GOST_ENCRYPT_ROUND(l, r, key[6], key[7], sbox);
+ GOST_ENCRYPT_ROUND(l, r, key[7], key[6], sbox);
+ GOST_ENCRYPT_ROUND(l, r, key[5], key[4], sbox);
+ GOST_ENCRYPT_ROUND(l, r, key[3], key[2], sbox);
+ GOST_ENCRYPT_ROUND(l, r, key[1], key[0], sbox);
+ GOST_ENCRYPT_ROUND(l, r, key[7], key[6], sbox);
+ GOST_ENCRYPT_ROUND(l, r, key[5], key[4], sbox);
+ GOST_ENCRYPT_ROUND(l, r, key[3], key[2], sbox);
+ GOST_ENCRYPT_ROUND(l, r, key[1], key[0], sbox);
+ GOST_ENCRYPT_ROUND(l, r, key[7], key[6], sbox);
+ GOST_ENCRYPT_ROUND(l, r, key[5], key[4], sbox);
+ GOST_ENCRYPT_ROUND(l, r, key[3], key[2], sbox);
+ GOST_ENCRYPT_ROUND(l, r, key[1], key[0], sbox);
+ *out = l, *(out + 1) = r;
+}
+
+void
+gost28147_set_key(struct gost28147_ctx *ctx, const uint8_t *key)
+{
+ unsigned i;
+
+ assert(key);
+ for (i = 0; i < 8; i++, key += 4)
+ ctx->key[i] = LE_READ_UINT32(key);
+}
+
+void
+gost28147_set_param(struct gost28147_ctx *ctx, const struct gost28147_param
*param)
+{
+ assert(param);
+ ctx->sbox = param->sbox;
+}
+
+void
+gost28147_encrypt(const struct gost28147_ctx *ctx,
+ size_t length, uint8_t *dst,
+ const uint8_t *src)
+{
+ uint32_t block[2];
+
+ assert(!(length % GOST28147_BLOCK_SIZE));
+
+ while (length)
+ {
+ block[0] = LE_READ_UINT32(src); src += 4;
+ block[1] = LE_READ_UINT32(src); src += 4;
+ _gost28147_encrypt_block(ctx->key, ctx->sbox, block, block);
+ LE_WRITE_UINT32(dst, block[0]); dst += 4;
+ LE_WRITE_UINT32(dst, block[1]); dst += 4;
+ length -= GOST28147_BLOCK_SIZE;
+ }
+}
+
+void
+gost28147_decrypt(const struct gost28147_ctx *ctx,
+ size_t length, uint8_t *dst,
+ const uint8_t *src)
+{
+ uint32_t block[2];
+
+ assert(!(length % GOST28147_BLOCK_SIZE));
+
+ while (length)
+ {
+ block[0] = LE_READ_UINT32(src); src += 4;
+ block[1] = LE_READ_UINT32(src); src += 4;
+ _gost28147_decrypt_block(ctx->key, ctx->sbox, block, block);
+ LE_WRITE_UINT32(dst, block[0]); dst += 4;
+ LE_WRITE_UINT32(dst, block[1]); dst += 4;
+ length -= GOST28147_BLOCK_SIZE;
+ }
+}
diff --git a/gost28147.h b/gost28147.h
new file mode 100644
index 000000000000..0df1662ce86d
--- /dev/null
+++ b/gost28147.h
@@ -0,0 +1,85 @@
+/* gost28147.h
+
+ The GOST 28147-89 cipher function, described in RFC 5831.
+
+ Copyright (C) 2020 Dmitry Baryshkov
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef NETTLE_GOST28147_H_INCLUDED
+#define NETTLE_GOST28147_H_INCLUDED
+
+#include "nettle-types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define gost28147_get_param_test_3411 nettle_gost28147_get_param_test_3411
+#define gost28147_get_param_CryptoPro_3411
nettle_gost28147_get_param_CryptoPro_3411
+
+#define gost28147_set_key nettle_gost28147_set_key
+#define gost28147_set_param nettle_gost28147_set_param
+#define gost28147_encrypt nettle_gost28147_encrypt
+#define gost28147_decrypt nettle_gost28147_decrypt
+
+#define GOST28147_KEY_SIZE 32
+#define GOST28147_BLOCK_SIZE 8
+
+struct gost28147_ctx
+{
+ uint32_t key[GOST28147_KEY_SIZE/4];
+ const uint32_t (*sbox)[256];
+};
+
+struct gost28147_param;
+
+const struct gost28147_param * gost28147_get_param_test_3411 (void);
+const struct gost28147_param * gost28147_get_param_CryptoPro_3411 (void);
+
+void
+gost28147_set_key(struct gost28147_ctx *ctx, const uint8_t *key);
+
+void
+gost28147_set_param(struct gost28147_ctx *ctx,
+ const struct gost28147_param *param);
+
+void
+gost28147_encrypt(const struct gost28147_ctx *ctx,
+ size_t length, uint8_t *dst,
+ const uint8_t *src);
+void
+gost28147_decrypt(const struct gost28147_ctx *ctx,
+ size_t length, uint8_t *dst,
+ const uint8_t *src);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NETTLE_GOST28147_H_INCLUDED */
diff --git a/testsuite/Makefile.in b/testsuite/Makefile.in
index 3f5e5f6b995c..07dd0ecf3e8d 100644
--- a/testsuite/Makefile.in
+++ b/testsuite/Makefile.in
@@ -17,7 +17,7 @@ TS_NETTLE_SOURCES = aes-test.c arcfour-test.c arctwo-test.c \
cnd-memcpy-test.c \
des-test.c des3-test.c \
md2-test.c md4-test.c md5-test.c md5-compat-test.c \
- memeql-test.c memxor-test.c gosthash94-test.c \
+ memeql-test.c memxor-test.c gost28147-test.c
gosthash94-test.c \
ripemd160-test.c hkdf-test.c \
salsa20-test.c \
sha1-test.c sha224-test.c sha256-test.c \
diff --git a/testsuite/gost28147-test.c b/testsuite/gost28147-test.c
new file mode 100644
index 000000000000..ee9615b15cf2
--- /dev/null
+++ b/testsuite/gost28147-test.c
@@ -0,0 +1,77 @@
+#include "testutils.h"
+#include "gost28147.h"
+#include "cfb.h"
+#include "macros.h"
+
+static void
+test_gost28147(const struct gost28147_param *param,
+ const struct tstring *key,
+ const struct tstring *cleartext,
+ const struct tstring *ciphertext)
+{
+ struct gost28147_ctx ctx;
+ uint8_t *data = xalloc(cleartext->length);
+ size_t length;
+
+ ASSERT (cleartext->length == ciphertext->length);
+ length = cleartext->length;
+
+ gost28147_set_param(&ctx, param);
+ gost28147_set_key(&ctx, key->data);
+ gost28147_encrypt(&ctx, length, data, cleartext->data);
+
+ if (!MEMEQ(length, data, ciphertext->data))
+ {
+ fprintf(stderr, "Encrypt failed:\nInput:");
+ tstring_print_hex(cleartext);
+ fprintf(stderr, "\nOutput: ");
+ print_hex(length, data);
+ fprintf(stderr, "\nExpected:");
+ tstring_print_hex(ciphertext);
+ fprintf(stderr, "\n");
+ FAIL();
+ }
+
+ gost28147_set_param(&ctx, param);
+ gost28147_set_key(&ctx, key->data);
+ gost28147_decrypt(&ctx, length, data, data);
+
+ if (!MEMEQ(length, data, cleartext->data))
+ {
+ fprintf(stderr, "Decrypt failed:\nInput:");
+ tstring_print_hex(ciphertext);
+ fprintf(stderr, "\nOutput: ");
+ print_hex(length, data);
+ fprintf(stderr, "\nExpected:");
+ tstring_print_hex(cleartext);
+ fprintf(stderr, "\n");
+ FAIL();
+ }
+
+ free(data);
+}
+
+void test_main(void)
+{
+ /* Examples from GOST R 34.11-94 standard, see RFC 5831, Section 7.3.1.
+ * Exaples there are represented in different endianness */
+ test_gost28147(gost28147_get_param_test_3411(),
+ SHEX("546D2033 68656C32 69736520 73736E62 20616779 69677474 73656865
202C3D73"),
+ SHEX("00000000 00000000"),
+ SHEX("1B0BBC32 CEBCAB42"));
+
+ test_gost28147(gost28147_get_param_test_3411(),
+ SHEX("2033394D 6C320D09 65201A16 6E62001D 67794106 74740E13 6865160D
3D730C11"),
+ SHEX("00000000 00000000"),
+ SHEX("FDCF9B5D C8EB0352"));
+
+ test_gost28147(gost28147_get_param_test_3411(),
+ SHEX("39B213F5 F209A13F 1AE9BA3A FF1D0C62 41F9E1C7 F1130085 16F20D73
F311B180"),
+ SHEX("00000000 00000000"),
+ SHEX("280EFF00 9958348D"));
+
+ test_gost28147(gost28147_get_param_test_3411(),
+ SHEX("EC0A8BA1 5EC004A8 BAC50CAC 0C621DEE E1C7B8E7 007AE2EC F2731BFF
4E80E2A0 "),
+ SHEX("00000000 00000000"),
+ SHEX("2D562A0D 190486E7 "));
+}
--
2.27.0
_______________________________________________
nettle-bugs mailing list
[email protected]
http://lists.lysator.liu.se/mailman/listinfo/nettle-bugs