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 /* Implementation of CryptoPro VKO 34.10-2001 algorithm */
22 static int VKO_compute_key(unsigned char *shared_key
, size_t shared_key_size
,
23 const EC_POINT
*pub_key
, EC_KEY
*priv_key
,
24 const unsigned char *ukm
)
26 unsigned char ukm_be
[8], databuf
[64], hashbuf
[64];
27 BIGNUM
*UKM
= NULL
, *p
= NULL
, *order
= NULL
, *X
= NULL
, *Y
= NULL
;
28 const BIGNUM
*key
= EC_KEY_get0_private_key(priv_key
);
29 EC_POINT
*pnt
= EC_POINT_new(EC_KEY_get0_group(priv_key
));
31 gost_hash_ctx hash_ctx
;
32 BN_CTX
*ctx
= BN_CTX_new();
34 for (i
= 0; i
< 8; i
++) {
35 ukm_be
[7 - i
] = ukm
[i
];
38 UKM
= getbnfrombuf(ukm_be
, 8);
40 order
= BN_CTX_get(ctx
);
43 EC_GROUP_get_order(EC_KEY_get0_group(priv_key
), order
, ctx
);
44 BN_mod_mul(p
, key
, UKM
, order
, ctx
);
45 EC_POINT_mul(EC_KEY_get0_group(priv_key
), pnt
, NULL
, pub_key
, p
, ctx
);
46 EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(priv_key
),
49 * Serialize elliptic curve point same way as we do it when saving key
51 store_bignum(Y
, databuf
, 32);
52 store_bignum(X
, databuf
+ 32, 32);
53 /* And reverse byte order of whole buffer */
54 for (i
= 0; i
< 64; i
++) {
55 hashbuf
[63 - i
] = databuf
[i
];
57 init_gost_hash_ctx(&hash_ctx
, &GostR3411_94_CryptoProParamSet
);
58 start_hash(&hash_ctx
);
59 hash_block(&hash_ctx
, hashbuf
, 64);
60 finish_hash(&hash_ctx
, shared_key
);
61 done_gost_hash_ctx(&hash_ctx
);
70 * EVP_PKEY_METHOD callback derive. Implements VKO R 34.10-2001
73 int pkey_gost2001_derive(EVP_PKEY_CTX
*ctx
, unsigned char *key
,
77 * Public key of peer in the ctx field peerkey Our private key in the ctx
78 * pkey ukm is in the algorithm specific context data
80 EVP_PKEY
*my_key
= EVP_PKEY_CTX_get0_pkey(ctx
);
81 EVP_PKEY
*peer_key
= EVP_PKEY_CTX_get0_peerkey(ctx
);
82 struct gost_pmeth_data
*data
= EVP_PKEY_CTX_get_data(ctx
);
84 if (!data
->shared_ukm
) {
85 GOSTerr(GOST_F_PKEY_GOST2001_DERIVE
, GOST_R_UKM_NOT_SET
);
95 VKO_compute_key(key
, 32,
96 EC_KEY_get0_public_key(EVP_PKEY_get0(peer_key
)),
97 (EC_KEY
*)EVP_PKEY_get0(my_key
), data
->shared_ukm
);
102 * EVP_PKEY_METHOD callback encrypt
103 * Implementation of GOST2001 key transport, cryptocom variation
106 * Generates ephemeral key based on pubk algorithm computes shared key using
107 * VKO and returns filled up GOST_KEY_TRANSPORT structure
111 * EVP_PKEY_METHOD callback encrypt
112 * Implementation of GOST2001 key transport, cryptopo variation
115 int pkey_GOST01cp_encrypt(EVP_PKEY_CTX
*pctx
, unsigned char *out
,
116 size_t *out_len
, const unsigned char *key
,
119 GOST_KEY_TRANSPORT
*gkt
= NULL
;
120 EVP_PKEY
*pubk
= EVP_PKEY_CTX_get0_pkey(pctx
);
121 struct gost_pmeth_data
*data
= EVP_PKEY_CTX_get_data(pctx
);
122 const struct gost_cipher_info
*param
= get_encryption_params(NULL
);
123 unsigned char ukm
[8], shared_key
[32], crypted_key
[44];
125 int key_is_ephemeral
= 1;
127 EVP_PKEY
*sec_key
= EVP_PKEY_CTX_get0_peerkey(pctx
);
128 if (data
->shared_ukm
) {
129 memcpy(ukm
, data
->shared_ukm
, 8);
132 if (RAND_bytes(ukm
, 8) <= 0) {
133 GOSTerr(GOST_F_PKEY_GOST01CP_ENCRYPT
,
134 GOST_R_RANDOM_GENERATOR_FAILURE
);
138 /* Check for private key in the peer_key of context */
140 key_is_ephemeral
= 0;
141 if (!gost_get0_priv_key(sec_key
)) {
142 GOSTerr(GOST_F_PKEY_GOST01CP_ENCRYPT
,
143 GOST_R_NO_PRIVATE_PART_OF_NON_EPHEMERAL_KEYPAIR
);
147 key_is_ephemeral
= 1;
149 sec_key
= EVP_PKEY_new();
150 EVP_PKEY_assign(sec_key
, EVP_PKEY_base_id(pubk
), EC_KEY_new());
151 EVP_PKEY_copy_parameters(sec_key
, pubk
);
152 if (!gost2001_keygen(EVP_PKEY_get0(sec_key
))) {
157 if (!get_gost_engine_param(GOST_PARAM_CRYPT_PARAMS
)
158 && param
== gost_cipher_list
) {
159 param
= gost_cipher_list
+ 1;
162 VKO_compute_key(shared_key
, 32,
163 EC_KEY_get0_public_key(EVP_PKEY_get0(pubk
)),
164 EVP_PKEY_get0(sec_key
), ukm
);
165 gost_init(&cctx
, param
->sblock
);
166 keyWrapCryptoPro(&cctx
, shared_key
, ukm
, key
, crypted_key
);
168 gkt
= GOST_KEY_TRANSPORT_new();
172 if (!ASN1_OCTET_STRING_set(gkt
->key_agreement_info
->eph_iv
, ukm
, 8)) {
175 if (!ASN1_OCTET_STRING_set(gkt
->key_info
->imit
, crypted_key
+ 40, 4)) {
178 if (!ASN1_OCTET_STRING_set
179 (gkt
->key_info
->encrypted_key
, crypted_key
+ 8, 32)) {
182 if (key_is_ephemeral
) {
184 (&gkt
->key_agreement_info
->ephem_key
, out
? sec_key
: pubk
)) {
185 GOSTerr(GOST_F_PKEY_GOST01CP_ENCRYPT
,
186 GOST_R_CANNOT_PACK_EPHEMERAL_KEY
);
190 ASN1_OBJECT_free(gkt
->key_agreement_info
->cipher
);
191 gkt
->key_agreement_info
->cipher
= OBJ_nid2obj(param
->nid
);
192 if (key_is_ephemeral
&& sec_key
)
193 EVP_PKEY_free(sec_key
);
194 if (!key_is_ephemeral
) {
195 /* Set control "public key from client certificate used" */
196 if (EVP_PKEY_CTX_ctrl(pctx
, -1, -1, EVP_PKEY_CTRL_PEER_KEY
, 3, NULL
)
198 GOSTerr(GOST_F_PKEY_GOST01CP_ENCRYPT
, GOST_R_CTRL_CALL_FAILED
);
202 if ((*out_len
= i2d_GOST_KEY_TRANSPORT(gkt
, out
? &out
: NULL
)) > 0)
204 GOST_KEY_TRANSPORT_free(gkt
);
207 if (key_is_ephemeral
&& sec_key
)
208 EVP_PKEY_free(sec_key
);
209 GOST_KEY_TRANSPORT_free(gkt
);
214 * EVP_PKEY_METHOD callback decrypt
215 * Implementation of GOST2001 key transport, cryptopo variation
217 int pkey_GOST01cp_decrypt(EVP_PKEY_CTX
*pctx
, unsigned char *key
,
218 size_t *key_len
, const unsigned char *in
,
221 const unsigned char *p
= in
;
222 EVP_PKEY
*priv
= EVP_PKEY_CTX_get0_pkey(pctx
);
223 GOST_KEY_TRANSPORT
*gkt
= NULL
;
225 unsigned char wrappedKey
[44];
226 unsigned char sharedKey
[32];
228 const struct gost_cipher_info
*param
= NULL
;
229 EVP_PKEY
*eph_key
= NULL
, *peerkey
= NULL
;
235 gkt
= d2i_GOST_KEY_TRANSPORT(NULL
, (const unsigned char **)&p
, in_len
);
237 GOSTerr(GOST_F_PKEY_GOST01CP_DECRYPT
,
238 GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO
);
242 /* If key transport structure contains public key, use it */
243 eph_key
= X509_PUBKEY_get(gkt
->key_agreement_info
->ephem_key
);
245 if (EVP_PKEY_derive_set_peer(pctx
, eph_key
) <= 0) {
246 GOSTerr(GOST_F_PKEY_GOST01CP_DECRYPT
,
247 GOST_R_INCOMPATIBLE_PEER_KEY
);
251 /* Set control "public key from client certificate used" */
252 if (EVP_PKEY_CTX_ctrl(pctx
, -1, -1, EVP_PKEY_CTRL_PEER_KEY
, 3, NULL
)
254 GOSTerr(GOST_F_PKEY_GOST01CP_DECRYPT
, GOST_R_CTRL_CALL_FAILED
);
258 peerkey
= EVP_PKEY_CTX_get0_peerkey(pctx
);
260 GOSTerr(GOST_F_PKEY_GOST01CP_DECRYPT
, GOST_R_NO_PEER_KEY
);
264 param
= get_encryption_params(gkt
->key_agreement_info
->cipher
);
269 gost_init(&ctx
, param
->sblock
);
270 OPENSSL_assert(gkt
->key_agreement_info
->eph_iv
->length
== 8);
271 memcpy(wrappedKey
, gkt
->key_agreement_info
->eph_iv
->data
, 8);
272 OPENSSL_assert(gkt
->key_info
->encrypted_key
->length
== 32);
273 memcpy(wrappedKey
+ 8, gkt
->key_info
->encrypted_key
->data
, 32);
274 OPENSSL_assert(gkt
->key_info
->imit
->length
== 4);
275 memcpy(wrappedKey
+ 40, gkt
->key_info
->imit
->data
, 4);
276 VKO_compute_key(sharedKey
, 32,
277 EC_KEY_get0_public_key(EVP_PKEY_get0(peerkey
)),
278 EVP_PKEY_get0(priv
), wrappedKey
);
279 if (!keyUnwrapCryptoPro(&ctx
, sharedKey
, wrappedKey
, key
)) {
280 GOSTerr(GOST_F_PKEY_GOST01CP_DECRYPT
,
281 GOST_R_ERROR_COMPUTING_SHARED_KEY
);
288 EVP_PKEY_free(eph_key
);
290 GOST_KEY_TRANSPORT_free(gkt
);