]> www.wagner.pp.ru Git - openssl-gost/engine.git/blob - gost_keyexpimp.c
Merge pull request #86 from vt-alt/curves
[openssl-gost/engine.git] / gost_keyexpimp.c
1 #include <arpa/inet.h>
2 #include <string.h>
3 #include <openssl/evp.h>
4 #include <openssl/hmac.h>
5
6 #include "gost_lcl.h"
7 #include "e_gost_err.h"
8
9 /*
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
12  * */
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)
18 {
19     unsigned char iv_full[16], mac_buf[16];
20     unsigned int mac_len;
21
22     EVP_CIPHER_CTX *ciph = NULL;
23     EVP_MD_CTX *mac = NULL;
24
25     int ret = 0;
26     int len;
27
28     mac_len = (cipher_nid == NID_magma_ctr) ? 8 :
29         (cipher_nid == NID_grasshopper_ctr) ? 16 : 0;
30
31     if (mac_len == 0) {
32         GOSTerr(GOST_F_GOST_KEXP15, GOST_R_INVALID_CIPHER);
33         goto err;
34     }
35
36     /* we expect IV of half length */
37     memset(iv_full, 0, 16);
38     memcpy(iv_full, iv, ivlen);
39
40     mac = EVP_MD_CTX_new();
41     if (mac == NULL) {
42         GOSTerr(GOST_F_GOST_KEXP15, ERR_R_MALLOC_FAILURE);
43         goto err;
44     }
45
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);
54         goto err;
55     }
56
57     ciph = EVP_CIPHER_CTX_new();
58     if (ciph == NULL) {
59         GOSTerr(GOST_F_GOST_KEXP15, ERR_R_MALLOC_FAILURE);
60         goto err;
61     }
62
63     if (EVP_CipherInit_ex
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);
70         goto err;
71     }
72
73     *out_len = shared_len + mac_len;
74
75     ret = 1;
76
77  err:
78     OPENSSL_cleanse(mac_buf, mac_len);
79     EVP_MD_CTX_free(mac);
80     EVP_CIPHER_CTX_free(ciph);
81
82     return ret;
83 }
84
85 /*
86  * Function expects that shared_key is a preallocated buffer
87  * with length defined as expkeylen - mac_len defined by mac_nid
88  * */
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)
94 {
95     unsigned char iv_full[16], out[48], mac_buf[16];
96     unsigned int mac_len;
97     const size_t shared_len = 32;
98
99     EVP_CIPHER_CTX *ciph = NULL;
100     EVP_MD_CTX *mac = NULL;
101
102     int ret = 0;
103     int len;
104
105     mac_len = (cipher_nid == NID_magma_ctr) ? 8 :
106         (cipher_nid == NID_grasshopper_ctr) ? 16 : 0;
107
108     if (mac_len == 0) {
109         GOSTerr(GOST_F_GOST_KIMP15, GOST_R_INVALID_CIPHER);
110         goto err;
111     }
112
113     /* we expect IV of half length */
114     memset(iv_full, 0, 16);
115     memcpy(iv_full, iv, ivlen);
116
117     ciph = EVP_CIPHER_CTX_new();
118     if (ciph == NULL) {
119         GOSTerr(GOST_F_GOST_KIMP15, ERR_R_MALLOC_FAILURE);
120         goto err;
121     }
122
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);
129         goto err;
130     }
131     /*Now we have shared key and mac in out[] */
132
133     mac = EVP_MD_CTX_new();
134     if (mac == NULL) {
135         GOSTerr(GOST_F_GOST_KIMP15, ERR_R_MALLOC_FAILURE);
136         goto err;
137     }
138
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);
147         goto err;
148     }
149
150     if (CRYPTO_memcmp(mac_buf, out + shared_len, mac_len) != 0) {
151         GOSTerr(GOST_F_GOST_KIMP15, GOST_R_BAD_MAC);
152         goto err;
153     }
154
155     memcpy(shared_key, out, shared_len);
156     ret = 1;
157
158  err:
159     OPENSSL_cleanse(out, sizeof(out));
160     EVP_MD_CTX_free(mac);
161     EVP_CIPHER_CTX_free(ciph);
162     return ret;
163 }
164
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)
170 {
171     int iters, i = 0;
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;
178
179     ctx = HMAC_CTX_new();
180     if (ctx == NULL) {
181         GOSTerr(GOST_F_GOST_KDFTREE2012_256, ERR_R_MALLOC_FAILURE);
182         return 0;
183     }
184
185     if ((keyout_len == 0) || (keyout_len % 32 != 0)) {
186         GOSTerr(GOST_F_GOST_KDFTREE2012_256, ERR_R_INTERNAL_ERROR);
187         return 0;
188     }
189     iters = keyout_len / 32;
190
191     len_ptr = (unsigned char *)&len_repr;
192     while (*len_ptr == 0) {
193         len_ptr++;
194         len_repr_len--;
195     }
196
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);
201
202         if (HMAC_Init_ex(ctx, key, keylen,
203                          EVP_get_digestbynid(NID_id_GostR3411_2012_256),
204                          NULL) <= 0
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);
212             HMAC_CTX_free(ctx);
213             return 0;
214         }
215
216         HMAC_CTX_reset(ctx);
217         ptr += 32;
218     }
219
220     HMAC_CTX_free(ctx);
221
222     return 1;
223 }
224
225 int gost_tlstree(int cipher_nid, const unsigned char *in, unsigned char *out,
226                  const unsigned char *tlsseq)
227 {
228 #ifndef L_ENDIAN
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;
233 #else
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;
238 #endif
239     uint64_t c1, c2, c3;
240     uint64_t seed1, seed2, seed3;
241     uint64_t seq;
242     unsigned char ko1[32], ko2[32];
243
244     switch (cipher_nid) {
245     case NID_magma_cbc:
246         c1 = mg_c1;
247         c2 = mg_c2;
248         c3 = mg_c3;
249         break;
250     case NID_grasshopper_cbc:
251         c1 = gh_c1;
252         c2 = gh_c2;
253         c3 = gh_c3;
254         break;
255     default:
256         return 0;
257     }
258     memcpy(&seq, tlsseq, 8);
259     seed1 = seq & c1;
260     seed2 = seq & c2;
261     seed3 = seq & c3;
262
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)
269                         return 0;
270
271     return 1;
272 }
273
274 #ifdef ENABLE_UNIT_TESTS
275 # include <stdio.h>
276 # include <string.h>
277 # include <openssl/obj_mac.h>
278
279 static void hexdump(FILE *f, const char *title, const unsigned char *s, int l)
280 {
281     int n = 0;
282
283     fprintf(f, "%s", title);
284     for (; n < l; ++n) {
285         if ((n % 16) == 0)
286             fprintf(f, "\n%04x", n);
287         fprintf(f, " %02x", s[n]);
288     }
289     fprintf(f, "\n");
290 }
291
292 int main(void)
293 {
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
299     };
300
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,
306     };
307
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,
313     };
314
315     const unsigned char magma_iv[] = { 0x67, 0xBE, 0xD6, 0x54 };
316
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
323     };
324
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,
330     };
331
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
344     };
345
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,
351     };
352
353     unsigned char buf[32 + 16];
354     int ret = 0;
355     int outlen = 40;
356     unsigned char kdf_result[64];
357
358     unsigned char kroot[32];
359     unsigned char tlsseq[8];
360     unsigned char out[32];
361
362     OpenSSL_add_all_algorithms();
363     memset(buf, 0, sizeof(buf));
364
365     memset(kroot, 0xFF, 32);
366     memset(tlsseq, 0, 8);
367     tlsseq[7] = 63;
368     memset(out, 0, 32);
369
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);
373
374     if (ret <= 0)
375         ERR_print_errors_fp(stderr);
376     else {
377         hexdump(stdout, "Magma key export", buf, 40);
378         if (memcmp(buf, magma_export, 40) != 0) {
379             fprintf(stdout, "ERROR! test failed\n");
380         }
381     }
382
383     ret = gost_kimp15(magma_export, 40,
384                       NID_magma_ctr, magma_key,
385                       NID_magma_mac, mac_magma_key, magma_iv, 4, buf);
386
387     if (ret <= 0)
388         ERR_print_errors_fp(stderr);
389     else {
390         hexdump(stdout, "Magma key import", buf, 32);
391         if (memcmp(buf, shared_key, 32) != 0) {
392             fprintf(stdout, "ERROR! test failed\n");
393         }
394     }
395
396     ret = gost_kdftree2012_256(kdf_result, 64, kdftree_key, 32, kdf_label, 4,
397                                kdf_seed, 8, 1);
398     if (ret <= 0)
399         ERR_print_errors_fp(stderr);
400     else {
401         hexdump(stdout, "KDF TREE", kdf_result, 64);
402         if (memcmp(kdf_result, kdf_etalon, 64) != 0) {
403             fprintf(stdout, "ERROR! test failed\n");
404         }
405     }
406
407     ret = gost_tlstree(NID_grasshopper_cbc, kroot, out, tlsseq);
408     if (ret <= 0)
409         ERR_print_errors_fp(stderr);
410     else {
411         hexdump(stdout, "Gost TLSTREE - grasshopper", out, 32);
412         if (memcmp(out, tlstree_gh_etalon, 32) != 0) {
413             fprintf(stdout, "ERROR! test failed\n");
414         }
415     }
416
417     return 0;
418 }
419
420 #endif