From 641223f4d077bfd41143420c852aabbef8ca7fdf Mon Sep 17 00:00:00 2001 From: Vitaly Chikunov Date: Wed, 25 Jul 2018 10:49:38 +0300 Subject: [PATCH 01/16] test_grasshopper: Warn if EVP_MD_meth_set_result_size is performed --- test_grasshopper.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/test_grasshopper.c b/test_grasshopper.c index 4ea195c..14252bc 100644 --- a/test_grasshopper.c +++ b/test_grasshopper.c @@ -23,7 +23,9 @@ } #define cRED "\033[1;31m" +#define cDRED "\033[0;31m" #define cGREEN "\033[1;32m" +#define cDGREEN "\033[0;32m" #define cNORM "\033[m" #define TEST_ASSERT(e) {if ((test = (e))) \ printf(cRED "Test FAILED\n" cNORM); \ @@ -240,10 +242,11 @@ static int test_omac() /* preload cbc cipher for omac set key */ EVP_add_cipher(cipher_gost_grasshopper_cbc()); T(EVP_DigestInit_ex(ctx, grasshopper_omac(), NULL)); - if (EVP_MD_CTX_size(ctx) != 8) { + if (EVP_MD_CTX_size(ctx) != sizeof(mac)) { /* strip const out of EVP_MD_CTX_md() to * overwrite output size, as test vector is 8 bytes */ - T(EVP_MD_meth_set_result_size((EVP_MD *)EVP_MD_CTX_md(ctx), 8)); + printf("Resize result size from %d to %zu\n", EVP_MD_CTX_size(ctx), sizeof(mac)); + T(EVP_MD_meth_set_result_size((EVP_MD *)EVP_MD_CTX_md(ctx), sizeof(mac))); } T(EVP_MD_meth_get_ctrl(EVP_MD_CTX_md(ctx))(ctx, EVP_MD_CTRL_SET_KEY, sizeof(K), (void *)K)); T(EVP_DigestUpdate(ctx, P, sizeof(P))); @@ -283,8 +286,8 @@ int main(int argc, char **argv) ret |= test_omac(); if (ret) - printf(cRED "= Some tests FAILED!\n" cNORM); + printf(cDRED "= Some tests FAILED!\n" cNORM); else - printf(cGREEN "= All tests passed!\n" cNORM); + printf(cDGREEN "= All tests passed!\n" cNORM); return ret; } -- 2.39.5 From 234823a6d6971a72b29247a4893db5a61f8b992a Mon Sep 17 00:00:00 2001 From: Vitaly Chikunov Date: Thu, 26 Jul 2018 07:31:42 +0300 Subject: [PATCH 02/16] test_grasshopper: Rework tests to be more flexible --- test_grasshopper.c | 217 ++++++++++++++++++++++++--------------------- 1 file changed, 115 insertions(+), 102 deletions(-) diff --git a/test_grasshopper.c b/test_grasshopper.c index 14252bc..fb6b967 100644 --- a/test_grasshopper.c +++ b/test_grasshopper.c @@ -32,14 +32,6 @@ else \ printf(cGREEN "Test passed\n" cNORM);} -enum e_mode { - E_ECB = 0, - E_CTR, - E_OFB, - E_CBC, - E_CFB, -}; - /* Test key from both GOST R 34.12-2015 and GOST R 34.13-2015. */ static const unsigned char K[] = { 0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff,0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77, @@ -54,48 +46,75 @@ static const unsigned char P[] = { 0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xee,0xff,0x0a,0x00, 0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xee,0xff,0x0a,0x00,0x11, }; -static const unsigned char E[6][sizeof(P)] = { - { /* ECB test vectors from GOST R 34.13-2015 A.1.1 */ - /* first 16 bytes is vector (b) from GOST R 34.12-2015 A.1 */ - 0x7f,0x67,0x9d,0x90,0xbe,0xbc,0x24,0x30,0x5a,0x46,0x8d,0x42,0xb9,0xd4,0xed,0xcd, - 0xb4,0x29,0x91,0x2c,0x6e,0x00,0x32,0xf9,0x28,0x54,0x52,0xd7,0x67,0x18,0xd0,0x8b, - 0xf0,0xca,0x33,0x54,0x9d,0x24,0x7c,0xee,0xf3,0xf5,0xa5,0x31,0x3b,0xd4,0xb1,0x57, - 0xd0,0xb0,0x9c,0xcd,0xe8,0x30,0xb9,0xeb,0x3a,0x02,0xc4,0xc5,0xaa,0x8a,0xda,0x98, - }, - { /* CTR test vectors from GOST R 34.13-2015 A.1.2 */ - 0xf1,0x95,0xd8,0xbe,0xc1,0x0e,0xd1,0xdb,0xd5,0x7b,0x5f,0xa2,0x40,0xbd,0xa1,0xb8, - 0x85,0xee,0xe7,0x33,0xf6,0xa1,0x3e,0x5d,0xf3,0x3c,0xe4,0xb3,0x3c,0x45,0xde,0xe4, - 0xa5,0xea,0xe8,0x8b,0xe6,0x35,0x6e,0xd3,0xd5,0xe8,0x77,0xf1,0x35,0x64,0xa3,0xa5, - 0xcb,0x91,0xfa,0xb1,0xf2,0x0c,0xba,0xb6,0xd1,0xc6,0xd1,0x58,0x20,0xbd,0xba,0x73, - }, - { /* OFB test vector generated from canonical implementation */ - 0x81,0x80,0x0a,0x59,0xb1,0x84,0x2b,0x24,0xff,0x1f,0x79,0x5e,0x89,0x7a,0xbd,0x95, - 0x77,0x91,0x46,0xdb,0x2d,0x93,0xa9,0x4e,0xd9,0x3c,0xf6,0x8b,0x32,0x39,0x7f,0x19, - 0xe9,0x3c,0x9e,0x57,0x44,0x1d,0x87,0x05,0x45,0xf2,0x40,0x36,0xa5,0x8c,0xee,0xa3, - 0xcf,0x3f,0x00,0x61,0xd5,0x64,0x23,0x54,0x5b,0x96,0x0d,0x86,0x4c,0xc8,0x68,0xda, - }, - { /* CBC test vector generated from canonical implementation */ - 0x68,0x99,0x72,0xd4,0xa0,0x85,0xfa,0x4d,0x90,0xe5,0x2e,0x3d,0x6d,0x7d,0xcc,0x27, - 0xab,0xf1,0x70,0xb2,0xb2,0x26,0xc3,0x01,0x0c,0xcf,0xa1,0x36,0xd6,0x59,0xcd,0xaa, - 0xca,0x71,0x92,0x72,0xab,0x1d,0x43,0x8e,0x15,0x50,0x7d,0x52,0x1e,0xcd,0x55,0x22, - 0xe0,0x11,0x08,0xff,0x8d,0x9d,0x3a,0x6d,0x8c,0xa2,0xa5,0x33,0xfa,0x61,0x4e,0x71, - }, - { /* CFB test vector generated from canonical implementation */ - 0x81,0x80,0x0a,0x59,0xb1,0x84,0x2b,0x24,0xff,0x1f,0x79,0x5e,0x89,0x7a,0xbd,0x95, - 0x68,0xc1,0xb9,0x9c,0x4d,0xf5,0x9c,0xc7,0x95,0x1e,0x37,0x39,0xb5,0xb3,0xcd,0xbf, - 0x07,0x3f,0x4d,0xd2,0xd6,0xde,0xb3,0xcf,0xb0,0x26,0x54,0x5f,0x7a,0xf1,0xd8,0xe8, - 0xe1,0xc8,0x52,0xe9,0xa8,0x56,0x71,0x62,0xdb,0xb5,0xda,0x7f,0x66,0xde,0xa9,0x26, - }, +static const unsigned char E_ecb[] = { + /* ECB test vectors from GOST R 34.13-2015 A.1.1 */ + /* first 16 bytes is vector (b) from GOST R 34.12-2015 A.1 */ + 0x7f,0x67,0x9d,0x90,0xbe,0xbc,0x24,0x30,0x5a,0x46,0x8d,0x42,0xb9,0xd4,0xed,0xcd, + 0xb4,0x29,0x91,0x2c,0x6e,0x00,0x32,0xf9,0x28,0x54,0x52,0xd7,0x67,0x18,0xd0,0x8b, + 0xf0,0xca,0x33,0x54,0x9d,0x24,0x7c,0xee,0xf3,0xf5,0xa5,0x31,0x3b,0xd4,0xb1,0x57, + 0xd0,0xb0,0x9c,0xcd,0xe8,0x30,0xb9,0xeb,0x3a,0x02,0xc4,0xc5,0xaa,0x8a,0xda,0x98, +}; +static const unsigned char E_ctr[] = { + /* CTR test vectors from GOST R 34.13-2015 A.1.2 */ + 0xf1,0x95,0xd8,0xbe,0xc1,0x0e,0xd1,0xdb,0xd5,0x7b,0x5f,0xa2,0x40,0xbd,0xa1,0xb8, + 0x85,0xee,0xe7,0x33,0xf6,0xa1,0x3e,0x5d,0xf3,0x3c,0xe4,0xb3,0x3c,0x45,0xde,0xe4, + 0xa5,0xea,0xe8,0x8b,0xe6,0x35,0x6e,0xd3,0xd5,0xe8,0x77,0xf1,0x35,0x64,0xa3,0xa5, + 0xcb,0x91,0xfa,0xb1,0xf2,0x0c,0xba,0xb6,0xd1,0xc6,0xd1,0x58,0x20,0xbd,0xba,0x73, +}; +/* + * Other modes (ofb, cbc, cfb) is impossible to test to match GOST R + * 34.13-2015 test vectors exactly, due to these vectors having exceeding + * IV length value (m) = 256 bits, while openssl have hard-coded limit + * of maximum IV length of 128 bits (EVP_MAX_IV_LENGTH). + * Also, current grasshopper code having fixed IV length of 128 bits. + * + * Thus, new test vectors are generated with truncated 128-bit IV using + * canonical GOST implementation from TC26. + */ +static const unsigned char E_ofb[] = { + /* OFB test vector generated from canonical implementation */ + 0x81,0x80,0x0a,0x59,0xb1,0x84,0x2b,0x24,0xff,0x1f,0x79,0x5e,0x89,0x7a,0xbd,0x95, + 0x77,0x91,0x46,0xdb,0x2d,0x93,0xa9,0x4e,0xd9,0x3c,0xf6,0x8b,0x32,0x39,0x7f,0x19, + 0xe9,0x3c,0x9e,0x57,0x44,0x1d,0x87,0x05,0x45,0xf2,0x40,0x36,0xa5,0x8c,0xee,0xa3, + 0xcf,0x3f,0x00,0x61,0xd5,0x64,0x23,0x54,0x5b,0x96,0x0d,0x86,0x4c,0xc8,0x68,0xda, }; -static const unsigned char iv_ctr[] = { 0x12,0x34,0x56,0x78,0x90,0xab,0xce,0xf0 }; +static const unsigned char E_cbc[] = { + /* CBC test vector generated from canonical implementation */ + 0x68,0x99,0x72,0xd4,0xa0,0x85,0xfa,0x4d,0x90,0xe5,0x2e,0x3d,0x6d,0x7d,0xcc,0x27, + 0xab,0xf1,0x70,0xb2,0xb2,0x26,0xc3,0x01,0x0c,0xcf,0xa1,0x36,0xd6,0x59,0xcd,0xaa, + 0xca,0x71,0x92,0x72,0xab,0x1d,0x43,0x8e,0x15,0x50,0x7d,0x52,0x1e,0xcd,0x55,0x22, + 0xe0,0x11,0x08,0xff,0x8d,0x9d,0x3a,0x6d,0x8c,0xa2,0xa5,0x33,0xfa,0x61,0x4e,0x71, +}; +static const unsigned char E_cfb[] = { + /* CFB test vector generated from canonical implementation */ + 0x81,0x80,0x0a,0x59,0xb1,0x84,0x2b,0x24,0xff,0x1f,0x79,0x5e,0x89,0x7a,0xbd,0x95, + 0x68,0xc1,0xb9,0x9c,0x4d,0xf5,0x9c,0xc7,0x95,0x1e,0x37,0x39,0xb5,0xb3,0xcd,0xbf, + 0x07,0x3f,0x4d,0xd2,0xd6,0xde,0xb3,0xcf,0xb0,0x26,0x54,0x5f,0x7a,0xf1,0xd8,0xe8, + 0xe1,0xc8,0x52,0xe9,0xa8,0x56,0x71,0x62,0xdb,0xb5,0xda,0x7f,0x66,0xde,0xa9,0x26, +}; + +static const unsigned char iv_ctr[] = { 0x12,0x34,0x56,0x78,0x90,0xab,0xce,0xf0, 0,0,0,0,0,0,0,0 }; /* truncated to 128-bits IV */ -static const unsigned char iv_128bit[] = { 0x12,0x34,0x56,0x78,0x90,0xab,0xce,0xf0,0xa1,0xb2,0xc3,0xd4,0xe5,0xf0,0x01,0x12 }; -static const unsigned char *iv[6] = { - NULL, /* ecb */ - iv_ctr, - iv_128bit, /* ofb */ - iv_128bit, /* cbc*/ - iv_128bit, /* cfb */ +static const unsigned char iv_128bit[] = { 0x12,0x34,0x56,0x78,0x90,0xab,0xce,0xf0, + 0xa1,0xb2,0xc3,0xd4,0xe5,0xf0,0x01,0x12 }; +struct testcase { + const char *name; + const EVP_CIPHER *(*type)(void); + int stream; + const unsigned char *plaintext; + const unsigned char *expected; + size_t size; + const unsigned char *iv; + size_t iv_size; + int acpkm; +}; +static struct testcase testcases[] = { + { "ecb", cipher_gost_grasshopper_ecb, 0, P, E_ecb, sizeof(P), NULL, 0, 0 }, + { "ctr", cipher_gost_grasshopper_ctr, 1, P, E_ctr, sizeof(P), iv_ctr, sizeof(iv_ctr), 0 }, + { "ofb", cipher_gost_grasshopper_ofb, 1, P, E_ofb, sizeof(P), iv_128bit, sizeof(iv_128bit), 0 }, + { "cbc", cipher_gost_grasshopper_cbc, 0, P, E_cbc, sizeof(P), iv_128bit, sizeof(iv_128bit), 0 }, + { "cfb", cipher_gost_grasshopper_cfb, 0, P, E_cfb, sizeof(P), iv_128bit, sizeof(iv_128bit), 0 }, + NULL }; static void hexdump(const void *ptr, size_t len) @@ -110,50 +129,48 @@ static void hexdump(const void *ptr, size_t len) printf("\n"); } -/* Test vectors from GOST R 34.13-2015 A.1 which* includes vectors - * from GOST R 34.12-2015 A.1 as first block of ecb mode. */ -static int test_block(const EVP_CIPHER *type, const char *mode, enum e_mode t) +static int test_block(const EVP_CIPHER *type, const char *name, + const unsigned char *pt, const unsigned char *exp, size_t size, + const unsigned char *iv, size_t iv_size, int acpkm) { EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); - unsigned char c[sizeof(P)]; + unsigned char c[size]; int outlen, tmplen; int ret = 0, test; OPENSSL_assert(ctx); - printf("Encryption test from GOST R 34.13-2015 [%s] \n", mode); - if (!t) { - /* output plain-text only once */ - printf(" p[%zu] = ", sizeof(P)); - hexdump(P, sizeof(P)); - } + printf("Encryption test from GOST R 34.13-2015 [%s] \n", name); /* test with single big chunk */ EVP_CIPHER_CTX_init(ctx); - T(EVP_CipherInit_ex(ctx, type, NULL, K, iv[t], 1)); + T(EVP_CipherInit_ex(ctx, type, NULL, K, iv, 1)); T(EVP_CIPHER_CTX_set_padding(ctx, 0)); memset(c, 0, sizeof(c)); - T(EVP_CipherUpdate(ctx, c, &outlen, P, sizeof(P))); + if (acpkm) + T(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_KEY_MESH, 256 / 8, NULL)); + T(EVP_CipherUpdate(ctx, c, &outlen, pt, size)); T(EVP_CipherFinal_ex(ctx, c + outlen, &tmplen)); EVP_CIPHER_CTX_cleanup(ctx); printf(" c[%d] = ", outlen); hexdump(c, outlen); - TEST_ASSERT(outlen != sizeof(P) || - memcmp(c, E[t], sizeof(P))); + TEST_ASSERT(outlen != size || memcmp(c, exp, size)); ret |= test; /* test with small chunks of block size */ - printf("Chunked encryption test from GOST R 34.13-2015 [%s] \n", mode); - int blocks = sizeof(P) / GRASSHOPPER_BLOCK_SIZE; + printf("Chunked encryption test from GOST R 34.13-2015 [%s] \n", name); + int blocks = size / GRASSHOPPER_BLOCK_SIZE; int z; EVP_CIPHER_CTX_init(ctx); - T(EVP_CipherInit_ex(ctx, type, NULL, K, iv[t], 1)); + T(EVP_CipherInit_ex(ctx, type, NULL, K, iv, 1)); T(EVP_CIPHER_CTX_set_padding(ctx, 0)); memset(c, 0, sizeof(c)); + if (acpkm) + T(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_KEY_MESH, 256 / 8, NULL)); for (z = 0; z < blocks; z++) { int offset = z * GRASSHOPPER_BLOCK_SIZE; int sz = GRASSHOPPER_BLOCK_SIZE; - T(EVP_CipherUpdate(ctx, c + offset, &outlen, P + offset, sz)); + T(EVP_CipherUpdate(ctx, c + offset, &outlen, pt + offset, sz)); } outlen = z * GRASSHOPPER_BLOCK_SIZE; T(EVP_CipherFinal_ex(ctx, c + outlen, &tmplen)); @@ -161,31 +178,33 @@ static int test_block(const EVP_CIPHER *type, const char *mode, enum e_mode t) printf(" c[%d] = ", outlen); hexdump(c, outlen); - TEST_ASSERT(outlen != sizeof(P) || - memcmp(c, E[t], sizeof(P))); + TEST_ASSERT(outlen != size || memcmp(c, exp, size)); ret |= test; /* test with single big chunk */ - printf("Decryption test from GOST R 34.13-2015 [%s] \n", mode); + printf("Decryption test from GOST R 34.13-2015 [%s] \n", name); EVP_CIPHER_CTX_init(ctx); - T(EVP_CipherInit_ex(ctx, type, NULL, K, iv[t], 0)); + T(EVP_CipherInit_ex(ctx, type, NULL, K, iv, 0)); T(EVP_CIPHER_CTX_set_padding(ctx, 0)); memset(c, 0, sizeof(c)); - T(EVP_CipherUpdate(ctx, c, &outlen, E[t], sizeof(P))); + if (acpkm) + T(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_KEY_MESH, 256 / 8, NULL)); + T(EVP_CipherUpdate(ctx, c, &outlen, exp, size)); T(EVP_CipherFinal_ex(ctx, c + outlen, &tmplen)); EVP_CIPHER_CTX_cleanup(ctx); EVP_CIPHER_CTX_free(ctx); printf(" d[%d] = ", outlen); hexdump(c, outlen); - TEST_ASSERT(outlen != sizeof(P) || - memcmp(c, P, sizeof(P))); + TEST_ASSERT(outlen != size || memcmp(c, pt, size)); ret |= test; return ret; } -static int test_stream(const EVP_CIPHER *type, const char *mode, enum e_mode t) +static int test_stream(const EVP_CIPHER *type, const char *name, + const unsigned char *pt, const unsigned char *exp, size_t size, + const unsigned char *iv, size_t iv_size, int acpkm) { EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); int ret = 0, test; @@ -193,31 +212,32 @@ static int test_stream(const EVP_CIPHER *type, const char *mode, enum e_mode t) OPENSSL_assert(ctx); /* Cycle through all lengths from 1 upto maximum size */ - printf("Stream encryption test from GOST R 34.13-2015 [%s] \n", mode); - for (z = 1; z <= sizeof(P); z++) { - unsigned char c[sizeof(P)]; + printf("Stream encryption test from GOST R 34.13-2015 [%s] \n", name); + for (z = 1; z <= size; z++) { + unsigned char c[size]; int outlen, tmplen; - int sz; + int sz = 0; int i; EVP_CIPHER_CTX_init(ctx); - EVP_CipherInit_ex(ctx, type, NULL, K, iv[t], 1); + EVP_CipherInit_ex(ctx, type, NULL, K, iv, 1); EVP_CIPHER_CTX_set_padding(ctx, 0); memset(c, 0xff, sizeof(c)); - for (i = 0; i < sizeof(P); i += z) { - if (i + z > sizeof(P)) - sz = sizeof(P) - i; + if (acpkm) + T(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_KEY_MESH, 256 / 8, NULL)); + for (i = 0; i < size; i += z) { + if (i + z > size) + sz = size - i; else sz = z; - EVP_CipherUpdate(ctx, c + i, &outlen, P + i, sz); + EVP_CipherUpdate(ctx, c + i, &outlen, pt + i, sz); OPENSSL_assert(outlen == sz); } outlen = i - z + sz; EVP_CipherFinal_ex(ctx, c + outlen, &tmplen); EVP_CIPHER_CTX_cleanup(ctx); - test = outlen != sizeof(P) || - memcmp(c, E[t], sizeof(P)); + test = outlen != size || memcmp(c, exp, size); printf("%c", test ? 'E' : '+'); ret |= test; } @@ -264,24 +284,17 @@ static int test_omac() int main(int argc, char **argv) { int ret = 0; + const struct testcase *t; - ret |= test_block(cipher_gost_grasshopper_ecb(), "ecb", E_ECB); - ret |= test_block(cipher_gost_grasshopper_ctr(), "ctr", E_CTR); - ret |= test_stream(cipher_gost_grasshopper_ctr(), "ctr", E_CTR); - /* - * Other modes (ofb, cbc, cfb) is impossible to test to match GOST R - * 34.13-2015 test vectors exactly, due to these vectors having exceeding - * IV length value (m) = 256 bits, while openssl have hard-coded limit - * of maximum IV length of 128 bits (EVP_MAX_IV_LENGTH). - * Also, current grasshopper code having fixed IV length of 128 bits. - * - * Thus, new test vectors are generated with truncated 128-bit IV using - * canonical GOST implementation from TC26. - */ - ret |= test_block(cipher_gost_grasshopper_ofb(), "ofb", E_OFB); - ret |= test_stream(cipher_gost_grasshopper_ctr(), "ofb", E_CTR); - ret |= test_block(cipher_gost_grasshopper_cbc(), "cbc", E_CBC); - ret |= test_block(cipher_gost_grasshopper_cfb(), "cfb", E_CFB); + for (t = testcases; t->name; t++) { + ret |= test_block(t->type(), t->name, + t->plaintext, t->expected, t->size, + t->iv, t->iv_size, t->acpkm); + if (t->stream) + ret |= test_stream(t->type(), t->name, + t->plaintext, t->expected, t->size, + t->iv, t->iv_size, t->acpkm); + } ret |= test_omac(); -- 2.39.5 From 488f3da97f0833c1608bffb6ea510be4314cef7f Mon Sep 17 00:00:00 2001 From: Vitaly Chikunov Date: Thu, 26 Jul 2018 07:34:07 +0300 Subject: [PATCH 03/16] Add kuznyechik_ctracpkm --- gost_eng.c | 4 ++ gost_grasshopper_cipher.c | 131 ++++++++++++++++++++++++++++++++++++-- gost_grasshopper_cipher.h | 8 +++ test/00-engine.t | 2 +- test_grasshopper.c | 21 ++++++ 5 files changed, 161 insertions(+), 5 deletions(-) diff --git a/gost_eng.c b/gost_eng.c index caedf9a..6ed13c7 100644 --- a/gost_eng.c +++ b/gost_eng.c @@ -49,6 +49,7 @@ static int gost_cipher_nids[] = { NID_grasshopper_ctr, NID_magma_cbc, NID_magma_ctr, + NID_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm, 0 }; @@ -253,6 +254,7 @@ static int bind_gost(ENGINE* e, const char* id) { || !EVP_add_cipher(cipher_gost_grasshopper_cfb()) || !EVP_add_cipher(cipher_gost_grasshopper_ofb()) || !EVP_add_cipher(cipher_gost_grasshopper_ctr()) + || !EVP_add_cipher(cipher_gost_grasshopper_ctracpkm()) || !EVP_add_cipher(cipher_magma_cbc()) || !EVP_add_cipher(cipher_magma_ctr()) || !EVP_add_digest(digest_gost()) @@ -332,6 +334,8 @@ static int gost_ciphers(ENGINE* e, const EVP_CIPHER** cipher, *cipher = cipher_gost_grasshopper_ofb(); } else if (nid == NID_grasshopper_ctr) { *cipher = cipher_gost_grasshopper_ctr(); + } else if (nid == NID_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm) { + *cipher = cipher_gost_grasshopper_ctracpkm(); } else if (nid == NID_magma_cbc) { *cipher = cipher_magma_cbc(); } else if (nid == NID_magma_ctr) { diff --git a/gost_grasshopper_cipher.c b/gost_grasshopper_cipher.c index baf25fe..a3f34d6 100644 --- a/gost_grasshopper_cipher.c +++ b/gost_grasshopper_cipher.c @@ -25,15 +25,17 @@ enum GRASSHOPPER_CIPHER_TYPE { GRASSHOPPER_CIPHER_CBC, GRASSHOPPER_CIPHER_OFB, GRASSHOPPER_CIPHER_CFB, - GRASSHOPPER_CIPHER_CTR + GRASSHOPPER_CIPHER_CTR, + GRASSHOPPER_CIPHER_CTRACPKM, }; -static EVP_CIPHER* gost_grasshopper_ciphers[5] = { +static EVP_CIPHER* gost_grasshopper_ciphers[6] = { [GRASSHOPPER_CIPHER_ECB] = NULL, [GRASSHOPPER_CIPHER_CBC] = NULL, [GRASSHOPPER_CIPHER_OFB] = NULL, [GRASSHOPPER_CIPHER_CFB] = NULL, - [GRASSHOPPER_CIPHER_CTR] = NULL + [GRASSHOPPER_CIPHER_CTR] = NULL, + [GRASSHOPPER_CIPHER_CTRACPKM] = NULL, }; static GRASSHOPPER_INLINE void gost_grasshopper_cipher_destroy_ofb(gost_grasshopper_cipher_ctx* c); @@ -50,7 +52,7 @@ struct GRASSHOPPER_CIPHER_PARAMS { bool padding; }; -static struct GRASSHOPPER_CIPHER_PARAMS gost_cipher_params[5] = { +static struct GRASSHOPPER_CIPHER_PARAMS gost_cipher_params[6] = { [GRASSHOPPER_CIPHER_ECB] = { NID_grasshopper_ecb, gost_grasshopper_cipher_init_ecb, @@ -104,8 +106,44 @@ static struct GRASSHOPPER_CIPHER_PARAMS gost_cipher_params[5] = { 16, false }, + [GRASSHOPPER_CIPHER_CTRACPKM] = { + NID_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm, + gost_grasshopper_cipher_init_ctracpkm, + gost_grasshopper_cipher_do_ctracpkm, + gost_grasshopper_cipher_destroy_ctr, + 1, + sizeof(gost_grasshopper_cipher_ctx_ctr), + 16, + false + }, +}; + +/* first 256 bit of D from draft-irtf-cfrg-re-keying-12 */ +static const unsigned char ACPKM_D_2018[] = { + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 64 bit */ + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 128 bit */ + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 256 bit */ }; +static void acpkm_grasshopper(gost_grasshopper_cipher_ctx_ctr *ctx) +{ + gost_grasshopper_cipher_ctx *c = &ctx->c; + unsigned char newkey[GRASSHOPPER_KEY_SIZE]; + const int J = GRASSHOPPER_KEY_SIZE / GRASSHOPPER_BLOCK_SIZE; + int n; + + for (n = 0; n < J; n++) { + const unsigned char *D_n = &ACPKM_D_2018[n * GRASSHOPPER_BLOCK_SIZE]; + + grasshopper_encrypt_block(&c->encrypt_round_keys, + (grasshopper_w128_t *)D_n, + (grasshopper_w128_t *)&newkey[n * GRASSHOPPER_BLOCK_SIZE], + &c->buffer); + } + gost_grasshopper_cipher_key(c, newkey); +} + /* Set 256 bit key into context */ GRASSHOPPER_INLINE void gost_grasshopper_cipher_key(gost_grasshopper_cipher_ctx* c, const uint8_t* k) { int i; @@ -218,6 +256,20 @@ GRASSHOPPER_INLINE int gost_grasshopper_cipher_init_ctr(EVP_CIPHER_CTX* ctx, con return gost_grasshopper_cipher_init(ctx, key, iv, enc); } +GRASSHOPPER_INLINE int gost_grasshopper_cipher_init_ctracpkm(EVP_CIPHER_CTX *ctx, const unsigned char *key, + const unsigned char *iv, + int enc) { + gost_grasshopper_cipher_ctx_ctr *c = EVP_CIPHER_CTX_get_cipher_data(ctx); + + /* NB: setting type makes EVP do_cipher callback useless */ + c->c.type = GRASSHOPPER_CIPHER_CTRACPKM; + EVP_CIPHER_CTX_set_num(ctx, 0); + c->section_size = 0; /* by default meshing is turned off */ + c->skip_sections = 0; /* will be set to 1 on EVP_CTRL_KEY_MESH */ + + return gost_grasshopper_cipher_init(ctx, key, iv, enc); +} + GRASSHOPPER_INLINE int gost_grasshopper_cipher_do(EVP_CIPHER_CTX* ctx, unsigned char* out, const unsigned char* in, size_t inl) { gost_grasshopper_cipher_ctx* c = (gost_grasshopper_cipher_ctx*) EVP_CIPHER_CTX_get_cipher_data(ctx); @@ -351,6 +403,64 @@ int gost_grasshopper_cipher_do_ctr(EVP_CIPHER_CTX* ctx, unsigned char* out, return 1; } +static inline void apply_acpkm_grasshopper(gost_grasshopper_cipher_ctx_ctr *ctx, unsigned int num) +{ + if (!ctx->section_size || + (num & (ctx->section_size - 1))) + return; + if (ctx->skip_sections) { + /* In no master key mode first section is using original key */ + --ctx->skip_sections; + return; + } + acpkm_grasshopper(ctx); +} + +#define GRASSHOPPER_BLOCK_MASK (GRASSHOPPER_BLOCK_SIZE - 1) +/* If meshing is not configured via ctrl (setting section_size) + * this function works exactly like plain ctr */ +int gost_grasshopper_cipher_do_ctracpkm(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t inl) { + gost_grasshopper_cipher_ctx_ctr *c = EVP_CIPHER_CTX_get_cipher_data(ctx); + unsigned char *iv = EVP_CIPHER_CTX_iv_noconst(ctx); + unsigned int num = EVP_CIPHER_CTX_num(ctx); + + while ((num & GRASSHOPPER_BLOCK_MASK) && inl) { + *out++ = *in++ ^ c->partial_buffer.b[num & GRASSHOPPER_BLOCK_MASK]; + --inl; + num++; + } + size_t blocks = inl / GRASSHOPPER_BLOCK_SIZE; + size_t i; + + // full parts + for (i = 0; i < blocks; i++) { + apply_acpkm_grasshopper(c, num); + grasshopper_encrypt_block(&c->c.encrypt_round_keys, + (grasshopper_w128_t *)iv, (grasshopper_w128_t *)out, &c->c.buffer); + grasshopper_append128((grasshopper_w128_t *)out, (grasshopper_w128_t *)in); + ctr128_inc(iv); + in += GRASSHOPPER_BLOCK_SIZE; + out += GRASSHOPPER_BLOCK_SIZE; + num += GRASSHOPPER_BLOCK_SIZE; + } + + // last part + size_t lasted = inl - blocks * GRASSHOPPER_BLOCK_SIZE; + if (lasted > 0) { + apply_acpkm_grasshopper(c, num); + grasshopper_encrypt_block(&c->c.encrypt_round_keys, + (grasshopper_w128_t *)iv, &c->partial_buffer, &c->c.buffer); + for (i = 0; i < lasted; i++) + out[i] = c->partial_buffer.b[i] ^ in[i]; + ctr128_inc(iv); + num += lasted; + } + EVP_CIPHER_CTX_set_num(ctx, num); + + return 1; +} + /* * Fixed 128-bit IV implementation make shift regiser redundant. */ @@ -549,6 +659,13 @@ int gost_grasshopper_cipher_ctl(EVP_CIPHER_CTX* ctx, int type, int arg, void* pt } break; } + case EVP_CTRL_KEY_MESH: + if (arg <= 1 || ((arg - 1) & arg)) + return -1; + gost_grasshopper_cipher_ctx_ctr *c = EVP_CIPHER_CTX_get_cipher_data(ctx); + c->section_size = arg; + c->skip_sections = 1; + break; default: GOSTerr(GOST_F_GOST_GRASSHOPPER_CIPHER_CTL, GOST_R_UNSUPPORTED_CIPHER_CTL_COMMAND); return -1; @@ -630,6 +747,10 @@ const GRASSHOPPER_INLINE EVP_CIPHER* cipher_gost_grasshopper_ctr() { return cipher_gost_grasshopper(EVP_CIPH_CTR_MODE, GRASSHOPPER_CIPHER_CTR); } +const GRASSHOPPER_INLINE EVP_CIPHER* cipher_gost_grasshopper_ctracpkm() { + return cipher_gost_grasshopper(EVP_CIPH_CTR_MODE, GRASSHOPPER_CIPHER_CTRACPKM); +} + void cipher_gost_grasshopper_destroy(void) { EVP_CIPHER_meth_free(gost_grasshopper_ciphers[GRASSHOPPER_CIPHER_ECB]); @@ -642,6 +763,8 @@ void cipher_gost_grasshopper_destroy(void) gost_grasshopper_ciphers[GRASSHOPPER_CIPHER_CFB] = NULL; EVP_CIPHER_meth_free(gost_grasshopper_ciphers[GRASSHOPPER_CIPHER_CTR]); gost_grasshopper_ciphers[GRASSHOPPER_CIPHER_CTR] = NULL; + EVP_CIPHER_meth_free(gost_grasshopper_ciphers[GRASSHOPPER_CIPHER_CTRACPKM]); + gost_grasshopper_ciphers[GRASSHOPPER_CIPHER_CTRACPKM] = NULL; } #if defined(__cplusplus) diff --git a/gost_grasshopper_cipher.h b/gost_grasshopper_cipher.h index c8957a0..0ab17c1 100644 --- a/gost_grasshopper_cipher.h +++ b/gost_grasshopper_cipher.h @@ -32,6 +32,9 @@ typedef struct { typedef struct { gost_grasshopper_cipher_ctx c; grasshopper_w128_t partial_buffer; + unsigned int skip_sections; /* 1 or 0, used to skip meshing for a first section */ + unsigned int section_size; /* After how much bytes mesh the key, + if 0 never mesh and work like plain ctr. */ } gost_grasshopper_cipher_ctx_ctr; typedef int (* grasshopper_init_cipher_func)(EVP_CIPHER_CTX* ctx, const unsigned char* key, const unsigned char* iv, @@ -56,6 +59,8 @@ int gost_grasshopper_cipher_init_cfb(EVP_CIPHER_CTX* ctx, const unsigned char* k int gost_grasshopper_cipher_init_ctr(EVP_CIPHER_CTX* ctx, const unsigned char* key, const unsigned char* iv, int enc); +int gost_grasshopper_cipher_init_ctracpkm(EVP_CIPHER_CTX* ctx, const unsigned char* key, const unsigned char* iv, int enc); + int gost_grasshopper_cipher_init(EVP_CIPHER_CTX* ctx, const unsigned char* key, const unsigned char* iv, int enc); @@ -76,6 +81,8 @@ int gost_grasshopper_cipher_do_cfb(EVP_CIPHER_CTX* ctx, unsigned char* out, int gost_grasshopper_cipher_do_ctr(EVP_CIPHER_CTX* ctx, unsigned char* out, const unsigned char* in, size_t inl); +int gost_grasshopper_cipher_do_ctracpkm(EVP_CIPHER_CTX* ctx, unsigned char* out, + const unsigned char* in, size_t inl); int gost_grasshopper_cipher_cleanup(EVP_CIPHER_CTX* ctx); @@ -96,6 +103,7 @@ extern const EVP_CIPHER* cipher_gost_grasshopper_cbc(); extern const EVP_CIPHER* cipher_gost_grasshopper_ofb(); extern const EVP_CIPHER* cipher_gost_grasshopper_cfb(); extern const EVP_CIPHER* cipher_gost_grasshopper_ctr(); +extern const EVP_CIPHER* cipher_gost_grasshopper_ctracpkm(); void cipher_gost_grasshopper_destroy(void); diff --git a/test/00-engine.t b/test/00-engine.t index adc78b5..16f2c35 100644 --- a/test/00-engine.t +++ b/test/00-engine.t @@ -40,7 +40,7 @@ if ( -f $engine . ".info") { $engine_info= < Date: Thu, 26 Jul 2018 12:07:11 +0300 Subject: [PATCH 04/16] Set default value for CTR ACPKM limit Default limit for Kuznyechik is 4KiB, from TLS 1.2 recommendations. As a consequence it does not need to be configured via EVP_CTRL_KEY_MESH. Also, explicitly set ACPKM limit in tests. --- gost_grasshopper_cipher.c | 4 ++-- test_grasshopper.c | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/gost_grasshopper_cipher.c b/gost_grasshopper_cipher.c index a3f34d6..07dfd91 100644 --- a/gost_grasshopper_cipher.c +++ b/gost_grasshopper_cipher.c @@ -264,8 +264,8 @@ GRASSHOPPER_INLINE int gost_grasshopper_cipher_init_ctracpkm(EVP_CIPHER_CTX *ctx /* NB: setting type makes EVP do_cipher callback useless */ c->c.type = GRASSHOPPER_CIPHER_CTRACPKM; EVP_CIPHER_CTX_set_num(ctx, 0); - c->section_size = 0; /* by default meshing is turned off */ - c->skip_sections = 0; /* will be set to 1 on EVP_CTRL_KEY_MESH */ + c->section_size = 4096; + c->skip_sections = 1; return gost_grasshopper_cipher_init(ctx, key, iv, enc); } diff --git a/test_grasshopper.c b/test_grasshopper.c index 1b0f913..db2c3e1 100644 --- a/test_grasshopper.c +++ b/test_grasshopper.c @@ -130,8 +130,8 @@ struct testcase { static struct testcase testcases[] = { { "ecb", cipher_gost_grasshopper_ecb, 0, P, E_ecb, sizeof(P), NULL, 0, 0 }, { "ctr", cipher_gost_grasshopper_ctr, 1, P, E_ctr, sizeof(P), iv_ctr, sizeof(iv_ctr), 0 }, - { "ctr-no-acpkm", cipher_gost_grasshopper_ctracpkm, 1, P, E_ctr, sizeof(P), iv_ctr, sizeof(iv_ctr), 0 }, - { "ctracpkm", cipher_gost_grasshopper_ctracpkm, 1, P_acpkm, E_acpkm, sizeof(P_acpkm), iv_ctr, sizeof(iv_ctr), 1 }, + { "ctr-no-acpkm", cipher_gost_grasshopper_ctracpkm, 1, P, E_ctr, sizeof(P), iv_ctr, sizeof(iv_ctr), 0 }, + { "ctracpkm", cipher_gost_grasshopper_ctracpkm, 1, P_acpkm, E_acpkm, sizeof(P_acpkm), iv_ctr, sizeof(iv_ctr), 256 / 8 }, { "ofb", cipher_gost_grasshopper_ofb, 1, P, E_ofb, sizeof(P), iv_128bit, sizeof(iv_128bit), 0 }, { "cbc", cipher_gost_grasshopper_cbc, 0, P, E_cbc, sizeof(P), iv_128bit, sizeof(iv_128bit), 0 }, { "cfb", cipher_gost_grasshopper_cfb, 0, P, E_cfb, sizeof(P), iv_128bit, sizeof(iv_128bit), 0 }, @@ -167,7 +167,7 @@ static int test_block(const EVP_CIPHER *type, const char *name, T(EVP_CIPHER_CTX_set_padding(ctx, 0)); memset(c, 0, sizeof(c)); if (acpkm) - T(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_KEY_MESH, 256 / 8, NULL)); + T(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_KEY_MESH, acpkm, NULL)); T(EVP_CipherUpdate(ctx, c, &outlen, pt, size)); T(EVP_CipherFinal_ex(ctx, c + outlen, &tmplen)); EVP_CIPHER_CTX_cleanup(ctx); @@ -186,7 +186,7 @@ static int test_block(const EVP_CIPHER *type, const char *name, T(EVP_CIPHER_CTX_set_padding(ctx, 0)); memset(c, 0, sizeof(c)); if (acpkm) - T(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_KEY_MESH, 256 / 8, NULL)); + T(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_KEY_MESH, acpkm, NULL)); for (z = 0; z < blocks; z++) { int offset = z * GRASSHOPPER_BLOCK_SIZE; int sz = GRASSHOPPER_BLOCK_SIZE; @@ -209,7 +209,7 @@ static int test_block(const EVP_CIPHER *type, const char *name, T(EVP_CIPHER_CTX_set_padding(ctx, 0)); memset(c, 0, sizeof(c)); if (acpkm) - T(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_KEY_MESH, 256 / 8, NULL)); + T(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_KEY_MESH, acpkm, NULL)); T(EVP_CipherUpdate(ctx, c, &outlen, exp, size)); T(EVP_CipherFinal_ex(ctx, c + outlen, &tmplen)); EVP_CIPHER_CTX_cleanup(ctx); @@ -245,7 +245,7 @@ static int test_stream(const EVP_CIPHER *type, const char *name, EVP_CIPHER_CTX_set_padding(ctx, 0); memset(c, 0xff, sizeof(c)); if (acpkm) - T(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_KEY_MESH, 256 / 8, NULL)); + T(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_KEY_MESH, acpkm, NULL)); for (i = 0; i < size; i += z) { if (i + z > size) sz = size - i; -- 2.39.5 From 2be13cb5c7e96d6bdead59b37717c2f49a581e9e Mon Sep 17 00:00:00 2001 From: Vitaly Chikunov Date: Thu, 26 Jul 2018 12:23:55 +0300 Subject: [PATCH 05/16] Ensure proper cipher type for EVP_CTRL_KEY_MESH --- gost_grasshopper_cipher.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/gost_grasshopper_cipher.c b/gost_grasshopper_cipher.c index 07dfd91..528a7ee 100644 --- a/gost_grasshopper_cipher.c +++ b/gost_grasshopper_cipher.c @@ -659,13 +659,16 @@ int gost_grasshopper_cipher_ctl(EVP_CIPHER_CTX* ctx, int type, int arg, void* pt } break; } - case EVP_CTRL_KEY_MESH: - if (arg <= 1 || ((arg - 1) & arg)) - return -1; + case EVP_CTRL_KEY_MESH: { gost_grasshopper_cipher_ctx_ctr *c = EVP_CIPHER_CTX_get_cipher_data(ctx); + if (c->c.type != GRASSHOPPER_CIPHER_CTRACPKM || + arg <= 1 || + ((arg - 1) & arg)) + return -1; c->section_size = arg; c->skip_sections = 1; break; + } default: GOSTerr(GOST_F_GOST_GRASSHOPPER_CIPHER_CTL, GOST_R_UNSUPPORTED_CIPHER_CTL_COMMAND); return -1; -- 2.39.5 From ae390d45207aadb69eb96d8c11c1ee888f70815f Mon Sep 17 00:00:00 2001 From: Vitaly Chikunov Date: Sat, 28 Jul 2018 10:36:29 +0300 Subject: [PATCH 06/16] Optimize out skip_sections and add tests for ACPKM-Master ACPKM-Master is from R 23565.1.017-2018, it will be required for ACPKM-OMAC for TLS 1.2. --- gost_grasshopper_cipher.c | 26 +++++++++----------------- gost_grasshopper_cipher.h | 1 - test_grasshopper.c | 34 ++++++++++++++++++++++++++++------ 3 files changed, 37 insertions(+), 24 deletions(-) diff --git a/gost_grasshopper_cipher.c b/gost_grasshopper_cipher.c index 528a7ee..e78fae7 100644 --- a/gost_grasshopper_cipher.c +++ b/gost_grasshopper_cipher.c @@ -126,9 +126,8 @@ static const unsigned char ACPKM_D_2018[] = { 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 256 bit */ }; -static void acpkm_grasshopper(gost_grasshopper_cipher_ctx_ctr *ctx) +static void acpkm_next(gost_grasshopper_cipher_ctx *c) { - gost_grasshopper_cipher_ctx *c = &ctx->c; unsigned char newkey[GRASSHOPPER_KEY_SIZE]; const int J = GRASSHOPPER_KEY_SIZE / GRASSHOPPER_BLOCK_SIZE; int n; @@ -265,7 +264,6 @@ GRASSHOPPER_INLINE int gost_grasshopper_cipher_init_ctracpkm(EVP_CIPHER_CTX *ctx c->c.type = GRASSHOPPER_CIPHER_CTRACPKM; EVP_CIPHER_CTX_set_num(ctx, 0); c->section_size = 4096; - c->skip_sections = 1; return gost_grasshopper_cipher_init(ctx, key, iv, enc); } @@ -403,20 +401,16 @@ int gost_grasshopper_cipher_do_ctr(EVP_CIPHER_CTX* ctx, unsigned char* out, return 1; } -static inline void apply_acpkm_grasshopper(gost_grasshopper_cipher_ctx_ctr *ctx, unsigned int num) +#define GRASSHOPPER_BLOCK_MASK (GRASSHOPPER_BLOCK_SIZE - 1) +static inline void apply_acpkm_grasshopper(gost_grasshopper_cipher_ctx_ctr *ctx, unsigned int *num) { if (!ctx->section_size || - (num & (ctx->section_size - 1))) - return; - if (ctx->skip_sections) { - /* In no master key mode first section is using original key */ - --ctx->skip_sections; + (*num < ctx->section_size)) return; - } - acpkm_grasshopper(ctx); + acpkm_next(&ctx->c); + *num &= GRASSHOPPER_BLOCK_MASK; } -#define GRASSHOPPER_BLOCK_MASK (GRASSHOPPER_BLOCK_SIZE - 1) /* If meshing is not configured via ctrl (setting section_size) * this function works exactly like plain ctr */ int gost_grasshopper_cipher_do_ctracpkm(EVP_CIPHER_CTX *ctx, unsigned char *out, @@ -435,7 +429,7 @@ int gost_grasshopper_cipher_do_ctracpkm(EVP_CIPHER_CTX *ctx, unsigned char *out, // full parts for (i = 0; i < blocks; i++) { - apply_acpkm_grasshopper(c, num); + apply_acpkm_grasshopper(c, &num); grasshopper_encrypt_block(&c->c.encrypt_round_keys, (grasshopper_w128_t *)iv, (grasshopper_w128_t *)out, &c->c.buffer); grasshopper_append128((grasshopper_w128_t *)out, (grasshopper_w128_t *)in); @@ -448,7 +442,7 @@ int gost_grasshopper_cipher_do_ctracpkm(EVP_CIPHER_CTX *ctx, unsigned char *out, // last part size_t lasted = inl - blocks * GRASSHOPPER_BLOCK_SIZE; if (lasted > 0) { - apply_acpkm_grasshopper(c, num); + apply_acpkm_grasshopper(c, &num); grasshopper_encrypt_block(&c->c.encrypt_round_keys, (grasshopper_w128_t *)iv, &c->partial_buffer, &c->c.buffer); for (i = 0; i < lasted; i++) @@ -662,11 +656,9 @@ int gost_grasshopper_cipher_ctl(EVP_CIPHER_CTX* ctx, int type, int arg, void* pt case EVP_CTRL_KEY_MESH: { gost_grasshopper_cipher_ctx_ctr *c = EVP_CIPHER_CTX_get_cipher_data(ctx); if (c->c.type != GRASSHOPPER_CIPHER_CTRACPKM || - arg <= 1 || - ((arg - 1) & arg)) + !arg || (arg % GRASSHOPPER_BLOCK_SIZE)) return -1; c->section_size = arg; - c->skip_sections = 1; break; } default: diff --git a/gost_grasshopper_cipher.h b/gost_grasshopper_cipher.h index 0ab17c1..cc67795 100644 --- a/gost_grasshopper_cipher.h +++ b/gost_grasshopper_cipher.h @@ -32,7 +32,6 @@ typedef struct { typedef struct { gost_grasshopper_cipher_ctx c; grasshopper_w128_t partial_buffer; - unsigned int skip_sections; /* 1 or 0, used to skip meshing for a first section */ unsigned int section_size; /* After how much bytes mesh the key, if 0 never mesh and work like plain ctr. */ } gost_grasshopper_cipher_ctx_ctr; diff --git a/test_grasshopper.c b/test_grasshopper.c index db2c3e1..ab6e200 100644 --- a/test_grasshopper.c +++ b/test_grasshopper.c @@ -80,6 +80,20 @@ static const unsigned char E_acpkm[] = { 0xDF,0xFD,0x07,0xEC,0x81,0x36,0x36,0x46,0x0C,0x4F,0x3B,0x74,0x34,0x23,0x16,0x3E, 0x64,0x09,0xA9,0xC2,0x82,0xFA,0xC8,0xD4,0x69,0xD2,0x21,0xE7,0xFB,0xD6,0xDE,0x5D, }; +/* Test vector from R 23565.1.017-2018 A.4.2. + * Key material from ACPKM-Master(K,768,3) for OMAC-ACPKM. */ +static const unsigned char E_acpkm_master[] = { + 0x0C,0xAB,0xF1,0xF2,0xEF,0xBC,0x4A,0xC1,0x60,0x48,0xDF,0x1A,0x24,0xC6,0x05,0xB2, + 0xC0,0xD1,0x67,0x3D,0x75,0x86,0xA8,0xEC,0x0D,0xD4,0x2C,0x45,0xA4,0xF9,0x5B,0xAE, + 0x0F,0x2E,0x26,0x17,0xE4,0x71,0x48,0x68,0x0F,0xC3,0xE6,0x17,0x8D,0xF2,0xC1,0x37, + 0xC9,0xDD,0xA8,0x9C,0xFF,0xA4,0x91,0xFE,0xAD,0xD9,0xB3,0xEA,0xB7,0x03,0xBB,0x31, + 0xBC,0x7E,0x92,0x7F,0x04,0x94,0x72,0x9F,0x51,0xB4,0x9D,0x3D,0xF9,0xC9,0x46,0x08, + 0x00,0xFB,0xBC,0xF5,0xED,0xEE,0x61,0x0E,0xA0,0x2F,0x01,0x09,0x3C,0x7B,0xC7,0x42, + 0xD7,0xD6,0x27,0x15,0x01,0xB1,0x77,0x77,0x52,0x63,0xC2,0xA3,0x49,0x5A,0x83,0x18, + 0xA8,0x1C,0x79,0xA0,0x4F,0x29,0x66,0x0E,0xA3,0xFD,0xA8,0x74,0xC6,0x30,0x79,0x9E, + 0x14,0x2C,0x57,0x79,0x14,0xFE,0xA9,0x0D,0x3B,0xC2,0x50,0x2E,0x83,0x36,0x85,0xD9, +}; +static const unsigned char P_acpkm_master[sizeof(E_acpkm_master)] = { 0 }; /* * Other modes (ofb, cbc, cfb) is impossible to test to match GOST R * 34.13-2015 test vectors exactly, due to these vectors having exceeding @@ -112,10 +126,14 @@ static const unsigned char E_cfb[] = { 0xe1,0xc8,0x52,0xe9,0xa8,0x56,0x71,0x62,0xdb,0xb5,0xda,0x7f,0x66,0xde,0xa9,0x26, }; -static const unsigned char iv_ctr[] = { 0x12,0x34,0x56,0x78,0x90,0xab,0xce,0xf0, 0,0,0,0,0,0,0,0 }; -/* truncated to 128-bits IV */ +static const unsigned char iv_ctr[] = { 0x12,0x34,0x56,0x78,0x90,0xab,0xce,0xf0, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; +/* Truncated to 128-bits IV from GOST examples. */ static const unsigned char iv_128bit[] = { 0x12,0x34,0x56,0x78,0x90,0xab,0xce,0xf0, 0xa1,0xb2,0xc3,0xd4,0xe5,0xf0,0x01,0x12 }; +/* Universal IV for ACPKM-Master. */ +static const unsigned char iv_acpkm_m[] = { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; struct testcase { const char *name; const EVP_CIPHER *(*type)(void); @@ -132,6 +150,8 @@ static struct testcase testcases[] = { { "ctr", cipher_gost_grasshopper_ctr, 1, P, E_ctr, sizeof(P), iv_ctr, sizeof(iv_ctr), 0 }, { "ctr-no-acpkm", cipher_gost_grasshopper_ctracpkm, 1, P, E_ctr, sizeof(P), iv_ctr, sizeof(iv_ctr), 0 }, { "ctracpkm", cipher_gost_grasshopper_ctracpkm, 1, P_acpkm, E_acpkm, sizeof(P_acpkm), iv_ctr, sizeof(iv_ctr), 256 / 8 }, + { "acpkm-Master", cipher_gost_grasshopper_ctracpkm, 0, P_acpkm_master, E_acpkm_master, sizeof(P_acpkm_master), + iv_acpkm_m, sizeof(iv_acpkm_m), 768 / 8 }, { "ofb", cipher_gost_grasshopper_ofb, 1, P, E_ofb, sizeof(P), iv_128bit, sizeof(iv_128bit), 0 }, { "cbc", cipher_gost_grasshopper_cbc, 0, P, E_cbc, sizeof(P), iv_128bit, sizeof(iv_128bit), 0 }, { "cfb", cipher_gost_grasshopper_cfb, 0, P, E_cfb, sizeof(P), iv_128bit, sizeof(iv_128bit), 0 }, @@ -155,12 +175,13 @@ static int test_block(const EVP_CIPHER *type, const char *name, const unsigned char *iv, size_t iv_size, int acpkm) { EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + const char *standard = acpkm? "R 23565.1.017-2018" : "GOST R 34.13-2015"; unsigned char c[size]; int outlen, tmplen; int ret = 0, test; OPENSSL_assert(ctx); - printf("Encryption test from GOST R 34.13-2015 [%s] \n", name); + printf("Encryption test from %s [%s] \n", standard, name); /* test with single big chunk */ EVP_CIPHER_CTX_init(ctx); T(EVP_CipherInit_ex(ctx, type, NULL, K, iv, 1)); @@ -178,7 +199,7 @@ static int test_block(const EVP_CIPHER *type, const char *name, ret |= test; /* test with small chunks of block size */ - printf("Chunked encryption test from GOST R 34.13-2015 [%s] \n", name); + printf("Chunked encryption test from %s [%s] \n", standard, name); int blocks = size / GRASSHOPPER_BLOCK_SIZE; int z; EVP_CIPHER_CTX_init(ctx); @@ -203,7 +224,7 @@ static int test_block(const EVP_CIPHER *type, const char *name, ret |= test; /* test with single big chunk */ - printf("Decryption test from GOST R 34.13-2015 [%s] \n", name); + printf("Decryption test from %s [%s] \n", standard, name); EVP_CIPHER_CTX_init(ctx); T(EVP_CipherInit_ex(ctx, type, NULL, K, iv, 0)); T(EVP_CIPHER_CTX_set_padding(ctx, 0)); @@ -228,12 +249,13 @@ static int test_stream(const EVP_CIPHER *type, const char *name, const unsigned char *iv, size_t iv_size, int acpkm) { EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + const char *standard = acpkm? "R 23565.1.017-2018" : "GOST R 34.13-2015"; int ret = 0, test; int z; OPENSSL_assert(ctx); /* Cycle through all lengths from 1 upto maximum size */ - printf("Stream encryption test from GOST R 34.13-2015 [%s] \n", name); + printf("Stream encryption test from %s [%s] \n", standard, name); for (z = 1; z <= size; z++) { unsigned char c[size]; int outlen, tmplen; -- 2.39.5 From 636dd0c1f36872f0abcb4f8a465e837929ed19d1 Mon Sep 17 00:00:00 2001 From: Vitaly Chikunov Date: Thu, 2 Aug 2018 00:03:06 +0300 Subject: [PATCH 07/16] Fix EVP_MD_CTX_copy_ex for OMAC Openssl copies a state between valid contexts. But, EVP_MD_CTX_copy_ex just memcpy-s private data (md_data), which points to OMAC_CTX), which have pointer to CMAC_CTX. Copying pointer makes CMAC context just the same on the both sides. As a consequence, we can not do normal copy of a state between CMAC contexts. As a fix, we just clone it if it's equal between copy sides. Reported-by: Gleb Fotengauer-Malinovskiy --- gost_omac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gost_omac.c b/gost_omac.c index c4e8111..af6eb2a 100644 --- a/gost_omac.c +++ b/gost_omac.c @@ -91,7 +91,7 @@ int omac_imit_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from) } if (c_to->cmac_ctx == c_from->cmac_ctx) { - return 1; + c_to->cmac_ctx = CMAC_CTX_new(); } return CMAC_CTX_copy(c_to->cmac_ctx, c_from->cmac_ctx); } -- 2.39.5 From 10ae275fd54e600c08ee330eaf9738aa476e0ca4 Mon Sep 17 00:00:00 2001 From: Vitaly Chikunov Date: Thu, 2 Aug 2018 16:59:14 +0300 Subject: [PATCH 08/16] Fix possible overflow of digest result writing Openssl is already have output result size in EVP_MD.md_size We should not exceed its value when writing digest output. This should be fixed more consistently, probably, by removing dgst_size from OMAC_CTX. --- compat.h | 5 +++++ gost_omac.c | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/compat.h b/compat.h index 91afcf5..29a2ad3 100644 --- a/compat.h +++ b/compat.h @@ -252,6 +252,11 @@ static inline int EVP_MD_meth_set_result_size(EVP_MD *md, int resultsize) return 1; } +static int EVP_MD_meth_get_result_size(const EVP_MD *md) +{ + return md->md_size; +} + static inline int EVP_MD_meth_set_input_blocksize(EVP_MD *md, int blocksize) { md->block_size = blocksize; diff --git a/gost_omac.c b/gost_omac.c index af6eb2a..d1f897a 100644 --- a/gost_omac.c +++ b/gost_omac.c @@ -7,6 +7,8 @@ #include "e_gost_err.h" #include "gost_lcl.h" +#define min(a,b) (((a) < (b)) ? (a) : (b)) + typedef struct omac_ctx { CMAC_CTX *cmac_ctx; size_t dgst_size; @@ -71,7 +73,8 @@ int omac_imit_final(EVP_MD_CTX *ctx, unsigned char *md) CMAC_Final(c->cmac_ctx, mac, &mac_size); - memcpy(md, mac, c->dgst_size); + int md_size = EVP_MD_meth_get_result_size(EVP_MD_CTX_md(ctx)); + memcpy(md, mac, min(md_size, c->dgst_size)); return 1; } -- 2.39.5 From e0816ed2014bad0e5293cafcce2c07a66a4f1cb0 Mon Sep 17 00:00:00 2001 From: Vitaly Chikunov Date: Thu, 2 Aug 2018 21:41:02 +0300 Subject: [PATCH 09/16] Allow EVP_MD_CTX_copy_ex OMAC before key is set Reported-by: Gleb Fotengauer-Malinovskiy --- gost_omac.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/gost_omac.c b/gost_omac.c index d1f897a..e78fd9d 100644 --- a/gost_omac.c +++ b/gost_omac.c @@ -92,6 +92,13 @@ int omac_imit_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from) { return 0; } + if (!c_from->cmac_ctx) { + if (c_to->cmac_ctx) { + CMAC_CTX_free(c_to->cmac_ctx); + c_to->cmac_ctx = NULL; + } + return 1; + } if (c_to->cmac_ctx == c_from->cmac_ctx) { c_to->cmac_ctx = CMAC_CTX_new(); -- 2.39.5 From 28ab2b8b0ab2d1677df3940cf4fcdf1597da4ccf Mon Sep 17 00:00:00 2001 From: Vitaly Chikunov Date: Sun, 5 Aug 2018 03:44:46 +0300 Subject: [PATCH 10/16] Add grasshopper_omac_acpkm (OMAC-ACPKM) --- CMakeLists.txt | 2 + gost_eng.c | 3 + gost_lcl.h | 2 + gost_omac_acpkm.c | 521 +++++++++++++++++++++++++++++++++++++++++++++ test_grasshopper.c | 62 ++++-- 5 files changed, 577 insertions(+), 13 deletions(-) create mode 100644 gost_omac_acpkm.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 0add5fd..a937569 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,6 +91,7 @@ set(GOST_EC_SOURCE_FILES set (GOST_OMAC_SOURCE_FILES gost_omac.c + gost_omac_acpkm.c ) set(GOST_LIB_SOURCE_FILES @@ -109,6 +110,7 @@ set(GOST_ENGINE_SOURCE_FILES gost_md2012.c gost_pmeth.c gost_omac.c + gost_omac_acpkm.c ) add_executable(test_grasshopper test_grasshopper.c) diff --git a/gost_eng.c b/gost_eng.c index 6ed13c7..11344db 100644 --- a/gost_eng.c +++ b/gost_eng.c @@ -123,6 +123,7 @@ static int gost_engine_destroy(ENGINE* e) { imit_gost_cp_12_destroy(); magma_omac_destroy(); grasshopper_omac_destroy(); + grasshopper_omac_acpkm_destroy(); cipher_gost_destroy(); cipher_gost_grasshopper_destroy(); @@ -301,6 +302,8 @@ static int gost_digests(ENGINE* e, const EVP_MD** digest, *digest = magma_omac(); } else if (nid == NID_grasshopper_mac) { *digest = grasshopper_omac(); + } else if (nid == NID_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm_omac) { + *digest = grasshopper_omac_acpkm(); } else { ok = 0; *digest = NULL; diff --git a/gost_lcl.h b/gost_lcl.h index 75d59b7..528794a 100644 --- a/gost_lcl.h +++ b/gost_lcl.h @@ -183,7 +183,9 @@ void imit_gost_cp_12_destroy(void); EVP_MD *magma_omac(void); void magma_omac_destroy(void); EVP_MD *grasshopper_omac(void); +EVP_MD *grasshopper_omac_acpkm(void); void grasshopper_omac_destroy(void); +void grasshopper_omac_acpkm_destroy(void); /* Cipher context used for EVP_CIPHER operation */ struct ossl_gost_cipher_ctx { int paramNID; diff --git a/gost_omac_acpkm.c b/gost_omac_acpkm.c new file mode 100644 index 0000000..6542bbf --- /dev/null +++ b/gost_omac_acpkm.c @@ -0,0 +1,521 @@ +/* + * Copyright (C) 2018 vt@altlinux.org. All Rights Reserved. + * Copyright (c) 2010 The OpenSSL Project. All rights reserved. + * + * Contents licensed under the terms of the OpenSSL license + * See https://www.openssl.org/source/license.html for details + */ +#include +#include +#include +#include +#include + +#include "e_gost_err.h" +#include "gost_lcl.h" +#include "gost_grasshopper_defines.h" +#include "gost_grasshopper_cipher.h" + +#define ACPKM_T_MAX (GRASSHOPPER_KEY_SIZE + GRASSHOPPER_BLOCK_SIZE) +/* + * CMAC code from crypto/cmac/cmac.c with ACPKM tweaks + */ +struct CMAC_ACPKM_CTX_st { + /* Cipher context to use */ + EVP_CIPHER_CTX *cctx; + /* CTR-ACPKM cipher */ + EVP_CIPHER_CTX *actx; + unsigned char km[ACPKM_T_MAX]; /* Key material */ + /* Temporary block */ + unsigned char tbl[EVP_MAX_BLOCK_LENGTH]; + /* Last (possibly partial) block */ + unsigned char last_block[EVP_MAX_BLOCK_LENGTH]; + /* Number of bytes in last block: -1 means context not initialised */ + int nlast_block; + unsigned int section_size; /* N */ + unsigned int num; /* processed bytes until section_size */ +}; +typedef struct CMAC_ACPKM_CTX_st CMAC_ACPKM_CTX; + +static unsigned char zero_iv[ACPKM_T_MAX]; + +/* Make temporary keys K1 and K2 */ + +static void make_kn(unsigned char *k1, unsigned char *l, int bl) +{ + int i; + /* Shift block to left, including carry */ + for (i = 0; i < bl; i++) { + k1[i] = l[i] << 1; + if (i < bl - 1 && l[i + 1] & 0x80) + k1[i] |= 1; + } + /* If MSB set fixup with R */ + if (l[0] & 0x80) + k1[bl - 1] ^= bl == 16 ? 0x87 : 0x1b; +} + +static CMAC_ACPKM_CTX *CMAC_ACPKM_CTX_new(void) +{ + CMAC_ACPKM_CTX *ctx; + ctx = OPENSSL_malloc(sizeof(CMAC_ACPKM_CTX)); + if (!ctx) + return NULL; + ctx->cctx = EVP_CIPHER_CTX_new(); + if (ctx->cctx == NULL) { + OPENSSL_free(ctx); + return NULL; + } + ctx->actx = EVP_CIPHER_CTX_new(); + if (ctx->actx == NULL) { + OPENSSL_free(ctx); + return NULL; + } + ctx->nlast_block = -1; + ctx->num = 0; + ctx->section_size = 4096; /* recommended value for Kuznyechik */ + return ctx; +} + +static void CMAC_ACPKM_CTX_cleanup(CMAC_ACPKM_CTX *ctx) +{ + EVP_CIPHER_CTX_cleanup(ctx->cctx); + EVP_CIPHER_CTX_cleanup(ctx->actx); + OPENSSL_cleanse(ctx->tbl, EVP_MAX_BLOCK_LENGTH); + OPENSSL_cleanse(ctx->km, ACPKM_T_MAX); + OPENSSL_cleanse(ctx->last_block, EVP_MAX_BLOCK_LENGTH); + ctx->nlast_block = -1; +} + +static void CMAC_ACPKM_CTX_free(CMAC_ACPKM_CTX *ctx) +{ + if (!ctx) + return; + CMAC_ACPKM_CTX_cleanup(ctx); + EVP_CIPHER_CTX_free(ctx->cctx); + EVP_CIPHER_CTX_free(ctx->actx); + OPENSSL_free(ctx); +} + +int CMAC_ACPKM_CTX_copy(CMAC_ACPKM_CTX *out, const CMAC_ACPKM_CTX *in) +{ + int bl; + if (in->nlast_block == -1) + return 0; + if (!EVP_CIPHER_CTX_copy(out->cctx, in->cctx)) + return 0; + if (!EVP_CIPHER_CTX_copy(out->actx, in->actx)) + return 0; + bl = EVP_CIPHER_CTX_block_size(in->cctx); + memcpy(out->km, in->km, ACPKM_T_MAX); + memcpy(out->tbl, in->tbl, bl); + memcpy(out->last_block, in->last_block, bl); + out->nlast_block = in->nlast_block; + out->section_size = in->section_size; + out->num = in->num; + return 1; +} + +static int CMAC_ACPKM_Init(CMAC_ACPKM_CTX *ctx, const void *key, size_t keylen, + const EVP_CIPHER *cipher, ENGINE *impl) +{ + /* All zeros means restart */ + if (!key && !cipher && !impl && keylen == 0) { + /* Not initialised */ + if (ctx->nlast_block == -1) + return 0; + if (!EVP_EncryptInit_ex(ctx->cctx, NULL, NULL, NULL, zero_iv)) + return 0; + memset(ctx->tbl, 0, EVP_CIPHER_CTX_block_size(ctx->cctx)); + ctx->nlast_block = 0; + /* No restart for ACPKM */ + return 1; + } + /* Initialise context */ + if (cipher) { + const EVP_CIPHER *acpkm; + + if (!EVP_EncryptInit_ex(ctx->cctx, cipher, impl, NULL, NULL)) + return 0; + switch (EVP_CIPHER_nid(cipher)) { + case NID_grasshopper_cbc: + acpkm = cipher_gost_grasshopper_ctracpkm(); + break; + default: + return 0; + } + if (!EVP_EncryptInit_ex(ctx->actx, acpkm, impl, NULL, NULL)) + return 0; + } + /* Non-NULL key means initialisation is complete */ + if (key) { + unsigned char acpkm_iv[EVP_MAX_BLOCK_LENGTH]; + + /* Initialize CTR for ACPKM-Master */ + if (!EVP_CIPHER_CTX_cipher(ctx->actx)) + return 0; + /* block size of ACPKM cipher could be 1, but, + * cbc cipher is same with correct block_size */ + const int block_size = EVP_CIPHER_CTX_block_size(ctx->cctx); + /* Wide IV = 1^{n/2} || 0, + * where a^r denotes the string that consists of r 'a' bits */ + memset(acpkm_iv, 0xff, block_size / 2); + memset(acpkm_iv + block_size / 2, 0, block_size / 2); + if (!EVP_EncryptInit_ex(ctx->actx, NULL, NULL, key, acpkm_iv)) + return 0; + /* EVP_CIPHER key_len may be different from EVP_CIPHER_CTX key_len */ + int key_len = EVP_CIPHER_key_length(EVP_CIPHER_CTX_cipher(ctx->actx)); + + /* Generate first key material (K^1 || K^1_1) */ + if (!EVP_Cipher(ctx->actx, ctx->km, zero_iv, key_len + block_size)) + return 0; + + /* Initialize cbc for CMAC */ + if (!EVP_CIPHER_CTX_cipher(ctx->cctx) || + !EVP_CIPHER_CTX_set_key_length(ctx->cctx, key_len)) + return 0; + /* set CBC key to K^1 */ + if (!EVP_EncryptInit_ex(ctx->cctx, NULL, NULL, ctx->km, zero_iv)) + return 0; + ctx->nlast_block = 0; + } + return 1; +} + +/* Encrypt zeros with master key + * to generate T*-sized key material */ +static int CMAC_ACPKM_Master(CMAC_ACPKM_CTX *ctx) +{ + return EVP_Cipher(ctx->actx, ctx->km, zero_iv, + EVP_CIPHER_key_length(EVP_CIPHER_CTX_cipher(ctx->actx)) + + EVP_CIPHER_CTX_block_size(ctx->cctx)); +} + +static int CMAC_ACPKM_Mesh(CMAC_ACPKM_CTX *ctx) +{ + if (ctx->num < ctx->section_size) + return 1; + ctx->num = 0; + if (!CMAC_ACPKM_Master(ctx)) + return 0; + /* Restart cbc with new key */ + if (!EVP_EncryptInit_ex(ctx->cctx, NULL, NULL, ctx->km, + EVP_CIPHER_CTX_iv(ctx->cctx))) + return 0; + return 1; +} + +static int CMAC_ACPKM_Update(CMAC_ACPKM_CTX *ctx, const void *in, size_t dlen) +{ + const unsigned char *data = in; + size_t bl; + if (ctx->nlast_block == -1) + return 0; + if (dlen == 0) + return 1; + bl = EVP_CIPHER_CTX_block_size(ctx->cctx); + /* Copy into partial block if we need to */ + if (ctx->nlast_block > 0) { + size_t nleft; + nleft = bl - ctx->nlast_block; + if (dlen < nleft) + nleft = dlen; + memcpy(ctx->last_block + ctx->nlast_block, data, nleft); + dlen -= nleft; + ctx->nlast_block += nleft; + /* If no more to process return */ + if (dlen == 0) + return 1; + data += nleft; + /* Else not final block so encrypt it */ + if (!CMAC_ACPKM_Mesh(ctx)) + return 0; + if (!EVP_Cipher(ctx->cctx, ctx->tbl, ctx->last_block, bl)) + return 0; + ctx->num += bl; + } + /* Encrypt all but one of the complete blocks left */ + while (dlen > bl) { + if (!CMAC_ACPKM_Mesh(ctx)) + return 0; + if (!EVP_Cipher(ctx->cctx, ctx->tbl, data, bl)) + return 0; + dlen -= bl; + data += bl; + ctx->num += bl; + } + /* Copy any data left to last block buffer */ + memcpy(ctx->last_block, data, dlen); + ctx->nlast_block = dlen; + return 1; + +} + +static int CMAC_ACPKM_Final(CMAC_ACPKM_CTX *ctx, unsigned char *out, + size_t *poutlen) +{ + int i, bl, lb; + if (ctx->nlast_block == -1) + return 0; + bl = EVP_CIPHER_CTX_block_size(ctx->cctx); + *poutlen = (size_t) bl; + if (!out) + return 1; + lb = ctx->nlast_block; + + if (!CMAC_ACPKM_Mesh(ctx)) + return 0; + int key_len = EVP_CIPHER_key_length(EVP_CIPHER_CTX_cipher(ctx->actx)); + /* Keys k1 and k2 */ + unsigned char *k1 = ctx->km + key_len; + unsigned char k2[EVP_MAX_BLOCK_LENGTH]; + make_kn(k2, ctx->km + key_len, bl); + + /* Is last block complete? */ + if (lb == bl) { + for (i = 0; i < bl; i++) + out[i] = ctx->last_block[i] ^ k1[i]; + } else { + ctx->last_block[lb] = 0x80; + if (bl - lb > 1) + memset(ctx->last_block + lb + 1, 0, bl - lb - 1); + for (i = 0; i < bl; i++) + out[i] = ctx->last_block[i] ^ k2[i]; + } + OPENSSL_cleanse(k1, bl); + OPENSSL_cleanse(k2, bl); + OPENSSL_cleanse(ctx->km, ACPKM_T_MAX); + if (!EVP_Cipher(ctx->cctx, out, out, bl)) { + OPENSSL_cleanse(out, bl); + return 0; + } + return 1; +} + +/* + * End of CMAC code from crypto/cmac/cmac.c with ACPKM tweaks + */ + +typedef struct omac_acpkm_ctx { + CMAC_ACPKM_CTX *cmac_ctx; + size_t dgst_size; + int cipher_nid; + int key_set; +} OMAC_ACPKM_CTX; + +#define MAX_GOST_OMAC_ACPKM_SIZE 16 + +static int omac_acpkm_init(EVP_MD_CTX *ctx, int cipher_nid) +{ + OMAC_ACPKM_CTX *c = EVP_MD_CTX_md_data(ctx); + memset(c, 0, sizeof(OMAC_ACPKM_CTX)); + c->cipher_nid = cipher_nid; + c->key_set = 0; + + switch (cipher_nid) { + case NID_grasshopper_cbc: + c->dgst_size = 16; + break; + } + + return 1; +} + +static int grasshopper_omac_acpkm_init(EVP_MD_CTX *ctx) +{ + return omac_acpkm_init(ctx, NID_grasshopper_cbc); +} + +static int omac_acpkm_imit_update(EVP_MD_CTX *ctx, const void *data, + size_t count) +{ + OMAC_ACPKM_CTX *c = EVP_MD_CTX_md_data(ctx); + if (!c->key_set) { + GOSTerr(GOST_F_OMAC_IMIT_UPDATE, GOST_R_MAC_KEY_NOT_SET); + return 0; + } + + return CMAC_ACPKM_Update(c->cmac_ctx, data, count); +} + +int omac_acpkm_imit_final(EVP_MD_CTX *ctx, unsigned char *md) +{ + OMAC_ACPKM_CTX *c = EVP_MD_CTX_md_data(ctx); + unsigned char mac[MAX_GOST_OMAC_ACPKM_SIZE]; + size_t mac_size = sizeof(mac); + + if (!c->key_set) { + GOSTerr(GOST_F_OMAC_IMIT_FINAL, GOST_R_MAC_KEY_NOT_SET); + return 0; + } + + CMAC_ACPKM_Final(c->cmac_ctx, mac, &mac_size); + + memcpy(md, mac, c->dgst_size); + return 1; +} + +int omac_acpkm_imit_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from) +{ + OMAC_ACPKM_CTX *c_to = EVP_MD_CTX_md_data(to); + const OMAC_ACPKM_CTX *c_from = EVP_MD_CTX_md_data(from); + + if (c_from && c_to) { + c_to->dgst_size = c_from->dgst_size; + c_to->cipher_nid = c_from->cipher_nid; + c_to->key_set = c_from->key_set; + } else { + return 0; + } + if (!c_from->cmac_ctx) { + if (c_to->cmac_ctx) { + CMAC_ACPKM_CTX_free(c_to->cmac_ctx); + c_to->cmac_ctx = NULL; + } + return 1; + } + if (c_to->cmac_ctx == c_from->cmac_ctx) { + c_to->cmac_ctx = CMAC_ACPKM_CTX_new(); + } + return CMAC_ACPKM_CTX_copy(c_to->cmac_ctx, c_from->cmac_ctx); +} + +/* Clean up imit ctx */ +int omac_acpkm_imit_cleanup(EVP_MD_CTX *ctx) +{ + OMAC_ACPKM_CTX *c = EVP_MD_CTX_md_data(ctx); + + if (c) { + CMAC_ACPKM_CTX_free(c->cmac_ctx); + memset(EVP_MD_CTX_md_data(ctx), 0, sizeof(OMAC_ACPKM_CTX)); + } + return 1; +} + +static int omac_acpkm_key(OMAC_ACPKM_CTX *c, const EVP_CIPHER *cipher, + const unsigned char *key, size_t key_size) +{ + int ret = 0; + + c->cmac_ctx = CMAC_ACPKM_CTX_new(); + if (c->cmac_ctx == NULL) { + GOSTerr(GOST_F_OMAC_KEY, ERR_R_MALLOC_FAILURE); + return 0; + } + + ret = CMAC_ACPKM_Init(c->cmac_ctx, key, key_size, cipher, NULL); + if (ret > 0) { + c->key_set = 1; + } + return 1; +} + +int omac_acpkm_imit_ctrl(EVP_MD_CTX *ctx, int type, int arg, void *ptr) +{ + switch (type) { + case EVP_MD_CTRL_KEY_LEN: + *((unsigned int *)(ptr)) = 32; + return 1; + case EVP_MD_CTRL_SET_KEY: + { + OMAC_ACPKM_CTX *c = EVP_MD_CTX_md_data(ctx); + const EVP_MD *md = EVP_MD_CTX_md(ctx); + const EVP_CIPHER *cipher = NULL; + + if (c->cipher_nid == NID_undef) { + switch (EVP_MD_nid(md)) { + case NID_grasshopper_mac: + c->cipher_nid = NID_grasshopper_cbc; + break; + } + } + cipher = EVP_get_cipherbynid(c->cipher_nid); + if (cipher == NULL) { + GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_CIPHER_NOT_FOUND); + } + if (EVP_MD_meth_get_init(EVP_MD_CTX_md(ctx)) (ctx) <= 0) { + GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_MAC_KEY_NOT_SET); + return 0; + } + EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NO_INIT); + if (c->key_set) { + GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_BAD_ORDER); + return 0; + } + if (arg == 0) { + struct gost_mac_key *key = (struct gost_mac_key *)ptr; + return omac_acpkm_key(c, cipher, key->key, 32); + } else if (arg == 32) { + return omac_acpkm_key(c, cipher, ptr, 32); + } + GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_INVALID_MAC_KEY_SIZE); + return 0; + } + case EVP_CTRL_KEY_MESH: + { + OMAC_ACPKM_CTX *c = EVP_MD_CTX_md_data(ctx); + if (!arg || (arg % EVP_MD_block_size(EVP_MD_CTX_md(ctx)))) + return -1; + c->cmac_ctx->section_size = arg; + if (ptr && *(int *)ptr) { + /* Set parameter T */ + if (!EVP_CIPHER_CTX_ctrl(c->cmac_ctx->actx, EVP_CTRL_KEY_MESH, *(int *)ptr, NULL)) + return 0; + } + return 1; + } + case EVP_MD_CTRL_MAC_LEN: + { + OMAC_ACPKM_CTX *c = EVP_MD_CTX_md_data(ctx); + switch (c->cipher_nid) { + case NID_grasshopper_cbc: + if (arg < 1 || arg > 16) { + GOSTerr(GOST_F_OMAC_IMIT_CTRL, GOST_R_INVALID_MAC_SIZE); + return 0; + } + c->dgst_size = arg; + break; + default: + return 0; + } + return 1; + } + + default: + return 0; + } +} + +static EVP_MD *_hidden_grasshopper_omac_acpkm_md = NULL; + +EVP_MD *grasshopper_omac_acpkm(void) +{ + if (_hidden_grasshopper_omac_acpkm_md == NULL) { + EVP_MD *md; + + if ((md = + EVP_MD_meth_new(NID_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm_omac, + NID_undef)) == NULL + || !EVP_MD_meth_set_result_size(md, MAX_GOST_OMAC_ACPKM_SIZE) + || !EVP_MD_meth_set_input_blocksize(md, GRASSHOPPER_BLOCK_SIZE) + || !EVP_MD_meth_set_app_datasize(md, sizeof(OMAC_ACPKM_CTX)) + || !EVP_MD_meth_set_flags(md, 0) + || !EVP_MD_meth_set_init(md, grasshopper_omac_acpkm_init) + || !EVP_MD_meth_set_update(md, omac_acpkm_imit_update) + || !EVP_MD_meth_set_final(md, omac_acpkm_imit_final) + || !EVP_MD_meth_set_copy(md, omac_acpkm_imit_copy) + || !EVP_MD_meth_set_cleanup(md, omac_acpkm_imit_cleanup) + || !EVP_MD_meth_set_ctrl(md, omac_acpkm_imit_ctrl)) { + EVP_MD_meth_free(md); + md = NULL; + } + _hidden_grasshopper_omac_acpkm_md = md; + } + return _hidden_grasshopper_omac_acpkm_md; +} + +void grasshopper_omac_acpkm_destroy(void) +{ + EVP_MD_meth_free(_hidden_grasshopper_omac_acpkm_md); + _hidden_grasshopper_omac_acpkm_md = NULL; +} diff --git a/test_grasshopper.c b/test_grasshopper.c index ab6e200..0134c67 100644 --- a/test_grasshopper.c +++ b/test_grasshopper.c @@ -33,7 +33,7 @@ printf(cGREEN "Test passed\n" cNORM);} /* Test key from both GOST R 34.12-2015 and GOST R 34.13-2015. */ -static const unsigned char K[] = { +static const unsigned char K[32] = { 0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff,0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77, 0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10,0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef, }; @@ -56,6 +56,19 @@ static const unsigned char P_acpkm[] = { 0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xEE,0xFF,0x0A,0x00,0x11,0x22,0x33, 0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xEE,0xFF,0x0A,0x00,0x11,0x22,0x33,0x44, }; +/* OMAC-ACPKM test vector from R 1323565.1.017-2018 A.4.1 */ +static const unsigned char P_omac_acpkm1[] = { + 0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x00,0xFF,0xEE,0xDD,0xCC,0xBB,0xAA,0x99,0x88, + 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77, +}; +/* OMAC-ACPKM test vector from R 1323565.1.017-2018 A.4.2 */ +static const unsigned char P_omac_acpkm2[] = { + 0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x00,0xFF,0xEE,0xDD,0xCC,0xBB,0xAA,0x99,0x88, + 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xEE,0xFF,0x0A, + 0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xEE,0xFF,0x0A,0x00, + 0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xEE,0xFF,0x0A,0x00,0x11, + 0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xEE,0xFF,0x0A,0x00,0x11,0x22, +}; static const unsigned char E_ecb[] = { /* ECB test vectors from GOST R 34.13-2015 A.1.1 */ /* first 16 bytes is vector (b) from GOST R 34.12-2015 A.1 */ @@ -134,6 +147,14 @@ static const unsigned char iv_128bit[] = { 0x12,0x34,0x56,0x78,0x90,0xab,0xce,0x /* Universal IV for ACPKM-Master. */ static const unsigned char iv_acpkm_m[] = { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; +static const unsigned char MAC_omac[] = { 0x33,0x6f,0x4d,0x29,0x60,0x59,0xfb,0xe3 }; +static const unsigned char MAC_omac_acpkm1[] = { + 0xB5,0x36,0x7F,0x47,0xB6,0x2B,0x99,0x5E,0xEB,0x2A,0x64,0x8C,0x58,0x43,0x14,0x5E, +}; +static const unsigned char MAC_omac_acpkm2[] = { + 0xFB,0xB8,0xDC,0xEE,0x45,0xBE,0xA6,0x7C,0x35,0xF5,0x8C,0x57,0x00,0x89,0x8E,0x5D, +}; + struct testcase { const char *name; const EVP_CIPHER *(*type)(void); @@ -291,34 +312,37 @@ static int test_stream(const EVP_CIPHER *type, const char *name, return ret; } -static int test_omac() +static int test_mac(const char *name, const char *from, + const EVP_MD *type, int acpkm, int acpkm_t, + const unsigned char *pt, size_t pt_size, + const unsigned char *mac, size_t mac_size) { EVP_MD_CTX *ctx = EVP_MD_CTX_new(); - unsigned char mac[] = { 0x33,0x6f,0x4d,0x29,0x60,0x59,0xfb,0xe3 }; unsigned char md_value[EVP_MAX_MD_SIZE]; unsigned int md_len; int test; OPENSSL_assert(ctx); - printf("OMAC test from GOST R 34.13-2015\n"); + printf("%s test from %s\n", name, from); EVP_MD_CTX_init(ctx); - /* preload cbc cipher for omac set key */ - EVP_add_cipher(cipher_gost_grasshopper_cbc()); - T(EVP_DigestInit_ex(ctx, grasshopper_omac(), NULL)); - if (EVP_MD_CTX_size(ctx) != sizeof(mac)) { + T(EVP_DigestInit_ex(ctx, type, NULL)); + if (EVP_MD_CTX_size(ctx) != mac_size) { /* strip const out of EVP_MD_CTX_md() to * overwrite output size, as test vector is 8 bytes */ - printf("Resize result size from %d to %zu\n", EVP_MD_CTX_size(ctx), sizeof(mac)); - T(EVP_MD_meth_set_result_size((EVP_MD *)EVP_MD_CTX_md(ctx), sizeof(mac))); + printf("Resize result size from %d to %zu\n", EVP_MD_CTX_size(ctx), mac_size); + T(EVP_MD_meth_set_result_size((EVP_MD *)EVP_MD_CTX_md(ctx), mac_size)); } T(EVP_MD_meth_get_ctrl(EVP_MD_CTX_md(ctx))(ctx, EVP_MD_CTRL_SET_KEY, sizeof(K), (void *)K)); - T(EVP_DigestUpdate(ctx, P, sizeof(P))); + if (acpkm) + T(EVP_MD_meth_get_ctrl(EVP_MD_CTX_md(ctx))(ctx, + EVP_CTRL_KEY_MESH, acpkm, acpkm_t ? &acpkm_t : NULL)); + T(EVP_DigestUpdate(ctx, pt, pt_size)); T(EVP_DigestFinal_ex(ctx, md_value, &md_len)); EVP_MD_CTX_free(ctx); printf(" MAC[%u] = ", md_len); hexdump(md_value, md_len); - TEST_ASSERT(md_len != sizeof(mac) || + TEST_ASSERT(md_len != mac_size || memcmp(mac, md_value, md_len)); return test; @@ -339,7 +363,19 @@ int main(int argc, char **argv) t->iv, t->iv_size, t->acpkm); } - ret |= test_omac(); + /* preload cbc cipher for omac set key */ + EVP_add_cipher(cipher_gost_grasshopper_cbc()); + + ret |= test_mac("OMAC", "GOST R 34.13-2015", grasshopper_omac(), 0, 0, + P, sizeof(P), MAC_omac, sizeof(MAC_omac)); + ret |= test_mac("OMAC-ACPKM", "R 1323565.1.017-2018 A.4.1", + grasshopper_omac_acpkm(), 32, 768 / 8, + P_omac_acpkm1, sizeof(P_omac_acpkm1), + MAC_omac_acpkm1, sizeof(MAC_omac_acpkm1)); + ret |= test_mac("OMAC-ACPKM", "R 1323565.1.017-2018 A.4.2", + grasshopper_omac_acpkm(), 32, 768 / 8, + P_omac_acpkm2, sizeof(P_omac_acpkm2), + MAC_omac_acpkm2, sizeof(MAC_omac_acpkm2)); if (ret) printf(cDRED "= Some tests FAILED!\n" cNORM); -- 2.39.5 From dd507838fbe0b7d8e56570384b5fd6b44a6403b6 Mon Sep 17 00:00:00 2001 From: Vitaly Chikunov Date: Wed, 8 Aug 2018 21:37:59 +0300 Subject: [PATCH 11/16] Add NIDs to compile with vanilla OpenSSL_1_1_0-stable --- compat.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/compat.h b/compat.h index 29a2ad3..f7effbe 100644 --- a/compat.h +++ b/compat.h @@ -344,4 +344,16 @@ static inline int (*EVP_MD_meth_get_ctrl(const EVP_MD *md))(EVP_MD_CTX *ctx, int # endif /* (OPENSSL_VERSION_NUMBER <= 0x10002100L) */ +# ifndef NID_id_tc26_cipher_gostr3412_2015_kuznyechik +# define NID_id_tc26_cipher_gostr3412_2015_kuznyechik 1176 +# define NID_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm 1177 +# define NID_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm_omac 1178 +# define NID_magma_ecb 1187 +# define NID_magma_ctr 1188 +# define NID_magma_ofb 1189 +# define NID_magma_cbc 1190 +# define NID_magma_cfb 1191 +# define NID_magma_mac 1192 +# endif + #endif /* !_GOST_COMPAT_H */ -- 2.39.5 From 4f5c0289ff2ad78c6761b8b63630ef62379a3c86 Mon Sep 17 00:00:00 2001 From: Dmitry Belyavskiy Date: Fri, 17 Aug 2018 17:32:18 +0300 Subject: [PATCH 12/16] Master is designed to be 1.1.1-compatible. --- CMakeLists.txt | 3 +-- gost_lcl.h | 1 - gost_md.c | 3 --- gost_md2012.c | 7 ------- 4 files changed, 1 insertion(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a937569..af73f45 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ include(GNUInstallDirs) enable_testing() -find_package(OpenSSL 1.0.2 REQUIRED) +find_package(OpenSSL 1.1.1 REQUIRED) include_directories(${OPENSSL_INCLUDE_DIR}) if (CMAKE_C_COMPILER_ID MATCHES "Clang") @@ -80,7 +80,6 @@ set(GOST_CORE_SOURCE_FILES gost_keywrap.c gost_keywrap.h gost_lcl.h - compat.h gost_params.c ) diff --git a/gost_lcl.h b/gost_lcl.h index 528794a..f63f23c 100644 --- a/gost_lcl.h +++ b/gost_lcl.h @@ -9,7 +9,6 @@ * OpenSSL 0.9.9 libraries required to compile and use * * this code * **********************************************************************/ -# include "compat.h" # include # include # include diff --git a/gost_md.c b/gost_md.c index 4b8e7e5..5d2c537 100644 --- a/gost_md.c +++ b/gost_md.c @@ -27,9 +27,6 @@ EVP_MD *digest_gost(void) EVP_MD *md; if ((md = EVP_MD_meth_new(NID_id_GostR3411_94, NID_undef)) == NULL -#if (OPENSSL_VERSION_NUMBER <= 0x10002100L) - || !EVP_MD_meth_set_flags(md, EVP_MD_FLAG_PKEY_METHOD_SIGNATURE) -#endif || !EVP_MD_meth_set_result_size(md, 32) || !EVP_MD_meth_set_input_blocksize(md, 32) || !EVP_MD_meth_set_app_datasize(md, diff --git a/gost_md2012.c b/gost_md2012.c index 5462dea..5acb111 100644 --- a/gost_md2012.c +++ b/gost_md2012.c @@ -9,7 +9,6 @@ * * **********************************************************************/ -#include "compat.h" #include #include "gosthash2012.h" @@ -38,9 +37,6 @@ EVP_MD *digest_gost2012_256(void) if ((md = EVP_MD_meth_new(NID_id_GostR3411_2012_256, NID_undef)) == NULL -#if (OPENSSL_VERSION_NUMBER <= 0x10002100L) - || !EVP_MD_meth_set_flags(md, EVP_MD_FLAG_PKEY_METHOD_SIGNATURE) -#endif || !EVP_MD_meth_set_result_size(md, 32) || !EVP_MD_meth_set_input_blocksize(md, 64) || !EVP_MD_meth_set_app_datasize(md, sizeof(gost2012_hash_ctx)) @@ -71,9 +67,6 @@ EVP_MD *digest_gost2012_512(void) if ((md = EVP_MD_meth_new(NID_id_GostR3411_2012_512, NID_undef)) == NULL -#if (OPENSSL_VERSION_NUMBER <= 0x10002100L) - || !EVP_MD_meth_set_flags(md, EVP_MD_FLAG_PKEY_METHOD_SIGNATURE) -#endif || !EVP_MD_meth_set_result_size(md, 64) || !EVP_MD_meth_set_input_blocksize(md, 64) || !EVP_MD_meth_set_app_datasize(md, sizeof(gost2012_hash_ctx)) -- 2.39.5 From ef3043e1e241a59a125a07504cb539dc64c9f0d8 Mon Sep 17 00:00:00 2001 From: Dmitry Belyavskiy Date: Fri, 17 Aug 2018 17:39:18 +0300 Subject: [PATCH 13/16] Not in master --- compat.h | 359 ------------------------------------------------------- gost.txt | 89 -------------- 2 files changed, 448 deletions(-) delete mode 100644 compat.h delete mode 100644 gost.txt diff --git a/compat.h b/compat.h deleted file mode 100644 index f7effbe..0000000 --- a/compat.h +++ /dev/null @@ -1,359 +0,0 @@ -/* - * Shim to provide small subset of openssl-1.1.0 API by openssl-1.0.2 - * - * Copyright (C) 2018 vt@altlinux.org. All Rights Reserved. - * - * Contents licensed under the terms of the OpenSSL license - * See https://www.openssl.org/source/license.html for details - */ - -#ifndef _GOST_COMPAT_H -#define _GOST_COMPAT_H - -# include -# if (OPENSSL_VERSION_NUMBER <= 0x10002100L) - -# include - -# include -# include -# include - -/* - * for crypto.h - */ - -# define OPENSSL_zalloc(num) CRYPTO_zalloc(num, __FILE__, __LINE__) -# define OPENSSL_clear_free(addr, num) \ - CRYPTO_clear_free(addr, num, __FILE__, __LINE__) - -static inline void *CRYPTO_zalloc(size_t num, const char *file, int line) -{ - void *ret = CRYPTO_malloc(num, file, line); - - if (ret != NULL) - memset(ret, 0, num); - return ret; -} - -static inline void CRYPTO_clear_free(void *str, size_t num, const char *file, int line) -{ - if (str == NULL) - return; - if (num) - OPENSSL_cleanse(str, num); - CRYPTO_free(str); -} - -/* - * for dsa.h - */ - -static inline void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps) -{ - if (pr != NULL) - *pr = sig->r; - if (ps != NULL) - *ps = sig->s; -} - -static inline int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s) -{ - if (r == NULL || s == NULL) - return 0; - BN_clear_free(sig->r); - BN_clear_free(sig->s); - sig->r = r; - sig->s = s; - return 1; -} - -/* - * for evp.h - */ - -#ifndef OPENSSL_FILE -# ifdef OPENSSL_NO_FILENAMES -# define OPENSSL_FILE "" -# define OPENSSL_LINE 0 -# else -# define OPENSSL_FILE __FILE__ -# define OPENSSL_LINE __LINE__ -# endif -#endif - -static inline void *EVP_CIPHER_CTX_get_cipher_data(const EVP_CIPHER_CTX *ctx) -{ - return ctx->cipher_data; -} - -static inline const unsigned char *EVP_CIPHER_CTX_original_iv(const EVP_CIPHER_CTX *ctx) -{ - return ctx->oiv; -} - -static inline unsigned char *EVP_CIPHER_CTX_iv_noconst(EVP_CIPHER_CTX *ctx) -{ - return ctx->iv; -} - -static inline int EVP_CIPHER_CTX_encrypting(const EVP_CIPHER_CTX *ctx) -{ - return ctx->encrypt; -} - -static inline unsigned char *EVP_CIPHER_CTX_buf_noconst(EVP_CIPHER_CTX *ctx) -{ - return ctx->buf; -} - -static inline int EVP_CIPHER_CTX_num(const EVP_CIPHER_CTX *ctx) -{ - return ctx->num; -} - -static inline void EVP_CIPHER_CTX_set_num(EVP_CIPHER_CTX *ctx, int num) -{ - ctx->num = num; -} - -static inline EVP_CIPHER *EVP_CIPHER_meth_new(int cipher_type, int block_size, int key_len) -{ - EVP_CIPHER *cipher = OPENSSL_zalloc(sizeof(EVP_CIPHER)); - - if (cipher != NULL) { - cipher->nid = cipher_type; - cipher->block_size = block_size; - cipher->key_len = key_len; - } - return cipher; -} - -static inline int EVP_CIPHER_meth_set_iv_length(EVP_CIPHER *cipher, int iv_len) -{ - cipher->iv_len = iv_len; - return 1; -} - -static inline int EVP_CIPHER_meth_set_flags(EVP_CIPHER *cipher, unsigned long flags) -{ - cipher->flags = flags; - return 1; -} - -static inline int EVP_CIPHER_meth_set_cleanup(EVP_CIPHER *cipher, - int (*cleanup) (EVP_CIPHER_CTX *)) -{ - cipher->cleanup = cleanup; - return 1; -} - -static inline int EVP_CIPHER_meth_set_set_asn1_params(EVP_CIPHER *cipher, - int (*set_asn1_parameters) (EVP_CIPHER_CTX *, - ASN1_TYPE *)) -{ - cipher->set_asn1_parameters = set_asn1_parameters; - return 1; -} - -static inline int EVP_CIPHER_meth_set_ctrl(EVP_CIPHER *cipher, - int (*ctrl) (EVP_CIPHER_CTX *, int type, - int arg, void *ptr)) -{ - cipher->ctrl = ctrl; - return 1; -} - -static inline int EVP_CIPHER_meth_set_do_cipher(EVP_CIPHER *cipher, - int (*do_cipher) (EVP_CIPHER_CTX *ctx, - unsigned char *out, - const unsigned char *in, - size_t inl)) -{ - cipher->do_cipher = do_cipher; - return 1; -} - -static inline int EVP_CIPHER_meth_set_get_asn1_params(EVP_CIPHER *cipher, - int (*get_asn1_parameters) (EVP_CIPHER_CTX *, - ASN1_TYPE *)) -{ - cipher->get_asn1_parameters = get_asn1_parameters; - return 1; -} - -static inline int EVP_CIPHER_meth_set_init(EVP_CIPHER *cipher, - int (*init) (EVP_CIPHER_CTX *ctx, - const unsigned char *key, - const unsigned char *iv, - int enc)) -{ - cipher->init = init; - return 1; -} - -static inline int EVP_CIPHER_meth_set_impl_ctx_size(EVP_CIPHER *cipher, int ctx_size) -{ - cipher->ctx_size = ctx_size; - return 1; -} - -static inline void EVP_CIPHER_meth_free(EVP_CIPHER *cipher) -{ - OPENSSL_free(cipher); -} - -static inline EVP_MD_CTX *EVP_MD_CTX_new(void) -{ - return OPENSSL_zalloc(sizeof(EVP_MD_CTX)); -} - -int ENGINE_finish(ENGINE *e); -static inline int EVP_MD_CTX_reset(EVP_MD_CTX *ctx) -{ - if (ctx == NULL) - return 1; - if (ctx->digest && ctx->digest->cleanup - && !EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_CLEANED)) - ctx->digest->cleanup(ctx); - if (ctx->digest && ctx->digest->ctx_size && ctx->md_data - && !EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_REUSE)) { - OPENSSL_clear_free(ctx->md_data, ctx->digest->ctx_size); - } - EVP_PKEY_CTX_free(ctx->pctx); -#ifndef OPENSSL_NO_ENGINE - ENGINE_finish(ctx->engine); -#endif - OPENSSL_cleanse(ctx, sizeof(*ctx)); - - return 1; -} - -static inline void EVP_MD_CTX_free(EVP_MD_CTX *ctx) -{ - EVP_MD_CTX_reset(ctx); - OPENSSL_free(ctx); -} - -static inline EVP_MD *EVP_MD_meth_new(int md_type, int pkey_type) -{ - EVP_MD *md = OPENSSL_zalloc(sizeof(*md)); - - if (md != NULL) { - md->type = md_type; - md->pkey_type = pkey_type; - } - return md; -} - -static inline int EVP_MD_meth_set_result_size(EVP_MD *md, int resultsize) -{ - md->md_size = resultsize; - return 1; -} - -static int EVP_MD_meth_get_result_size(const EVP_MD *md) -{ - return md->md_size; -} - -static inline int EVP_MD_meth_set_input_blocksize(EVP_MD *md, int blocksize) -{ - md->block_size = blocksize; - return 1; -} - -static inline int EVP_MD_meth_set_app_datasize(EVP_MD *md, int datasize) -{ - md->ctx_size = datasize; - return 1; -} - -static inline int EVP_MD_meth_set_flags(EVP_MD *md, unsigned long flags) -{ - md->flags = flags; - return 1; -} - -static inline int EVP_MD_meth_set_init(EVP_MD *md, int (*init)(EVP_MD_CTX *ctx)) -{ - md->init = init; - return 1; -} - -static inline int EVP_MD_meth_set_update(EVP_MD *md, int (*update)(EVP_MD_CTX *ctx, - const void *data, - size_t count)) -{ - md->update = update; - return 1; -} - -static inline int EVP_MD_meth_set_final(EVP_MD *md, int (*final)(EVP_MD_CTX *ctx, - unsigned char *md)) -{ - md->final = final; - return 1; -} - -static inline int EVP_MD_meth_set_copy(EVP_MD *md, int (*copy)(EVP_MD_CTX *to, - const EVP_MD_CTX *from)) -{ - md->copy = copy; - return 1; -} - -static inline int EVP_MD_meth_set_cleanup(EVP_MD *md, int (*cleanup)(EVP_MD_CTX *ctx)) -{ - md->cleanup = cleanup; - return 1; -} - -static inline int EVP_MD_meth_set_ctrl(EVP_MD *md, int (*ctrl)(EVP_MD_CTX *ctx, int cmd, - int p1, void *p2)) -{ - md->md_ctrl = ctrl; - return 1; -} - -static inline void EVP_MD_meth_free(EVP_MD *md) -{ - OPENSSL_free(md); -} - -static inline const unsigned char *EVP_CIPHER_CTX_iv(const EVP_CIPHER_CTX *ctx) -{ - return ctx->iv; -} - -static inline void *EVP_MD_CTX_md_data(const EVP_MD_CTX *ctx) -{ - return ctx->md_data; -} - -static inline int (*EVP_MD_meth_get_init(const EVP_MD *md))(EVP_MD_CTX *ctx) -{ - return md->init; -} - -static inline int (*EVP_MD_meth_get_ctrl(const EVP_MD *md))(EVP_MD_CTX *ctx, int cmd, - int p1, void *p2) -{ - return md->md_ctrl; -} - -# endif /* (OPENSSL_VERSION_NUMBER <= 0x10002100L) */ - -# ifndef NID_id_tc26_cipher_gostr3412_2015_kuznyechik -# define NID_id_tc26_cipher_gostr3412_2015_kuznyechik 1176 -# define NID_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm 1177 -# define NID_id_tc26_cipher_gostr3412_2015_kuznyechik_ctracpkm_omac 1178 -# define NID_magma_ecb 1187 -# define NID_magma_ctr 1188 -# define NID_magma_ofb 1189 -# define NID_magma_cbc 1190 -# define NID_magma_cfb 1191 -# define NID_magma_mac 1192 -# endif - -#endif /* !_GOST_COMPAT_H */ diff --git a/gost.txt b/gost.txt deleted file mode 100644 index 4a515f9..0000000 --- a/gost.txt +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright 1999-2018 The OpenSSL Project Authors. All Rights Reserved. -# -# Licensed under the OpenSSL license (the "License"). You may not use -# this file except in compliance with the License. You can obtain a copy -# in the file LICENSE in the source distribution or at -# https://www.openssl.org/source/license.html - -# Function codes -GOST_F_DECODE_GOST_ALGOR_PARAMS:100:decode_gost_algor_params -GOST_F_ENCODE_GOST_ALGOR_PARAMS:101:encode_gost_algor_params -GOST_F_FILL_GOST_EC_PARAMS:102:fill_GOST_EC_params -GOST_F_GET_ENCRYPTION_PARAMS:103:get_encryption_params -GOST_F_GOST89_GET_ASN1_PARAMETERS:104:gost89_get_asn1_parameters -GOST_F_GOST89_SET_ASN1_PARAMETERS:105:gost89_set_asn1_parameters -GOST_F_GOST_CIPHER_CTL:106:gost_cipher_ctl -GOST_F_GOST_EC_COMPUTE_PUBLIC:107:gost_ec_compute_public -GOST_F_GOST_EC_KEYGEN:108:gost_ec_keygen -GOST_F_GOST_EC_SIGN:109:gost_ec_sign -GOST_F_GOST_EC_VERIFY:110:gost_ec_verify -GOST_F_GOST_GRASSHOPPER_CIPHER_CTL:111:gost_grasshopper_cipher_ctl -GOST_F_GOST_GRASSHOPPER_SET_ASN1_PARAMETERS:112:\ - gost_grasshopper_set_asn1_parameters -GOST_F_GOST_IMIT_CTRL:113:gost_imit_ctrl -GOST_F_GOST_IMIT_FINAL:114:gost_imit_final -GOST_F_GOST_IMIT_UPDATE:115:gost_imit_update -GOST_F_OMAC_IMIT_CTRL:116:omac_imit_ctrl -GOST_F_OMAC_IMIT_FINAL:117:omac_imit_final -GOST_F_OMAC_IMIT_UPDATE:118:omac_imit_update -GOST_F_OMAC_KEY:138:omac_key -GOST_F_PARAM_COPY_GOST_EC:119:param_copy_gost_ec -GOST_F_PKEY_GOST2001_PARAMGEN:120:pkey_gost2001_paramgen -GOST_F_PKEY_GOST2012_PARAMGEN:121:pkey_gost2012_paramgen -GOST_F_PKEY_GOST_CTRL:122:pkey_gost_ctrl -GOST_F_PKEY_GOST_ECCP_DECRYPT:123:pkey_GOST_ECcp_decrypt -GOST_F_PKEY_GOST_ECCP_ENCRYPT:124:pkey_GOST_ECcp_encrypt -GOST_F_PKEY_GOST_EC_CTRL_STR_256:125:pkey_gost_ec_ctrl_str_256 -GOST_F_PKEY_GOST_EC_CTRL_STR_512:126:pkey_gost_ec_ctrl_str_512 -GOST_F_PKEY_GOST_EC_DERIVE:127:pkey_gost_ec_derive -GOST_F_PKEY_GOST_GRASSHOPPER_MAC_SIGNCTX_INIT:141:\ - pkey_gost_grasshopper_mac_signctx_init -GOST_F_PKEY_GOST_MAC_CTRL:128:pkey_gost_mac_ctrl -GOST_F_PKEY_GOST_MAC_CTRL_STR:129:pkey_gost_mac_ctrl_str -GOST_F_PKEY_GOST_MAC_KEYGEN_BASE:130:pkey_gost_mac_keygen_base -GOST_F_PKEY_GOST_MAC_SIGNCTX_INIT:131:pkey_gost_mac_signctx_init -GOST_F_PKEY_GOST_MAGMA_MAC_SIGNCTX_INIT:142:pkey_gost_magma_mac_signctx_init -GOST_F_PKEY_GOST_OMAC_CTRL:139:pkey_gost_omac_ctrl -GOST_F_PKEY_GOST_OMAC_CTRL_STR:140:pkey_gost_omac_ctrl_str -GOST_F_PRINT_GOST_EC_PUB:132:print_gost_ec_pub -GOST_F_PRIV_DECODE_GOST:133:priv_decode_gost -GOST_F_PUB_DECODE_GOST_EC:134:pub_decode_gost_ec -GOST_F_PUB_ENCODE_GOST_EC:135:pub_encode_gost_ec -GOST_F_UNPACK_CP_SIGNATURE:136:unpack_cp_signature -GOST_F_VKO_COMPUTE_KEY:137:VKO_compute_key - -#Reason codes -GOST_R_BAD_KEY_PARAMETERS_FORMAT:100:bad key parameters format -GOST_R_BAD_ORDER:132:bad order -GOST_R_BAD_PKEY_PARAMETERS_FORMAT:101:bad pkey parameters format -GOST_R_CANNOT_PACK_EPHEMERAL_KEY:102:cannot pack ephemeral key -GOST_R_CIPHER_NOT_FOUND:103:cipher not found -GOST_R_CTRL_CALL_FAILED:104:ctrl call failed -GOST_R_ERROR_COMPUTING_SHARED_KEY:105:error computing shared key -GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO:106:error parsing key transport info -GOST_R_ERROR_POINT_MUL:107:error point mul -GOST_R_INCOMPATIBLE_ALGORITHMS:108:incompatible algorithms -GOST_R_INCOMPATIBLE_PEER_KEY:109:incompatible peer key -GOST_R_INVALID_CIPHER_PARAMS:110:invalid cipher params -GOST_R_INVALID_CIPHER_PARAM_OID:111:invalid cipher param oid -GOST_R_INVALID_DIGEST_TYPE:112:invalid digest type -GOST_R_INVALID_IV_LENGTH:113:invalid iv length -GOST_R_INVALID_MAC_KEY_LENGTH:114:invalid mac key length -GOST_R_INVALID_MAC_KEY_SIZE:115:invalid mac key size -GOST_R_INVALID_MAC_PARAMS:116:invalid mac params -GOST_R_INVALID_MAC_SIZE:117:invalid mac size -GOST_R_INVALID_PARAMSET:118:invalid paramset -GOST_R_KEY_IS_NOT_INITIALIZED:119:key is not initialized -GOST_R_KEY_PARAMETERS_MISSING:120:key parameters missing -GOST_R_MAC_KEY_NOT_SET:121:mac key not set -GOST_R_NO_PARAMETERS_SET:122:no parameters set -GOST_R_NO_PEER_KEY:123:no peer key -GOST_R_NO_PRIVATE_PART_OF_NON_EPHEMERAL_KEYPAIR:124:\ - no private part of non ephemeral keypair -GOST_R_PUBLIC_KEY_UNDEFINED:125:public key undefined -GOST_R_RNG_ERROR:126:rng error -GOST_R_SIGNATURE_MISMATCH:127:signature mismatch -GOST_R_SIGNATURE_PARTS_GREATER_THAN_Q:128:signature parts greater than q -GOST_R_UKM_NOT_SET:129:ukm not set -GOST_R_UNSUPPORTED_CIPHER_CTL_COMMAND:130:unsupported cipher ctl command -GOST_R_UNSUPPORTED_PARAMETER_SET:131:unsupported parameter set -- 2.39.5 From ff4079d54b1213d5e0d41da3c912c3c700bb644c Mon Sep 17 00:00:00 2001 From: Dmitry Belyavskiy Date: Fri, 17 Aug 2018 18:02:32 +0300 Subject: [PATCH 14/16] libgost => gost --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index af73f45..9cd784d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -125,7 +125,7 @@ add_library(gost_core STATIC ${GOST_LIB_SOURCE_FILES}) set_target_properties(gost_core PROPERTIES POSITION_INDEPENDENT_CODE ON) add_library(gost_engine MODULE ${GOST_ENGINE_SOURCE_FILES}) -set_target_properties(gost_engine PROPERTIES PREFIX "" OUTPUT_NAME "libgost") +set_target_properties(gost_engine PROPERTIES PREFIX "" OUTPUT_NAME "gost") target_link_libraries(gost_engine gost_core ${OPENSSL_CRYPTO_LIBRARY}) set(GOST_SUM_SOURCE_FILES -- 2.39.5 From 1b64cb921e3100f76c164a482dfc3396b022be4c Mon Sep 17 00:00:00 2001 From: Dmitry Belyavskiy Date: Sat, 18 Aug 2018 20:37:15 +0300 Subject: [PATCH 15/16] Comment out branch 1.1.0 --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index b3d8ad1..e9c90be 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,9 +17,9 @@ matrix: - env: OPENSSL_BRANCH=master os: linux compiler: gcc - - env: OPENSSL_BRANCH=OpenSSL_1_1_0-stable - os: linux - compiler: gcc +# - env: OPENSSL_BRANCH=OpenSSL_1_1_0-stable +# os: linux +# compiler: gcc # - env: OPENSSL_BRANCH=OpenSSL_1_0_2-stable # os: linux # compiler: gcc -- 2.39.5 From 3feabe343608ffbcb8afc887e3931796dd7f5b46 Mon Sep 17 00:00:00 2001 From: Sergey Aganin Date: Mon, 20 Aug 2018 14:47:37 +0300 Subject: [PATCH 16/16] Fixed GOST_PK_FORMAT param --- INSTALL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/INSTALL.md b/INSTALL.md index 5849af2..8e36721 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -102,7 +102,7 @@ BouncyCastle cryptoprovider has some problems with private key parsing from PrivateKeyInfo, so if you want to use old private key representation format, which supported by BC, you must add: - PK_PARAMS = LEGACY_PK_WRAP + GOST_PK_FORMAT = LEGACY_PK_WRAP to `[gost_section]`. -- 2.39.5