-/* Transform ECDH shared key into little endian as required by Cryptocom
- * key exchange */
-static void *make_key_le(const void *in, size_t inlen, void *out, size_t *outlen)
- {
- const char* inbuf= in;
- char* outbuf= out;
- int i;
- if (*outlen < inlen)
- {
- return NULL;
- }
- for (i=0;i<inlen;i++)
- {
- outbuf[inlen-1-i]=inbuf[i];
- }
- *outlen = inlen;
- return out;
- }
-
-/* Create gost 2001 ephemeral key with same parameters as peer key */
-static EC_KEY *make_ec_ephemeral_key(EC_KEY *peer_key,BIGNUM *seckey)
- {
- EC_KEY *out = EC_KEY_new();
- EC_KEY_copy(out,peer_key);
- EC_KEY_set_private_key(out,seckey);
- gost2001_compute_public(out);
- return out;
- }
-/* Packs GOST elliptic curve key into EVP_PKEY setting same parameters
- * as in passed pubkey
- */
-static EVP_PKEY *ec_ephemeral_key_to_EVP(EVP_PKEY *pubk,int type,EC_KEY *ephemeral)
- {
- EVP_PKEY *newkey;
- newkey = EVP_PKEY_new();
- EVP_PKEY_assign(newkey,type,ephemeral);
- return newkey;
- }
-
-/*
- * EVP_PKEY_METHOD callback encrypt
- * Implementation of GOST2001 key transport, cryptocom variation
- */
-
-int pkey_GOST01cc_encrypt (EVP_PKEY_CTX *pctx,unsigned char *out,
- size_t *out_len, const unsigned char *key,size_t key_len)
- {
- EVP_PKEY *pubk = EVP_PKEY_CTX_get0_pkey(pctx);
- struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(pctx);
- GOST_KEY_TRANSPORT *gkt = NULL;
- int ret=0;
- gost_ctx ctx;
- EC_KEY *ephemeral=NULL;
- const EC_POINT *pub_key_point=NULL;
- unsigned char shared_key[32],encrypted_key[32],hmac[4],
- iv[8]={0,0,0,0,0,0,0,0};
- ephemeral = make_ec_ephemeral_key(EVP_PKEY_get0(pubk), gost_get_priv_key(data->eph_seckey));
- if (!ephemeral) goto err;
- /* compute shared key */
- pub_key_point=EC_KEY_get0_public_key(EVP_PKEY_get0(pubk));
- if (!ECDH_compute_key(shared_key,32,pub_key_point,ephemeral,make_key_le))
- {
- GOSTerr(GOST_F_PKEY_GOST01CC_ENCRYPT,GOST_R_ERROR_COMPUTING_SHARED_KEY);
- goto err;
- }
- /* encrypt session key */
- gost_init(&ctx, &GostR3411_94_CryptoProParamSet);
- gost_key(&ctx,shared_key);
- encrypt_cryptocom_key(key,key_len,encrypted_key,&ctx);
- /* compute hmac of session key */
- if (!gost_mac(&ctx,32,key,32,hmac))
- {
- GOSTerr(GOST_F_PKEY_GOST01CC_ENCRYPT,GOST_R_ERROR_COMPUTING_MAC);
- return -1;
- }
- gkt = GOST_KEY_TRANSPORT_new();
- if (!gkt)
- {
- GOSTerr(GOST_F_PKEY_GOST01CC_ENCRYPT,GOST_R_NO_MEMORY);
- return -1;
- }
- /* Store IV which is always zero in our case */
- if (!ASN1_OCTET_STRING_set(gkt->key_agreement_info->eph_iv,iv,8))
- {
- GOSTerr(GOST_F_PKEY_GOST01CC_ENCRYPT,GOST_R_ERROR_STORING_IV);
- goto err;
- }
- if (!ASN1_OCTET_STRING_set(gkt->key_info->imit,hmac,4))
- {
- GOSTerr(GOST_F_PKEY_GOST01CC_ENCRYPT,GOST_R_ERROR_STORING_MAC);
- goto err;
- }
- if (!ASN1_OCTET_STRING_set(gkt->key_info->encrypted_key,encrypted_key,32))
- {
- GOSTerr(GOST_F_PKEY_GOST01CC_ENCRYPT,GOST_R_ERROR_STORING_ENCRYPTED_KEY);
- goto err;
- }
-
- if (!X509_PUBKEY_set(&gkt->key_agreement_info->ephem_key,data->eph_seckey))
- {
- GOSTerr(GOST_F_PKEY_GOST01CC_ENCRYPT,GOST_R_CANNOT_PACK_EPHEMERAL_KEY);
- goto err;
- }
- ASN1_OBJECT_free(gkt->key_agreement_info->cipher);
- gkt->key_agreement_info->cipher = OBJ_nid2obj(NID_id_Gost28147_89_cc);
- if ((*out_len = i2d_GOST_KEY_TRANSPORT(gkt,&out))>0) ret = 1;
- ;
- err:
- if (gkt) GOST_KEY_TRANSPORT_free(gkt);
- return ret;
- }
-/*
- * EVP_PKEY_METHOD callback decrypt
- * Implementation of GOST2001 key transport, cryptocom variation
- */
-int pkey_GOST01cc_decrypt (EVP_PKEY_CTX *pctx, unsigned char *key, size_t *key_len, const unsigned char *in, size_t in_len)
- {
- /* Form DH params from compute shared key */
- EVP_PKEY *priv=EVP_PKEY_CTX_get0_pkey(pctx);
- GOST_KEY_TRANSPORT *gkt = NULL;
- const unsigned char *p=in;
- unsigned char shared_key[32];
- unsigned char hmac[4],hmac_comp[4];
- unsigned char iv[8];
- int i;
- gost_ctx ctx;
- const EC_POINT *pub_key_point;
- EVP_PKEY *eph_key;