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