Remove Gost94 signature algorithm.
[openssl.git] / engines / ccgost / 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_cpa(EVP_CIPHER_CTX *ctx, const unsigned char *key,
26                                 const unsigned char *iv, int enc);
27 /* Handles block of data in CFB mode */
28 static int gost_cipher_do_cfb(EVP_CIPHER_CTX *ctx, unsigned char *out,
29                               const unsigned char *in, size_t inl);
30 /* Handles block of data in CNT mode */
31 static int gost_cipher_do_cnt(EVP_CIPHER_CTX *ctx, unsigned char *out,
32                               const unsigned char *in, size_t inl);
33 /* Cleanup function */
34 static int gost_cipher_cleanup(EVP_CIPHER_CTX *);
35 /* set/get cipher parameters */
36 static int gost89_set_asn1_parameters(EVP_CIPHER_CTX *ctx, ASN1_TYPE *params);
37 static int gost89_get_asn1_parameters(EVP_CIPHER_CTX *ctx, ASN1_TYPE *params);
38 /* Control function */
39 static int gost_cipher_ctl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr);
40
41 EVP_CIPHER cipher_gost = {
42     NID_id_Gost28147_89,
43     1,                          /* block_size */
44     32,                         /* key_size */
45     8,                          /* iv_len */
46     EVP_CIPH_CFB_MODE | EVP_CIPH_NO_PADDING |
47         EVP_CIPH_CUSTOM_IV | EVP_CIPH_RAND_KEY | EVP_CIPH_ALWAYS_CALL_INIT,
48     gost_cipher_init,
49     gost_cipher_do_cfb,
50     gost_cipher_cleanup,
51     sizeof(struct ossl_gost_cipher_ctx), /* ctx_size */
52     gost89_set_asn1_parameters,
53     gost89_get_asn1_parameters,
54     gost_cipher_ctl,
55     NULL,
56 };
57
58 EVP_CIPHER cipher_gost_cpacnt = {
59     NID_gost89_cnt,
60     1,                          /* block_size */
61     32,                         /* key_size */
62     8,                          /* iv_len */
63     EVP_CIPH_OFB_MODE | EVP_CIPH_NO_PADDING |
64         EVP_CIPH_CUSTOM_IV | EVP_CIPH_RAND_KEY | EVP_CIPH_ALWAYS_CALL_INIT,
65     gost_cipher_init_cpa,
66     gost_cipher_do_cnt,
67     gost_cipher_cleanup,
68     sizeof(struct ossl_gost_cipher_ctx), /* ctx_size */
69     gost89_set_asn1_parameters,
70     gost89_get_asn1_parameters,
71     gost_cipher_ctl,
72     NULL,
73 };
74
75 /* Implementation of GOST 28147-89 in MAC (imitovstavka) mode */
76 /* Init functions which set specific parameters */
77 static int gost_imit_init_cpa(EVP_MD_CTX *ctx);
78 /* process block of data */
79 static int gost_imit_update(EVP_MD_CTX *ctx, const void *data, size_t count);
80 /* Return computed value */
81 static int gost_imit_final(EVP_MD_CTX *ctx, unsigned char *md);
82 /* Copies context */
83 static int gost_imit_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from);
84 static int gost_imit_cleanup(EVP_MD_CTX *ctx);
85 /* Control function, knows how to set MAC key.*/
86 static int gost_imit_ctrl(EVP_MD_CTX *ctx, int type, int arg, void *ptr);
87
88 EVP_MD imit_gost_cpa = {
89     NID_id_Gost28147_89_MAC,
90     NID_undef,
91     4,
92     0,
93     gost_imit_init_cpa,
94     gost_imit_update,
95     gost_imit_final,
96     gost_imit_copy,
97     gost_imit_cleanup,
98     NULL,
99     NULL,
100     {0, 0, 0, 0, 0},
101     8,
102     sizeof(struct ossl_gost_imit_ctx),
103     gost_imit_ctrl
104 };
105
106 /*
107  * Correspondence between gost parameter OIDs and substitution blocks
108  * NID field is filed by register_gost_NID function in engine.c
109  * upon engine initialization
110  */
111
112 struct gost_cipher_info gost_cipher_list[] = {
113     /*- NID *//*
114      * Subst block
115      *//*
116      * Key meshing
117      */
118     /*
119      * {NID_id_GostR3411_94_CryptoProParamSet,&GostR3411_94_CryptoProParamSet,0},
120      */
121     {NID_id_Gost28147_89_CryptoPro_A_ParamSet, &Gost28147_CryptoProParamSetA,
122      1},
123     {NID_id_Gost28147_89_CryptoPro_B_ParamSet, &Gost28147_CryptoProParamSetB,
124      1},
125     {NID_id_Gost28147_89_CryptoPro_C_ParamSet, &Gost28147_CryptoProParamSetC,
126      1},
127     {NID_id_Gost28147_89_CryptoPro_D_ParamSet, &Gost28147_CryptoProParamSetD,
128      1},
129     {NID_id_Gost28147_89_TestParamSet, &Gost28147_TestParamSet, 1},
130     {NID_undef, NULL, 0}
131 };
132
133 /*
134  * get encryption parameters from crypto network settings FIXME For now we
135  * use environment var CRYPT_PARAMS as place to store these settings.
136  * Actually, it is better to use engine control command, read from
137  * configuration file to set them
138  */
139 const struct gost_cipher_info *get_encryption_params(ASN1_OBJECT *obj)
140 {
141     int nid;
142     struct gost_cipher_info *param;
143     if (!obj) {
144         const char *params = get_gost_engine_param(GOST_PARAM_CRYPT_PARAMS);
145         if (!params || !strlen(params))
146             return &gost_cipher_list[1];
147
148         nid = OBJ_txt2nid(params);
149         if (nid == NID_undef) {
150             GOSTerr(GOST_F_GET_ENCRYPTION_PARAMS,
151                     GOST_R_INVALID_CIPHER_PARAM_OID);
152             return NULL;
153         }
154     } else {
155         nid = OBJ_obj2nid(obj);
156     }
157     for (param = gost_cipher_list; param->sblock != NULL && param->nid != nid;
158          param++) ;
159     if (!param->sblock) {
160         GOSTerr(GOST_F_GET_ENCRYPTION_PARAMS, GOST_R_INVALID_CIPHER_PARAMS);
161         return NULL;
162     }
163     return param;
164 }
165
166 /* Sets cipher param from paramset NID. */
167 static int gost_cipher_set_param(struct ossl_gost_cipher_ctx *c, int nid)
168 {
169     const struct gost_cipher_info *param;
170     param =
171         get_encryption_params((nid == NID_undef ? NULL : OBJ_nid2obj(nid)));
172     if (!param)
173         return 0;
174
175     c->paramNID = param->nid;
176     c->key_meshing = param->key_meshing;
177     c->count = 0;
178     gost_init(&(c->cctx), param->sblock);
179     return 1;
180 }
181
182 /* Initializes EVP_CIPHER_CTX by paramset NID */
183 static int gost_cipher_init_param(EVP_CIPHER_CTX *ctx,
184                                   const unsigned char *key,
185                                   const unsigned char *iv, int enc,
186                                   int paramNID, int mode)
187 {
188     struct ossl_gost_cipher_ctx *c = ctx->cipher_data;
189     if (ctx->app_data == NULL) {
190         if (!gost_cipher_set_param(c, paramNID))
191             return 0;
192         ctx->app_data = ctx->cipher_data;
193     }
194     if (key)
195         gost_key(&(c->cctx), key);
196     if (iv)
197         memcpy(ctx->oiv, iv, EVP_CIPHER_CTX_iv_length(ctx));
198     memcpy(ctx->iv, ctx->oiv, EVP_CIPHER_CTX_iv_length(ctx));
199     return 1;
200 }
201
202 static int gost_cipher_init_cpa(EVP_CIPHER_CTX *ctx, const unsigned char *key,
203                                 const unsigned char *iv, int enc)
204 {
205     struct ossl_gost_cipher_ctx *c = ctx->cipher_data;
206     gost_init(&(c->cctx), &Gost28147_CryptoProParamSetA);
207     c->key_meshing = 1;
208     c->count = 0;
209     if (key)
210         gost_key(&(c->cctx), key);
211     if (iv)
212         memcpy(ctx->oiv, iv, EVP_CIPHER_CTX_iv_length(ctx));
213     memcpy(ctx->iv, ctx->oiv, EVP_CIPHER_CTX_iv_length(ctx));
214     return 1;
215 }
216
217 /* Initializes EVP_CIPHER_CTX with default values */
218 int gost_cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
219                      const unsigned char *iv, int enc)
220 {
221     return gost_cipher_init_param(ctx, key, iv, enc, NID_undef,
222                                   EVP_CIPH_CFB_MODE);
223 }
224
225 /*
226  * Wrapper around gostcrypt function from gost89.c which perform key meshing
227  * when nesseccary
228  */
229 static void gost_crypt_mesh(void *ctx, unsigned char *iv, unsigned char *buf)
230 {
231     struct ossl_gost_cipher_ctx *c = ctx;
232     assert(c->count % 8 == 0 && c->count <= 1024);
233     if (c->key_meshing && c->count == 1024) {
234         cryptopro_key_meshing(&(c->cctx), iv);
235     }
236     gostcrypt(&(c->cctx), iv, buf);
237     c->count = c->count % 1024 + 8;
238 }
239
240 static void gost_cnt_next(void *ctx, unsigned char *iv, unsigned char *buf)
241 {
242     struct ossl_gost_cipher_ctx *c = ctx;
243     word32 g, go;
244     unsigned char buf1[8];
245     assert(c->count % 8 == 0 && c->count <= 1024);
246     if (c->key_meshing && c->count == 1024) {
247         cryptopro_key_meshing(&(c->cctx), iv);
248     }
249     if (c->count == 0) {
250         gostcrypt(&(c->cctx), iv, buf1);
251     } else {
252         memcpy(buf1, iv, 8);
253     }
254     g = buf1[0] | (buf1[1] << 8) | (buf1[2] << 16) | ((word32) buf1[3] << 24);
255     g += 0x01010101;
256     buf1[0] = (unsigned char)(g & 0xff);
257     buf1[1] = (unsigned char)((g >> 8) & 0xff);
258     buf1[2] = (unsigned char)((g >> 16) & 0xff);
259     buf1[3] = (unsigned char)((g >> 24) & 0xff);
260     g = buf1[4] | (buf1[5] << 8) | (buf1[6] << 16) | ((word32) buf1[7] << 24);
261     go = g;
262     g += 0x01010104;
263     if (go > g)                 /* overflow */
264         g++;
265     buf1[4] = (unsigned char)(g & 0xff);
266     buf1[5] = (unsigned char)((g >> 8) & 0xff);
267     buf1[6] = (unsigned char)((g >> 16) & 0xff);
268     buf1[7] = (unsigned char)((g >> 24) & 0xff);
269     memcpy(iv, buf1, 8);
270     gostcrypt(&(c->cctx), buf1, buf);
271     c->count = c->count % 1024 + 8;
272 }
273
274 /* GOST encryption in CFB mode */
275 int gost_cipher_do_cfb(EVP_CIPHER_CTX *ctx, unsigned char *out,
276                        const unsigned char *in, size_t inl)
277 {
278     const unsigned char *in_ptr = in;
279     unsigned char *out_ptr = out;
280     size_t i = 0;
281     size_t j = 0;
282 /* process partial block if any */
283     if (ctx->num) {
284         for (j = ctx->num, i = 0; j < 8 && i < inl;
285              j++, i++, in_ptr++, out_ptr++) {
286             if (!ctx->encrypt)
287                 ctx->buf[j + 8] = *in_ptr;
288             *out_ptr = ctx->buf[j] ^ (*in_ptr);
289             if (ctx->encrypt)
290                 ctx->buf[j + 8] = *out_ptr;
291         }
292         if (j == 8) {
293             memcpy(ctx->iv, ctx->buf + 8, 8);
294             ctx->num = 0;
295         } else {
296             ctx->num = j;
297             return 1;
298         }
299     }
300
301     for (; i + 8 < inl; i += 8, in_ptr += 8, out_ptr += 8) {
302         /*
303          * block cipher current iv
304          */
305         gost_crypt_mesh(ctx->cipher_data, ctx->iv, ctx->buf);
306         /*
307          * xor next block of input text with it and output it
308          */
309         /*
310          * output this block
311          */
312         if (!ctx->encrypt)
313             memcpy(ctx->iv, in_ptr, 8);
314         for (j = 0; j < 8; j++) {
315             out_ptr[j] = ctx->buf[j] ^ in_ptr[j];
316         }
317         /* Encrypt */
318         /* Next iv is next block of cipher text */
319         if (ctx->encrypt)
320             memcpy(ctx->iv, out_ptr, 8);
321     }
322 /* Process rest of buffer */
323     if (i < inl) {
324         gost_crypt_mesh(ctx->cipher_data, ctx->iv, ctx->buf);
325         if (!ctx->encrypt)
326             memcpy(ctx->buf + 8, in_ptr, inl - i);
327         for (j = 0; i < inl; j++, i++) {
328             out_ptr[j] = ctx->buf[j] ^ in_ptr[j];
329         }
330         ctx->num = j;
331         if (ctx->encrypt)
332             memcpy(ctx->buf + 8, out_ptr, j);
333     } else {
334         ctx->num = 0;
335     }
336     return 1;
337 }
338
339 static int gost_cipher_do_cnt(EVP_CIPHER_CTX *ctx, unsigned char *out,
340                               const unsigned char *in, size_t inl)
341 {
342     const unsigned char *in_ptr = in;
343     unsigned char *out_ptr = out;
344     size_t i = 0;
345     size_t j;
346 /* process partial block if any */
347     if (ctx->num) {
348         for (j = ctx->num, i = 0; j < 8 && i < inl;
349              j++, i++, in_ptr++, out_ptr++) {
350             *out_ptr = ctx->buf[j] ^ (*in_ptr);
351         }
352         if (j == 8) {
353             ctx->num = 0;
354         } else {
355             ctx->num = j;
356             return 1;
357         }
358     }
359
360     for (; i + 8 < inl; i += 8, in_ptr += 8, out_ptr += 8) {
361         /*
362          * block cipher current iv
363          */
364         /* Encrypt */
365         gost_cnt_next(ctx->cipher_data, ctx->iv, ctx->buf);
366         /*
367          * xor next block of input text with it and output it
368          */
369         /*
370          * output this block
371          */
372         for (j = 0; j < 8; j++) {
373             out_ptr[j] = ctx->buf[j] ^ in_ptr[j];
374         }
375     }
376 /* Process rest of buffer */
377     if (i < inl) {
378         gost_cnt_next(ctx->cipher_data, ctx->iv, ctx->buf);
379         for (j = 0; i < inl; j++, i++) {
380             out_ptr[j] = ctx->buf[j] ^ in_ptr[j];
381         }
382         ctx->num = j;
383     } else {
384         ctx->num = 0;
385     }
386     return 1;
387 }
388
389 /* Cleaning up of EVP_CIPHER_CTX */
390 int gost_cipher_cleanup(EVP_CIPHER_CTX *ctx)
391 {
392     gost_destroy(&((struct ossl_gost_cipher_ctx *)ctx->cipher_data)->cctx);
393     ctx->app_data = NULL;
394     return 1;
395 }
396
397 /* Control function for gost cipher */
398 int gost_cipher_ctl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr)
399 {
400     switch (type) {
401     case EVP_CTRL_RAND_KEY:
402         {
403             if (RAND_bytes((unsigned char *)ptr, ctx->key_len) <= 0) {
404                 GOSTerr(GOST_F_GOST_CIPHER_CTL,
405                         GOST_R_RANDOM_GENERATOR_ERROR);
406                 return -1;
407             }
408             break;
409         }
410     case EVP_CTRL_PBE_PRF_NID:
411         if (ptr) {
412             *((int *)ptr) = NID_id_HMACGostR3411_94;
413             return 1;
414         } else {
415             return 0;
416         }
417
418     default:
419         GOSTerr(GOST_F_GOST_CIPHER_CTL,
420                 GOST_R_UNSUPPORTED_CIPHER_CTL_COMMAND);
421         return -1;
422     }
423     return 1;
424 }
425
426 /* Set cipher parameters from ASN1 structure */
427 int gost89_set_asn1_parameters(EVP_CIPHER_CTX *ctx, ASN1_TYPE *params)
428 {
429     int len = 0;
430     unsigned char *buf = NULL;
431     unsigned char *p = NULL;
432     struct ossl_gost_cipher_ctx *c = ctx->cipher_data;
433     GOST_CIPHER_PARAMS *gcp = GOST_CIPHER_PARAMS_new();
434     ASN1_OCTET_STRING *os = NULL;
435     if (!gcp) {
436         GOSTerr(GOST_F_GOST89_SET_ASN1_PARAMETERS, ERR_R_MALLOC_FAILURE);
437         return 0;
438     }
439     if (!ASN1_OCTET_STRING_set(gcp->iv, ctx->iv, ctx->cipher->iv_len)) {
440         GOST_CIPHER_PARAMS_free(gcp);
441         GOSTerr(GOST_F_GOST89_SET_ASN1_PARAMETERS, ERR_R_MALLOC_FAILURE);
442         return 0;
443     }
444     ASN1_OBJECT_free(gcp->enc_param_set);
445     gcp->enc_param_set = OBJ_nid2obj(c->paramNID);
446
447     len = i2d_GOST_CIPHER_PARAMS(gcp, NULL);
448     p = buf = OPENSSL_malloc(len);
449     if (!buf) {
450         GOST_CIPHER_PARAMS_free(gcp);
451         GOSTerr(GOST_F_GOST89_SET_ASN1_PARAMETERS, ERR_R_MALLOC_FAILURE);
452         return 0;
453     }
454     i2d_GOST_CIPHER_PARAMS(gcp, &p);
455     GOST_CIPHER_PARAMS_free(gcp);
456
457     os = ASN1_OCTET_STRING_new();
458
459     if (!os || !ASN1_OCTET_STRING_set(os, buf, len)) {
460         OPENSSL_free(buf);
461         GOSTerr(GOST_F_GOST89_SET_ASN1_PARAMETERS, ERR_R_MALLOC_FAILURE);
462         return 0;
463     }
464     OPENSSL_free(buf);
465
466     ASN1_TYPE_set(params, V_ASN1_SEQUENCE, os);
467     return 1;
468 }
469
470 /* Store parameters into ASN1 structure */
471 int gost89_get_asn1_parameters(EVP_CIPHER_CTX *ctx, ASN1_TYPE *params)
472 {
473     int ret = -1;
474     int len;
475     GOST_CIPHER_PARAMS *gcp = NULL;
476     unsigned char *p;
477     struct ossl_gost_cipher_ctx *c = ctx->cipher_data;
478     if (ASN1_TYPE_get(params) != V_ASN1_SEQUENCE) {
479         return ret;
480     }
481
482     p = params->value.sequence->data;
483
484     gcp = d2i_GOST_CIPHER_PARAMS(NULL, (const unsigned char **)&p,
485                                  params->value.sequence->length);
486
487     len = gcp->iv->length;
488     if (len != ctx->cipher->iv_len) {
489         GOST_CIPHER_PARAMS_free(gcp);
490         GOSTerr(GOST_F_GOST89_GET_ASN1_PARAMETERS, GOST_R_INVALID_IV_LENGTH);
491         return -1;
492     }
493     if (!gost_cipher_set_param(c, OBJ_obj2nid(gcp->enc_param_set))) {
494         GOST_CIPHER_PARAMS_free(gcp);
495         return -1;
496     }
497     memcpy(ctx->oiv, gcp->iv->data, len);
498
499     GOST_CIPHER_PARAMS_free(gcp);
500
501     return 1;
502 }
503
504 int gost_imit_init_cpa(EVP_MD_CTX *ctx)
505 {
506     struct ossl_gost_imit_ctx *c = ctx->md_data;
507     memset(c->buffer, 0, sizeof(c->buffer));
508     memset(c->partial_block, 0, sizeof(c->partial_block));
509     c->count = 0;
510     c->bytes_left = 0;
511     c->key_meshing = 1;
512     gost_init(&(c->cctx), &Gost28147_CryptoProParamSetA);
513     return 1;
514 }
515
516 static void mac_block_mesh(struct ossl_gost_imit_ctx *c,
517                            const unsigned char *data)
518 {
519     unsigned char buffer[8];
520     /*
521      * We are using local buffer for iv because CryptoPro doesn't interpret
522      * internal state of MAC algorithm as iv during keymeshing (but does
523      * initialize internal state from iv in key transport
524      */
525     assert(c->count % 8 == 0 && c->count <= 1024);
526     if (c->key_meshing && c->count == 1024) {
527         cryptopro_key_meshing(&(c->cctx), buffer);
528     }
529     mac_block(&(c->cctx), c->buffer, data);
530     c->count = c->count % 1024 + 8;
531 }
532
533 int gost_imit_update(EVP_MD_CTX *ctx, const void *data, size_t count)
534 {
535     struct ossl_gost_imit_ctx *c = ctx->md_data;
536     const unsigned char *p = data;
537     size_t bytes = count, i;
538     if (!(c->key_set)) {
539         GOSTerr(GOST_F_GOST_IMIT_UPDATE, GOST_R_MAC_KEY_NOT_SET);
540         return 0;
541     }
542     if (c->bytes_left) {
543         for (i = c->bytes_left; i < 8 && bytes > 0; bytes--, i++, p++) {
544             c->partial_block[i] = *p;
545         }
546         if (i == 8) {
547             mac_block_mesh(c, c->partial_block);
548         } else {
549             c->bytes_left = i;
550             return 1;
551         }
552     }
553     while (bytes > 8) {
554         mac_block_mesh(c, p);
555         p += 8;
556         bytes -= 8;
557     }
558     if (bytes > 0) {
559         memcpy(c->partial_block, p, bytes);
560     }
561     c->bytes_left = bytes;
562     return 1;
563 }
564
565 int gost_imit_final(EVP_MD_CTX *ctx, unsigned char *md)
566 {
567     struct ossl_gost_imit_ctx *c = ctx->md_data;
568     if (!c->key_set) {
569         GOSTerr(GOST_F_GOST_IMIT_FINAL, GOST_R_MAC_KEY_NOT_SET);
570         return 0;
571     }
572     if (c->count == 0 && c->bytes_left) {
573         unsigned char buffer[8];
574         memset(buffer, 0, 8);
575         gost_imit_update(ctx, buffer, 8);
576     }
577     if (c->bytes_left) {
578         int i;
579         for (i = c->bytes_left; i < 8; i++) {
580             c->partial_block[i] = 0;
581         }
582         mac_block_mesh(c, c->partial_block);
583     }
584     get_mac(c->buffer, 32, md);
585     return 1;
586 }
587
588 int gost_imit_ctrl(EVP_MD_CTX *ctx, int type, int arg, void *ptr)
589 {
590     switch (type) {
591     case EVP_MD_CTRL_KEY_LEN:
592         *((unsigned int *)(ptr)) = 32;
593         return 1;
594     case EVP_MD_CTRL_SET_KEY:
595         {
596             if (arg != 32) {
597                 GOSTerr(GOST_F_GOST_IMIT_CTRL, GOST_R_INVALID_MAC_KEY_LENGTH);
598                 return 0;
599             }
600
601             gost_key(&(((struct ossl_gost_imit_ctx *)(ctx->md_data))->cctx),
602                      ptr);
603             ((struct ossl_gost_imit_ctx *)(ctx->md_data))->key_set = 1;
604             return 1;
605
606         }
607     default:
608         return 0;
609     }
610 }
611
612 int gost_imit_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from)
613 {
614     memcpy(to->md_data, from->md_data, sizeof(struct ossl_gost_imit_ctx));
615     return 1;
616 }
617
618 /* Clean up imit ctx */
619 int gost_imit_cleanup(EVP_MD_CTX *ctx)
620 {
621     memset(ctx->md_data, 0, sizeof(struct ossl_gost_imit_ctx));
622     return 1;
623 }