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