]> www.wagner.pp.ru Git - openssl-gost/engine.git/blob - gost_keyexpimp.c
KDF TREE + test
[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 int gost_kimp15(const unsigned char *expkey, const size_t expkeylen,
86                 int cipher_nid, const unsigned char *cipher_key,
87                 int mac_nid, unsigned char *mac_key,
88                 const unsigned char *iv, const size_t ivlen,
89                 unsigned char *shared_key, size_t shared_len)
90 {
91     unsigned char iv_full[16], out[48], mac_buf[16];
92     unsigned int mac_len;
93
94     EVP_CIPHER_CTX *ciph = NULL;
95     EVP_MD_CTX *mac = NULL;
96
97     int ret = 0;
98     int len;
99
100     mac_len = (cipher_nid == NID_magma_ctr) ? 8 :
101         (cipher_nid == NID_grasshopper_ctr) ? 16 : 0;
102
103     if (mac_len == 0) {
104         GOSTerr(GOST_F_GOST_KIMP15, GOST_R_INVALID_CIPHER);
105         goto err;
106     }
107
108     /* we expect IV of half length */
109     memset(iv_full, 0, 16);
110     memcpy(iv_full, iv, ivlen);
111
112     ciph = EVP_CIPHER_CTX_new();
113     if (ciph == NULL) {
114         GOSTerr(GOST_F_GOST_KIMP15, ERR_R_MALLOC_FAILURE);
115         goto err;
116     }
117
118     if (EVP_CipherInit_ex
119         (ciph, EVP_get_cipherbynid(cipher_nid), NULL, NULL, NULL, 0) <= 0
120         || EVP_CipherInit_ex(ciph, NULL, NULL, cipher_key, iv_full, 0) <= 0
121         || EVP_CipherUpdate(ciph, out, &len, expkey, expkeylen) <= 0
122         || EVP_CipherFinal_ex(ciph, out + len, &len) <= 0) {
123         GOSTerr(GOST_F_GOST_KIMP15, ERR_R_INTERNAL_ERROR);
124         goto err;
125     }
126     /*Now we have shared key and mac in out[] */
127
128     mac = EVP_MD_CTX_new();
129     if (mac == NULL) {
130         GOSTerr(GOST_F_GOST_KIMP15, ERR_R_MALLOC_FAILURE);
131         goto err;
132     }
133
134     if (EVP_DigestInit_ex(mac, EVP_get_digestbynid(mac_nid), NULL) <= 0
135         || EVP_MD_CTX_ctrl(mac, EVP_MD_CTRL_SET_KEY, 32, mac_key) <= 0
136         || EVP_MD_CTX_ctrl(mac, EVP_MD_CTRL_MAC_LEN, mac_len, NULL) <= 0
137         || EVP_DigestUpdate(mac, iv, ivlen) <= 0
138         || EVP_DigestUpdate(mac, out, shared_len) <= 0
139         /* As we set MAC length directly, we should not allow overwriting it */
140         || EVP_DigestFinal_ex(mac, mac_buf, NULL) <= 0) {
141         GOSTerr(GOST_F_GOST_KIMP15, ERR_R_INTERNAL_ERROR);
142         goto err;
143     }
144
145     if (CRYPTO_memcmp(mac_buf, out + shared_len, mac_len) != 0) {
146         GOSTerr(GOST_F_GOST_KIMP15, GOST_R_BAD_MAC);
147         goto err;
148     }
149
150     memcpy(shared_key, out, shared_len);
151     ret = 1;
152
153  err:
154     OPENSSL_cleanse(out, sizeof(out));
155     EVP_MD_CTX_free(mac);
156     EVP_CIPHER_CTX_free(ciph);
157     return ret;
158 }
159
160 int gost_kdftree2012_256(unsigned char *keyout, size_t keyout_len,
161                          const unsigned char *key, size_t keylen,
162                          const unsigned char *label, size_t label_len,
163                          const unsigned char *seed, size_t seed_len,
164                          const size_t representation)
165 {
166     int iters, i = 0;
167     unsigned char zero = 0;
168     unsigned char *ptr = keyout;
169     HMAC_CTX *ctx = NULL;
170     unsigned char *len_ptr = NULL;
171     uint32_t len_repr = htonl(keyout_len * 8);
172     size_t len_repr_len = 4;
173
174     ctx = HMAC_CTX_new();
175     if (ctx == NULL) {
176         GOSTerr(GOST_F_GOST_KDFTREE2012_256, ERR_R_MALLOC_FAILURE);
177         return 0;
178     }
179
180     if ((keyout_len == 0) || (keyout_len % 32 != 0)) {
181         GOSTerr(GOST_F_GOST_KDFTREE2012_256, ERR_R_INTERNAL_ERROR);
182         return 0;
183     }
184     iters = keyout_len / 32;
185
186     len_ptr = (unsigned char *)&len_repr;
187     while (*len_ptr == 0) {
188         len_ptr++;
189         len_repr_len--;
190     }
191
192     for (i = 1; i <= iters; i++) {
193         uint32_t iter_net = htonl(i);
194         unsigned char *rep_ptr =
195             ((unsigned char *)&iter_net) + (4 - representation);
196
197         if (HMAC_Init_ex(ctx, key, keylen,
198                          EVP_get_digestbynid(NID_id_GostR3411_2012_256),
199                          NULL) <= 0
200             || HMAC_Update(ctx, rep_ptr, representation) <= 0
201             || HMAC_Update(ctx, label, label_len) <= 0
202             || HMAC_Update(ctx, &zero, 1) <= 0
203             || HMAC_Update(ctx, seed, seed_len) <= 0
204             || HMAC_Update(ctx, len_ptr, len_repr_len) <= 0
205             || HMAC_Final(ctx, ptr, NULL) <= 0) {
206             GOSTerr(GOST_F_GOST_KDFTREE2012_256, ERR_R_INTERNAL_ERROR);
207             HMAC_CTX_free(ctx);
208             return 0;
209         }
210
211         HMAC_CTX_reset(ctx);
212         ptr += 32;
213     }
214
215     HMAC_CTX_free(ctx);
216
217     return 1;
218 }
219
220 #ifdef ENABLE_UNIT_TESTS
221 # include <stdio.h>
222 # include <string.h>
223 # include <openssl/obj_mac.h>
224
225 static void hexdump(FILE *f, const char *title, const unsigned char *s, int l)
226 {
227     int n = 0;
228
229     fprintf(f, "%s", title);
230     for (; n < l; ++n) {
231         if ((n % 16) == 0)
232             fprintf(f, "\n%04x", n);
233         fprintf(f, " %02x", s[n]);
234     }
235     fprintf(f, "\n");
236 }
237
238 int main(void)
239 {
240     const unsigned char shared_key[] = {
241         0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
242         0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
243         0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
244         0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF
245     };
246
247     const unsigned char magma_key[] = {
248         0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
249         0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
250         0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
251         0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
252     };
253
254     unsigned char mac_magma_key[] = {
255         0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
256         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
257         0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
258         0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
259     };
260
261     const unsigned char magma_iv[] = { 0x67, 0xBE, 0xD6, 0x54 };
262
263     const unsigned char magma_export[] = {
264         0xCF, 0xD5, 0xA1, 0x2D, 0x5B, 0x81, 0xB6, 0xE1,
265         0xE9, 0x9C, 0x91, 0x6D, 0x07, 0x90, 0x0C, 0x6A,
266         0xC1, 0x27, 0x03, 0xFB, 0x3A, 0xBD, 0xED, 0x55,
267         0x56, 0x7B, 0xF3, 0x74, 0x2C, 0x89, 0x9C, 0x75,
268         0x5D, 0xAF, 0xE7, 0xB4, 0x2E, 0x3A, 0x8B, 0xD9
269     };
270
271     unsigned char kdftree_key[] = {
272         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
273         0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
274         0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
275         0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
276     };
277
278     unsigned char kdf_label[] = { 0x26, 0xBD, 0xB8, 0x78 };
279     unsigned char kdf_seed[] =
280         { 0xAF, 0x21, 0x43, 0x41, 0x45, 0x65, 0x63, 0x78 };
281     const unsigned char kdf_etalon[] = {
282         0x22, 0xB6, 0x83, 0x78, 0x45, 0xC6, 0xBE, 0xF6,
283         0x5E, 0xA7, 0x16, 0x72, 0xB2, 0x65, 0x83, 0x10,
284         0x86, 0xD3, 0xC7, 0x6A, 0xEB, 0xE6, 0xDA, 0xE9,
285         0x1C, 0xAD, 0x51, 0xD8, 0x3F, 0x79, 0xD1, 0x6B,
286         0x07, 0x4C, 0x93, 0x30, 0x59, 0x9D, 0x7F, 0x8D,
287         0x71, 0x2F, 0xCA, 0x54, 0x39, 0x2F, 0x4D, 0xDD,
288         0xE9, 0x37, 0x51, 0x20, 0x6B, 0x35, 0x84, 0xC8,
289         0xF4, 0x3F, 0x9E, 0x6D, 0xC5, 0x15, 0x31, 0xF9
290     };
291
292     unsigned char buf[32 + 16];
293     int ret = 0;
294     int outlen = 40;
295     unsigned char kdf_result[64];
296
297     OpenSSL_add_all_algorithms();
298     memset(buf, 0, sizeof(buf));
299
300     ret = gost_kexp15(shared_key, 32,
301                       NID_magma_ctr, magma_key,
302                       NID_magma_mac, mac_magma_key, magma_iv, 4, buf, &outlen);
303
304     if (ret <= 0)
305         ERR_print_errors_fp(stderr);
306     else {
307         hexdump(stdout, "Magma key export", buf, 40);
308         if (memcmp(buf, magma_export, 40) != 0) {
309             fprintf(stdout, "ERROR! test failed\n");
310         }
311     }
312
313     ret = gost_kimp15(magma_export, 40,
314                       NID_magma_ctr, magma_key,
315                       NID_magma_mac, mac_magma_key, magma_iv, 4, buf, 32);
316
317     if (ret <= 0)
318         ERR_print_errors_fp(stderr);
319     else {
320         hexdump(stdout, "Magma key import", buf, 32);
321         if (memcmp(buf, shared_key, 32) != 0) {
322             fprintf(stdout, "ERROR! test failed\n");
323         }
324     }
325
326     ret = gost_kdftree2012_256(kdf_result, 64, kdftree_key, 32, kdf_label, 4,
327                                kdf_seed, 8, 1);
328     if (ret <= 0)
329         ERR_print_errors_fp(stderr);
330     else {
331         hexdump(stdout, "KDF TREE", kdf_result, 64);
332         if (memcmp(kdf_result, kdf_etalon, 64) != 0) {
333             fprintf(stdout, "ERROR! test failed\n");
334         }
335     }
336
337     return 0;
338 }
339
340 #endif