]> www.wagner.pp.ru Git - openssl-gost/engine.git/blob - gost_crypt.c
Missing free
[openssl-gost/engine.git] / gost_crypt.c
1 /**********************************************************************
2  *                          gost_crypt.c                              *
3  *             Copyright (c) 2005-2006 Cryptocom LTD                  *
4  *         This file is distributed under the same license as OpenSSL *
5  *                                                                    *
6  *       OpenSSL interface to GOST 28147-89 cipher functions          *
7  *          Requires OpenSSL 0.9.9 for compilation                    *
8  **********************************************************************/
9 #include <string.h>
10 #include "gost89.h"
11 #include <openssl/err.h>
12 #include <openssl/rand.h>
13 #include "e_gost_err.h"
14 #include "gost_lcl.h"
15
16 #if !defined(CCGOST_DEBUG) && !defined(DEBUG)
17 # ifndef NDEBUG
18 #  define NDEBUG
19 # endif
20 #endif
21 #include <assert.h>
22
23 static int gost_cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
24                             const unsigned char *iv, int enc);
25 static int gost_cipher_init_cbc(EVP_CIPHER_CTX *ctx, const unsigned char *key,
26                                 const unsigned char *iv, int enc);
27 static int gost_cipher_init_cpa(EVP_CIPHER_CTX *ctx, const unsigned char *key,
28                                 const unsigned char *iv, int enc);
29 static int gost_cipher_init_cp_12(EVP_CIPHER_CTX *ctx,
30                                   const unsigned char *key,
31                                   const unsigned char *iv, int enc);
32 /* Handles block of data in CFB mode */
33 static int gost_cipher_do_cfb(EVP_CIPHER_CTX *ctx, unsigned char *out,
34                               const unsigned char *in, size_t inl);
35 /* Handles block of data in CBC mode */
36 static int gost_cipher_do_cbc(EVP_CIPHER_CTX *ctx, unsigned char *out,
37                               const unsigned char *in, size_t inl);
38 /* Handles block of data in CNT mode */
39 static int gost_cipher_do_cnt(EVP_CIPHER_CTX *ctx, unsigned char *out,
40                               const unsigned char *in, size_t inl);
41 /* Cleanup function */
42 static int gost_cipher_cleanup(EVP_CIPHER_CTX *);
43 /* set/get cipher parameters */
44 static int gost89_set_asn1_parameters(EVP_CIPHER_CTX *ctx, ASN1_TYPE *params);
45 static int gost89_get_asn1_parameters(EVP_CIPHER_CTX *ctx, ASN1_TYPE *params);
46 /* Control function */
47 static int gost_cipher_ctl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr);
48
49 static int magma_cipher_init_cbc(EVP_CIPHER_CTX *ctx, const unsigned char *key,
50                                 const unsigned char *iv, int enc);
51 /* Handles block of data in CBC mode */
52 static int magma_cipher_do_cbc(EVP_CIPHER_CTX *ctx, unsigned char *out,
53                               const unsigned char *in, size_t inl);
54 static EVP_CIPHER *_hidden_Gost28147_89_cipher = NULL;
55 const EVP_CIPHER *cipher_gost(void)
56 {
57     if (_hidden_Gost28147_89_cipher == NULL
58         && ((_hidden_Gost28147_89_cipher =
59              EVP_CIPHER_meth_new(NID_id_Gost28147_89, 1 /* block_size */ ,
60                                  32 /* key_size */ )) == NULL
61             || !EVP_CIPHER_meth_set_iv_length(_hidden_Gost28147_89_cipher, 8)
62             || !EVP_CIPHER_meth_set_flags(_hidden_Gost28147_89_cipher,
63                                           EVP_CIPH_CFB_MODE |
64                                           EVP_CIPH_NO_PADDING |
65                                           EVP_CIPH_CUSTOM_IV |
66                                           EVP_CIPH_RAND_KEY |
67                                           EVP_CIPH_ALWAYS_CALL_INIT)
68             || !EVP_CIPHER_meth_set_init(_hidden_Gost28147_89_cipher,
69                                          gost_cipher_init)
70             || !EVP_CIPHER_meth_set_do_cipher(_hidden_Gost28147_89_cipher,
71                                               gost_cipher_do_cfb)
72             || !EVP_CIPHER_meth_set_cleanup(_hidden_Gost28147_89_cipher,
73                                             gost_cipher_cleanup)
74             || !EVP_CIPHER_meth_set_impl_ctx_size(_hidden_Gost28147_89_cipher,
75                                                   sizeof(struct
76                                                          ossl_gost_cipher_ctx))
77             ||
78             !EVP_CIPHER_meth_set_set_asn1_params(_hidden_Gost28147_89_cipher,
79                                                  gost89_set_asn1_parameters)
80             ||
81             !EVP_CIPHER_meth_set_get_asn1_params(_hidden_Gost28147_89_cipher,
82                                                  gost89_get_asn1_parameters)
83             || !EVP_CIPHER_meth_set_ctrl(_hidden_Gost28147_89_cipher,
84                                          gost_cipher_ctl))) {
85         EVP_CIPHER_meth_free(_hidden_Gost28147_89_cipher);
86         _hidden_Gost28147_89_cipher = NULL;
87     }
88     return _hidden_Gost28147_89_cipher;
89 }
90
91 static EVP_CIPHER *_hidden_Gost28147_89_cbc = NULL;
92 const EVP_CIPHER *cipher_gost_cbc(void)
93 {
94     if (_hidden_Gost28147_89_cbc == NULL
95         && ((_hidden_Gost28147_89_cbc =
96              EVP_CIPHER_meth_new(NID_gost89_cbc, 8 /* block_size */ ,
97                                  32 /* key_size */ )) == NULL
98             || !EVP_CIPHER_meth_set_iv_length(_hidden_Gost28147_89_cbc, 8)
99             || !EVP_CIPHER_meth_set_flags(_hidden_Gost28147_89_cbc,
100                                           EVP_CIPH_CBC_MODE |
101                                           EVP_CIPH_CUSTOM_IV |
102                                           EVP_CIPH_RAND_KEY |
103                                           EVP_CIPH_ALWAYS_CALL_INIT)
104             || !EVP_CIPHER_meth_set_init(_hidden_Gost28147_89_cbc,
105                                          gost_cipher_init_cbc)
106             || !EVP_CIPHER_meth_set_do_cipher(_hidden_Gost28147_89_cbc,
107                                               gost_cipher_do_cbc)
108             || !EVP_CIPHER_meth_set_cleanup(_hidden_Gost28147_89_cbc,
109                                             gost_cipher_cleanup)
110             || !EVP_CIPHER_meth_set_impl_ctx_size(_hidden_Gost28147_89_cbc,
111                                                   sizeof(struct
112                                                          ossl_gost_cipher_ctx))
113             || !EVP_CIPHER_meth_set_set_asn1_params(_hidden_Gost28147_89_cbc,
114                                                     gost89_set_asn1_parameters)
115             || !EVP_CIPHER_meth_set_get_asn1_params(_hidden_Gost28147_89_cbc,
116                                                     gost89_get_asn1_parameters)
117             || !EVP_CIPHER_meth_set_ctrl(_hidden_Gost28147_89_cbc,
118                                          gost_cipher_ctl))) {
119         EVP_CIPHER_meth_free(_hidden_Gost28147_89_cbc);
120         _hidden_Gost28147_89_cbc = NULL;
121     }
122     return _hidden_Gost28147_89_cbc;
123 }
124
125 static EVP_CIPHER *_hidden_gost89_cnt = NULL;
126 const EVP_CIPHER *cipher_gost_cpacnt(void)
127 {
128     if (_hidden_gost89_cnt == NULL
129         && ((_hidden_gost89_cnt =
130              EVP_CIPHER_meth_new(NID_gost89_cnt, 1 /* block_size */ ,
131                                  32 /* key_size */ )) == NULL
132             || !EVP_CIPHER_meth_set_iv_length(_hidden_gost89_cnt, 8)
133             || !EVP_CIPHER_meth_set_flags(_hidden_gost89_cnt,
134                                           EVP_CIPH_OFB_MODE |
135                                           EVP_CIPH_NO_PADDING |
136                                           EVP_CIPH_CUSTOM_IV |
137                                           EVP_CIPH_RAND_KEY |
138                                           EVP_CIPH_ALWAYS_CALL_INIT)
139             || !EVP_CIPHER_meth_set_init(_hidden_gost89_cnt,
140                                          gost_cipher_init_cpa)
141             || !EVP_CIPHER_meth_set_do_cipher(_hidden_gost89_cnt,
142                                               gost_cipher_do_cnt)
143             || !EVP_CIPHER_meth_set_cleanup(_hidden_gost89_cnt,
144                                             gost_cipher_cleanup)
145             || !EVP_CIPHER_meth_set_impl_ctx_size(_hidden_gost89_cnt,
146                                                   sizeof(struct
147                                                          ossl_gost_cipher_ctx))
148             || !EVP_CIPHER_meth_set_set_asn1_params(_hidden_gost89_cnt,
149                                                     gost89_set_asn1_parameters)
150             || !EVP_CIPHER_meth_set_get_asn1_params(_hidden_gost89_cnt,
151                                                     gost89_get_asn1_parameters)
152             || !EVP_CIPHER_meth_set_ctrl(_hidden_gost89_cnt,
153                                          gost_cipher_ctl))) {
154         EVP_CIPHER_meth_free(_hidden_gost89_cnt);
155         _hidden_gost89_cnt = NULL;
156     }
157     return _hidden_gost89_cnt;
158 }
159
160 static EVP_CIPHER *_hidden_gost89_cnt_12 = NULL;
161 const EVP_CIPHER *cipher_gost_cpcnt_12(void)
162 {
163     if (_hidden_gost89_cnt_12 == NULL
164         && ((_hidden_gost89_cnt_12 =
165              EVP_CIPHER_meth_new(NID_gost89_cnt_12, 1 /* block_size */ ,
166                                  32 /* key_size */ )) == NULL
167             || !EVP_CIPHER_meth_set_iv_length(_hidden_gost89_cnt_12, 8)
168             || !EVP_CIPHER_meth_set_flags(_hidden_gost89_cnt_12,
169                                           EVP_CIPH_OFB_MODE |
170                                           EVP_CIPH_NO_PADDING |
171                                           EVP_CIPH_CUSTOM_IV |
172                                           EVP_CIPH_RAND_KEY |
173                                           EVP_CIPH_ALWAYS_CALL_INIT)
174             || !EVP_CIPHER_meth_set_init(_hidden_gost89_cnt_12,
175                                          gost_cipher_init_cp_12)
176             || !EVP_CIPHER_meth_set_do_cipher(_hidden_gost89_cnt_12,
177                                               gost_cipher_do_cnt)
178             || !EVP_CIPHER_meth_set_cleanup(_hidden_gost89_cnt_12,
179                                             gost_cipher_cleanup)
180             || !EVP_CIPHER_meth_set_impl_ctx_size(_hidden_gost89_cnt_12,
181                                                   sizeof(struct
182                                                          ossl_gost_cipher_ctx))
183             || !EVP_CIPHER_meth_set_set_asn1_params(_hidden_gost89_cnt_12,
184                                                     gost89_set_asn1_parameters)
185             || !EVP_CIPHER_meth_set_get_asn1_params(_hidden_gost89_cnt_12,
186                                                     gost89_get_asn1_parameters)
187             || !EVP_CIPHER_meth_set_ctrl(_hidden_gost89_cnt_12,
188                                          gost_cipher_ctl))) {
189         EVP_CIPHER_meth_free(_hidden_gost89_cnt_12);
190         _hidden_gost89_cnt_12 = NULL;
191     }
192     return _hidden_gost89_cnt_12;
193 }
194
195 static EVP_CIPHER *_hidden_magma_cbc = NULL;
196 const EVP_CIPHER *cipher_magma_cbc(void)
197 {
198     if (_hidden_magma_cbc == NULL
199         && ((_hidden_magma_cbc =
200              EVP_CIPHER_meth_new(NID_magma_cbc, 8 /* block_size */ ,
201                                  32 /* key_size */ )) == NULL
202             || !EVP_CIPHER_meth_set_iv_length(_hidden_magma_cbc, 8)
203             || !EVP_CIPHER_meth_set_flags(_hidden_magma_cbc,
204                                           EVP_CIPH_CBC_MODE |
205                                           EVP_CIPH_CUSTOM_IV |
206                                           EVP_CIPH_RAND_KEY |
207                                           EVP_CIPH_ALWAYS_CALL_INIT)
208             || !EVP_CIPHER_meth_set_init(_hidden_magma_cbc,
209                                          magma_cipher_init_cbc)
210             || !EVP_CIPHER_meth_set_do_cipher(_hidden_magma_cbc,
211                                               magma_cipher_do_cbc)
212             || !EVP_CIPHER_meth_set_cleanup(_hidden_magma_cbc,
213                                             gost_cipher_cleanup)
214             || !EVP_CIPHER_meth_set_impl_ctx_size(_hidden_magma_cbc,
215                                                   sizeof(struct
216                                                          ossl_gost_cipher_ctx))
217             || !EVP_CIPHER_meth_set_set_asn1_params(_hidden_magma_cbc,
218                                                     gost89_set_asn1_parameters)
219             || !EVP_CIPHER_meth_set_get_asn1_params(_hidden_magma_cbc,
220                                                     gost89_get_asn1_parameters)
221             || !EVP_CIPHER_meth_set_ctrl(_hidden_magma_cbc,
222                                          gost_cipher_ctl))) {
223         EVP_CIPHER_meth_free(_hidden_magma_cbc);
224         _hidden_magma_cbc = NULL;
225     }
226     return _hidden_magma_cbc;
227 }
228
229 void cipher_gost_destroy(void)
230 {
231     EVP_CIPHER_meth_free(_hidden_Gost28147_89_cipher);
232     _hidden_Gost28147_89_cipher = NULL;
233     EVP_CIPHER_meth_free(_hidden_gost89_cnt);
234     _hidden_gost89_cnt = NULL;
235     EVP_CIPHER_meth_free(_hidden_Gost28147_89_cbc);
236     _hidden_Gost28147_89_cbc = NULL;
237     EVP_CIPHER_meth_free(_hidden_gost89_cnt_12);
238     _hidden_gost89_cnt_12 = NULL;
239     EVP_CIPHER_meth_free(_hidden_magma_cbc);
240     _hidden_magma_cbc = NULL;
241 }
242
243 /* Implementation of GOST 28147-89 in MAC (imitovstavka) mode */
244 /* Init functions which set specific parameters */
245 static int gost_imit_init_cpa(EVP_MD_CTX *ctx);
246 static int gost_imit_init_cp_12(EVP_MD_CTX *ctx);
247 /* process block of data */
248 static int gost_imit_update(EVP_MD_CTX *ctx, const void *data, size_t count);
249 /* Return computed value */
250 static int gost_imit_final(EVP_MD_CTX *ctx, unsigned char *md);
251 /* Copies context */
252 static int gost_imit_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from);
253 static int gost_imit_cleanup(EVP_MD_CTX *ctx);
254 /* Control function, knows how to set MAC key.*/
255 static int gost_imit_ctrl(EVP_MD_CTX *ctx, int type, int arg, void *ptr);
256
257 static EVP_MD *_hidden_Gost28147_89_MAC_md = NULL;
258 static EVP_MD *_hidden_Gost28147_89_12_MAC_md = NULL;
259
260 EVP_MD *imit_gost_cpa(void)
261 {
262     if (_hidden_Gost28147_89_MAC_md == NULL) {
263         EVP_MD *md;
264
265         if ((md = EVP_MD_meth_new(NID_id_Gost28147_89_MAC, NID_undef)) == NULL
266             || !EVP_MD_meth_set_result_size(md, 4)
267             || !EVP_MD_meth_set_input_blocksize(md, 8)
268             || !EVP_MD_meth_set_app_datasize(md,
269                                              sizeof(struct
270                                                     ossl_gost_imit_ctx))
271             || !EVP_MD_meth_set_flags(md, 0)
272             || !EVP_MD_meth_set_init(md, gost_imit_init_cpa)
273             || !EVP_MD_meth_set_update(md, gost_imit_update)
274             || !EVP_MD_meth_set_final(md, gost_imit_final)
275             || !EVP_MD_meth_set_copy(md, gost_imit_copy)
276             || !EVP_MD_meth_set_cleanup(md, gost_imit_cleanup)
277             || !EVP_MD_meth_set_ctrl(md, gost_imit_ctrl)) {
278             EVP_MD_meth_free(md);
279             md = NULL;
280         }
281         _hidden_Gost28147_89_MAC_md = md;
282     }
283     return _hidden_Gost28147_89_MAC_md;
284 }
285
286 void imit_gost_cpa_destroy(void)
287 {
288     EVP_MD_meth_free(_hidden_Gost28147_89_MAC_md);
289     _hidden_Gost28147_89_MAC_md = NULL;
290 }
291
292 EVP_MD *imit_gost_cp_12(void)
293 {
294     if (_hidden_Gost28147_89_12_MAC_md == NULL) {
295         EVP_MD *md;
296
297         if ((md = EVP_MD_meth_new(NID_gost_mac_12, NID_undef)) == NULL
298             || !EVP_MD_meth_set_result_size(md, 4)
299             || !EVP_MD_meth_set_input_blocksize(md, 8)
300             || !EVP_MD_meth_set_app_datasize(md,
301                                              sizeof(struct
302                                                     ossl_gost_imit_ctx))
303             || !EVP_MD_meth_set_flags(md, 0)
304             || !EVP_MD_meth_set_init(md, gost_imit_init_cp_12)
305             || !EVP_MD_meth_set_update(md, gost_imit_update)
306             || !EVP_MD_meth_set_final(md, gost_imit_final)
307             || !EVP_MD_meth_set_copy(md, gost_imit_copy)
308             || !EVP_MD_meth_set_cleanup(md, gost_imit_cleanup)
309             || !EVP_MD_meth_set_ctrl(md, gost_imit_ctrl)) {
310             EVP_MD_meth_free(md);
311             md = NULL;
312         }
313         _hidden_Gost28147_89_12_MAC_md = md;
314     }
315     return _hidden_Gost28147_89_12_MAC_md;
316 }
317
318 void imit_gost_cp_12_destroy(void)
319 {
320     EVP_MD_meth_free(_hidden_Gost28147_89_12_MAC_md);
321     _hidden_Gost28147_89_12_MAC_md = NULL;
322 }
323
324 /*
325  * Correspondence between gost parameter OIDs and substitution blocks
326  * NID field is filed by register_gost_NID function in engine.c
327  * upon engine initialization
328  */
329
330 struct gost_cipher_info gost_cipher_list[] = {
331     /*- NID *//*
332      * Subst block
333      *//*
334      * Key meshing
335      */
336     /*
337      * {NID_id_GostR3411_94_CryptoProParamSet,&GostR3411_94_CryptoProParamSet,0},
338      */
339     {NID_id_Gost28147_89_CryptoPro_A_ParamSet, &Gost28147_CryptoProParamSetA,
340      1},
341     {NID_id_Gost28147_89_CryptoPro_B_ParamSet, &Gost28147_CryptoProParamSetB,
342      1},
343     {NID_id_Gost28147_89_CryptoPro_C_ParamSet, &Gost28147_CryptoProParamSetC,
344      1},
345     {NID_id_Gost28147_89_CryptoPro_D_ParamSet, &Gost28147_CryptoProParamSetD,
346      1},
347     {NID_id_tc26_gost_28147_param_Z, &Gost28147_TC26ParamSetZ, 1},
348     {NID_id_Gost28147_89_TestParamSet, &Gost28147_TestParamSet, 1},
349     {NID_undef, NULL, 0}
350 };
351
352 /*
353  * get encryption parameters from crypto network settings FIXME For now we
354  * use environment var CRYPT_PARAMS as place to store these settings.
355  * Actually, it is better to use engine control command, read from
356  * configuration file to set them
357  */
358 const struct gost_cipher_info *get_encryption_params(ASN1_OBJECT *obj)
359 {
360     int nid;
361     struct gost_cipher_info *param;
362     if (!obj) {
363         const char *params = get_gost_engine_param(GOST_PARAM_CRYPT_PARAMS);
364         if (!params || !strlen(params)) {
365             int i;
366             for (i = 0; gost_cipher_list[i].nid != NID_undef; i++)
367                 if (gost_cipher_list[i].nid == NID_id_tc26_gost_28147_param_Z)
368                     return &gost_cipher_list[i];
369             return &gost_cipher_list[0];
370         }
371
372         nid = OBJ_txt2nid(params);
373         if (nid == NID_undef) {
374             GOSTerr(GOST_F_GET_ENCRYPTION_PARAMS,
375                     GOST_R_INVALID_CIPHER_PARAM_OID);
376             return NULL;
377         }
378     } else {
379         nid = OBJ_obj2nid(obj);
380     }
381     for (param = gost_cipher_list; param->sblock != NULL && param->nid != nid;
382          param++) ;
383     if (!param->sblock) {
384         GOSTerr(GOST_F_GET_ENCRYPTION_PARAMS, GOST_R_INVALID_CIPHER_PARAMS);
385         return NULL;
386     }
387     return param;
388 }
389
390 /* Sets cipher param from paramset NID. */
391 static int gost_cipher_set_param(struct ossl_gost_cipher_ctx *c, int nid)
392 {
393     const struct gost_cipher_info *param;
394     param =
395         get_encryption_params((nid == NID_undef ? NULL : OBJ_nid2obj(nid)));
396     if (!param)
397         return 0;
398
399     c->paramNID = param->nid;
400     c->key_meshing = param->key_meshing;
401     c->count = 0;
402     gost_init(&(c->cctx), param->sblock);
403     return 1;
404 }
405
406 /* Initializes EVP_CIPHER_CTX by paramset NID */
407 static int gost_cipher_init_param(EVP_CIPHER_CTX *ctx,
408                                   const unsigned char *key,
409                                   const unsigned char *iv, int enc,
410                                   int paramNID, int mode)
411 {
412     struct ossl_gost_cipher_ctx *c = EVP_CIPHER_CTX_get_cipher_data(ctx);
413     if (EVP_CIPHER_CTX_get_app_data(ctx) == NULL) {
414         if (!gost_cipher_set_param(c, paramNID))
415             return 0;
416         EVP_CIPHER_CTX_set_app_data(ctx, EVP_CIPHER_CTX_get_cipher_data(ctx));
417     }
418     if (key)
419         gost_key(&(c->cctx), key);
420     if (iv) {
421         memcpy((unsigned char *)EVP_CIPHER_CTX_original_iv(ctx), iv,
422                EVP_CIPHER_CTX_iv_length(ctx));
423     }
424     memcpy(EVP_CIPHER_CTX_iv_noconst(ctx),
425            EVP_CIPHER_CTX_original_iv(ctx), EVP_CIPHER_CTX_iv_length(ctx));
426     return 1;
427 }
428
429 static int magma_cipher_init_param(EVP_CIPHER_CTX *ctx,
430                                   const unsigned char *key,
431                                   const unsigned char *iv, int enc,
432                                   int paramNID, int mode)
433 {
434     struct ossl_gost_cipher_ctx *c = EVP_CIPHER_CTX_get_cipher_data(ctx);
435     if (EVP_CIPHER_CTX_get_app_data(ctx) == NULL) {
436         if (!gost_cipher_set_param(c, NID_id_tc26_gost_28147_param_Z))
437             return 0;
438         EVP_CIPHER_CTX_set_app_data(ctx, EVP_CIPHER_CTX_get_cipher_data(ctx));
439     }
440     if (key)
441         magma_key(&(c->cctx), key);
442     if (iv) {
443         memcpy((unsigned char *)EVP_CIPHER_CTX_original_iv(ctx), iv,
444                EVP_CIPHER_CTX_iv_length(ctx));
445     }
446     memcpy(EVP_CIPHER_CTX_iv_noconst(ctx),
447            EVP_CIPHER_CTX_original_iv(ctx), EVP_CIPHER_CTX_iv_length(ctx));
448     return 1;
449 }
450
451 static int gost_cipher_init_cnt(EVP_CIPHER_CTX *ctx,
452                                 const unsigned char *key,
453                                 const unsigned char *iv,
454                                 gost_subst_block * block)
455 {
456     struct ossl_gost_cipher_ctx *c = EVP_CIPHER_CTX_get_cipher_data(ctx);
457     gost_init(&(c->cctx), block);
458     c->key_meshing = 1;
459     c->count = 0;
460     if (key)
461         gost_key(&(c->cctx), key);
462     if (iv) {
463         memcpy((unsigned char *)EVP_CIPHER_CTX_original_iv(ctx), iv,
464                EVP_CIPHER_CTX_iv_length(ctx));
465     }
466     memcpy(EVP_CIPHER_CTX_iv_noconst(ctx),
467            EVP_CIPHER_CTX_original_iv(ctx), EVP_CIPHER_CTX_iv_length(ctx));
468     return 1;
469 }
470
471 static int gost_cipher_init_cpa(EVP_CIPHER_CTX *ctx, const unsigned char *key,
472                                 const unsigned char *iv, int enc)
473 {
474     return gost_cipher_init_cnt(ctx, key, iv, &Gost28147_CryptoProParamSetA);
475 }
476
477 static int gost_cipher_init_cp_12(EVP_CIPHER_CTX *ctx,
478                                   const unsigned char *key,
479                                   const unsigned char *iv, int enc)
480 {
481     return gost_cipher_init_cnt(ctx, key, iv, &Gost28147_TC26ParamSetZ);
482 }
483
484 /* Initializes EVP_CIPHER_CTX with default values */
485 int gost_cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
486                      const unsigned char *iv, int enc)
487 {
488     return gost_cipher_init_param(ctx, key, iv, enc, NID_undef,
489                                   EVP_CIPH_CFB_MODE);
490 }
491
492 /* Initializes EVP_CIPHER_CTX with default values */
493 int gost_cipher_init_cbc(EVP_CIPHER_CTX *ctx, const unsigned char *key,
494                          const unsigned char *iv, int enc)
495 {
496     return gost_cipher_init_param(ctx, key, iv, enc, NID_undef,
497                                   EVP_CIPH_CBC_MODE);
498 }
499
500 /* Initializes EVP_CIPHER_CTX with default values */
501 int magma_cipher_init_cbc(EVP_CIPHER_CTX *ctx, const unsigned char *key,
502                          const unsigned char *iv, int enc)
503 {
504     return magma_cipher_init_param(ctx, key, iv, enc, NID_undef,
505                                   EVP_CIPH_CBC_MODE);
506 }
507
508 /*
509  * Wrapper around gostcrypt function from gost89.c which perform key meshing
510  * when nesseccary
511  */
512 static void gost_crypt_mesh(void *ctx, unsigned char *iv, unsigned char *buf)
513 {
514     struct ossl_gost_cipher_ctx *c = ctx;
515     assert(c->count % 8 == 0 && c->count <= 1024);
516     if (c->key_meshing && c->count == 1024) {
517         cryptopro_key_meshing(&(c->cctx), iv);
518     }
519     gostcrypt(&(c->cctx), iv, buf);
520     c->count = c->count % 1024 + 8;
521 }
522
523 static void gost_cnt_next(void *ctx, unsigned char *iv, unsigned char *buf)
524 {
525     struct ossl_gost_cipher_ctx *c = ctx;
526     word32 g, go;
527     unsigned char buf1[8];
528     assert(c->count % 8 == 0 && c->count <= 1024);
529     if (c->key_meshing && c->count == 1024) {
530         cryptopro_key_meshing(&(c->cctx), iv);
531     }
532     if (c->count == 0) {
533         gostcrypt(&(c->cctx), iv, buf1);
534     } else {
535         memcpy(buf1, iv, 8);
536     }
537     g = buf1[0] | (buf1[1] << 8) | (buf1[2] << 16) | ((word32) buf1[3] << 24);
538     g += 0x01010101;
539     buf1[0] = (unsigned char)(g & 0xff);
540     buf1[1] = (unsigned char)((g >> 8) & 0xff);
541     buf1[2] = (unsigned char)((g >> 16) & 0xff);
542     buf1[3] = (unsigned char)((g >> 24) & 0xff);
543     g = buf1[4] | (buf1[5] << 8) | (buf1[6] << 16) | ((word32) buf1[7] << 24);
544     go = g;
545     g += 0x01010104;
546     if (go > g)                 /* overflow */
547         g++;
548     buf1[4] = (unsigned char)(g & 0xff);
549     buf1[5] = (unsigned char)((g >> 8) & 0xff);
550     buf1[6] = (unsigned char)((g >> 16) & 0xff);
551     buf1[7] = (unsigned char)((g >> 24) & 0xff);
552     memcpy(iv, buf1, 8);
553     gostcrypt(&(c->cctx), buf1, buf);
554     c->count = c->count % 1024 + 8;
555 }
556
557 /* GOST encryption in CBC mode */
558 int gost_cipher_do_cbc(EVP_CIPHER_CTX *ctx, unsigned char *out,
559                        const unsigned char *in, size_t inl)
560 {
561     unsigned char b[8];
562     const unsigned char *in_ptr = in;
563     unsigned char *out_ptr = out;
564     int i;
565     struct ossl_gost_cipher_ctx *c = EVP_CIPHER_CTX_get_cipher_data(ctx);
566     unsigned char *iv = EVP_CIPHER_CTX_iv_noconst(ctx);
567     if (EVP_CIPHER_CTX_encrypting(ctx)) {
568         while (inl > 0) {
569
570             for (i = 0; i < 8; i++) {
571                 b[i] = iv[i] ^ in_ptr[i];
572             }
573             gostcrypt(&(c->cctx), b, out_ptr);
574             memcpy(iv, out_ptr, 8);
575             out_ptr += 8;
576             in_ptr += 8;
577             inl -= 8;
578         }
579     } else {
580         while (inl > 0) {
581             gostdecrypt(&(c->cctx), in_ptr, b);
582             for (i = 0; i < 8; i++) {
583                 out_ptr[i] = iv[i] ^ b[i];
584             }
585             memcpy(iv, in_ptr, 8);
586             out_ptr += 8;
587             in_ptr += 8;
588             inl -= 8;
589         }
590     }
591     return 1;
592 }
593
594 /* GOST encryption in CBC mode */
595 int magma_cipher_do_cbc(EVP_CIPHER_CTX *ctx, unsigned char *out,
596                        const unsigned char *in, size_t inl)
597 {
598     unsigned char b[8];
599                 unsigned char d[8];
600     const unsigned char *in_ptr = in;
601     unsigned char *out_ptr = out;
602     int i;
603     struct ossl_gost_cipher_ctx *c = EVP_CIPHER_CTX_get_cipher_data(ctx);
604     unsigned char *iv = EVP_CIPHER_CTX_iv_noconst(ctx);
605     if (EVP_CIPHER_CTX_encrypting(ctx)) {
606         while (inl > 0) {
607
608             for (i = 0; i < 8; i++) {
609                 b[7-i] = iv[i] ^ in_ptr[i];
610             }
611             gostcrypt(&(c->cctx), b, d);
612
613             for (i = 0; i < 8; i++) {
614                 out_ptr[7-i] = d[i];
615             }
616             memcpy(iv, out_ptr, 8);
617             out_ptr += 8;
618             in_ptr += 8;
619             inl -= 8;
620         }
621     } else {
622         while (inl > 0) {
623             for (i = 0; i < 8; i++) {
624                 d[7-i] = in_ptr[i];
625             }
626             gostdecrypt(&(c->cctx), d, b);
627             for (i = 0; i < 8; i++) {
628                 out_ptr[i] = iv[i] ^ b[7-i];
629             }
630             memcpy(iv, in_ptr, 8);
631             out_ptr += 8;
632             in_ptr += 8;
633             inl -= 8;
634         }
635     }
636     return 1;
637 }
638
639 /* GOST encryption in CFB mode */
640 int gost_cipher_do_cfb(EVP_CIPHER_CTX *ctx, unsigned char *out,
641                        const unsigned char *in, size_t inl)
642 {
643     const unsigned char *in_ptr = in;
644     unsigned char *out_ptr = out;
645     size_t i = 0;
646     size_t j = 0;
647     unsigned char *buf = EVP_CIPHER_CTX_buf_noconst(ctx);
648     unsigned char *iv = EVP_CIPHER_CTX_iv_noconst(ctx);
649 /* process partial block if any */
650     if (EVP_CIPHER_CTX_num(ctx)) {
651         for (j = EVP_CIPHER_CTX_num(ctx), i = 0; j < 8 && i < inl;
652              j++, i++, in_ptr++, out_ptr++) {
653             if (!EVP_CIPHER_CTX_encrypting(ctx))
654                 buf[j + 8] = *in_ptr;
655             *out_ptr = buf[j] ^ (*in_ptr);
656             if (EVP_CIPHER_CTX_encrypting(ctx))
657                 buf[j + 8] = *out_ptr;
658         }
659         if (j == 8) {
660             memcpy(iv, buf + 8, 8);
661             EVP_CIPHER_CTX_set_num(ctx, 0);
662         } else {
663             EVP_CIPHER_CTX_set_num(ctx, j);
664             return 1;
665         }
666     }
667
668     for (; i + 8 < inl; i += 8, in_ptr += 8, out_ptr += 8) {
669         /*
670          * block cipher current iv
671          */
672         gost_crypt_mesh(EVP_CIPHER_CTX_get_cipher_data(ctx), iv, buf);
673         /*
674          * xor next block of input text with it and output it
675          */
676         /*
677          * output this block
678          */
679         if (!EVP_CIPHER_CTX_encrypting(ctx))
680             memcpy(iv, in_ptr, 8);
681         for (j = 0; j < 8; j++) {
682             out_ptr[j] = buf[j] ^ in_ptr[j];
683         }
684         /* Encrypt */
685         /* Next iv is next block of cipher text */
686         if (EVP_CIPHER_CTX_encrypting(ctx))
687             memcpy(iv, out_ptr, 8);
688     }
689 /* Process rest of buffer */
690     if (i < inl) {
691         gost_crypt_mesh(EVP_CIPHER_CTX_get_cipher_data(ctx), iv, buf);
692         if (!EVP_CIPHER_CTX_encrypting(ctx))
693             memcpy(buf + 8, in_ptr, inl - i);
694         for (j = 0; i < inl; j++, i++) {
695             out_ptr[j] = buf[j] ^ in_ptr[j];
696         }
697         EVP_CIPHER_CTX_set_num(ctx, j);
698         if (EVP_CIPHER_CTX_encrypting(ctx))
699             memcpy(buf + 8, out_ptr, j);
700     } else {
701         EVP_CIPHER_CTX_set_num(ctx, 0);
702     }
703     return 1;
704 }
705
706 static int gost_cipher_do_cnt(EVP_CIPHER_CTX *ctx, unsigned char *out,
707                               const unsigned char *in, size_t inl)
708 {
709     const unsigned char *in_ptr = in;
710     unsigned char *out_ptr = out;
711     size_t i = 0;
712     size_t j;
713     unsigned char *buf = EVP_CIPHER_CTX_buf_noconst(ctx);
714     unsigned char *iv = EVP_CIPHER_CTX_iv_noconst(ctx);
715 /* process partial block if any */
716     if (EVP_CIPHER_CTX_num(ctx)) {
717         for (j = EVP_CIPHER_CTX_num(ctx), i = 0; j < 8 && i < inl;
718              j++, i++, in_ptr++, out_ptr++) {
719             *out_ptr = buf[j] ^ (*in_ptr);
720         }
721         if (j == 8) {
722             EVP_CIPHER_CTX_set_num(ctx, 0);
723         } else {
724             EVP_CIPHER_CTX_set_num(ctx, j);
725             return 1;
726         }
727     }
728
729     for (; i + 8 < inl; i += 8, in_ptr += 8, out_ptr += 8) {
730         /*
731          * block cipher current iv
732          */
733         /* Encrypt */
734         gost_cnt_next(EVP_CIPHER_CTX_get_cipher_data(ctx), iv, buf);
735         /*
736          * xor next block of input text with it and output it
737          */
738         /*
739          * output this block
740          */
741         for (j = 0; j < 8; j++) {
742             out_ptr[j] = buf[j] ^ in_ptr[j];
743         }
744     }
745 /* Process rest of buffer */
746     if (i < inl) {
747         gost_cnt_next(EVP_CIPHER_CTX_get_cipher_data(ctx), iv, buf);
748         for (j = 0; i < inl; j++, i++) {
749             out_ptr[j] = buf[j] ^ in_ptr[j];
750         }
751         EVP_CIPHER_CTX_set_num(ctx, j);
752     } else {
753         EVP_CIPHER_CTX_set_num(ctx, 0);
754     }
755     return 1;
756 }
757
758 /* Cleaning up of EVP_CIPHER_CTX */
759 int gost_cipher_cleanup(EVP_CIPHER_CTX *ctx)
760 {
761     gost_destroy(&
762                  ((struct ossl_gost_cipher_ctx *)
763                   EVP_CIPHER_CTX_get_cipher_data(ctx))->cctx);
764     EVP_CIPHER_CTX_set_app_data(ctx, NULL);
765     return 1;
766 }
767
768 /* Control function for gost cipher */
769 int gost_cipher_ctl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr)
770 {
771     switch (type) {
772 #if 0
773     case EVP_CTRL_INIT:
774         {
775             struct ossl_gost_cipher_ctx *c =
776                 EVP_CIPHER_CTX_get_cipher_data(ctx);
777             if (c == NULL) {
778                 return -1;
779             }
780             return gost_cipher_set_param(c, arg);
781         }
782 #endif
783     case EVP_CTRL_RAND_KEY:
784         {
785             if (RAND_bytes
786                 ((unsigned char *)ptr, EVP_CIPHER_CTX_key_length(ctx)) <= 0) {
787                 GOSTerr(GOST_F_GOST_CIPHER_CTL, GOST_R_RNG_ERROR);
788                 return -1;
789             }
790             break;
791         }
792     case EVP_CTRL_PBE_PRF_NID:
793         if (ptr) {
794             const char *params = get_gost_engine_param(GOST_PARAM_PBE_PARAMS);
795             int nid = NID_id_tc26_hmac_gost_3411_2012_512;
796
797             if (params) {
798                 if (!strcmp("md_gost12_256", params))
799                     nid = NID_id_tc26_hmac_gost_3411_2012_256;
800                 else if (!strcmp("md_gost12_512", params))
801                     nid = NID_id_tc26_hmac_gost_3411_2012_512;
802                 else if (!strcmp("md_gost94", params))
803                     nid = NID_id_HMACGostR3411_94;
804             }
805             *((int *)ptr) = nid;
806             return 1;
807         } else {
808             return 0;
809         }
810
811     case EVP_CTRL_SET_SBOX:
812         if (ptr) {
813             struct ossl_gost_cipher_ctx *c =
814                 EVP_CIPHER_CTX_get_cipher_data(ctx);
815             int nid;
816             int cur_meshing;
817             int ret;
818
819             if (c == NULL) {
820                 return -1;
821             }
822
823             if (c->count != 0) {
824                 return -1;
825             }
826
827             nid = OBJ_txt2nid(ptr);
828             if (nid == NID_undef) {
829                 return 0;
830             }
831
832             cur_meshing = c->key_meshing;
833             ret = gost_cipher_set_param(c, nid);
834             c->key_meshing = cur_meshing;
835             return ret;
836         } else {
837             return 0;
838         }
839     case EVP_CTRL_KEY_MESH:
840         {
841             struct ossl_gost_cipher_ctx *c =
842                 EVP_CIPHER_CTX_get_cipher_data(ctx);
843
844             if (c == NULL) {
845                 return -1;
846             }
847
848             if (c->count != 0) {
849                 return -1;
850             }
851
852             c->key_meshing = arg;
853             return 1;
854         }
855     default:
856         GOSTerr(GOST_F_GOST_CIPHER_CTL,
857                 GOST_R_UNSUPPORTED_CIPHER_CTL_COMMAND);
858         return -1;
859     }
860     return 1;
861 }
862
863 /* Set cipher parameters from ASN1 structure */
864 int gost89_set_asn1_parameters(EVP_CIPHER_CTX *ctx, ASN1_TYPE *params)
865 {
866     int len = 0;
867     unsigned char *buf = NULL;
868     unsigned char *p = NULL;
869     struct ossl_gost_cipher_ctx *c = EVP_CIPHER_CTX_get_cipher_data(ctx);
870     GOST_CIPHER_PARAMS *gcp = GOST_CIPHER_PARAMS_new();
871     ASN1_OCTET_STRING *os = NULL;
872     if (!gcp) {
873         GOSTerr(GOST_F_GOST89_SET_ASN1_PARAMETERS, ERR_R_MALLOC_FAILURE);
874         return 0;
875     }
876     if (!ASN1_OCTET_STRING_set
877         (gcp->iv, EVP_CIPHER_CTX_iv(ctx), EVP_CIPHER_CTX_iv_length(ctx))) {
878         GOST_CIPHER_PARAMS_free(gcp);
879         GOSTerr(GOST_F_GOST89_SET_ASN1_PARAMETERS, ERR_R_MALLOC_FAILURE);
880         return 0;
881     }
882     ASN1_OBJECT_free(gcp->enc_param_set);
883     gcp->enc_param_set = OBJ_nid2obj(c->paramNID);
884
885     len = i2d_GOST_CIPHER_PARAMS(gcp, NULL);
886     p = buf = OPENSSL_malloc(len);
887     if (!buf) {
888         GOST_CIPHER_PARAMS_free(gcp);
889         GOSTerr(GOST_F_GOST89_SET_ASN1_PARAMETERS, ERR_R_MALLOC_FAILURE);
890         return 0;
891     }
892     i2d_GOST_CIPHER_PARAMS(gcp, &p);
893     GOST_CIPHER_PARAMS_free(gcp);
894
895     os = ASN1_OCTET_STRING_new();
896
897     if (!os || !ASN1_OCTET_STRING_set(os, buf, len)) {
898         OPENSSL_free(buf);
899         GOSTerr(GOST_F_GOST89_SET_ASN1_PARAMETERS, ERR_R_MALLOC_FAILURE);
900         return 0;
901     }
902     OPENSSL_free(buf);
903
904     ASN1_TYPE_set(params, V_ASN1_SEQUENCE, os);
905     return 1;
906 }
907
908 /* Store parameters into ASN1 structure */
909 int gost89_get_asn1_parameters(EVP_CIPHER_CTX *ctx, ASN1_TYPE *params)
910 {
911     int ret = -1;
912     int len;
913     GOST_CIPHER_PARAMS *gcp = NULL;
914     unsigned char *p;
915     struct ossl_gost_cipher_ctx *c = EVP_CIPHER_CTX_get_cipher_data(ctx);
916     int nid;
917
918     if (ASN1_TYPE_get(params) != V_ASN1_SEQUENCE) {
919         return ret;
920     }
921
922     p = params->value.sequence->data;
923
924     gcp = d2i_GOST_CIPHER_PARAMS(NULL, (const unsigned char **)&p,
925                                  params->value.sequence->length);
926
927     len = gcp->iv->length;
928     if (len != EVP_CIPHER_CTX_iv_length(ctx)) {
929         GOST_CIPHER_PARAMS_free(gcp);
930         GOSTerr(GOST_F_GOST89_GET_ASN1_PARAMETERS, GOST_R_INVALID_IV_LENGTH);
931         return -1;
932     }
933
934     nid = OBJ_obj2nid(gcp->enc_param_set);
935     if (nid == NID_undef) {
936         GOST_CIPHER_PARAMS_free(gcp);
937         GOSTerr(GOST_F_GOST89_GET_ASN1_PARAMETERS,
938                 GOST_R_INVALID_CIPHER_PARAM_OID);
939         return -1;
940     }
941
942     if (!gost_cipher_set_param(c, nid)) {
943         GOST_CIPHER_PARAMS_free(gcp);
944         return -1;
945     }
946     /*XXX missing non-const accessor */
947     memcpy((unsigned char *)EVP_CIPHER_CTX_original_iv(ctx), gcp->iv->data,
948            EVP_CIPHER_CTX_iv_length(ctx));
949
950     GOST_CIPHER_PARAMS_free(gcp);
951
952     return 1;
953 }
954
955 static int gost_imit_init(EVP_MD_CTX *ctx, gost_subst_block * block)
956 {
957     struct ossl_gost_imit_ctx *c = EVP_MD_CTX_md_data(ctx);
958     memset(c->buffer, 0, sizeof(c->buffer));
959     memset(c->partial_block, 0, sizeof(c->partial_block));
960     c->count = 0;
961     c->bytes_left = 0;
962     c->key_meshing = 1;
963     c->dgst_size = 4;
964     gost_init(&(c->cctx), block);
965     return 1;
966 }
967
968 static int gost_imit_init_cpa(EVP_MD_CTX *ctx)
969 {
970     return gost_imit_init(ctx, &Gost28147_CryptoProParamSetA);
971 }
972
973 static int gost_imit_init_cp_12(EVP_MD_CTX *ctx)
974 {
975     return gost_imit_init(ctx, &Gost28147_TC26ParamSetZ);
976 }
977
978 static void mac_block_mesh(struct ossl_gost_imit_ctx *c,
979                            const unsigned char *data)
980 {
981     unsigned char buffer[8];
982     /*
983      * We are using local buffer for iv because CryptoPro doesn't interpret
984      * internal state of MAC algorithm as iv during keymeshing (but does
985      * initialize internal state from iv in key transport
986      */
987     assert(c->count % 8 == 0 && c->count <= 1024);
988     if (c->key_meshing && c->count == 1024) {
989         cryptopro_key_meshing(&(c->cctx), buffer);
990     }
991     mac_block(&(c->cctx), c->buffer, data);
992     c->count = c->count % 1024 + 8;
993 }
994
995 int gost_imit_update(EVP_MD_CTX *ctx, const void *data, size_t count)
996 {
997     struct ossl_gost_imit_ctx *c = EVP_MD_CTX_md_data(ctx);
998     const unsigned char *p = data;
999     size_t bytes = count, i;
1000     if (!(c->key_set)) {
1001         GOSTerr(GOST_F_GOST_IMIT_UPDATE, GOST_R_MAC_KEY_NOT_SET);
1002         return 0;
1003     }
1004     if (c->bytes_left) {
1005         for (i = c->bytes_left; i < 8 && bytes > 0; bytes--, i++, p++) {
1006             c->partial_block[i] = *p;
1007         }
1008         if (i == 8) {
1009             mac_block_mesh(c, c->partial_block);
1010         } else {
1011             c->bytes_left = i;
1012             return 1;
1013         }
1014     }
1015     while (bytes > 8) {
1016         mac_block_mesh(c, p);
1017         p += 8;
1018         bytes -= 8;
1019     }
1020     if (bytes > 0) {
1021         memcpy(c->partial_block, p, bytes);
1022     }
1023     c->bytes_left = bytes;
1024     return 1;
1025 }
1026
1027 int gost_imit_final(EVP_MD_CTX *ctx, unsigned char *md)
1028 {
1029     struct ossl_gost_imit_ctx *c = EVP_MD_CTX_md_data(ctx);
1030     if (!c->key_set) {
1031         GOSTerr(GOST_F_GOST_IMIT_FINAL, GOST_R_MAC_KEY_NOT_SET);
1032         return 0;
1033     }
1034     if (c->count == 0 && c->bytes_left) {
1035         unsigned char buffer[8];
1036         memset(buffer, 0, 8);
1037         gost_imit_update(ctx, buffer, 8);
1038     }
1039     if (c->bytes_left) {
1040         int i;
1041         for (i = c->bytes_left; i < 8; i++) {
1042             c->partial_block[i] = 0;
1043         }
1044         mac_block_mesh(c, c->partial_block);
1045     }
1046     get_mac(c->buffer, 8 * c->dgst_size, md);
1047     return 1;
1048 }
1049
1050 int gost_imit_ctrl(EVP_MD_CTX *ctx, int type, int arg, void *ptr)
1051 {
1052     switch (type) {
1053     case EVP_MD_CTRL_KEY_LEN:
1054         *((unsigned int *)(ptr)) = 32;
1055         return 1;
1056     case EVP_MD_CTRL_SET_KEY:
1057         {
1058             struct ossl_gost_imit_ctx *gost_imit_ctx =
1059                 EVP_MD_CTX_md_data(ctx);
1060
1061             if (EVP_MD_meth_get_init(EVP_MD_CTX_md(ctx)) (ctx) <= 0) {
1062                 GOSTerr(GOST_F_GOST_IMIT_CTRL, GOST_R_MAC_KEY_NOT_SET);
1063                 return 0;
1064             }
1065             EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NO_INIT);
1066
1067             if (arg == 0) {
1068                 struct gost_mac_key *key = (struct gost_mac_key *)ptr;
1069                 if (key->mac_param_nid != NID_undef) {
1070                     const struct gost_cipher_info *param =
1071                         get_encryption_params(OBJ_nid2obj
1072                                               (key->mac_param_nid));
1073                     if (param == NULL) {
1074                         GOSTerr(GOST_F_GOST_IMIT_CTRL,
1075                                 GOST_R_INVALID_MAC_PARAMS);
1076                         return 0;
1077                     }
1078                     gost_init(&(gost_imit_ctx->cctx), param->sblock);
1079                 }
1080                 gost_key(&(gost_imit_ctx->cctx), key->key);
1081                 gost_imit_ctx->key_set = 1;
1082
1083                 return 1;
1084             } else if (arg == 32) {
1085                 gost_key(&(gost_imit_ctx->cctx), ptr);
1086                 gost_imit_ctx->key_set = 1;
1087                 return 1;
1088             }
1089             GOSTerr(GOST_F_GOST_IMIT_CTRL, GOST_R_INVALID_MAC_KEY_SIZE);
1090             return 0;
1091         }
1092     case EVP_MD_CTRL_MAC_LEN:
1093         {
1094             struct ossl_gost_imit_ctx *c = EVP_MD_CTX_md_data(ctx);
1095             if (arg < 1 || arg > 8) {
1096                 GOSTerr(GOST_F_GOST_IMIT_CTRL, GOST_R_INVALID_MAC_SIZE);
1097                 return 0;
1098             }
1099             c->dgst_size = arg;
1100             return 1;
1101         }
1102
1103     default:
1104         return 0;
1105     }
1106 }
1107
1108 int gost_imit_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from)
1109 {
1110     if (EVP_MD_CTX_md_data(to) && EVP_MD_CTX_md_data(from)) {
1111         memcpy(EVP_MD_CTX_md_data(to), EVP_MD_CTX_md_data(from),
1112                sizeof(struct ossl_gost_imit_ctx));
1113     }
1114     return 1;
1115 }
1116
1117 /* Clean up imit ctx */
1118 int gost_imit_cleanup(EVP_MD_CTX *ctx)
1119 {
1120     memset(EVP_MD_CTX_md_data(ctx), 0, sizeof(struct ossl_gost_imit_ctx));
1121     return 1;
1122 }