]> www.wagner.pp.ru Git - openssl-gost/engine.git/blob - gost_keyexpimp.c
Update comment to match reality
[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 #ifdef ENABLE_UNIT_TESTS
226 # include <stdio.h>
227 # include <string.h>
228 # include <openssl/obj_mac.h>
229
230 static void hexdump(FILE *f, const char *title, const unsigned char *s, int l)
231 {
232     int n = 0;
233
234     fprintf(f, "%s", title);
235     for (; n < l; ++n) {
236         if ((n % 16) == 0)
237             fprintf(f, "\n%04x", n);
238         fprintf(f, " %02x", s[n]);
239     }
240     fprintf(f, "\n");
241 }
242
243 int main(void)
244 {
245     const unsigned char shared_key[] = {
246         0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
247         0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
248         0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
249         0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF
250     };
251
252     const unsigned char magma_key[] = {
253         0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
254         0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
255         0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
256         0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
257     };
258
259     unsigned char mac_magma_key[] = {
260         0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
261         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
262         0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
263         0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
264     };
265
266     const unsigned char magma_iv[] = { 0x67, 0xBE, 0xD6, 0x54 };
267
268     const unsigned char magma_export[] = {
269         0xCF, 0xD5, 0xA1, 0x2D, 0x5B, 0x81, 0xB6, 0xE1,
270         0xE9, 0x9C, 0x91, 0x6D, 0x07, 0x90, 0x0C, 0x6A,
271         0xC1, 0x27, 0x03, 0xFB, 0x3A, 0xBD, 0xED, 0x55,
272         0x56, 0x7B, 0xF3, 0x74, 0x2C, 0x89, 0x9C, 0x75,
273         0x5D, 0xAF, 0xE7, 0xB4, 0x2E, 0x3A, 0x8B, 0xD9
274     };
275
276     unsigned char kdftree_key[] = {
277         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
278         0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
279         0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
280         0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
281     };
282
283     unsigned char kdf_label[] = { 0x26, 0xBD, 0xB8, 0x78 };
284     unsigned char kdf_seed[] =
285         { 0xAF, 0x21, 0x43, 0x41, 0x45, 0x65, 0x63, 0x78 };
286     const unsigned char kdf_etalon[] = {
287         0x22, 0xB6, 0x83, 0x78, 0x45, 0xC6, 0xBE, 0xF6,
288         0x5E, 0xA7, 0x16, 0x72, 0xB2, 0x65, 0x83, 0x10,
289         0x86, 0xD3, 0xC7, 0x6A, 0xEB, 0xE6, 0xDA, 0xE9,
290         0x1C, 0xAD, 0x51, 0xD8, 0x3F, 0x79, 0xD1, 0x6B,
291         0x07, 0x4C, 0x93, 0x30, 0x59, 0x9D, 0x7F, 0x8D,
292         0x71, 0x2F, 0xCA, 0x54, 0x39, 0x2F, 0x4D, 0xDD,
293         0xE9, 0x37, 0x51, 0x20, 0x6B, 0x35, 0x84, 0xC8,
294         0xF4, 0x3F, 0x9E, 0x6D, 0xC5, 0x15, 0x31, 0xF9
295     };
296
297     unsigned char buf[32 + 16];
298     int ret = 0;
299     int outlen = 40;
300     unsigned char kdf_result[64];
301
302     OpenSSL_add_all_algorithms();
303     memset(buf, 0, sizeof(buf));
304
305     ret = gost_kexp15(shared_key, 32,
306                       NID_magma_ctr, magma_key,
307                       NID_magma_mac, mac_magma_key, magma_iv, 4, buf, &outlen);
308
309     if (ret <= 0)
310         ERR_print_errors_fp(stderr);
311     else {
312         hexdump(stdout, "Magma key export", buf, 40);
313         if (memcmp(buf, magma_export, 40) != 0) {
314             fprintf(stdout, "ERROR! test failed\n");
315         }
316     }
317
318     ret = gost_kimp15(magma_export, 40,
319                       NID_magma_ctr, magma_key,
320                       NID_magma_mac, mac_magma_key, magma_iv, 4, buf);
321
322     if (ret <= 0)
323         ERR_print_errors_fp(stderr);
324     else {
325         hexdump(stdout, "Magma key import", buf, 32);
326         if (memcmp(buf, shared_key, 32) != 0) {
327             fprintf(stdout, "ERROR! test failed\n");
328         }
329     }
330
331     ret = gost_kdftree2012_256(kdf_result, 64, kdftree_key, 32, kdf_label, 4,
332                                kdf_seed, 8, 1);
333     if (ret <= 0)
334         ERR_print_errors_fp(stderr);
335     else {
336         hexdump(stdout, "KDF TREE", kdf_result, 64);
337         if (memcmp(kdf_result, kdf_etalon, 64) != 0) {
338             fprintf(stdout, "ERROR! test failed\n");
339         }
340     }
341
342     return 0;
343 }
344
345 #endif