1 /**********************************************************************
3 * Copyright (c) 2005-2006 Cryptocom LTD *
4 * This file is distributed under the same license as OpenSSL *
6 * VK0 34.10-2001 key exchange and GOST R 34.10-2001 *
7 * based PKCS7/SMIME support *
8 * Requires OpenSSL 0.9.9 for compilation *
9 **********************************************************************/
10 #include <openssl/evp.h>
11 #include <openssl/rand.h>
13 #include <openssl/objects.h>
16 #include "e_gost_err.h"
17 #include "gost_keywrap.h"
19 #include "gost2001_keyx.h"
21 /* Transform ECDH shared key into little endian as required by Cryptocom
23 static void *make_key_le(const void *in
, size_t inlen
, void *out
, size_t *outlen
)
25 const char* inbuf
= in
;
34 outbuf
[inlen
-1-i
]=inbuf
[i
];
40 /* Create gost 2001 ephemeral key with same parameters as peer key */
41 static EC_KEY
*make_ec_ephemeral_key(EC_KEY
*peer_key
,BIGNUM
*seckey
)
43 EC_KEY
*out
= EC_KEY_new();
44 EC_KEY_copy(out
,peer_key
);
45 EC_KEY_set_private_key(out
,seckey
);
46 gost2001_compute_public(out
);
49 /* Packs GOST elliptic curve key into EVP_PKEY setting same parameters
52 static EVP_PKEY
*ec_ephemeral_key_to_EVP(EVP_PKEY
*pubk
,int type
,EC_KEY
*ephemeral
)
55 newkey
= EVP_PKEY_new();
56 EVP_PKEY_assign(newkey
,type
,ephemeral
);
61 * EVP_PKEY_METHOD callback encrypt
62 * Implementation of GOST2001 key transport, cryptocom variation
65 int pkey_GOST01cc_encrypt (EVP_PKEY_CTX
*pctx
,unsigned char *out
,
66 size_t *out_len
, const unsigned char *key
,size_t key_len
)
68 EVP_PKEY
*pubk
= EVP_PKEY_CTX_get0_pkey(pctx
);
69 struct gost_pmeth_data
*data
= EVP_PKEY_CTX_get_data(pctx
);
70 GOST_KEY_TRANSPORT
*gkt
= NULL
;
73 EC_KEY
*ephemeral
=NULL
;
74 const EC_POINT
*pub_key_point
=NULL
;
75 unsigned char shared_key
[32],encrypted_key
[32],hmac
[4],
76 iv
[8]={0,0,0,0,0,0,0,0};
77 ephemeral
= make_ec_ephemeral_key(EVP_PKEY_get0(pubk
), gost_get_priv_key(data
->eph_seckey
));
78 if (!ephemeral
) goto err
;
79 /* compute shared key */
80 pub_key_point
=EC_KEY_get0_public_key(EVP_PKEY_get0(pubk
));
81 if (!ECDH_compute_key(shared_key
,32,pub_key_point
,ephemeral
,make_key_le
))
83 GOSTerr(GOST_F_PKEY_GOST01CC_ENCRYPT
,GOST_R_ERROR_COMPUTING_SHARED_KEY
);
86 /* encrypt session key */
87 gost_init(&ctx
, &GostR3411_94_CryptoProParamSet
);
88 gost_key(&ctx
,shared_key
);
89 encrypt_cryptocom_key(key
,key_len
,encrypted_key
,&ctx
);
90 /* compute hmac of session key */
91 if (!gost_mac(&ctx
,32,key
,32,hmac
))
93 GOSTerr(GOST_F_PKEY_GOST01CC_ENCRYPT
,GOST_R_ERROR_COMPUTING_MAC
);
96 gkt
= GOST_KEY_TRANSPORT_new();
99 GOSTerr(GOST_F_PKEY_GOST01CC_ENCRYPT
,GOST_R_NO_MEMORY
);
102 /* Store IV which is always zero in our case */
103 if (!ASN1_OCTET_STRING_set(gkt
->key_agreement_info
->eph_iv
,iv
,8))
105 GOSTerr(GOST_F_PKEY_GOST01CC_ENCRYPT
,GOST_R_ERROR_STORING_IV
);
108 if (!ASN1_OCTET_STRING_set(gkt
->key_info
->imit
,hmac
,4))
110 GOSTerr(GOST_F_PKEY_GOST01CC_ENCRYPT
,GOST_R_ERROR_STORING_MAC
);
113 if (!ASN1_OCTET_STRING_set(gkt
->key_info
->encrypted_key
,encrypted_key
,32))
115 GOSTerr(GOST_F_PKEY_GOST01CC_ENCRYPT
,GOST_R_ERROR_STORING_ENCRYPTED_KEY
);
119 if (!X509_PUBKEY_set(&gkt
->key_agreement_info
->ephem_key
,data
->eph_seckey
))
121 GOSTerr(GOST_F_PKEY_GOST01CC_ENCRYPT
,GOST_R_CANNOT_PACK_EPHEMERAL_KEY
);
124 ASN1_OBJECT_free(gkt
->key_agreement_info
->cipher
);
125 gkt
->key_agreement_info
->cipher
= OBJ_nid2obj(NID_id_Gost28147_89_cc
);
126 if ((*out_len
= i2d_GOST_KEY_TRANSPORT(gkt
,&out
))>0) ret
= 1;
129 if (gkt
) GOST_KEY_TRANSPORT_free(gkt
);
133 * EVP_PKEY_METHOD callback decrypt
134 * Implementation of GOST2001 key transport, cryptocom variation
136 int pkey_GOST01cc_decrypt (EVP_PKEY_CTX
*pctx
, unsigned char *key
, size_t *key_len
, const unsigned char *in
, size_t in_len
)
138 /* Form DH params from compute shared key */
139 EVP_PKEY
*priv
=EVP_PKEY_CTX_get0_pkey(pctx
);
140 GOST_KEY_TRANSPORT
*gkt
= NULL
;
141 const unsigned char *p
=in
;
142 unsigned char shared_key
[32];
143 unsigned char hmac
[4],hmac_comp
[4];
147 const EC_POINT
*pub_key_point
;
155 /* Parse passed octet string and find out public key, iv and HMAC*/
156 gkt
= d2i_GOST_KEY_TRANSPORT(NULL
,(const unsigned char **)&p
,
160 GOSTerr(GOST_F_PKEY_GOST01CC_DECRYPT
,GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO
);
163 eph_key
= X509_PUBKEY_get(gkt
->key_agreement_info
->ephem_key
);
164 /* Initialization vector is really ignored here */
165 OPENSSL_assert(gkt
->key_agreement_info
->eph_iv
->length
==8);
166 memcpy(iv
,gkt
->key_agreement_info
->eph_iv
->data
,8);
167 /* HMAC should be computed and checked */
168 OPENSSL_assert(gkt
->key_info
->imit
->length
==4);
169 memcpy(hmac
,gkt
->key_info
->imit
->data
,4);
170 /* Compute shared key */
171 pub_key_point
=EC_KEY_get0_public_key(EVP_PKEY_get0(eph_key
));
172 i
=ECDH_compute_key(shared_key
,32,pub_key_point
,EVP_PKEY_get0(priv
),make_key_le
);
173 EVP_PKEY_free(eph_key
);
176 GOSTerr(GOST_F_PKEY_GOST01CC_DECRYPT
,GOST_R_ERROR_COMPUTING_SHARED_KEY
);
177 GOST_KEY_TRANSPORT_free(gkt
);
180 /* Decrypt session key */
181 gost_init(&ctx
, &GostR3411_94_CryptoProParamSet
);
182 gost_key(&ctx
,shared_key
);
184 if (!decrypt_cryptocom_key(key
,*key_len
,gkt
->key_info
->encrypted_key
->data
,
185 gkt
->key_info
->encrypted_key
->length
, &ctx
))
187 GOST_KEY_TRANSPORT_free(gkt
);
190 GOST_KEY_TRANSPORT_free(gkt
);
191 /* check HMAC of session key*/
192 if (!gost_mac(&ctx
,32,key
,32,hmac_comp
))
194 GOSTerr(GOST_F_PKEY_GOST01CC_DECRYPT
,GOST_R_ERROR_COMPUTING_MAC
);
197 /* HMAC of session key is not correct */
198 if (memcmp(hmac
,hmac_comp
,4)!=0)
200 GOSTerr(GOST_F_PKEY_GOST01CC_DECRYPT
,GOST_R_SESSION_KEY_MAC_DOES_NOT_MATCH
);
206 /* Implementation of CryptoPro VKO 34.10-2001 algorithm */
207 static int VKO_compute_key(unsigned char *shared_key
,size_t shared_key_size
,const EC_POINT
*pub_key
,EC_KEY
*priv_key
,const unsigned char *ukm
)
209 unsigned char ukm_be
[8],databuf
[64],hashbuf
[64];
210 BIGNUM
*UKM
=NULL
,*p
=NULL
,*order
=NULL
,*X
=NULL
,*Y
=NULL
;
211 const BIGNUM
* key
=EC_KEY_get0_private_key(priv_key
);
212 EC_POINT
*pnt
=EC_POINT_new(EC_KEY_get0_group(priv_key
));
214 gost_hash_ctx hash_ctx
;
215 BN_CTX
*ctx
= BN_CTX_new();
222 UKM
=getbnfrombuf(ukm_be
,8);
224 order
= BN_CTX_get(ctx
);
227 EC_GROUP_get_order(EC_KEY_get0_group(priv_key
),order
,ctx
);
228 BN_mod_mul(p
,key
,UKM
,order
,ctx
);
229 EC_POINT_mul(EC_KEY_get0_group(priv_key
),pnt
,NULL
,pub_key
,p
,ctx
);
230 EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(priv_key
),
232 /*Serialize elliptic curve point same way as we do it when saving
234 store_bignum(Y
,databuf
,32);
235 store_bignum(X
,databuf
+32,32);
236 /* And reverse byte order of whole buffer */
239 hashbuf
[63-i
]=databuf
[i
];
241 init_gost_hash_ctx(&hash_ctx
,&GostR3411_94_CryptoProParamSet
);
242 start_hash(&hash_ctx
);
243 hash_block(&hash_ctx
,hashbuf
,64);
244 finish_hash(&hash_ctx
,shared_key
);
245 done_gost_hash_ctx(&hash_ctx
);
253 /* Generates ephemeral key based on pubk algorithm
254 * computes shared key using VKO and returns filled up
255 * GOST_KEY_TRANSPORT structure
257 /* Public, because it would be needed in SSL implementation */
258 GOST_KEY_TRANSPORT
*make_rfc4490_keytransport_2001(EVP_PKEY
*pubk
,BIGNUM
*eph_key
,
259 const unsigned char *key
,size_t keylen
, unsigned char *ukm
,
263 const struct gost_cipher_info
*param
=get_encryption_params(NULL
);
264 EC_KEY
*ephemeral
= NULL
;
265 GOST_KEY_TRANSPORT
*gkt
=NULL
;
266 const EC_POINT
*pub_key_point
= EC_KEY_get0_public_key(EVP_PKEY_get0(pubk
));
267 unsigned char shared_key
[32],crypted_key
[44];
269 EVP_PKEY
*newkey
=NULL
;
271 /* Do not use vizir cipher parameters with cryptopro */
272 if (!get_gost_engine_param(GOST_PARAM_CRYPT_PARAMS
) && param
== gost_cipher_list
)
274 param
= gost_cipher_list
+1;
276 ephemeral
= make_ec_ephemeral_key(EVP_PKEY_get0(pubk
),eph_key
);
277 VKO_compute_key(shared_key
,32,pub_key_point
,ephemeral
,ukm
);
278 gost_init(&ctx
,param
->sblock
);
279 keyWrapCryptoPro(&ctx
,shared_key
,ukm
,key
,crypted_key
);
280 gkt
= GOST_KEY_TRANSPORT_new();
285 if(!ASN1_OCTET_STRING_set(gkt
->key_agreement_info
->eph_iv
,
290 if (!ASN1_OCTET_STRING_set(gkt
->key_info
->imit
,crypted_key
+40,4))
294 if (!ASN1_OCTET_STRING_set(gkt
->key_info
->encrypted_key
,crypted_key
+8,32))
298 newkey
= ec_ephemeral_key_to_EVP(pubk
,NID_id_GostR3410_2001
,ephemeral
);
299 if (!X509_PUBKEY_set(&gkt
->key_agreement_info
->ephem_key
,newkey
))
301 GOSTerr(GOST_F_MAKE_RFC4490_KEYTRANSPORT_2001
,GOST_R_CANNOT_PACK_EPHEMERAL_KEY
);
304 ASN1_OBJECT_free(gkt
->key_agreement_info
->cipher
);
305 gkt
->key_agreement_info
->cipher
= OBJ_nid2obj(param
->nid
);
306 EVP_PKEY_free(newkey
);
309 GOSTerr(GOST_F_MAKE_RFC4490_KEYTRANSPORT_2001
,
310 GOST_R_MALLOC_FAILURE
);
312 GOST_KEY_TRANSPORT_free(gkt
);
317 * EVP_PKEY_METHOD callback encrypt
318 * Implementation of GOST2001 key transport, cryptopo variation
321 int pkey_GOST01cp_encrypt (EVP_PKEY_CTX
*pctx
, unsigned char *out
, size_t *out_len
, const unsigned char *key
,size_t key_len
)
323 GOST_KEY_TRANSPORT
*gkt
=NULL
;
324 EVP_PKEY
*pubk
= EVP_PKEY_CTX_get0_pkey(pctx
);
325 struct gost_pmeth_data
*data
= EVP_PKEY_CTX_get_data(pctx
);
326 unsigned char ukm
[8];
328 if (RAND_bytes(ukm
,8)<=0)
330 GOSTerr(GOST_F_PKEY_GOST01CP_ENCRYPT
,
331 GOST_R_RANDOM_GENERATOR_FAILURE
);
335 if (!(gkt
=make_rfc4490_keytransport_2001(pubk
,gost_get_priv_key(data
->eph_seckey
),key
, key_len
,ukm
,8)))
339 if ((*out_len
= i2d_GOST_KEY_TRANSPORT(gkt
,&out
))>0) ret
=1;
340 GOST_KEY_TRANSPORT_free(gkt
);
343 GOST_KEY_TRANSPORT_free(gkt
);
346 /* Public, because it would be needed in SSL implementation */
347 int decrypt_rfc4490_shared_key_2001(EVP_PKEY
*priv
,GOST_KEY_TRANSPORT
*gkt
,
348 unsigned char *key_buf
,int key_buf_len
)
350 unsigned char wrappedKey
[44];
351 unsigned char sharedKey
[32];
353 const struct gost_cipher_info
*param
=NULL
;
354 EVP_PKEY
*eph_key
=NULL
;
356 eph_key
= X509_PUBKEY_get(gkt
->key_agreement_info
->ephem_key
);
357 param
= get_encryption_params(gkt
->key_agreement_info
->cipher
);
358 gost_init(&ctx
,param
->sblock
);
359 OPENSSL_assert(gkt
->key_agreement_info
->eph_iv
->length
==8);
360 memcpy(wrappedKey
,gkt
->key_agreement_info
->eph_iv
->data
,8);
361 OPENSSL_assert(gkt
->key_info
->encrypted_key
->length
==32);
362 memcpy(wrappedKey
+8,gkt
->key_info
->encrypted_key
->data
,32);
363 OPENSSL_assert(gkt
->key_info
->imit
->length
==4);
364 memcpy(wrappedKey
+40,gkt
->key_info
->imit
->data
,4);
365 VKO_compute_key(sharedKey
,32,EC_KEY_get0_public_key(EVP_PKEY_get0(eph_key
)),
366 EVP_PKEY_get0(priv
),wrappedKey
);
367 if (!keyUnwrapCryptoPro(&ctx
,sharedKey
,wrappedKey
,key_buf
))
369 GOSTerr(GOST_F_PKCS7_GOST94CP_KEY_TRANSPORT_DECRYPT
,
370 GOST_R_ERROR_COMPUTING_SHARED_KEY
);
374 EVP_PKEY_free(eph_key
);
377 EVP_PKEY_free(eph_key
);
381 * EVP_PKEY_METHOD callback decrypt
382 * Implementation of GOST2001 key transport, cryptopo variation
384 int pkey_GOST01cp_decrypt (EVP_PKEY_CTX
*pctx
, unsigned char *key
, size_t * key_len
, const unsigned char *in
, size_t in_len
)
386 const unsigned char *p
= in
;
387 EVP_PKEY
*priv
= EVP_PKEY_CTX_get0_pkey(pctx
);
388 GOST_KEY_TRANSPORT
*gkt
= NULL
;
396 gkt
= d2i_GOST_KEY_TRANSPORT(NULL
,(const unsigned char **)&p
,
400 GOSTerr(GOST_F_PKCS7_GOST94CP_KEY_TRANSPORT_DECRYPT
,GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO
);
403 ret
= decrypt_rfc4490_shared_key_2001(priv
,gkt
,key
,*key_len
);
404 GOST_KEY_TRANSPORT_free(gkt
);