]> www.wagner.pp.ru Git - openssl-gost/engine.git/blob - gost_keyexpimp.c
Add static to functions that not need to be exported
[openssl-gost/engine.git] / gost_keyexpimp.c
1 /*
2  * Copyright (c) 2019 Dmitry Belyavskiy <beldmit@gmail.com>
3  * Copyright (c) 2020 Vitaly Chikunov <vt@altlinux.org>
4  *
5  * Contents licensed under the terms of the OpenSSL license
6  * See https://www.openssl.org/source/license.html for details
7  */
8 #ifdef _WIN32
9 #include <winsock.h>
10 #else
11 #include <arpa/inet.h>
12 #endif
13 #include <string.h>
14 #include <openssl/evp.h>
15 #include <openssl/hmac.h>
16
17 #include "gost_lcl.h"
18 #include "e_gost_err.h"
19
20 int omac_imit_ctrl(EVP_MD_CTX *ctx, int type, int arg, void *ptr);
21 /*
22  * Function expects that out is a preallocated buffer of length
23  * defined as sum of shared_len and mac length defined by mac_nid
24  * */
25 int gost_kexp15(const unsigned char *shared_key, const int shared_len,
26                 int cipher_nid, const unsigned char *cipher_key,
27                 int mac_nid, unsigned char *mac_key,
28                 const unsigned char *iv, const size_t ivlen,
29                 unsigned char *out, int *out_len)
30 {
31     unsigned char iv_full[16], mac_buf[16];
32     unsigned int mac_len;
33
34     EVP_CIPHER_CTX *ciph = NULL;
35     EVP_MD_CTX *mac = NULL;
36
37     int ret = 0;
38     int len;
39
40     mac_len = (cipher_nid == NID_magma_ctr) ? 8 :
41         (cipher_nid == NID_grasshopper_ctr) ? 16 : 0;
42
43     if (mac_len == 0) {
44         GOSTerr(GOST_F_GOST_KEXP15, GOST_R_INVALID_CIPHER);
45         goto err;
46     }
47
48     /* we expect IV of half length */
49     memset(iv_full, 0, 16);
50     memcpy(iv_full, iv, ivlen);
51
52     mac = EVP_MD_CTX_new();
53     if (mac == NULL) {
54         GOSTerr(GOST_F_GOST_KEXP15, ERR_R_MALLOC_FAILURE);
55         goto err;
56     }
57
58     if (EVP_DigestInit_ex(mac, EVP_get_digestbynid(mac_nid), NULL) <= 0
59         || omac_imit_ctrl(mac, EVP_MD_CTRL_SET_KEY, 32, mac_key) <= 0
60         || omac_imit_ctrl(mac, EVP_MD_CTRL_XOF_LEN, mac_len, NULL) <= 0
61         || EVP_DigestUpdate(mac, iv, ivlen) <= 0
62         || EVP_DigestUpdate(mac, shared_key, shared_len) <= 0
63         /* As we set MAC length directly, we should not allow overwriting it */
64         || EVP_DigestFinalXOF(mac, mac_buf, mac_len) <= 0) {
65         GOSTerr(GOST_F_GOST_KEXP15, ERR_R_INTERNAL_ERROR);
66         goto err;
67     }
68
69     ciph = EVP_CIPHER_CTX_new();
70     if (ciph == NULL) {
71         GOSTerr(GOST_F_GOST_KEXP15, ERR_R_MALLOC_FAILURE);
72         goto err;
73     }
74
75     if (EVP_CipherInit_ex
76         (ciph, EVP_get_cipherbynid(cipher_nid), NULL, NULL, NULL, 1) <= 0
77         || EVP_CipherInit_ex(ciph, NULL, NULL, cipher_key, iv_full, 1) <= 0
78         || EVP_CipherUpdate(ciph, out, &len, shared_key, shared_len) <= 0
79         || EVP_CipherUpdate(ciph, out + shared_len, &len, mac_buf, mac_len) <= 0
80         || EVP_CipherFinal_ex(ciph, out + shared_len + len, out_len) <= 0) {
81         GOSTerr(GOST_F_GOST_KEXP15, ERR_R_INTERNAL_ERROR);
82         goto err;
83     }
84
85     *out_len = shared_len + mac_len;
86
87     ret = 1;
88
89  err:
90     OPENSSL_cleanse(mac_buf, mac_len);
91     EVP_MD_CTX_free(mac);
92     EVP_CIPHER_CTX_free(ciph);
93
94     return ret;
95 }
96
97 /*
98  * Function expects that shared_key is a preallocated buffer
99  * with length defined as expkeylen + mac_len defined by mac_nid
100  * */
101 int gost_kimp15(const unsigned char *expkey, const size_t expkeylen,
102                 int cipher_nid, const unsigned char *cipher_key,
103                 int mac_nid, unsigned char *mac_key,
104                 const unsigned char *iv, const size_t ivlen,
105                 unsigned char *shared_key)
106 {
107     unsigned char iv_full[16], out[48], mac_buf[16];
108     unsigned int mac_len;
109     const size_t shared_len = 32;
110
111     EVP_CIPHER_CTX *ciph = NULL;
112     EVP_MD_CTX *mac = NULL;
113
114     int ret = 0;
115     int len;
116
117     mac_len = (cipher_nid == NID_magma_ctr) ? 8 :
118         (cipher_nid == NID_grasshopper_ctr) ? 16 : 0;
119
120     if (mac_len == 0) {
121         GOSTerr(GOST_F_GOST_KIMP15, GOST_R_INVALID_CIPHER);
122         goto err;
123     }
124
125     /* we expect IV of half length */
126     memset(iv_full, 0, 16);
127     memcpy(iv_full, iv, ivlen);
128
129     ciph = EVP_CIPHER_CTX_new();
130     if (ciph == NULL) {
131         GOSTerr(GOST_F_GOST_KIMP15, ERR_R_MALLOC_FAILURE);
132         goto err;
133     }
134
135     if (EVP_CipherInit_ex
136         (ciph, EVP_get_cipherbynid(cipher_nid), NULL, NULL, NULL, 0) <= 0
137         || EVP_CipherInit_ex(ciph, NULL, NULL, cipher_key, iv_full, 0) <= 0
138         || EVP_CipherUpdate(ciph, out, &len, expkey, expkeylen) <= 0
139         || EVP_CipherFinal_ex(ciph, out + len, &len) <= 0) {
140         GOSTerr(GOST_F_GOST_KIMP15, ERR_R_INTERNAL_ERROR);
141         goto err;
142     }
143     /*Now we have shared key and mac in out[] */
144
145     mac = EVP_MD_CTX_new();
146     if (mac == NULL) {
147         GOSTerr(GOST_F_GOST_KIMP15, ERR_R_MALLOC_FAILURE);
148         goto err;
149     }
150
151     if (EVP_DigestInit_ex(mac, EVP_get_digestbynid(mac_nid), NULL) <= 0
152         || omac_imit_ctrl(mac, EVP_MD_CTRL_SET_KEY, 32, mac_key) <= 0
153         || omac_imit_ctrl(mac, EVP_MD_CTRL_XOF_LEN, mac_len, NULL) <= 0
154         || EVP_DigestUpdate(mac, iv, ivlen) <= 0
155         || EVP_DigestUpdate(mac, out, shared_len) <= 0
156         /* As we set MAC length directly, we should not allow overwriting it */
157         || EVP_DigestFinalXOF(mac, mac_buf, mac_len) <= 0) {
158         GOSTerr(GOST_F_GOST_KIMP15, ERR_R_INTERNAL_ERROR);
159         goto err;
160     }
161
162     if (CRYPTO_memcmp(mac_buf, out + shared_len, mac_len) != 0) {
163         GOSTerr(GOST_F_GOST_KIMP15, GOST_R_BAD_MAC);
164         goto err;
165     }
166
167     memcpy(shared_key, out, shared_len);
168     ret = 1;
169
170  err:
171     OPENSSL_cleanse(out, sizeof(out));
172     EVP_MD_CTX_free(mac);
173     EVP_CIPHER_CTX_free(ciph);
174     return ret;
175 }
176
177 int gost_kdftree2012_256(unsigned char *keyout, size_t keyout_len,
178                          const unsigned char *key, size_t keylen,
179                          const unsigned char *label, size_t label_len,
180                          const unsigned char *seed, size_t seed_len,
181                          const size_t representation)
182 {
183     int iters, i = 0;
184     unsigned char zero = 0;
185     unsigned char *ptr = keyout;
186     HMAC_CTX *ctx;
187     unsigned char *len_ptr = NULL;
188     uint32_t len_repr = htonl(keyout_len * 8);
189     size_t len_repr_len = 4;
190
191     ctx = HMAC_CTX_new();
192     if (ctx == NULL) {
193         GOSTerr(GOST_F_GOST_KDFTREE2012_256, ERR_R_MALLOC_FAILURE);
194         return 0;
195     }
196
197     if ((keyout_len == 0) || (keyout_len % 32 != 0)) {
198         GOSTerr(GOST_F_GOST_KDFTREE2012_256, ERR_R_INTERNAL_ERROR);
199         return 0;
200     }
201     iters = keyout_len / 32;
202
203     len_ptr = (unsigned char *)&len_repr;
204     while (*len_ptr == 0) {
205         len_ptr++;
206         len_repr_len--;
207     }
208
209     for (i = 1; i <= iters; i++) {
210         uint32_t iter_net = htonl(i);
211         unsigned char *rep_ptr =
212             ((unsigned char *)&iter_net) + (4 - representation);
213
214         if (HMAC_Init_ex(ctx, key, keylen,
215                          EVP_get_digestbynid(NID_id_GostR3411_2012_256),
216                          NULL) <= 0
217             || HMAC_Update(ctx, rep_ptr, representation) <= 0
218             || HMAC_Update(ctx, label, label_len) <= 0
219             || HMAC_Update(ctx, &zero, 1) <= 0
220             || HMAC_Update(ctx, seed, seed_len) <= 0
221             || HMAC_Update(ctx, len_ptr, len_repr_len) <= 0
222             || HMAC_Final(ctx, ptr, NULL) <= 0) {
223             GOSTerr(GOST_F_GOST_KDFTREE2012_256, ERR_R_INTERNAL_ERROR);
224             HMAC_CTX_free(ctx);
225             return 0;
226         }
227
228         HMAC_CTX_reset(ctx);
229         ptr += 32;
230     }
231
232     HMAC_CTX_free(ctx);
233
234     return 1;
235 }
236
237 int gost_tlstree(int cipher_nid, const unsigned char *in, unsigned char *out,
238                  const unsigned char *tlsseq)
239 {
240 #ifndef L_ENDIAN
241     uint64_t gh_c1 = 0xFFFFFFFF00000000, gh_c2 = 0xFFFFFFFFFFF80000,
242         gh_c3 = 0xFFFFFFFFFFFFFFC0;
243     uint64_t mg_c1 = 0xFFFFFFC000000000, mg_c2 = 0xFFFFFFFFFE000000,
244         mg_c3 = 0xFFFFFFFFFFFFF000;
245 #else
246     uint64_t gh_c1 = 0x00000000FFFFFFFF, gh_c2 = 0x0000F8FFFFFFFFFF,
247         gh_c3 = 0xC0FFFFFFFFFFFFFF;
248     uint64_t mg_c1 = 0x00000000C0FFFFFF, mg_c2 = 0x000000FEFFFFFFFF,
249         mg_c3 = 0x00F0FFFFFFFFFFFF;
250 #endif
251     uint64_t c1, c2, c3;
252     uint64_t seed1, seed2, seed3;
253     uint64_t seq;
254     unsigned char ko1[32], ko2[32];
255
256     switch (cipher_nid) {
257     case NID_magma_cbc:
258         c1 = mg_c1;
259         c2 = mg_c2;
260         c3 = mg_c3;
261         break;
262     case NID_grasshopper_cbc:
263         c1 = gh_c1;
264         c2 = gh_c2;
265         c3 = gh_c3;
266         break;
267     default:
268         return 0;
269     }
270     memcpy(&seq, tlsseq, 8);
271     seed1 = seq & c1;
272     seed2 = seq & c2;
273     seed3 = seq & c3;
274
275     if (gost_kdftree2012_256(ko1, 32, in, 32, (const unsigned char *)"level1", 6,
276                          (const unsigned char *)&seed1, 8, 1) <= 0
277                           || gost_kdftree2012_256(ko2, 32, ko1, 32, (const unsigned char *)"level2", 6,
278                          (const unsigned char *)&seed2, 8, 1) <= 0
279         || gost_kdftree2012_256(out, 32, ko2, 32, (const unsigned char *)"level3", 6,
280                          (const unsigned char *)&seed3, 8, 1) <= 0)
281                         return 0;
282
283     return 1;
284 }
285
286 #define GOST_WRAP_FLAGS  EVP_CIPH_CTRL_INIT | EVP_CIPH_WRAP_MODE | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER | EVP_CIPH_FLAG_DEFAULT_ASN1
287
288 #define MAGMA_MAC_WRAP_LEN 8
289 #define KUZNYECHIK_MAC_WRAP_LEN 16
290 #define MAX_MAC_WRAP_LEN KUZNYECHIK_MAC_WRAP_LEN
291 #define GOSTKEYLEN 32
292 #define MAGMA_WRAPPED_KEY_LEN GOSTKEYLEN + MAGMA_MAC_WRAP_LEN
293 #define KUZNYECHIK_WRAPPED_KEY_LEN GOSTKEYLEN + KUZNYECHIK_MAC_WRAP_LEN
294 #define MAX_WRAPPED_KEY_LEN KUZNYECHIK_WRAPPED_KEY_LEN
295
296 typedef struct {
297         unsigned char iv[8];   /* Max IV size is half of base cipher block length */
298         unsigned char key[GOSTKEYLEN*2]; /* Combined cipher and mac keys */
299         unsigned char wrapped[MAX_WRAPPED_KEY_LEN]; /* Max size */
300         size_t wrap_count;
301 } GOST_WRAP_CTX;
302
303 static int magma_wrap_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
304         const unsigned char *iv, int enc)
305 {
306         GOST_WRAP_CTX *cctx = EVP_CIPHER_CTX_get_cipher_data(ctx);
307         memset(cctx->wrapped, 0, MAX_WRAPPED_KEY_LEN);
308         cctx->wrap_count = 0;
309
310         if (iv) {
311                 memset(cctx->iv, 0, 8);
312                 memcpy(cctx->iv, iv, 4);
313         }
314
315         if (key) {
316                 memcpy(cctx->key, key, GOSTKEYLEN*2);
317         }
318         return 1;
319 }
320
321 static int magma_wrap_do(EVP_CIPHER_CTX *ctx, unsigned char *out,
322         const unsigned char *in, size_t inl)
323 {
324         GOST_WRAP_CTX *cctx = EVP_CIPHER_CTX_get_cipher_data(ctx);
325         int enc = EVP_CIPHER_CTX_encrypting(ctx) ? 1 : 0;
326
327         if (out == NULL)
328                 return GOSTKEYLEN;
329
330         if (inl <= MAGMA_WRAPPED_KEY_LEN) {
331                 if (cctx->wrap_count + inl > MAGMA_WRAPPED_KEY_LEN)
332                         return -1;
333
334                 if (cctx->wrap_count + inl <= MAGMA_WRAPPED_KEY_LEN)
335                 {
336                         memcpy(cctx->wrapped+cctx->wrap_count, in, inl);
337                         cctx->wrap_count += inl;
338                 }
339         }
340
341         if (cctx->wrap_count < MAGMA_WRAPPED_KEY_LEN)
342                 return 0;
343
344         if (enc) {
345 #if 0
346                 return gost_kexp15(cctx->key, 32, NID_magma_ctr, in, NID_magma_mac,
347                         cctx->key, /* FIXME mac_key, */ cctx->iv, 4, out, &outl);
348 #endif
349                 return -1;
350         } else {
351                 return gost_kimp15(cctx->wrapped, cctx->wrap_count, NID_magma_ctr,
352                 cctx->key+GOSTKEYLEN, NID_magma_mac, cctx->key, cctx->iv, 4, out) > 0 ? GOSTKEYLEN : 0;
353         }
354         return 1;
355 }
356
357 static int kuznyechik_wrap_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
358         const unsigned char *iv, int enc)
359 {
360         GOST_WRAP_CTX *cctx = EVP_CIPHER_CTX_get_cipher_data(ctx);
361         memset(cctx->wrapped, 0, KUZNYECHIK_WRAPPED_KEY_LEN);
362         cctx->wrap_count = 0;
363
364         if (iv) {
365                 memset(cctx->iv, 0, 8);
366                 memcpy(cctx->iv, iv, 8);
367         }
368
369         if (key) {
370                 memcpy(cctx->key, key, GOSTKEYLEN*2);
371         }
372         return 1;
373 }
374
375 static int kuznyechik_wrap_do(EVP_CIPHER_CTX *ctx, unsigned char *out,
376         const unsigned char *in, size_t inl)
377 {
378         GOST_WRAP_CTX *cctx = EVP_CIPHER_CTX_get_cipher_data(ctx);
379         int enc = EVP_CIPHER_CTX_encrypting(ctx) ? 1 : 0;
380
381         if (out == NULL)
382                 return GOSTKEYLEN;
383
384         if (inl <= KUZNYECHIK_WRAPPED_KEY_LEN) {
385                 if (cctx->wrap_count + inl > KUZNYECHIK_WRAPPED_KEY_LEN)
386                         return -1;
387
388                 if (cctx->wrap_count + inl <= KUZNYECHIK_WRAPPED_KEY_LEN)
389                 {
390                         memcpy(cctx->wrapped+cctx->wrap_count, in, inl);
391                         cctx->wrap_count += inl;
392                 }
393         }
394
395         if (cctx->wrap_count < KUZNYECHIK_WRAPPED_KEY_LEN)
396                 return 0;
397
398         if (enc) {
399 #if 0
400                 return gost_kexp15(cctx->key, 32, NID_magma_ctr, in, NID_magma_mac,
401                         cctx->key, /* FIXME mac_key, */ cctx->iv, 4, out, &outl);
402 #endif
403                 return -1;
404         } else {
405                 return gost_kimp15(cctx->wrapped, cctx->wrap_count, NID_kuznyechik_ctr,
406                 cctx->key+GOSTKEYLEN, NID_kuznyechik_mac, cctx->key, cctx->iv, 8, out) > 0 ? GOSTKEYLEN : 0;
407         }
408 }
409
410 static int wrap_ctrl (EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr)
411 {
412         switch(type)
413         {
414                 case EVP_CTRL_INIT:
415                         EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW);
416                         return 1;
417                 default:
418                         return -2;
419         }
420 }
421
422 static GOST_cipher wrap_template_cipher = {
423     .key_len = GOSTKEYLEN * 2,
424     .flags = GOST_WRAP_FLAGS,
425     .ctx_size = sizeof(GOST_WRAP_CTX),
426     .ctrl = wrap_ctrl,
427 };
428
429 GOST_cipher magma_kexp15_cipher = {
430     .template = &wrap_template_cipher,
431     .nid = NID_magma_kexp15,
432     .block_size = 8,
433     .iv_len = 4,
434     .init = magma_wrap_init,
435     .do_cipher = magma_wrap_do,
436 };
437
438 GOST_cipher kuznyechik_kexp15_cipher = {
439     .template = &wrap_template_cipher,
440     .nid = NID_kuznyechik_kexp15,
441     .block_size = 16,
442     .iv_len = 8,
443     .init = kuznyechik_wrap_init,
444     .do_cipher = kuznyechik_wrap_do,
445 };
446 /* vim: set expandtab cinoptions=\:0,l1,t0,g0,(0 sw=4 : */