3 #include <openssl/evp.h>
4 #include <openssl/hmac.h>
7 #include "e_gost_err.h"
10 * Function expects that out is a preallocated buffer of length
11 * defined as sum of shared_len and mac length defined by mac_nid
13 int gost_kexp15(const unsigned char *shared_key, const int shared_len,
14 int cipher_nid, const unsigned char *cipher_key,
15 int mac_nid, unsigned char *mac_key,
16 const unsigned char *iv, const size_t ivlen,
17 unsigned char *out, int *out_len)
19 unsigned char iv_full[16], mac_buf[16];
22 EVP_CIPHER_CTX *ciph = NULL;
23 EVP_MD_CTX *mac = NULL;
28 mac_len = (cipher_nid == NID_magma_ctr) ? 8 :
29 (cipher_nid == NID_grasshopper_ctr) ? 16 : 0;
32 GOSTerr(GOST_F_GOST_KEXP15, GOST_R_INVALID_CIPHER);
36 /* we expect IV of half length */
37 memset(iv_full, 0, 16);
38 memcpy(iv_full, iv, ivlen);
40 mac = EVP_MD_CTX_new();
42 GOSTerr(GOST_F_GOST_KEXP15, ERR_R_MALLOC_FAILURE);
46 if (EVP_DigestInit_ex(mac, EVP_get_digestbynid(mac_nid), NULL) <= 0
47 || EVP_MD_CTX_ctrl(mac, EVP_MD_CTRL_SET_KEY, 32, mac_key) <= 0
48 || EVP_MD_CTX_ctrl(mac, EVP_MD_CTRL_MAC_LEN, mac_len, NULL) <= 0
49 || EVP_DigestUpdate(mac, iv, ivlen) <= 0
50 || EVP_DigestUpdate(mac, shared_key, shared_len) <= 0
51 /* As we set MAC length directly, we should not allow overwriting it */
52 || EVP_DigestFinal_ex(mac, mac_buf, NULL) <= 0) {
53 GOSTerr(GOST_F_GOST_KEXP15, ERR_R_INTERNAL_ERROR);
57 ciph = EVP_CIPHER_CTX_new();
59 GOSTerr(GOST_F_GOST_KEXP15, ERR_R_MALLOC_FAILURE);
64 (ciph, EVP_get_cipherbynid(cipher_nid), NULL, NULL, NULL, 1) <= 0
65 || EVP_CipherInit_ex(ciph, NULL, NULL, cipher_key, iv_full, 1) <= 0
66 || EVP_CipherUpdate(ciph, out, &len, shared_key, shared_len) <= 0
67 || EVP_CipherUpdate(ciph, out + shared_len, &len, mac_buf, mac_len) <= 0
68 || EVP_CipherFinal_ex(ciph, out + shared_len + len, out_len) <= 0) {
69 GOSTerr(GOST_F_GOST_KEXP15, ERR_R_INTERNAL_ERROR);
73 *out_len = shared_len + mac_len;
78 OPENSSL_cleanse(mac_buf, mac_len);
80 EVP_CIPHER_CTX_free(ciph);
86 * Function expects that shared_key is a preallocated buffer
87 * with length defined as expkeylen - mac_len defined by mac_nid
89 int gost_kimp15(const unsigned char *expkey, const size_t expkeylen,
90 int cipher_nid, const unsigned char *cipher_key,
91 int mac_nid, unsigned char *mac_key,
92 const unsigned char *iv, const size_t ivlen,
93 unsigned char *shared_key)
95 unsigned char iv_full[16], out[48], mac_buf[16];
97 const size_t shared_len = 32;
99 EVP_CIPHER_CTX *ciph = NULL;
100 EVP_MD_CTX *mac = NULL;
105 mac_len = (cipher_nid == NID_magma_ctr) ? 8 :
106 (cipher_nid == NID_grasshopper_ctr) ? 16 : 0;
109 GOSTerr(GOST_F_GOST_KIMP15, GOST_R_INVALID_CIPHER);
113 /* we expect IV of half length */
114 memset(iv_full, 0, 16);
115 memcpy(iv_full, iv, ivlen);
117 ciph = EVP_CIPHER_CTX_new();
119 GOSTerr(GOST_F_GOST_KIMP15, ERR_R_MALLOC_FAILURE);
123 if (EVP_CipherInit_ex
124 (ciph, EVP_get_cipherbynid(cipher_nid), NULL, NULL, NULL, 0) <= 0
125 || EVP_CipherInit_ex(ciph, NULL, NULL, cipher_key, iv_full, 0) <= 0
126 || EVP_CipherUpdate(ciph, out, &len, expkey, expkeylen) <= 0
127 || EVP_CipherFinal_ex(ciph, out + len, &len) <= 0) {
128 GOSTerr(GOST_F_GOST_KIMP15, ERR_R_INTERNAL_ERROR);
131 /*Now we have shared key and mac in out[] */
133 mac = EVP_MD_CTX_new();
135 GOSTerr(GOST_F_GOST_KIMP15, ERR_R_MALLOC_FAILURE);
139 if (EVP_DigestInit_ex(mac, EVP_get_digestbynid(mac_nid), NULL) <= 0
140 || EVP_MD_CTX_ctrl(mac, EVP_MD_CTRL_SET_KEY, 32, mac_key) <= 0
141 || EVP_MD_CTX_ctrl(mac, EVP_MD_CTRL_MAC_LEN, mac_len, NULL) <= 0
142 || EVP_DigestUpdate(mac, iv, ivlen) <= 0
143 || EVP_DigestUpdate(mac, out, shared_len) <= 0
144 /* As we set MAC length directly, we should not allow overwriting it */
145 || EVP_DigestFinal_ex(mac, mac_buf, NULL) <= 0) {
146 GOSTerr(GOST_F_GOST_KIMP15, ERR_R_INTERNAL_ERROR);
150 if (CRYPTO_memcmp(mac_buf, out + shared_len, mac_len) != 0) {
151 GOSTerr(GOST_F_GOST_KIMP15, GOST_R_BAD_MAC);
155 memcpy(shared_key, out, shared_len);
159 OPENSSL_cleanse(out, sizeof(out));
160 EVP_MD_CTX_free(mac);
161 EVP_CIPHER_CTX_free(ciph);
165 int gost_kdftree2012_256(unsigned char *keyout, size_t keyout_len,
166 const unsigned char *key, size_t keylen,
167 const unsigned char *label, size_t label_len,
168 const unsigned char *seed, size_t seed_len,
169 const size_t representation)
172 unsigned char zero = 0;
173 unsigned char *ptr = keyout;
174 HMAC_CTX *ctx = NULL;
175 unsigned char *len_ptr = NULL;
176 uint32_t len_repr = htonl(keyout_len * 8);
177 size_t len_repr_len = 4;
179 ctx = HMAC_CTX_new();
181 GOSTerr(GOST_F_GOST_KDFTREE2012_256, ERR_R_MALLOC_FAILURE);
185 if ((keyout_len == 0) || (keyout_len % 32 != 0)) {
186 GOSTerr(GOST_F_GOST_KDFTREE2012_256, ERR_R_INTERNAL_ERROR);
189 iters = keyout_len / 32;
191 len_ptr = (unsigned char *)&len_repr;
192 while (*len_ptr == 0) {
197 for (i = 1; i <= iters; i++) {
198 uint32_t iter_net = htonl(i);
199 unsigned char *rep_ptr =
200 ((unsigned char *)&iter_net) + (4 - representation);
202 if (HMAC_Init_ex(ctx, key, keylen,
203 EVP_get_digestbynid(NID_id_GostR3411_2012_256),
205 || HMAC_Update(ctx, rep_ptr, representation) <= 0
206 || HMAC_Update(ctx, label, label_len) <= 0
207 || HMAC_Update(ctx, &zero, 1) <= 0
208 || HMAC_Update(ctx, seed, seed_len) <= 0
209 || HMAC_Update(ctx, len_ptr, len_repr_len) <= 0
210 || HMAC_Final(ctx, ptr, NULL) <= 0) {
211 GOSTerr(GOST_F_GOST_KDFTREE2012_256, ERR_R_INTERNAL_ERROR);
225 int gost_tlstree(int cipher_nid, const unsigned char *in, unsigned char *out,
226 const unsigned char *tlsseq)
229 uint64_t gh_c1 = 0xFFFFFFFF00000000, gh_c2 = 0xFFFFFFFFFFF80000,
230 gh_c3 = 0xFFFFFFFFFFFFFFC0;
231 uint64_t mg_c1 = 0xFFFFFFC000000000, mg_c2 = 0xFFFFFFFFFE000000,
232 mg_c3 = 0xFFFFFFFFFFFFF000;
234 uint64_t gh_c1 = 0x00000000FFFFFFFF, gh_c2 = 0x0000F8FFFFFFFFFF,
235 gh_c3 = 0xC0FFFFFFFFFFFFFF;
236 uint64_t mg_c1 = 0x00000000C0FFFFFF, mg_c2 = 0x000000FEFFFFFFFF,
237 mg_c3 = 0x00F0FFFFFFFFFFFF;
240 uint64_t seed1, seed2, seed3;
242 unsigned char ko1[32], ko2[32];
244 switch (cipher_nid) {
250 case NID_grasshopper_cbc:
258 memcpy(&seq, tlsseq, 8);
263 if (gost_kdftree2012_256(ko1, 32, in, 32, (const unsigned char *)"level1", 6,
264 (const unsigned char *)&seed1, 8, 1) <= 0
265 || gost_kdftree2012_256(ko2, 32, ko1, 32, (const unsigned char *)"level2", 6,
266 (const unsigned char *)&seed2, 8, 1) <= 0
267 || gost_kdftree2012_256(out, 32, ko2, 32, (const unsigned char *)"level3", 6,
268 (const unsigned char *)&seed3, 8, 1) <= 0)
274 #ifdef ENABLE_UNIT_TESTS
277 # include <openssl/obj_mac.h>
279 static void hexdump(FILE *f, const char *title, const unsigned char *s, int l)
283 fprintf(f, "%s", title);
286 fprintf(f, "\n%04x", n);
287 fprintf(f, " %02x", s[n]);
294 const unsigned char shared_key[] = {
295 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
296 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
297 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
298 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF
301 const unsigned char magma_key[] = {
302 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
303 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
304 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
305 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
308 unsigned char mac_magma_key[] = {
309 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
310 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
311 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
312 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
315 const unsigned char magma_iv[] = { 0x67, 0xBE, 0xD6, 0x54 };
317 const unsigned char magma_export[] = {
318 0xCF, 0xD5, 0xA1, 0x2D, 0x5B, 0x81, 0xB6, 0xE1,
319 0xE9, 0x9C, 0x91, 0x6D, 0x07, 0x90, 0x0C, 0x6A,
320 0xC1, 0x27, 0x03, 0xFB, 0x3A, 0xBD, 0xED, 0x55,
321 0x56, 0x7B, 0xF3, 0x74, 0x2C, 0x89, 0x9C, 0x75,
322 0x5D, 0xAF, 0xE7, 0xB4, 0x2E, 0x3A, 0x8B, 0xD9
325 unsigned char kdftree_key[] = {
326 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
327 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
328 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
329 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
332 unsigned char kdf_label[] = { 0x26, 0xBD, 0xB8, 0x78 };
333 unsigned char kdf_seed[] =
334 { 0xAF, 0x21, 0x43, 0x41, 0x45, 0x65, 0x63, 0x78 };
335 const unsigned char kdf_etalon[] = {
336 0x22, 0xB6, 0x83, 0x78, 0x45, 0xC6, 0xBE, 0xF6,
337 0x5E, 0xA7, 0x16, 0x72, 0xB2, 0x65, 0x83, 0x10,
338 0x86, 0xD3, 0xC7, 0x6A, 0xEB, 0xE6, 0xDA, 0xE9,
339 0x1C, 0xAD, 0x51, 0xD8, 0x3F, 0x79, 0xD1, 0x6B,
340 0x07, 0x4C, 0x93, 0x30, 0x59, 0x9D, 0x7F, 0x8D,
341 0x71, 0x2F, 0xCA, 0x54, 0x39, 0x2F, 0x4D, 0xDD,
342 0xE9, 0x37, 0x51, 0x20, 0x6B, 0x35, 0x84, 0xC8,
343 0xF4, 0x3F, 0x9E, 0x6D, 0xC5, 0x15, 0x31, 0xF9
346 const unsigned char tlstree_gh_etalon[] = {
347 0x50, 0x76, 0x42, 0xd9, 0x58, 0xc5, 0x20, 0xc6,
348 0xd7, 0xee, 0xf5, 0xca, 0x8a, 0x53, 0x16, 0xd4,
349 0xf3, 0x4b, 0x85, 0x5d, 0x2d, 0xd4, 0xbc, 0xbf,
350 0x4e, 0x5b, 0xf0, 0xff, 0x64, 0x1a, 0x19, 0xff,
353 unsigned char buf[32 + 16];
356 unsigned char kdf_result[64];
358 unsigned char kroot[32];
359 unsigned char tlsseq[8];
360 unsigned char out[32];
362 OpenSSL_add_all_algorithms();
363 memset(buf, 0, sizeof(buf));
365 memset(kroot, 0xFF, 32);
366 memset(tlsseq, 0, 8);
370 ret = gost_kexp15(shared_key, 32,
371 NID_magma_ctr, magma_key,
372 NID_magma_mac, mac_magma_key, magma_iv, 4, buf, &outlen);
375 ERR_print_errors_fp(stderr);
377 hexdump(stdout, "Magma key export", buf, 40);
378 if (memcmp(buf, magma_export, 40) != 0) {
379 fprintf(stdout, "ERROR! test failed\n");
383 ret = gost_kimp15(magma_export, 40,
384 NID_magma_ctr, magma_key,
385 NID_magma_mac, mac_magma_key, magma_iv, 4, buf);
388 ERR_print_errors_fp(stderr);
390 hexdump(stdout, "Magma key import", buf, 32);
391 if (memcmp(buf, shared_key, 32) != 0) {
392 fprintf(stdout, "ERROR! test failed\n");
396 ret = gost_kdftree2012_256(kdf_result, 64, kdftree_key, 32, kdf_label, 4,
399 ERR_print_errors_fp(stderr);
401 hexdump(stdout, "KDF TREE", kdf_result, 64);
402 if (memcmp(kdf_result, kdf_etalon, 64) != 0) {
403 fprintf(stdout, "ERROR! test failed\n");
407 ret = gost_tlstree(NID_grasshopper_cbc, kroot, out, tlsseq);
409 ERR_print_errors_fp(stderr);
411 hexdump(stdout, "Gost TLSTREE - grasshopper", out, 32);
412 if (memcmp(out, tlstree_gh_etalon, 32) != 0) {
413 fprintf(stdout, "ERROR! test failed\n");