gost2001_keyx.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. /**********************************************************************
  2. * gost_keyx.c *
  3. * Copyright (c) 2005-2006 Cryptocom LTD *
  4. * This file is distributed under the same license as OpenSSL *
  5. * *
  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>
  12. #include <string.h>
  13. #include <openssl/objects.h>
  14. #include "gost89.h"
  15. #include "gosthash.h"
  16. #include "e_gost_err.h"
  17. #include "gost_keywrap.h"
  18. #include "gost_lcl.h"
  19. #include "gost2001_keyx.h"
  20. /* Implementation of CryptoPro VKO 34.10-2001 algorithm */
  21. 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)
  22. {
  23. unsigned char ukm_be[8],databuf[64],hashbuf[64];
  24. BIGNUM *UKM=NULL,*p=NULL,*order=NULL,*X=NULL,*Y=NULL;
  25. const BIGNUM* key=EC_KEY_get0_private_key(priv_key);
  26. EC_POINT *pnt=EC_POINT_new(EC_KEY_get0_group(priv_key));
  27. int i;
  28. gost_hash_ctx hash_ctx;
  29. BN_CTX *ctx = BN_CTX_new();
  30. for (i=0;i<8;i++)
  31. {
  32. ukm_be[7-i]=ukm[i];
  33. }
  34. BN_CTX_start(ctx);
  35. UKM=getbnfrombuf(ukm_be,8);
  36. p=BN_CTX_get(ctx);
  37. order = BN_CTX_get(ctx);
  38. X=BN_CTX_get(ctx);
  39. Y=BN_CTX_get(ctx);
  40. EC_GROUP_get_order(EC_KEY_get0_group(priv_key),order,ctx);
  41. BN_mod_mul(p,key,UKM,order,ctx);
  42. EC_POINT_mul(EC_KEY_get0_group(priv_key),pnt,NULL,pub_key,p,ctx);
  43. EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(priv_key),
  44. pnt,X,Y,ctx);
  45. /*Serialize elliptic curve point same way as we do it when saving
  46. * key */
  47. store_bignum(Y,databuf,32);
  48. store_bignum(X,databuf+32,32);
  49. /* And reverse byte order of whole buffer */
  50. for (i=0;i<64;i++)
  51. {
  52. hashbuf[63-i]=databuf[i];
  53. }
  54. init_gost_hash_ctx(&hash_ctx,&GostR3411_94_CryptoProParamSet);
  55. start_hash(&hash_ctx);
  56. hash_block(&hash_ctx,hashbuf,64);
  57. finish_hash(&hash_ctx,shared_key);
  58. done_gost_hash_ctx(&hash_ctx);
  59. BN_free(UKM);
  60. BN_CTX_end(ctx);
  61. BN_CTX_free(ctx);
  62. EC_POINT_free(pnt);
  63. return 32;
  64. }
  65. /*
  66. * EVP_PKEY_METHOD callback derive. Implements VKO R 34.10-2001
  67. * algorithm
  68. */
  69. int pkey_gost2001_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen)
  70. {
  71. /* Public key of peer in the ctx field peerkey
  72. * Our private key in the ctx pkey
  73. * ukm is in the algorithm specific context data
  74. */
  75. EVP_PKEY *my_key = EVP_PKEY_CTX_get0_pkey(ctx);
  76. EVP_PKEY *peer_key = EVP_PKEY_CTX_get0_peerkey(ctx);
  77. struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx);
  78. if (!data->shared_ukm) {
  79. GOSTerr(GOST_F_PKEY_GOST2001_DERIVE, GOST_R_UKM_NOT_SET);
  80. return 0;
  81. }
  82. if (key == NULL) {
  83. *keylen = 32;
  84. return 32;
  85. }
  86. *keylen=VKO_compute_key(key, 32, EC_KEY_get0_public_key(EVP_PKEY_get0(peer_key)),
  87. (EC_KEY *)EVP_PKEY_get0(my_key),data->shared_ukm);
  88. return 1;
  89. }
  90. /*
  91. * EVP_PKEY_METHOD callback encrypt
  92. * Implementation of GOST2001 key transport, cryptocom variation
  93. */
  94. /* Generates ephemeral key based on pubk algorithm
  95. * computes shared key using VKO and returns filled up
  96. * GOST_KEY_TRANSPORT structure
  97. */
  98. /*
  99. * EVP_PKEY_METHOD callback encrypt
  100. * Implementation of GOST2001 key transport, cryptopo variation
  101. */
  102. int pkey_GOST01cp_encrypt(EVP_PKEY_CTX *pctx, unsigned char *out, size_t *out_len, const unsigned char *key,size_t key_len)
  103. {
  104. GOST_KEY_TRANSPORT *gkt=NULL;
  105. EVP_PKEY *pubk = EVP_PKEY_CTX_get0_pkey(pctx);
  106. struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(pctx);
  107. const struct gost_cipher_info *param=get_encryption_params(NULL);
  108. unsigned char ukm[8], shared_key[32], crypted_key[44];
  109. int ret=0;
  110. int key_is_ephemeral=1;
  111. gost_ctx cctx;
  112. EVP_PKEY *sec_key=EVP_PKEY_CTX_get0_peerkey(pctx);
  113. if (data->shared_ukm)
  114. {
  115. memcpy(ukm, data->shared_ukm,8);
  116. }
  117. else if (out)
  118. {
  119. if (RAND_bytes(ukm,8)<=0)
  120. {
  121. GOSTerr(GOST_F_PKEY_GOST01CP_ENCRYPT,
  122. GOST_R_RANDOM_GENERATOR_FAILURE);
  123. return 0;
  124. }
  125. }
  126. /* Check for private key in the peer_key of context */
  127. if (sec_key)
  128. {
  129. key_is_ephemeral=0;
  130. if (!gost_get0_priv_key(sec_key))
  131. {
  132. GOSTerr(GOST_F_PKEY_GOST01CP_ENCRYPT,
  133. GOST_R_NO_PRIVATE_PART_OF_NON_EPHEMERAL_KEYPAIR);
  134. goto err;
  135. }
  136. }
  137. else
  138. {
  139. key_is_ephemeral=1;
  140. if (out)
  141. {
  142. sec_key = EVP_PKEY_new();
  143. EVP_PKEY_assign(sec_key,EVP_PKEY_base_id(pubk),EC_KEY_new());
  144. EVP_PKEY_copy_parameters(sec_key,pubk);
  145. if (!gost2001_keygen(EVP_PKEY_get0(sec_key)))
  146. {
  147. goto err;
  148. }
  149. }
  150. }
  151. if (!get_gost_engine_param(GOST_PARAM_CRYPT_PARAMS) && param == gost_cipher_list)
  152. {
  153. param= gost_cipher_list+1;
  154. }
  155. if (out)
  156. {
  157. VKO_compute_key(shared_key,32,EC_KEY_get0_public_key(EVP_PKEY_get0(pubk)),EVP_PKEY_get0(sec_key),ukm);
  158. gost_init(&cctx,param->sblock);
  159. keyWrapCryptoPro(&cctx,shared_key,ukm,key,crypted_key);
  160. }
  161. gkt = GOST_KEY_TRANSPORT_new();
  162. if (!gkt)
  163. {
  164. goto err;
  165. }
  166. if(!ASN1_OCTET_STRING_set(gkt->key_agreement_info->eph_iv,
  167. ukm,8))
  168. {
  169. goto err;
  170. }
  171. if (!ASN1_OCTET_STRING_set(gkt->key_info->imit,crypted_key+40,4))
  172. {
  173. goto err;
  174. }
  175. if (!ASN1_OCTET_STRING_set(gkt->key_info->encrypted_key,crypted_key+8,32))
  176. {
  177. goto err;
  178. }
  179. if (key_is_ephemeral) {
  180. if (!X509_PUBKEY_set(&gkt->key_agreement_info->ephem_key,out?sec_key:pubk))
  181. {
  182. GOSTerr(GOST_F_PKEY_GOST01CP_ENCRYPT,
  183. GOST_R_CANNOT_PACK_EPHEMERAL_KEY);
  184. goto err;
  185. }
  186. }
  187. ASN1_OBJECT_free(gkt->key_agreement_info->cipher);
  188. gkt->key_agreement_info->cipher = OBJ_nid2obj(param->nid);
  189. if (key_is_ephemeral && sec_key) EVP_PKEY_free(sec_key);
  190. if (!key_is_ephemeral)
  191. {
  192. /* Set control "public key from client certificate used" */
  193. if (EVP_PKEY_CTX_ctrl(pctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 3, NULL) <= 0)
  194. {
  195. GOSTerr(GOST_F_PKEY_GOST01CP_ENCRYPT,
  196. GOST_R_CTRL_CALL_FAILED);
  197. goto err;
  198. }
  199. }
  200. if ((*out_len = i2d_GOST_KEY_TRANSPORT(gkt,out?&out:NULL))>0) ret =1;
  201. GOST_KEY_TRANSPORT_free(gkt);
  202. return ret;
  203. err:
  204. if (key_is_ephemeral && sec_key) EVP_PKEY_free(sec_key);
  205. GOST_KEY_TRANSPORT_free(gkt);
  206. return -1;
  207. }
  208. /*
  209. * EVP_PKEY_METHOD callback decrypt
  210. * Implementation of GOST2001 key transport, cryptopo variation
  211. */
  212. int pkey_GOST01cp_decrypt(EVP_PKEY_CTX *pctx, unsigned char *key, size_t * key_len, const unsigned char *in, size_t in_len)
  213. {
  214. const unsigned char *p = in;
  215. EVP_PKEY *priv = EVP_PKEY_CTX_get0_pkey(pctx);
  216. GOST_KEY_TRANSPORT *gkt = NULL;
  217. int ret=0;
  218. unsigned char wrappedKey[44];
  219. unsigned char sharedKey[32];
  220. gost_ctx ctx;
  221. const struct gost_cipher_info *param=NULL;
  222. EVP_PKEY *eph_key=NULL, *peerkey=NULL;
  223. if (!key)
  224. {
  225. *key_len = 32;
  226. return 1;
  227. }
  228. gkt = d2i_GOST_KEY_TRANSPORT(NULL,(const unsigned char **)&p,
  229. in_len);
  230. if (!gkt)
  231. {
  232. GOSTerr(GOST_F_PKEY_GOST01CP_DECRYPT,GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO);
  233. return -1;
  234. }
  235. /* If key transport structure contains public key, use it */
  236. eph_key = X509_PUBKEY_get(gkt->key_agreement_info->ephem_key);
  237. if (eph_key)
  238. {
  239. if (EVP_PKEY_derive_set_peer(pctx, eph_key) <= 0)
  240. {
  241. GOSTerr(GOST_F_PKEY_GOST01CP_DECRYPT,
  242. GOST_R_INCOMPATIBLE_PEER_KEY);
  243. goto err;
  244. }
  245. }
  246. else
  247. {
  248. /* Set control "public key from client certificate used" */
  249. if (EVP_PKEY_CTX_ctrl(pctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 3, NULL) <= 0)
  250. {
  251. GOSTerr(GOST_F_PKEY_GOST01CP_DECRYPT,
  252. GOST_R_CTRL_CALL_FAILED);
  253. goto err;
  254. }
  255. }
  256. peerkey = EVP_PKEY_CTX_get0_peerkey(pctx);
  257. if (!peerkey)
  258. {
  259. GOSTerr(GOST_F_PKEY_GOST01CP_DECRYPT,
  260. GOST_R_NO_PEER_KEY);
  261. goto err;
  262. }
  263. param = get_encryption_params(gkt->key_agreement_info->cipher);
  264. gost_init(&ctx,param->sblock);
  265. OPENSSL_assert(gkt->key_agreement_info->eph_iv->length==8);
  266. memcpy(wrappedKey,gkt->key_agreement_info->eph_iv->data,8);
  267. OPENSSL_assert(gkt->key_info->encrypted_key->length==32);
  268. memcpy(wrappedKey+8,gkt->key_info->encrypted_key->data,32);
  269. OPENSSL_assert(gkt->key_info->imit->length==4);
  270. memcpy(wrappedKey+40,gkt->key_info->imit->data,4);
  271. VKO_compute_key(sharedKey,32,EC_KEY_get0_public_key(EVP_PKEY_get0(peerkey)),
  272. EVP_PKEY_get0(priv),wrappedKey);
  273. if (!keyUnwrapCryptoPro(&ctx,sharedKey,wrappedKey,key))
  274. {
  275. GOSTerr(GOST_F_PKEY_GOST01CP_DECRYPT,
  276. GOST_R_ERROR_COMPUTING_SHARED_KEY);
  277. goto err;
  278. }
  279. ret=1;
  280. err:
  281. if (eph_key) EVP_PKEY_free(eph_key);
  282. if (gkt) GOST_KEY_TRANSPORT_free(gkt);
  283. return ret;
  284. }