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