static int pub_decode_gost01(EVP_PKEY *pk,X509_PUBKEY *pub) { X509_ALGOR *palg = NULL; const unsigned char *pubkey_buf = NULL; unsigned char *databuf; ASN1_OBJECT *palgobj = NULL; int pub_len,i,j; EC_POINT *pub_key; BIGNUM *X,*Y; ASN1_OCTET_STRING *octet= NULL; int len; const EC_GROUP *group; if (!X509_PUBKEY_get0_param(&palgobj,&pubkey_buf,&pub_len, &palg, pub)) return 0; EVP_PKEY_assign(pk,OBJ_obj2nid(palgobj),NULL); if (!decode_gost_algor_params(pk,palg)) return 0; group = EC_KEY_get0_group(EVP_PKEY_get0(pk)); octet = d2i_ASN1_OCTET_STRING(NULL,&pubkey_buf,pub_len); if (!octet) { GOSTerr(GOST_F_PUB_DECODE_GOST01,ERR_R_MALLOC_FAILURE); return 0; } databuf = OPENSSL_malloc(octet->length); for (i=0,j=octet->length-1;i<octet->length;i++,j--) { databuf[j]=octet->data[i]; } len=octet->length/2; ASN1_OCTET_STRING_free(octet); Y= getbnfrombuf(databuf,len); X= getbnfrombuf(databuf+len,len); OPENSSL_free(databuf); pub_key = EC_POINT_new(group); if (!EC_POINT_set_affine_coordinates_GFp(group ,pub_key,X,Y,NULL)) { GOSTerr(GOST_F_PUB_DECODE_GOST01, ERR_R_EC_LIB); EC_POINT_free(pub_key); BN_free(X); BN_free(Y); return 0; } BN_free(X); BN_free(Y); if (!EC_KEY_set_public_key(EVP_PKEY_get0(pk),pub_key)) { GOSTerr(GOST_F_PUB_DECODE_GOST01, ERR_R_EC_LIB); EC_POINT_free(pub_key); return 0; } EC_POINT_free(pub_key); return 1; }
/* Unpack signature according to cryptopro rules */ DSA_SIG *unpack_cp_signature(const unsigned char *sig,size_t siglen) { DSA_SIG *s; s = DSA_SIG_new(); if (s == NULL) { GOSTerr(GOST_F_UNPACK_CP_SIGNATURE,GOST_R_NO_MEMORY); return NULL; } s->s = getbnfrombuf(sig , siglen/2); s->r = getbnfrombuf(sig + siglen/2, siglen/2); return s; }
/* Convert little-endian byte array into bignum */ BIGNUM *hashsum2bn(const unsigned char *dgst) { unsigned char buf[32]; int i; for (i=0;i<32;i++) { buf[31-i]=dgst[i]; } return getbnfrombuf(buf,32); }
/* ------------------ private key functions -----------------------------*/ static int priv_decode_gost( EVP_PKEY *pk, PKCS8_PRIV_KEY_INFO *p8inf) { const unsigned char *pkey_buf = NULL,*p=NULL; int priv_len = 0; BIGNUM *pk_num=NULL; int ret =0; X509_ALGOR *palg =NULL; ASN1_OBJECT *palg_obj = NULL; ASN1_INTEGER *priv_key=NULL; if (!PKCS8_pkey_get0(&palg_obj,&pkey_buf,&priv_len,&palg,p8inf)) return 0; p = pkey_buf; if (!decode_gost_algor_params(pk,palg)) { return 0; } if (V_ASN1_OCTET_STRING == *p) { /* New format - Little endian octet string */ unsigned char rev_buf[32]; int i; ASN1_OCTET_STRING *s = d2i_ASN1_OCTET_STRING(NULL,&p,priv_len); if (!s||s->length !=32) { GOSTerr(GOST_F_PRIV_DECODE_GOST, EVP_R_DECODE_ERROR); return 0; } for (i=0;i<32;i++) { rev_buf[31-i]=s->data[i]; } ASN1_STRING_free(s); pk_num = getbnfrombuf(rev_buf,32); } else { priv_key=d2i_ASN1_INTEGER(NULL,&p,priv_len); if (!priv_key) return 0; ret= ((pk_num = ASN1_INTEGER_to_BN(priv_key, NULL))!=NULL) ; ASN1_INTEGER_free(priv_key); if (!ret) { GOSTerr(GOST_F_PRIV_DECODE_GOST, EVP_R_DECODE_ERROR); return 0; } } ret= gost_set_priv_key(pk,pk_num); BN_free(pk_num); return ret; }
/* Convert little-endian byte array into bignum */ BIGNUM *hashsum2bn(const unsigned char *dgst,int dlen) { unsigned char buf[64]; int i; OPENSSL_assert(dlen==32 || dlen == 64); for (i=0;i<dlen;i++) { buf[dlen-1-i]=dgst[i]; } return getbnfrombuf(buf,dlen); }
/* Convert little-endian byte array into bignum */ BIGNUM *hashsum2bn(const unsigned char *dgst, int len) { unsigned char buf[64]; int i; if (len > sizeof(buf)) return NULL; for (i = 0; i < len; i++) { buf[len - i - 1] = dgst[i]; } return getbnfrombuf(buf, len); }
/* Implementation of CryptoPro VKO 34.10-2001 algorithm */ 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) { unsigned char ukm_be[8], databuf[64], hashbuf[64]; BIGNUM *UKM = NULL, *p = NULL, *order = NULL, *X = NULL, *Y = NULL; const BIGNUM *key = EC_KEY_get0_private_key (priv_key); EC_POINT *pnt = EC_POINT_new (EC_KEY_get0_group (priv_key)); int i; gost_hash_ctx hash_ctx; BN_CTX *ctx = BN_CTX_new (); for (i = 0; i < 8; i++) { ukm_be[7 - i] = ukm[i]; } BN_CTX_start (ctx); UKM = getbnfrombuf (ukm_be, 8); p = BN_CTX_get (ctx); order = BN_CTX_get (ctx); X = BN_CTX_get (ctx); Y = BN_CTX_get (ctx); EC_GROUP_get_order (EC_KEY_get0_group (priv_key), order, ctx); BN_mod_mul (p, key, UKM, order, ctx); EC_POINT_mul (EC_KEY_get0_group (priv_key), pnt, NULL, pub_key, p, ctx); EC_POINT_get_affine_coordinates_GFp (EC_KEY_get0_group (priv_key), pnt, X, Y, ctx); /*Serialize elliptic curve point same way as we do it when saving * key */ store_bignum (Y, databuf, 32); store_bignum (X, databuf + 32, 32); /* And reverse byte order of whole buffer */ for (i = 0; i < 64; i++) { hashbuf[63 - i] = databuf[i]; } init_gost_hash_ctx (&hash_ctx, &GostR3411_94_CryptoProParamSet); start_hash (&hash_ctx); hash_block (&hash_ctx, hashbuf, 64); finish_hash (&hash_ctx, shared_key); done_gost_hash_ctx (&hash_ctx); BN_free (UKM); BN_CTX_end (ctx); BN_CTX_free (ctx); EC_POINT_free (pnt); return 32; }