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