]> www.wagner.pp.ru Git - openssl-gost/engine.git/blob - gost_crypt.c
Fixes of error codes. Check result of EC_POINT_mul
[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[4];
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, GOST_R_RNG_ERROR);
468                 return -1;
469             }
470             break;
471         }
472     case EVP_CTRL_PBE_PRF_NID:
473         if (ptr) {
474             const char *params = get_gost_engine_param(GOST_PARAM_PBE_PARAMS);
475             int nid = NID_id_tc26_hmac_gost_3411_2012_512;
476
477             if (params) {
478                 if (!strcmp("md_gost12_256", params))
479                     nid = NID_id_tc26_hmac_gost_3411_2012_256;
480                 else if (!strcmp("md_gost12_512", params))
481                     nid = NID_id_tc26_hmac_gost_3411_2012_512;
482                 else if (!strcmp("md_gost94", params))
483                     nid = NID_id_HMACGostR3411_94;
484             }
485             *((int *)ptr) = nid;
486             return 1;
487         } else {
488             return 0;
489         }
490
491     default:
492         GOSTerr(GOST_F_GOST_CIPHER_CTL,
493                 GOST_R_UNSUPPORTED_CIPHER_CTL_COMMAND);
494         return -1;
495     }
496     return 1;
497 }
498
499 /* Set cipher parameters from ASN1 structure */
500 int gost89_set_asn1_parameters(EVP_CIPHER_CTX *ctx, ASN1_TYPE *params)
501 {
502     int len = 0;
503     unsigned char *buf = NULL;
504     unsigned char *p = NULL;
505     struct ossl_gost_cipher_ctx *c = ctx->cipher_data;
506     GOST_CIPHER_PARAMS *gcp = GOST_CIPHER_PARAMS_new();
507     ASN1_OCTET_STRING *os = NULL;
508     if (!gcp) {
509         GOSTerr(GOST_F_GOST89_SET_ASN1_PARAMETERS, ERR_R_MALLOC_FAILURE);
510         return 0;
511     }
512     if (!ASN1_OCTET_STRING_set(gcp->iv, ctx->iv, ctx->cipher->iv_len)) {
513         GOST_CIPHER_PARAMS_free(gcp);
514         GOSTerr(GOST_F_GOST89_SET_ASN1_PARAMETERS, ERR_R_MALLOC_FAILURE);
515         return 0;
516     }
517     ASN1_OBJECT_free(gcp->enc_param_set);
518     gcp->enc_param_set = OBJ_nid2obj(c->paramNID);
519
520     len = i2d_GOST_CIPHER_PARAMS(gcp, NULL);
521     p = buf = OPENSSL_malloc(len);
522     if (!buf) {
523         GOST_CIPHER_PARAMS_free(gcp);
524         GOSTerr(GOST_F_GOST89_SET_ASN1_PARAMETERS, ERR_R_MALLOC_FAILURE);
525         return 0;
526     }
527     i2d_GOST_CIPHER_PARAMS(gcp, &p);
528     GOST_CIPHER_PARAMS_free(gcp);
529
530     os = ASN1_OCTET_STRING_new();
531
532     if (!os || !ASN1_OCTET_STRING_set(os, buf, len)) {
533         OPENSSL_free(buf);
534         GOSTerr(GOST_F_GOST89_SET_ASN1_PARAMETERS, ERR_R_MALLOC_FAILURE);
535         return 0;
536     }
537     OPENSSL_free(buf);
538
539     ASN1_TYPE_set(params, V_ASN1_SEQUENCE, os);
540     return 1;
541 }
542
543 /* Store parameters into ASN1 structure */
544 int gost89_get_asn1_parameters(EVP_CIPHER_CTX *ctx, ASN1_TYPE *params)
545 {
546     int ret = -1;
547     int len;
548     GOST_CIPHER_PARAMS *gcp = NULL;
549     unsigned char *p;
550     struct ossl_gost_cipher_ctx *c = ctx->cipher_data;
551     int nid;
552
553     if (ASN1_TYPE_get(params) != V_ASN1_SEQUENCE) {
554         return ret;
555     }
556
557     p = params->value.sequence->data;
558
559     gcp = d2i_GOST_CIPHER_PARAMS(NULL, (const unsigned char **)&p,
560                                  params->value.sequence->length);
561
562     len = gcp->iv->length;
563     if (len != ctx->cipher->iv_len) {
564         GOST_CIPHER_PARAMS_free(gcp);
565         GOSTerr(GOST_F_GOST89_GET_ASN1_PARAMETERS, GOST_R_INVALID_IV_LENGTH);
566         return -1;
567     }
568
569     nid = OBJ_obj2nid(gcp->enc_param_set);
570     if (nid == NID_undef) {
571         GOST_CIPHER_PARAMS_free(gcp);
572         GOSTerr(GOST_F_GOST89_GET_ASN1_PARAMETERS,
573                 GOST_R_INVALID_CIPHER_PARAM_OID);
574         return -1;
575     }
576
577     if (!gost_cipher_set_param(c, nid)) {
578         GOST_CIPHER_PARAMS_free(gcp);
579         return -1;
580     }
581     memcpy(ctx->oiv, gcp->iv->data, len);
582
583     GOST_CIPHER_PARAMS_free(gcp);
584
585     return 1;
586 }
587
588 static int gost_imit_init(EVP_MD_CTX *ctx, gost_subst_block * block)
589 {
590     struct ossl_gost_imit_ctx *c = ctx->md_data;
591     memset(c->buffer, 0, sizeof(c->buffer));
592     memset(c->partial_block, 0, sizeof(c->partial_block));
593     c->count = 0;
594     c->bytes_left = 0;
595     c->key_meshing = 1;
596     gost_init(&(c->cctx), block);
597     return 1;
598 }
599
600 static int gost_imit_init_cpa(EVP_MD_CTX *ctx)
601 {
602     return gost_imit_init(ctx, &Gost28147_CryptoProParamSetA);
603 }
604
605 static int gost_imit_init_cp_12(EVP_MD_CTX *ctx)
606 {
607     return gost_imit_init(ctx, &Gost28147_TC26ParamSetZ);
608 }
609
610 static void mac_block_mesh(struct ossl_gost_imit_ctx *c,
611                            const unsigned char *data)
612 {
613     unsigned char buffer[8];
614     /*
615      * We are using local buffer for iv because CryptoPro doesn't interpret
616      * internal state of MAC algorithm as iv during keymeshing (but does
617      * initialize internal state from iv in key transport
618      */
619     assert(c->count % 8 == 0 && c->count <= 1024);
620     if (c->key_meshing && c->count == 1024) {
621         cryptopro_key_meshing(&(c->cctx), buffer);
622     }
623     mac_block(&(c->cctx), c->buffer, data);
624     c->count = c->count % 1024 + 8;
625 }
626
627 int gost_imit_update(EVP_MD_CTX *ctx, const void *data, size_t count)
628 {
629     struct ossl_gost_imit_ctx *c = ctx->md_data;
630     const unsigned char *p = data;
631     size_t bytes = count, i;
632     if (!(c->key_set)) {
633         GOSTerr(GOST_F_GOST_IMIT_UPDATE, GOST_R_MAC_KEY_NOT_SET);
634         return 0;
635     }
636     if (c->bytes_left) {
637         for (i = c->bytes_left; i < 8 && bytes > 0; bytes--, i++, p++) {
638             c->partial_block[i] = *p;
639         }
640         if (i == 8) {
641             mac_block_mesh(c, c->partial_block);
642         } else {
643             c->bytes_left = i;
644             return 1;
645         }
646     }
647     while (bytes > 8) {
648         mac_block_mesh(c, p);
649         p += 8;
650         bytes -= 8;
651     }
652     if (bytes > 0) {
653         memcpy(c->partial_block, p, bytes);
654     }
655     c->bytes_left = bytes;
656     return 1;
657 }
658
659 int gost_imit_final(EVP_MD_CTX *ctx, unsigned char *md)
660 {
661     struct ossl_gost_imit_ctx *c = ctx->md_data;
662     if (!c->key_set) {
663         GOSTerr(GOST_F_GOST_IMIT_FINAL, GOST_R_MAC_KEY_NOT_SET);
664         return 0;
665     }
666     if (c->count == 0 && c->bytes_left) {
667         unsigned char buffer[8];
668         memset(buffer, 0, 8);
669         gost_imit_update(ctx, buffer, 8);
670     }
671     if (c->bytes_left) {
672         int i;
673         for (i = c->bytes_left; i < 8; i++) {
674             c->partial_block[i] = 0;
675         }
676         mac_block_mesh(c, c->partial_block);
677     }
678     get_mac(c->buffer, 32, md);
679     return 1;
680 }
681
682 int gost_imit_ctrl(EVP_MD_CTX *ctx, int type, int arg, void *ptr)
683 {
684     switch (type) {
685     case EVP_MD_CTRL_KEY_LEN:
686         *((unsigned int *)(ptr)) = 32;
687         return 1;
688     case EVP_MD_CTRL_SET_KEY:
689         {
690             if (arg != 32) {
691                 GOSTerr(GOST_F_GOST_IMIT_CTRL, GOST_R_INVALID_MAC_KEY_LENGTH);
692                 return 0;
693             }
694
695             gost_key(&(((struct ossl_gost_imit_ctx *)(ctx->md_data))->cctx),
696                      ptr);
697             ((struct ossl_gost_imit_ctx *)(ctx->md_data))->key_set = 1;
698             return 1;
699
700         }
701     default:
702         return 0;
703     }
704 }
705
706 int gost_imit_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from)
707 {
708     memcpy(to->md_data, from->md_data, sizeof(struct ossl_gost_imit_ctx));
709     return 1;
710 }
711
712 /* Clean up imit ctx */
713 int gost_imit_cleanup(EVP_MD_CTX *ctx)
714 {
715     memset(ctx->md_data, 0, sizeof(struct ossl_gost_imit_ctx));
716     return 1;
717 }