1 /**********************************************************************
3 * Copyright (c) 2005-2006 Cryptocom LTD *
4 * This file is distributed under the same license as OpenSSL *
6 * OpenSSL interface to GOST 28147-89 cipher functions *
7 * Requires OpenSSL 0.9.9 for compilation *
8 **********************************************************************/
11 #include <openssl/rand.h>
12 #include "e_gost_err.h"
15 #if !defined(CCGOST_DEBUG) && !defined(DEBUG)
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
);
40 EVP_CIPHER cipher_gost
= {
45 EVP_CIPH_CFB_MODE
| EVP_CIPH_NO_PADDING
|
46 EVP_CIPH_CUSTOM_IV
| EVP_CIPH_RAND_KEY
| EVP_CIPH_ALWAYS_CALL_INIT
,
50 sizeof(struct ossl_gost_cipher_ctx
), /* ctx_size */
51 gost89_set_asn1_parameters
,
52 gost89_get_asn1_parameters
,
57 EVP_CIPHER cipher_gost_cpacnt
= {
62 EVP_CIPH_OFB_MODE
| EVP_CIPH_NO_PADDING
|
63 EVP_CIPH_CUSTOM_IV
| EVP_CIPH_RAND_KEY
| EVP_CIPH_ALWAYS_CALL_INIT
,
67 sizeof(struct ossl_gost_cipher_ctx
), /* ctx_size */
68 gost89_set_asn1_parameters
,
69 gost89_get_asn1_parameters
,
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
);
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
);
87 EVP_MD imit_gost_cpa
= {
88 NID_id_Gost28147_89_MAC
,
101 sizeof(struct ossl_gost_imit_ctx
),
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
111 struct gost_cipher_info gost_cipher_list
[] = {
118 * {NID_id_GostR3411_94_CryptoProParamSet,&GostR3411_94_CryptoProParamSet,0},
120 {NID_id_Gost28147_89_cc
, &GostR3411_94_CryptoProParamSet
, 0},
121 {NID_id_Gost28147_89_CryptoPro_A_ParamSet
, &Gost28147_CryptoProParamSetA
,
123 {NID_id_Gost28147_89_CryptoPro_B_ParamSet
, &Gost28147_CryptoProParamSetB
,
125 {NID_id_Gost28147_89_CryptoPro_C_ParamSet
, &Gost28147_CryptoProParamSetC
,
127 {NID_id_Gost28147_89_CryptoPro_D_ParamSet
, &Gost28147_CryptoProParamSetD
,
129 {NID_id_Gost28147_89_TestParamSet
, &Gost28147_TestParamSet
, 1},
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
139 const struct gost_cipher_info
*get_encryption_params(ASN1_OBJECT
*obj
)
142 struct gost_cipher_info
*param
;
144 const char *params
= get_gost_engine_param(GOST_PARAM_CRYPT_PARAMS
);
145 if (!params
|| !strlen(params
))
146 return &gost_cipher_list
[1];
148 nid
= OBJ_txt2nid(params
);
149 if (nid
== NID_undef
) {
150 GOSTerr(GOST_F_GET_ENCRYPTION_PARAMS
,
151 GOST_R_INVALID_CIPHER_PARAM_OID
);
155 nid
= OBJ_obj2nid(obj
);
157 for (param
= gost_cipher_list
; param
->sblock
!= NULL
&& param
->nid
!= nid
;
159 if (!param
->sblock
) {
160 GOSTerr(GOST_F_GET_ENCRYPTION_PARAMS
, GOST_R_INVALID_CIPHER_PARAMS
);
166 /* Sets cipher param from paramset NID. */
167 static int gost_cipher_set_param(struct ossl_gost_cipher_ctx
*c
, int nid
)
169 const struct gost_cipher_info
*param
;
171 get_encryption_params((nid
== NID_undef
? NULL
: OBJ_nid2obj(nid
)));
175 c
->paramNID
= param
->nid
;
176 c
->key_meshing
= param
->key_meshing
;
178 gost_init(&(c
->cctx
), param
->sblock
);
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
)
188 struct ossl_gost_cipher_ctx
*c
= ctx
->cipher_data
;
189 if (ctx
->app_data
== NULL
) {
190 if (!gost_cipher_set_param(c
, paramNID
))
192 ctx
->app_data
= ctx
->cipher_data
;
195 gost_key(&(c
->cctx
), key
);
197 memcpy(ctx
->oiv
, iv
, EVP_CIPHER_CTX_iv_length(ctx
));
198 memcpy(ctx
->iv
, ctx
->oiv
, EVP_CIPHER_CTX_iv_length(ctx
));
202 static int gost_cipher_init_cpa(EVP_CIPHER_CTX
*ctx
, const unsigned char *key
,
203 const unsigned char *iv
, int enc
)
205 struct ossl_gost_cipher_ctx
*c
= ctx
->cipher_data
;
206 gost_init(&(c
->cctx
), &Gost28147_CryptoProParamSetA
);
210 gost_key(&(c
->cctx
), key
);
212 memcpy(ctx
->oiv
, iv
, EVP_CIPHER_CTX_iv_length(ctx
));
213 memcpy(ctx
->iv
, ctx
->oiv
, EVP_CIPHER_CTX_iv_length(ctx
));
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
)
221 return gost_cipher_init_param(ctx
, key
, iv
, enc
, NID_undef
,
226 * Wrapper around gostcrypt function from gost89.c which perform key meshing
229 static void gost_crypt_mesh(void *ctx
, unsigned char *iv
, unsigned char *buf
)
231 struct ossl_gost_cipher_ctx
*c
= ctx
;
232 assert(c
->count
% 8 == 0 && c
->count
<= 1024);
233 if (c
->key_meshing
&& c
->count
== 1024) {
234 cryptopro_key_meshing(&(c
->cctx
), iv
);
236 gostcrypt(&(c
->cctx
), iv
, buf
);
237 c
->count
= c
->count
% 1024 + 8;
240 static void gost_cnt_next(void *ctx
, unsigned char *iv
, unsigned char *buf
)
242 struct ossl_gost_cipher_ctx
*c
= ctx
;
244 unsigned char buf1
[8];
245 assert(c
->count
% 8 == 0 && c
->count
<= 1024);
246 if (c
->key_meshing
&& c
->count
== 1024) {
247 cryptopro_key_meshing(&(c
->cctx
), iv
);
250 gostcrypt(&(c
->cctx
), iv
, buf1
);
254 g
= buf1
[0] | (buf1
[1] << 8) | (buf1
[2] << 16) | (buf1
[3] << 24);
256 buf1
[0] = (unsigned char)(g
& 0xff);
257 buf1
[1] = (unsigned char)((g
>> 8) & 0xff);
258 buf1
[2] = (unsigned char)((g
>> 16) & 0xff);
259 buf1
[3] = (unsigned char)((g
>> 24) & 0xff);
260 g
= buf1
[4] | (buf1
[5] << 8) | (buf1
[6] << 16) | (buf1
[7] << 24);
263 if (go
> g
) /* overflow */
265 buf1
[4] = (unsigned char)(g
& 0xff);
266 buf1
[5] = (unsigned char)((g
>> 8) & 0xff);
267 buf1
[6] = (unsigned char)((g
>> 16) & 0xff);
268 buf1
[7] = (unsigned char)((g
>> 24) & 0xff);
270 gostcrypt(&(c
->cctx
), buf1
, buf
);
271 c
->count
= c
->count
% 1024 + 8;
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
)
278 const unsigned char *in_ptr
= in
;
279 unsigned char *out_ptr
= out
;
282 /* process partial block if any */
284 for (j
= ctx
->num
, i
= 0; j
< 8 && i
< inl
;
285 j
++, i
++, in_ptr
++, out_ptr
++) {
287 ctx
->buf
[j
+ 8] = *in_ptr
;
288 *out_ptr
= ctx
->buf
[j
] ^ (*in_ptr
);
290 ctx
->buf
[j
+ 8] = *out_ptr
;
293 memcpy(ctx
->iv
, ctx
->buf
+ 8, 8);
301 for (; i
+ 8 < inl
; i
+= 8, in_ptr
+= 8, out_ptr
+= 8) {
303 * block cipher current iv
305 gost_crypt_mesh(ctx
->cipher_data
, ctx
->iv
, ctx
->buf
);
307 * xor next block of input text with it and output it
313 memcpy(ctx
->iv
, in_ptr
, 8);
314 for (j
= 0; j
< 8; j
++) {
315 out_ptr
[j
] = ctx
->buf
[j
] ^ in_ptr
[j
];
318 /* Next iv is next block of cipher text */
320 memcpy(ctx
->iv
, out_ptr
, 8);
322 /* Process rest of buffer */
324 gost_crypt_mesh(ctx
->cipher_data
, ctx
->iv
, ctx
->buf
);
326 memcpy(ctx
->buf
+ 8, in_ptr
, inl
- i
);
327 for (j
= 0; i
< inl
; j
++, i
++) {
328 out_ptr
[j
] = ctx
->buf
[j
] ^ in_ptr
[j
];
332 memcpy(ctx
->buf
+ 8, out_ptr
, j
);
339 static int gost_cipher_do_cnt(EVP_CIPHER_CTX
*ctx
, unsigned char *out
,
340 const unsigned char *in
, size_t inl
)
342 const unsigned char *in_ptr
= in
;
343 unsigned char *out_ptr
= out
;
346 /* process partial block if any */
348 for (j
= ctx
->num
, i
= 0; j
< 8 && i
< inl
;
349 j
++, i
++, in_ptr
++, out_ptr
++) {
350 *out_ptr
= ctx
->buf
[j
] ^ (*in_ptr
);
360 for (; i
+ 8 < inl
; i
+= 8, in_ptr
+= 8, out_ptr
+= 8) {
362 * block cipher current iv
365 gost_cnt_next(ctx
->cipher_data
, ctx
->iv
, ctx
->buf
);
367 * xor next block of input text with it and output it
372 for (j
= 0; j
< 8; j
++) {
373 out_ptr
[j
] = ctx
->buf
[j
] ^ in_ptr
[j
];
376 /* Process rest of buffer */
378 gost_cnt_next(ctx
->cipher_data
, ctx
->iv
, ctx
->buf
);
379 for (j
= 0; i
< inl
; j
++, i
++) {
380 out_ptr
[j
] = ctx
->buf
[j
] ^ in_ptr
[j
];
389 /* Cleaning up of EVP_CIPHER_CTX */
390 int gost_cipher_cleanup(EVP_CIPHER_CTX
*ctx
)
392 gost_destroy(&((struct ossl_gost_cipher_ctx
*)ctx
->cipher_data
)->cctx
);
393 ctx
->app_data
= NULL
;
397 /* Control function for gost cipher */
398 int gost_cipher_ctl(EVP_CIPHER_CTX
*ctx
, int type
, int arg
, void *ptr
)
401 case EVP_CTRL_RAND_KEY
:
403 if (RAND_bytes((unsigned char *)ptr
, ctx
->key_len
) <= 0) {
404 GOSTerr(GOST_F_GOST_CIPHER_CTL
,
405 GOST_R_RANDOM_GENERATOR_ERROR
);
410 case EVP_CTRL_PBE_PRF_NID
:
412 *((int *)ptr
) = NID_id_HMACGostR3411_94
;
419 GOSTerr(GOST_F_GOST_CIPHER_CTL
,
420 GOST_R_UNSUPPORTED_CIPHER_CTL_COMMAND
);
426 /* Set cipher parameters from ASN1 structure */
427 int gost89_set_asn1_parameters(EVP_CIPHER_CTX
*ctx
, ASN1_TYPE
*params
)
430 unsigned char *buf
= NULL
;
431 unsigned char *p
= NULL
;
432 struct ossl_gost_cipher_ctx
*c
= ctx
->cipher_data
;
433 GOST_CIPHER_PARAMS
*gcp
= GOST_CIPHER_PARAMS_new();
434 ASN1_OCTET_STRING
*os
= NULL
;
436 GOSTerr(GOST_F_GOST89_SET_ASN1_PARAMETERS
, GOST_R_NO_MEMORY
);
439 if (!ASN1_OCTET_STRING_set(gcp
->iv
, ctx
->iv
, ctx
->cipher
->iv_len
)) {
440 GOST_CIPHER_PARAMS_free(gcp
);
441 GOSTerr(GOST_F_GOST89_SET_ASN1_PARAMETERS
, GOST_R_NO_MEMORY
);
444 ASN1_OBJECT_free(gcp
->enc_param_set
);
445 gcp
->enc_param_set
= OBJ_nid2obj(c
->paramNID
);
447 len
= i2d_GOST_CIPHER_PARAMS(gcp
, NULL
);
448 p
= buf
= (unsigned char *)OPENSSL_malloc(len
);
450 GOST_CIPHER_PARAMS_free(gcp
);
451 GOSTerr(GOST_F_GOST89_SET_ASN1_PARAMETERS
, GOST_R_NO_MEMORY
);
454 i2d_GOST_CIPHER_PARAMS(gcp
, &p
);
455 GOST_CIPHER_PARAMS_free(gcp
);
457 os
= ASN1_OCTET_STRING_new();
459 if (!os
|| !ASN1_OCTET_STRING_set(os
, buf
, len
)) {
461 GOSTerr(GOST_F_GOST89_SET_ASN1_PARAMETERS
, GOST_R_NO_MEMORY
);
466 ASN1_TYPE_set(params
, V_ASN1_SEQUENCE
, os
);
470 /* Store parameters into ASN1 structure */
471 int gost89_get_asn1_parameters(EVP_CIPHER_CTX
*ctx
, ASN1_TYPE
*params
)
475 GOST_CIPHER_PARAMS
*gcp
= NULL
;
477 struct ossl_gost_cipher_ctx
*c
= ctx
->cipher_data
;
478 if (ASN1_TYPE_get(params
) != V_ASN1_SEQUENCE
) {
482 p
= params
->value
.sequence
->data
;
484 gcp
= d2i_GOST_CIPHER_PARAMS(NULL
, (const unsigned char **)&p
,
485 params
->value
.sequence
->length
);
487 len
= gcp
->iv
->length
;
488 if (len
!= ctx
->cipher
->iv_len
) {
489 GOST_CIPHER_PARAMS_free(gcp
);
490 GOSTerr(GOST_F_GOST89_GET_ASN1_PARAMETERS
, GOST_R_INVALID_IV_LENGTH
);
493 if (!gost_cipher_set_param(c
, OBJ_obj2nid(gcp
->enc_param_set
))) {
494 GOST_CIPHER_PARAMS_free(gcp
);
497 memcpy(ctx
->oiv
, gcp
->iv
->data
, len
);
499 GOST_CIPHER_PARAMS_free(gcp
);
504 int gost_imit_init_cpa(EVP_MD_CTX
*ctx
)
506 struct ossl_gost_imit_ctx
*c
= ctx
->md_data
;
507 memset(c
->buffer
, 0, sizeof(c
->buffer
));
508 memset(c
->partial_block
, 0, sizeof(c
->partial_block
));
512 gost_init(&(c
->cctx
), &Gost28147_CryptoProParamSetA
);
516 static void mac_block_mesh(struct ossl_gost_imit_ctx
*c
,
517 const unsigned char *data
)
519 unsigned char buffer
[8];
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
525 assert(c
->count
% 8 == 0 && c
->count
<= 1024);
526 if (c
->key_meshing
&& c
->count
== 1024) {
527 cryptopro_key_meshing(&(c
->cctx
), buffer
);
529 mac_block(&(c
->cctx
), c
->buffer
, data
);
530 c
->count
= c
->count
% 1024 + 8;
533 int gost_imit_update(EVP_MD_CTX
*ctx
, const void *data
, size_t count
)
535 struct ossl_gost_imit_ctx
*c
= ctx
->md_data
;
536 const unsigned char *p
= data
;
537 size_t bytes
= count
, i
;
539 GOSTerr(GOST_F_GOST_IMIT_UPDATE
, GOST_R_MAC_KEY_NOT_SET
);
543 for (i
= c
->bytes_left
; i
< 8 && bytes
> 0; bytes
--, i
++, p
++) {
544 c
->partial_block
[i
] = *p
;
547 mac_block_mesh(c
, c
->partial_block
);
554 mac_block_mesh(c
, p
);
559 memcpy(c
->partial_block
, p
, bytes
);
561 c
->bytes_left
= bytes
;
565 int gost_imit_final(EVP_MD_CTX
*ctx
, unsigned char *md
)
567 struct ossl_gost_imit_ctx
*c
= ctx
->md_data
;
569 GOSTerr(GOST_F_GOST_IMIT_FINAL
, GOST_R_MAC_KEY_NOT_SET
);
572 if (c
->count
== 0 && c
->bytes_left
) {
573 unsigned char buffer
[8];
574 memset(buffer
, 0, 8);
575 gost_imit_update(ctx
, buffer
, 8);
579 for (i
= c
->bytes_left
; i
< 8; i
++) {
580 c
->partial_block
[i
] = 0;
582 mac_block_mesh(c
, c
->partial_block
);
584 get_mac(c
->buffer
, 32, md
);
588 int gost_imit_ctrl(EVP_MD_CTX
*ctx
, int type
, int arg
, void *ptr
)
591 case EVP_MD_CTRL_KEY_LEN
:
592 *((unsigned int *)(ptr
)) = 32;
594 case EVP_MD_CTRL_SET_KEY
:
597 GOSTerr(GOST_F_GOST_IMIT_CTRL
, GOST_R_INVALID_MAC_KEY_LENGTH
);
601 gost_key(&(((struct ossl_gost_imit_ctx
*)(ctx
->md_data
))->cctx
),
603 ((struct ossl_gost_imit_ctx
*)(ctx
->md_data
))->key_set
= 1;
612 int gost_imit_copy(EVP_MD_CTX
*to
, const EVP_MD_CTX
*from
)
614 memcpy(to
->md_data
, from
->md_data
, sizeof(struct ossl_gost_imit_ctx
));
618 /* Clean up imit ctx */
619 int gost_imit_cleanup(EVP_MD_CTX
*ctx
)
621 memset(ctx
->md_data
, 0, sizeof(struct ossl_gost_imit_ctx
));