Signed-off-by: Dmitry Eremin-Solenikov dbaryshkov@gmail.com --- gost28147.c | 87 +++++++++++++++++++++++++++ gost28147.h | 18 ++++++ testsuite/gost28147-test.c | 147 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 252 insertions(+)
diff --git a/gost28147.c b/gost28147.c index e4d3ad30..1715ecaa 100644 --- a/gost28147.c +++ b/gost28147.c @@ -32,6 +32,7 @@
#include "macros.h" #include "gost28147.h" +#include "memxor.h"
/* pre-initialized GOST lookup tables based on rotated S-Box */ const struct gost28147_param gost28147_param_test_3411 = @@ -2351,3 +2352,89 @@ gost28147_encrypt_for_cfb(struct gost28147_ctx *ctx, ctx->key_count += GOST28147_BLOCK_SIZE; } } + +static void +gost28147_cnt_next_iv(struct gost28147_ctx *ctx, + uint8_t *iv, uint8_t *out) +{ + uint32_t block[2]; + uint32_t temp; + + block[0] = LE_READ_UINT32(iv + 0); + block[1] = LE_READ_UINT32(iv + 4); + if (ctx->key_count == 0) + { + gost28147_encrypt_simple(ctx->key, ctx->sbox, block, block); + } + if (ctx->key_meshing && ctx->key_count == 1024) + { + gost28147_key_mesh_cryptopro(ctx); + gost28147_encrypt_simple(ctx->key, ctx->sbox, block, block); + ctx->key_count = 0; + } + + LE_WRITE_UINT32(iv + 0, block[0]); + LE_WRITE_UINT32(iv + 4, block[1]); + + block[0] += 0x01010101; + temp = block[1] + 0x01010104; + if (temp < block[1]) + block[1] = temp + 1; /* Overflow */ + else + block[1] = temp; + + LE_WRITE_UINT32(iv + 0, block[0]); + LE_WRITE_UINT32(iv + 4, block[1]); + + gost28147_encrypt_simple(ctx->key, ctx->sbox, block, block); + + LE_WRITE_UINT32(out + 0, block[0]); + LE_WRITE_UINT32(out + 4, block[1]); + + ctx->key_count += GOST28147_BLOCK_SIZE; +} + +void +gost28147_cnt_init(struct gost28147_cnt_ctx *ctx, + const uint8_t *key, + const struct gost28147_param *param) +{ + gost28147_set_key(&ctx->ctx, key); + gost28147_set_param(&ctx->ctx, param); + ctx->bytes = 0; +} + +void +gost28147_cnt_crypt(struct gost28147_cnt_ctx *ctx, + uint8_t *iv, + size_t length, uint8_t *dst, + const uint8_t *src) +{ + size_t block_size = GOST28147_BLOCK_SIZE; + + if (ctx->bytes) + { + size_t part = ctx->bytes < length ? ctx->bytes : length; + memxor3(dst, src, ctx->buffer + block_size - ctx->bytes, part); + dst += part; + src += part; + length -= part; + ctx->bytes -= part; + ctx->bytes %= block_size; + } + while (length >= block_size) + { + gost28147_cnt_next_iv(&ctx->ctx, iv, ctx->buffer); + memxor3(dst, src, ctx->buffer, block_size); + length -= block_size; + src += block_size; + dst += block_size; + } + + if (length != 0) + { + gost28147_cnt_next_iv(&ctx->ctx, iv, ctx->buffer); + memxor3(dst, src, ctx->buffer, length); + ctx->bytes = block_size - length; + } +} diff --git a/gost28147.h b/gost28147.h index b7340428..3dd0e3bb 100644 --- a/gost28147.h +++ b/gost28147.h @@ -61,6 +61,9 @@ extern "C" { #define gost28147_encrypt_for_cfb nettle_gost28147_encrypt_for_cfb #define gost28147_decrypt nettle_gost28147_decrypt
+#define gost28147_cnt_init nettle_gost28147_cnt_init +#define gost28147_cnt_crypt nettle_gost28147_cnt_crypt + #define GOST28147_KEY_SIZE 32 #define GOST28147_BLOCK_SIZE 8
@@ -111,6 +114,21 @@ gost28147_encrypt_for_cfb(struct gost28147_ctx *ctx, size_t length, uint8_t *dst, const uint8_t *src);
+struct gost28147_cnt_ctx { + struct gost28147_ctx ctx; + size_t bytes; + uint8_t buffer[GOST28147_BLOCK_SIZE]; +}; + +void +gost28147_cnt_init(struct gost28147_cnt_ctx *ctx, + const uint8_t *key, + const struct gost28147_param *param); +void +gost28147_cnt_crypt(struct gost28147_cnt_ctx *ctx, + uint8_t *iv, + size_t length, uint8_t *dst, + const uint8_t *src); #ifdef __cplusplus } #endif diff --git a/testsuite/gost28147-test.c b/testsuite/gost28147-test.c index 939bedee..201e6ed6 100644 --- a/testsuite/gost28147-test.c +++ b/testsuite/gost28147-test.c @@ -104,6 +104,76 @@ test_gost28147_cfb(const struct gost28147_param *param, free(data); }
+static void +test_gost28147_cnt(const struct gost28147_param *param, + const struct tstring *key, + const struct tstring *start_iv, + const struct tstring *end_iv, + const struct tstring *cleartext, + const struct tstring *ciphertext) +{ + struct gost28147_cnt_ctx ctx; + uint8_t *data = xalloc(cleartext->length); + uint8_t iv[GOST28147_BLOCK_SIZE]; + size_t length; + + ASSERT (cleartext->length == ciphertext->length); + length = cleartext->length; + + gost28147_cnt_init(&ctx, key->data, param); + memcpy(iv, start_iv->data, GOST28147_BLOCK_SIZE); + gost28147_cnt_crypt(&ctx, iv, 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(); + } + + if (!MEMEQ(GOST28147_BLOCK_SIZE, iv, end_iv->data)) + { + fprintf(stderr, "Encrypt failed IV check:\nOutput:"); + print_hex(GOST28147_BLOCK_SIZE, iv); + fprintf(stderr, "\nExpected:"); + tstring_print_hex(end_iv); + fprintf(stderr, "\n"); + FAIL(); + } + + gost28147_cnt_init(&ctx, key->data, param); + memcpy(iv, start_iv->data, GOST28147_BLOCK_SIZE); + gost28147_cnt_crypt(&ctx, iv, length, data, data); + + if (!MEMEQ(length, data, cleartext->data)) + { + fprintf(stderr, "Decrypt failed:\nOutput:"); + print_hex(length, data); + fprintf(stderr, "\nExpected:"); + tstring_print_hex(cleartext); + fprintf(stderr, "\n"); + FAIL(); + } + + if (!MEMEQ(GOST28147_BLOCK_SIZE, iv, end_iv->data)) + { + fprintf(stderr, "Decrypt failed IV check:\nInput:"); + fprintf(stderr, "\nOutput: "); + print_hex(GOST28147_BLOCK_SIZE, iv); + fprintf(stderr, "\nExpected:"); + tstring_print_hex(end_iv); + fprintf(stderr, "\n"); + FAIL(); + } + + free(data); +} + void test_main(void) { /* Examples from GOST R 34.11-94 standard */ @@ -259,4 +329,81 @@ void test_main(void) "e229b58607397d78 8e5a8f834ce73d68 3ee502e6644f5eb4 4977f0c0fa6fc8fb" "9f846f55fb305e89 93a9f3a6a3d726bb d8a8d9951dfefcd7 a893662f04530664" "7f3129aeb79fbac4 6d68d12432f411")); + + test_gost28147_cnt(&gost28147_param_CryptoPro_A, + SHEX("599f84bac3f3d2f1 60e1e3f26a961af9 9c48b24ebcbbbf7c d8f3accd968d286a"), + SHEX("8dafa8d158ed058d"), + SHEX("f1a0e3294f65be75"), + SHEX("90a23966ae01b9a3 524ec8ed6cdd8830"), + SHEX("6e7262cce3593690 833afea91bc9bece")); + test_gost28147_cnt(&gost28147_param_CryptoPro_A, + SHEX("1b5ddb77cff9ec95 5ecc679f5d28ad4a 27f432c6b2cbb145 6a88140c9b9b5f48"), + SHEX("71588ce155f4f6b3"), + SHEX("6aeaa0a59e10e0ce"), + SHEX("3d0b69f7a8e4fc99 222eeed16312fea8 9dcb6c4d488ce8bd 8b60f1bf7be379d5" + "2b259713ef35daf4 bc77ceeae93fa4b6 01d5732958dad767 17ace4752f5723ac" + "9621c7622df732b5 445f72b15fba1b1e db4a098c9261a2b0 4968e5b3a28f134b" + "f54d84daaba0b6d1 5a6319e8a209f676 6f9b480a155db720 219a2eb96dfa1ec2" + "0eef15ab5901fe43 90f262ca4a9a4838 ab6f9d21b3ada760 46e3efd0e31dc5e1" + "b8a1e29920c576cc aa8aa94555a07800 64decf5bdf2648cd ba8ab5fbfd4ad5c4" + "e043a67190a48bca 2e887bacb2dcf201 cbda6e9127284488 9ad212f1a6f5b761" + "ce7962523ce61473 d1419250bddc3bd0 a7118c3ae42df252 d32f7c8e54904e23" + "aeb3a0f3257e66aa 0f6f817277bbd347 e805ffe15bc93750 334917afab1de115" + "f2e5985e2d051f0d 5597edff5ee00fc3 9cbd82c206be4566 ae33be2848e92d1a" + "e6658edf7603734b c08071f9acbaa0b0 191a0ad435128876 05758f7cb5f01975" + "6d05cb0dbc8de9f0 d4db3c3c298e2c32 1df7b649cfdb63ee 3cfa33736fe4974e" + "2fc94c5c65feeafb c6ddc11c473ff450 2fde1b5b0b16cab6 4644f2c10da11da6" + "dbf03db16c053185 8e74aef23926f7c1 e74cdd9d40b8f3c5 c216646baadb4b82" + "5cd302d38f26798d b0787019580cb431 88441c916ff45239 a8f5c01bfef20e4b" + "ac0ac27e9c9beb5d 4e4f42d8710a9727 031496a63d04ea9f 1414274cd9a2895f" + "654ae19d2cb8f8d4 8f2a5736cc069c2c c51316dffcae2216 a82b716f1db34754" + "3f2d0a689f2ef690 d8a12109d497b97b 7f9b6aedd1f0e3b6 28c7628200c938a1" + "8278ce87c853ac4f 2e31b9507f36004a 32e6d8bb59450e91 1b38a9bcb95e6c6a" + "9c03011cdee81f1e e3de25a25679e1bd 58c493e6d08a4d08 abf7aac37dc1ee68" + "37bc780b19682b2b 2e6dc46faa3bc619 cbf158b9608545ae 5297ba2432137216" + "6e7bc198acb1edb4 cc6ccf45fc508980 8e7aa4d364506337 c96cf1c43dfbde5a" + "5ca82135e62e8c2a 3c1217799a0d2e79 eb671f2bf86ecac1 fa45189edf6ae6cb" + "e95cc309af935813 bf90848775d68228 8de72fa3fb97742a 730482067669b10b" + "19fcaeb3dd2ae5c1 05d88095229071fc c29242fdf170b468 88a49e0a244013c8" + "a2564f39e606f1dc f5130ead9c8bafe9 e38872ffa06dda08 70b92e83c5bb32a5" + "74c7fb7b76af02bb 2bb85e6502fe0ea0 99ce013b35e1b022 e594bddd8ebbf675" + "bfbfee7ab158b481 b8393eb61ededa1b d5f7dd7d659caa56 93b8af4853c722e4" + "1cdfe979b42089cc 2a792c09be78cfcc f290d665c529fcda 69fcc0d67099613f" + "6002d81222c834c6 3bb3c233a15c8f4c d15272f242058e18 1f16dab853a15f01" + "321b90b3539bd085 612d17ed0aa4a527 09757cbc30f75e59 9a07968428864ba7" + "223528c7ed0dc3ce 98cc2decd498098e 525f2b9a13be9916 73d11f81e5a20878" + "cb0c20d4a5ea4b5b 955a929a52"), + SHEX("8ecd8fc8ace11548 2dae248ac7fbba0f 1d8a95a243efcbdc 5957a7c70ee3e2b9" + "0d862962cb834d07 0c40d47b2ecababf 4a603b3198c88847 d982abfc8f48e246" + "abd3a1ab8a05228c f4ec9a1e76ab1a60 d9256bb856e5b2ea 10f36204325eaa3b" + "7b57bc3b8b4347f2 d5037e5101ff7728 ca90a3fe7e2e7016 751844f01b8505ea" + "e321f72686763c67 9dfcbc107f77e4ed d312f883001f4b92 95925cf35af3b7d0" + "a95ff218c46662c1 840e66e8807d1ff0 ba019b71ae93cc27 54349abdcaee5209" + "929db0d5d9ba2fb9 96dcfabdceea1a7b 9a1d13a711e29a64 f6d3eec633b76eef" + "259e1e7ce31f2c6e a9c0f8c1bf3bf834 039ba1405b0c3c09 669d63e2e2048f06" + "847468b25c3b4cad 0b3f03b3078a64a7 3656263966dae96d 1bd588e85caf5a4c" + "49f7f5b778f0deec cd16239e8c13be6b 6f9b07e5bbcc3a1b 6f43dfff462aae47" + "19189a2509c92440 0c4ba7da5e0deefa 62458ecc2f23081d 92f0fe820fd71160" + "7e0b0b75f4f53bc0 a4e872a5b6fa5aad 5a4f39b5a212960a 3284b2a106685657" + "97a37b2261765d30 1a31ab9906c51a96 cfcf14ffb2c4cc2b bf0c9d918f795bbc" + "a96b916ab4935c7b 5dc28a75c0c108fa 99f94d5e0c066460 a9014a340f338495" + "6930c11c36f8fc30 23b271e5524d121a c9beeec9cb0185f3 db30f941a940b006" + "2977cdc5ec580248 8353446ad2ca05d8 5a08eba9f4e6c79d d57b740b31b7a557" + "7c7afd1a0ed79741 bfddc6196c778c18 525783ba7125ee39 bbe243a014dc0e84" + "b42bde3ee536b7a2 929805b896e5d08c 089335c281e0fc59 71e244495ddafb9c" + "aa709f43a8a5d967 d98fa31ebe0eecdf 122b6ae71c1217e7 c46d50c9527ad5e8" + "7fbc0715acdb9366 b1f0a77b2fe9ecd0 47695987f14c3e4b 9b117913e496f656" + "046e0b33fc40f6c7 c143b1bf0eb387fd 0b1c63463ad3a017 5925946c9c3d0c81" + "ce82724228f9376a 6de412f421aaf7fe 2755401a14c3395b bf63c25f101f1425" + "d0cef3144813a50b 4d38cf0d34c00a11 b4b572c84bc26fe7 9d93f7dfb843727e" + "da3e201fbc212ace 00fa969f3de58896 ef2984df6c1c96d8 5847aa92f307e5fb" + "afea957e0b71cd81 0fb70a598f314dd1 c3f32f705c591897 af77955eaf400612" + "816186084ebc8946 072e5b10aa12f0a7 84e29a08f1de59e3 0e474bffc3c918af" + "959c672ade8a7a99 04c4b8974c042971 05dab3d6db6c71e6 e803bf947dde3dc8" + "44fa7d62b43603ee 365264b4856dd578 f06f672d0ee02c88 9b55192940f68c12" + "bb2c839640c036f5 77ff708c75920bad 059b7ea2fca9d164 768213ba225e330e" + "2670a9be7428f5e2 c496ee3abc97a62c 2ae0648d35c61aca f492fac3f11f98e4" + "4388693a09bf63e5 96290b9b6223148a 95e41c5c0aa9c5b9 6f4f2b256f741e18" + "d5fe277d3f6e552c 67e6deb5ccc02dff c4e40621a5c8d3d6 6ca1c3fb8892b11d" + "90e135059b296dba f1f41e232e")); }