From 3b27d50d79a9e7bdf3a98910c951c323ce41d6d5 Mon Sep 17 00:00:00 2001 From: Dmitry Belyavskiy Date: Mon, 3 Sep 2018 16:47:01 +0300 Subject: [PATCH] KDF TREE + test --- e_gost_err.c | 1 + e_gost_err.h | 1 + gost.txt | 1 + gost_ec_keyx.c | 111 ++++++++++++++++++++++++++++++++++++++++------- gost_keyexpimp.c | 102 +++++++++++++++++++++++++++++++++++++++---- 5 files changed, 193 insertions(+), 23 deletions(-) diff --git a/e_gost_err.c b/e_gost_err.c index 7269287..da9ab55 100644 --- a/e_gost_err.c +++ b/e_gost_err.c @@ -36,6 +36,7 @@ static ERR_STRING_DATA GOST_str_functs[] = { {ERR_PACK(0, GOST_F_GOST_IMIT_CTRL, 0), "gost_imit_ctrl"}, {ERR_PACK(0, GOST_F_GOST_IMIT_FINAL, 0), "gost_imit_final"}, {ERR_PACK(0, GOST_F_GOST_IMIT_UPDATE, 0), "gost_imit_update"}, + {ERR_PACK(0, GOST_F_GOST_KDFTREE2012_256, 0), "gost_kdftree2012_256"}, {ERR_PACK(0, GOST_F_GOST_KEXP15, 0), "gost_kexp15"}, {ERR_PACK(0, GOST_F_GOST_KIMP15, 0), "gost_kimp15"}, {ERR_PACK(0, GOST_F_OMAC_ACPKM_IMIT_CTRL, 0), "omac_acpkm_imit_ctrl"}, diff --git a/e_gost_err.h b/e_gost_err.h index 312689f..ce53f82 100644 --- a/e_gost_err.h +++ b/e_gost_err.h @@ -43,6 +43,7 @@ void ERR_GOST_error(int function, int reason, char *file, int line); # define GOST_F_GOST_IMIT_CTRL 113 # define GOST_F_GOST_IMIT_FINAL 114 # define GOST_F_GOST_IMIT_UPDATE 115 +# define GOST_F_GOST_KDFTREE2012_256 149 # define GOST_F_GOST_KEXP15 143 # define GOST_F_GOST_KIMP15 148 # define GOST_F_OMAC_ACPKM_IMIT_CTRL 144 diff --git a/gost.txt b/gost.txt index bf9246a..3f3ffcd 100644 --- a/gost.txt +++ b/gost.txt @@ -23,6 +23,7 @@ GOST_F_GOST_GRASSHOPPER_SET_ASN1_PARAMETERS:112:\ 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_GOST_KDFTREE2012_256:149:gost_kdftree2012_256 GOST_F_GOST_KEXP15:143:gost_kexp15 GOST_F_GOST_KIMP15:148:gost_kimp15 GOST_F_OMAC_ACPKM_IMIT_CTRL:144:omac_acpkm_imit_ctrl diff --git a/gost_ec_keyx.c b/gost_ec_keyx.c index 03537a3..cc6aacb 100644 --- a/gost_ec_keyx.c +++ b/gost_ec_keyx.c @@ -84,7 +84,7 @@ static int VKO_compute_key(unsigned char *shared_key, size_t shared_key_size, EVP_DigestInit_ex(mdctx, md, NULL); EVP_DigestUpdate(mdctx, databuf, buf_len); EVP_DigestFinal_ex(mdctx, shared_key, NULL); - ret = 32; + ret = (EVP_MD_size(md) > 0) ? EVP_MD_size(md) : 0; err: BN_free(UKM); @@ -100,6 +100,57 @@ static int VKO_compute_key(unsigned char *shared_key, size_t shared_key_size, return ret; } +/* + * keyout expected to be 64 bytes + * */ +static int gost_keg(const unsigned char *ukm_source, int pkey_nid, + const EC_POINT *pub_key, EC_KEY *priv_key, + unsigned char *keyout) +{ +/* Adjust UKM */ + unsigned char real_ukm[16]; + size_t keylen; + + memset(real_ukm, 0, 16); + if (memcmp(ukm_source, real_ukm, 16) == 0) + real_ukm[15] = 1; + else + memcpy(real_ukm, ukm_source, 16); + + switch (pkey_nid) { + case NID_id_GostR3410_2012_512: + keylen = + VKO_compute_key(keyout, 64, pub_key, priv_key, real_ukm, 16, + NID_id_GostR3411_2012_512); + return (keylen) ? keylen : 0; + break; + + case NID_id_GostR3410_2012_256: + { + unsigned char tmpkey[32]; + keylen = + VKO_compute_key(tmpkey, 32, pub_key, priv_key, real_ukm, 16, + NID_id_GostR3411_2012_256); + + if (keylen == 0) + return 0; + + if (gost_kdftree2012_256 + (keyout, 64, tmpkey, 32, (const unsigned char *)"kdf tree", 8, + ukm_source + 16, 8, 1) > 0) + keylen = 64; + else + keylen = 0; + + OPENSSL_cleanse(tmpkey, 32); + return (keylen) ? keylen : 0; + break; + } + default: + return 0; + } +} + /* * EVP_PKEY_METHOD callback derive. * Implements VKO R 34.10-2001/2012 algorithms @@ -120,22 +171,52 @@ int pkey_gost_ec_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen) GOSTerr(GOST_F_PKEY_GOST_EC_DERIVE, GOST_R_UKM_NOT_SET); return 0; } + /* + * shared_ukm_size = 8 stands for pre-2018 cipher suites + * It means 32 bytes of key length, 8 byte UKM, 32-bytes hash + * + * shared_ukm_size = 32 stands for pre-2018 cipher suites + * It means 64 bytes of shared_key, 16 bytes of UKM and either + * 64 bytes of hash or 64 bytes of TLSTREE output + * */ - if (key == NULL) { - *keylen = 32; - return 1; - } + switch (data->shared_ukm_size) { + case 8: + { + if (key == NULL) { + *keylen = 32; + return 1; + } - EVP_PKEY_get_default_digest_nid(my_key, &dgst_nid); - if (dgst_nid == NID_id_GostR3411_2012_512) - dgst_nid = NID_id_GostR3411_2012_256; + EVP_PKEY_get_default_digest_nid(my_key, &dgst_nid); + if (dgst_nid == NID_id_GostR3411_2012_512) + dgst_nid = NID_id_GostR3411_2012_256; - *keylen = - VKO_compute_key(key, 32, - EC_KEY_get0_public_key(EVP_PKEY_get0(peer_key)), - (EC_KEY *)EVP_PKEY_get0(my_key), data->shared_ukm, 8, - dgst_nid); - return (*keylen) ? 1 : 0; + *keylen = + VKO_compute_key(key, 32, + EC_KEY_get0_public_key(EVP_PKEY_get0(peer_key)), + (EC_KEY *)EVP_PKEY_get0(my_key), + data->shared_ukm, 8, dgst_nid); + return (*keylen) ? 1 : 0; + } + break; + case 32: + { + if (key == NULL) { + *keylen = 64; + return 1; + } + + *keylen = gost_keg(data->shared_ukm, EVP_PKEY_id(my_key), + EC_KEY_get0_public_key(EVP_PKEY_get0(peer_key)), + (EC_KEY *)EVP_PKEY_get0(my_key), key); + return (*keylen) ? 1 : 0; + } + + break; + default: + return 0; + } } /* @@ -145,7 +226,7 @@ int pkey_gost_ec_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen) /* * EVP_PKEY_METHOD callback encrypt - * Implementation of GOST2001 key transport, cryptopo variation + * Implementation of GOST2001/12 key transport, cryptopro variation */ int pkey_GOST_ECcp_encrypt(EVP_PKEY_CTX *pctx, unsigned char *out, diff --git a/gost_keyexpimp.c b/gost_keyexpimp.c index c881e68..bfdefbc 100644 --- a/gost_keyexpimp.c +++ b/gost_keyexpimp.c @@ -1,5 +1,7 @@ +#include #include #include +#include #include "gost_lcl.h" #include "e_gost_err.h" @@ -109,7 +111,7 @@ int gost_kimp15(const unsigned char *expkey, const size_t expkeylen, ciph = EVP_CIPHER_CTX_new(); if (ciph == NULL) { - GOSTerr(GOST_F_GOST_KEXP15, ERR_R_MALLOC_FAILURE); + GOSTerr(GOST_F_GOST_KIMP15, ERR_R_MALLOC_FAILURE); goto err; } @@ -125,7 +127,7 @@ int gost_kimp15(const unsigned char *expkey, const size_t expkeylen, mac = EVP_MD_CTX_new(); if (mac == NULL) { - GOSTerr(GOST_F_GOST_KEXP15, ERR_R_MALLOC_FAILURE); + GOSTerr(GOST_F_GOST_KIMP15, ERR_R_MALLOC_FAILURE); goto err; } @@ -155,13 +157,64 @@ int gost_kimp15(const unsigned char *expkey, const size_t expkeylen, return ret; } -/* - * keyout expected to be 64 bytes - * */ -int gost_keg(const unsigned char *seckey, const size_t seckey_len, - const EC_POINT *pub, const unsigned char *h, unsigned char *keyout) +int gost_kdftree2012_256(unsigned char *keyout, size_t keyout_len, + const unsigned char *key, size_t keylen, + const unsigned char *label, size_t label_len, + const unsigned char *seed, size_t seed_len, + const size_t representation) { - return 0; + int iters, i = 0; + unsigned char zero = 0; + unsigned char *ptr = keyout; + HMAC_CTX *ctx = NULL; + unsigned char *len_ptr = NULL; + uint32_t len_repr = htonl(keyout_len * 8); + size_t len_repr_len = 4; + + ctx = HMAC_CTX_new(); + if (ctx == NULL) { + GOSTerr(GOST_F_GOST_KDFTREE2012_256, ERR_R_MALLOC_FAILURE); + return 0; + } + + if ((keyout_len == 0) || (keyout_len % 32 != 0)) { + GOSTerr(GOST_F_GOST_KDFTREE2012_256, ERR_R_INTERNAL_ERROR); + return 0; + } + iters = keyout_len / 32; + + len_ptr = (unsigned char *)&len_repr; + while (*len_ptr == 0) { + len_ptr++; + len_repr_len--; + } + + for (i = 1; i <= iters; i++) { + uint32_t iter_net = htonl(i); + unsigned char *rep_ptr = + ((unsigned char *)&iter_net) + (4 - representation); + + if (HMAC_Init_ex(ctx, key, keylen, + EVP_get_digestbynid(NID_id_GostR3411_2012_256), + NULL) <= 0 + || HMAC_Update(ctx, rep_ptr, representation) <= 0 + || HMAC_Update(ctx, label, label_len) <= 0 + || HMAC_Update(ctx, &zero, 1) <= 0 + || HMAC_Update(ctx, seed, seed_len) <= 0 + || HMAC_Update(ctx, len_ptr, len_repr_len) <= 0 + || HMAC_Final(ctx, ptr, NULL) <= 0) { + GOSTerr(GOST_F_GOST_KDFTREE2012_256, ERR_R_INTERNAL_ERROR); + HMAC_CTX_free(ctx); + return 0; + } + + HMAC_CTX_reset(ctx); + ptr += 32; + } + + HMAC_CTX_free(ctx); + + return 1; } #ifdef ENABLE_UNIT_TESTS @@ -215,9 +268,31 @@ int main(void) 0x5D, 0xAF, 0xE7, 0xB4, 0x2E, 0x3A, 0x8B, 0xD9 }; + unsigned char kdftree_key[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + }; + + unsigned char kdf_label[] = { 0x26, 0xBD, 0xB8, 0x78 }; + unsigned char kdf_seed[] = + { 0xAF, 0x21, 0x43, 0x41, 0x45, 0x65, 0x63, 0x78 }; + const unsigned char kdf_etalon[] = { + 0x22, 0xB6, 0x83, 0x78, 0x45, 0xC6, 0xBE, 0xF6, + 0x5E, 0xA7, 0x16, 0x72, 0xB2, 0x65, 0x83, 0x10, + 0x86, 0xD3, 0xC7, 0x6A, 0xEB, 0xE6, 0xDA, 0xE9, + 0x1C, 0xAD, 0x51, 0xD8, 0x3F, 0x79, 0xD1, 0x6B, + 0x07, 0x4C, 0x93, 0x30, 0x59, 0x9D, 0x7F, 0x8D, + 0x71, 0x2F, 0xCA, 0x54, 0x39, 0x2F, 0x4D, 0xDD, + 0xE9, 0x37, 0x51, 0x20, 0x6B, 0x35, 0x84, 0xC8, + 0xF4, 0x3F, 0x9E, 0x6D, 0xC5, 0x15, 0x31, 0xF9 + }; + unsigned char buf[32 + 16]; int ret = 0; int outlen = 40; + unsigned char kdf_result[64]; OpenSSL_add_all_algorithms(); memset(buf, 0, sizeof(buf)); @@ -248,6 +323,17 @@ int main(void) } } + ret = gost_kdftree2012_256(kdf_result, 64, kdftree_key, 32, kdf_label, 4, + kdf_seed, 8, 1); + if (ret <= 0) + ERR_print_errors_fp(stderr); + else { + hexdump(stdout, "KDF TREE", kdf_result, 64); + if (memcmp(kdf_result, kdf_etalon, 64) != 0) { + fprintf(stdout, "ERROR! test failed\n"); + } + } + return 0; } -- 2.39.2