]> www.wagner.pp.ru Git - openssl-gost/engine.git/blob - gost_keyexpimp.c
Provide cmake test if alignment requirement is strict
[openssl-gost/engine.git] / gost_keyexpimp.c
1 #ifdef _WIN32
2 #include <winsock.h>
3 #else
4 #include <arpa/inet.h>
5 #endif
6 #include <string.h>
7 #include <openssl/evp.h>
8 #include <openssl/hmac.h>
9 #include <openssl/buffer.h>
10
11 #include "gost_lcl.h"
12 #include "e_gost_err.h"
13
14 int omac_imit_ctrl(EVP_MD_CTX *ctx, int type, int arg, void *ptr);
15 /*
16  * Function expects that out is a preallocated buffer of length
17  * defined as sum of shared_len and mac length defined by mac_nid
18  * */
19 int gost_kexp15(const unsigned char *shared_key, const int shared_len,
20                 int cipher_nid, const unsigned char *cipher_key,
21                 int mac_nid, unsigned char *mac_key,
22                 const unsigned char *iv, const size_t ivlen,
23                 unsigned char *out, int *out_len)
24 {
25     unsigned char iv_full[16], mac_buf[16];
26     unsigned int mac_len;
27
28     EVP_CIPHER_CTX *ciph = NULL;
29     EVP_MD_CTX *mac = NULL;
30
31     int ret = 0;
32     int len;
33
34     mac_len = (cipher_nid == NID_magma_ctr) ? 8 :
35         (cipher_nid == NID_grasshopper_ctr) ? 16 : 0;
36
37     if (mac_len == 0) {
38         GOSTerr(GOST_F_GOST_KEXP15, GOST_R_INVALID_CIPHER);
39         goto err;
40     }
41
42     /* we expect IV of half length */
43     memset(iv_full, 0, 16);
44     memcpy(iv_full, iv, ivlen);
45
46     mac = EVP_MD_CTX_new();
47     if (mac == NULL) {
48         GOSTerr(GOST_F_GOST_KEXP15, ERR_R_MALLOC_FAILURE);
49         goto err;
50     }
51
52     if (EVP_DigestInit_ex(mac, EVP_get_digestbynid(mac_nid), NULL) <= 0
53         || omac_imit_ctrl(mac, EVP_MD_CTRL_SET_KEY, 32, mac_key) <= 0
54         || omac_imit_ctrl(mac, EVP_MD_CTRL_XOF_LEN, mac_len, NULL) <= 0
55         || EVP_DigestUpdate(mac, iv, ivlen) <= 0
56         || EVP_DigestUpdate(mac, shared_key, shared_len) <= 0
57         /* As we set MAC length directly, we should not allow overwriting it */
58         || EVP_DigestFinalXOF(mac, mac_buf, mac_len) <= 0) {
59         GOSTerr(GOST_F_GOST_KEXP15, ERR_R_INTERNAL_ERROR);
60         goto err;
61     }
62
63     ciph = EVP_CIPHER_CTX_new();
64     if (ciph == NULL) {
65         GOSTerr(GOST_F_GOST_KEXP15, ERR_R_MALLOC_FAILURE);
66         goto err;
67     }
68
69     if (EVP_CipherInit_ex
70         (ciph, EVP_get_cipherbynid(cipher_nid), NULL, NULL, NULL, 1) <= 0
71         || EVP_CipherInit_ex(ciph, NULL, NULL, cipher_key, iv_full, 1) <= 0
72         || EVP_CipherUpdate(ciph, out, &len, shared_key, shared_len) <= 0
73         || EVP_CipherUpdate(ciph, out + shared_len, &len, mac_buf, mac_len) <= 0
74         || EVP_CipherFinal_ex(ciph, out + shared_len + len, out_len) <= 0) {
75         GOSTerr(GOST_F_GOST_KEXP15, ERR_R_INTERNAL_ERROR);
76         goto err;
77     }
78
79     *out_len = shared_len + mac_len;
80
81     ret = 1;
82
83  err:
84     OPENSSL_cleanse(mac_buf, mac_len);
85     EVP_MD_CTX_free(mac);
86     EVP_CIPHER_CTX_free(ciph);
87
88     return ret;
89 }
90
91 /*
92  * Function expects that shared_key is a preallocated buffer
93  * with length defined as expkeylen + mac_len defined by mac_nid
94  * */
95 int gost_kimp15(const unsigned char *expkey, const size_t expkeylen,
96                 int cipher_nid, const unsigned char *cipher_key,
97                 int mac_nid, unsigned char *mac_key,
98                 const unsigned char *iv, const size_t ivlen,
99                 unsigned char *shared_key)
100 {
101     unsigned char iv_full[16], out[48], mac_buf[16];
102     unsigned int mac_len;
103     const size_t shared_len = 32;
104
105     EVP_CIPHER_CTX *ciph = NULL;
106     EVP_MD_CTX *mac = NULL;
107
108     int ret = 0;
109     int len;
110
111     mac_len = (cipher_nid == NID_magma_ctr) ? 8 :
112         (cipher_nid == NID_grasshopper_ctr) ? 16 : 0;
113
114     if (mac_len == 0) {
115         GOSTerr(GOST_F_GOST_KIMP15, GOST_R_INVALID_CIPHER);
116         goto err;
117     }
118
119     /* we expect IV of half length */
120     memset(iv_full, 0, 16);
121     memcpy(iv_full, iv, ivlen);
122
123     ciph = EVP_CIPHER_CTX_new();
124     if (ciph == NULL) {
125         GOSTerr(GOST_F_GOST_KIMP15, ERR_R_MALLOC_FAILURE);
126         goto err;
127     }
128
129     if (EVP_CipherInit_ex
130         (ciph, EVP_get_cipherbynid(cipher_nid), NULL, NULL, NULL, 0) <= 0
131         || EVP_CipherInit_ex(ciph, NULL, NULL, cipher_key, iv_full, 0) <= 0
132         || EVP_CipherUpdate(ciph, out, &len, expkey, expkeylen) <= 0
133         || EVP_CipherFinal_ex(ciph, out + len, &len) <= 0) {
134         GOSTerr(GOST_F_GOST_KIMP15, ERR_R_INTERNAL_ERROR);
135         goto err;
136     }
137     /*Now we have shared key and mac in out[] */
138
139     mac = EVP_MD_CTX_new();
140     if (mac == NULL) {
141         GOSTerr(GOST_F_GOST_KIMP15, ERR_R_MALLOC_FAILURE);
142         goto err;
143     }
144
145     if (EVP_DigestInit_ex(mac, EVP_get_digestbynid(mac_nid), NULL) <= 0
146         || omac_imit_ctrl(mac, EVP_MD_CTRL_SET_KEY, 32, mac_key) <= 0
147         || omac_imit_ctrl(mac, EVP_MD_CTRL_XOF_LEN, mac_len, NULL) <= 0
148         || EVP_DigestUpdate(mac, iv, ivlen) <= 0
149         || EVP_DigestUpdate(mac, out, shared_len) <= 0
150         /* As we set MAC length directly, we should not allow overwriting it */
151         || EVP_DigestFinalXOF(mac, mac_buf, mac_len) <= 0) {
152         GOSTerr(GOST_F_GOST_KIMP15, ERR_R_INTERNAL_ERROR);
153         goto err;
154     }
155
156     if (CRYPTO_memcmp(mac_buf, out + shared_len, mac_len) != 0) {
157         GOSTerr(GOST_F_GOST_KIMP15, GOST_R_BAD_MAC);
158         goto err;
159     }
160
161     memcpy(shared_key, out, shared_len);
162     ret = 1;
163
164  err:
165     OPENSSL_cleanse(out, sizeof(out));
166     EVP_MD_CTX_free(mac);
167     EVP_CIPHER_CTX_free(ciph);
168     return ret;
169 }
170
171 int gost_kdftree2012_256(unsigned char *keyout, size_t keyout_len,
172                          const unsigned char *key, size_t keylen,
173                          const unsigned char *label, size_t label_len,
174                          const unsigned char *seed, size_t seed_len,
175                          const size_t representation)
176 {
177     int iters, i = 0;
178     unsigned char zero = 0;
179     unsigned char *ptr = keyout;
180     HMAC_CTX *ctx;
181     unsigned char *len_ptr = NULL;
182     uint32_t len_repr = htonl(keyout_len * 8);
183     size_t len_repr_len = 4;
184
185     ctx = HMAC_CTX_new();
186     if (ctx == NULL) {
187         GOSTerr(GOST_F_GOST_KDFTREE2012_256, ERR_R_MALLOC_FAILURE);
188         return 0;
189     }
190
191     if ((keyout_len == 0) || (keyout_len % 32 != 0)) {
192         GOSTerr(GOST_F_GOST_KDFTREE2012_256, ERR_R_INTERNAL_ERROR);
193         return 0;
194     }
195     iters = keyout_len / 32;
196
197     len_ptr = (unsigned char *)&len_repr;
198     while (*len_ptr == 0) {
199         len_ptr++;
200         len_repr_len--;
201     }
202
203     for (i = 1; i <= iters; i++) {
204         uint32_t iter_net = htonl(i);
205         unsigned char *rep_ptr =
206             ((unsigned char *)&iter_net) + (4 - representation);
207
208         if (HMAC_Init_ex(ctx, key, keylen,
209                          EVP_get_digestbynid(NID_id_GostR3411_2012_256),
210                          NULL) <= 0
211             || HMAC_Update(ctx, rep_ptr, representation) <= 0
212             || HMAC_Update(ctx, label, label_len) <= 0
213             || HMAC_Update(ctx, &zero, 1) <= 0
214             || HMAC_Update(ctx, seed, seed_len) <= 0
215             || HMAC_Update(ctx, len_ptr, len_repr_len) <= 0
216             || HMAC_Final(ctx, ptr, NULL) <= 0) {
217             GOSTerr(GOST_F_GOST_KDFTREE2012_256, ERR_R_INTERNAL_ERROR);
218             HMAC_CTX_free(ctx);
219             return 0;
220         }
221
222         HMAC_CTX_reset(ctx);
223         ptr += 32;
224     }
225
226     HMAC_CTX_free(ctx);
227
228     return 1;
229 }
230
231 int gost_tlstree(int cipher_nid, const unsigned char *in, unsigned char *out,
232                  const unsigned char *tlsseq)
233 {
234 #ifndef L_ENDIAN
235     uint64_t gh_c1 = 0xFFFFFFFF00000000, gh_c2 = 0xFFFFFFFFFFF80000,
236         gh_c3 = 0xFFFFFFFFFFFFFFC0;
237     uint64_t mg_c1 = 0xFFFFFFC000000000, mg_c2 = 0xFFFFFFFFFE000000,
238         mg_c3 = 0xFFFFFFFFFFFFF000;
239 #else
240     uint64_t gh_c1 = 0x00000000FFFFFFFF, gh_c2 = 0x0000F8FFFFFFFFFF,
241         gh_c3 = 0xC0FFFFFFFFFFFFFF;
242     uint64_t mg_c1 = 0x00000000C0FFFFFF, mg_c2 = 0x000000FEFFFFFFFF,
243         mg_c3 = 0x00F0FFFFFFFFFFFF;
244 #endif
245     uint64_t c1, c2, c3;
246     uint64_t seed1, seed2, seed3;
247     uint64_t seq;
248     unsigned char ko1[32], ko2[32];
249
250     switch (cipher_nid) {
251     case NID_magma_cbc:
252         c1 = mg_c1;
253         c2 = mg_c2;
254         c3 = mg_c3;
255         break;
256     case NID_grasshopper_cbc:
257         c1 = gh_c1;
258         c2 = gh_c2;
259         c3 = gh_c3;
260         break;
261     default:
262         return 0;
263     }
264 #ifndef L_ENDIAN
265     BUF_reverse(&seq, tlsseq, 8);
266 #else
267     memcpy(&seq, tlsseq, 8);
268 #endif
269     seed1 = seq & c1;
270     seed2 = seq & c2;
271     seed3 = seq & c3;
272
273     if (gost_kdftree2012_256(ko1, 32, in, 32, (const unsigned char *)"level1", 6,
274                          (const unsigned char *)&seed1, 8, 1) <= 0
275                           || gost_kdftree2012_256(ko2, 32, ko1, 32, (const unsigned char *)"level2", 6,
276                          (const unsigned char *)&seed2, 8, 1) <= 0
277         || gost_kdftree2012_256(out, 32, ko2, 32, (const unsigned char *)"level3", 6,
278                          (const unsigned char *)&seed3, 8, 1) <= 0)
279                         return 0;
280
281     return 1;
282 }