const int vko_dgst_nid)
{
unsigned char *databuf = NULL;
- BIGNUM *scalar = NULL, *X = NULL, *Y = NULL;
+ BIGNUM *scalar = NULL, *X = NULL, *Y = NULL, *order = NULL;
const EC_GROUP *grp = NULL;
EC_POINT *pnt = NULL;
BN_CTX *ctx = NULL;
goto err;
}
+ order = BN_CTX_get(ctx);
grp = EC_KEY_get0_group(priv_key);
scalar = BN_CTX_get(ctx);
X = BN_CTX_get(ctx);
+ EC_GROUP_get_order(grp, order, ctx);
if ((Y = BN_CTX_get(ctx)) == NULL
|| (pnt = EC_POINT_new(grp)) == NULL
goto err;
}
- half_len = BN_num_bytes(EC_GROUP_get0_field(grp));
+ half_len = BN_num_bytes(order);
buf_len = 2 * half_len;
if ((databuf = OPENSSL_malloc(buf_len)) == NULL) {
GOSTerr(GOST_F_VKO_COMPUTE_KEY, ERR_R_MALLOC_FAILURE);
}
}
+int pkey_gost_ec_compute_key(void *out, size_t outlen, const EC_POINT *pub_key,
+ const EC_KEY *eckey)
+{
+ BN_CTX *ctx;
+ EC_POINT *tmp = NULL;
+ BIGNUM *x = NULL;
+ const BIGNUM *priv_key;
+ const EC_GROUP *group;
+ int ret = 0;
+ size_t buflen,len;
+ unsigned char *buf = NULL;
+ int nid;
+
+ if (outlen > INT_MAX) {
+ GOSTerr(GOST_F_PKEY_GOST_EC_COMPUTE_KEY, EC_R_INVALID_OUTPUT_LENGTH);
+ return 0;
+ }
+
+ if ((ctx = BN_CTX_new()) == NULL)
+ goto err;
+ BN_CTX_start(ctx);
+ x = BN_CTX_get(ctx);
+ if (x == NULL) {
+ GOSTerr(GOST_F_PKEY_GOST_EC_COMPUTE_KEY, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ priv_key = EC_KEY_get0_private_key(eckey);
+ if (priv_key == NULL) {
+ GOSTerr(GOST_F_PKEY_GOST_EC_COMPUTE_KEY, EC_R_MISSING_PRIVATE_KEY);
+ goto err;
+ }
+
+ group = EC_KEY_get0_group(eckey);
+
+ nid = EC_GROUP_get_curve_name(group);
+ if (nid == NID_id_tc26_gost_3410_2012_256_paramSetA
+ || nid == NID_id_tc26_gost_3410_2012_512_paramSetC) {
+ if (!EC_GROUP_get_cofactor(group, x, NULL) ||
+ // or use BN_mul(...)
+ !BN_mod_mul(x, x, priv_key, EC_GROUP_get0_order(group), ctx)) {
+ GOSTerr(GOST_F_PKEY_GOST_EC_COMPUTE_KEY, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ priv_key = x;
+ }
+
+ if ((tmp = EC_POINT_new(group)) == NULL) {
+ GOSTerr(GOST_F_PKEY_GOST_EC_COMPUTE_KEY, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (!gost_ec_point_mul(group, tmp, NULL, pub_key, priv_key, ctx)) {
+ GOSTerr(GOST_F_PKEY_GOST_EC_COMPUTE_KEY, EC_R_POINT_ARITHMETIC_FAILURE);
+ goto err;
+ }
+
+ if (!EC_POINT_get_affine_coordinates(group, tmp, x, NULL, ctx)) {
+ GOSTerr(GOST_F_PKEY_GOST_EC_COMPUTE_KEY, EC_R_POINT_ARITHMETIC_FAILURE);
+ goto err;
+ }
+
+ buflen = (EC_GROUP_get_degree(group) + 7) / 8;
+ len = BN_num_bytes(x);
+ if (len > buflen) {
+ GOSTerr(GOST_F_PKEY_GOST_EC_COMPUTE_KEY, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ if ((buf = OPENSSL_malloc(buflen)) == NULL) {
+ GOSTerr(GOST_F_PKEY_GOST_EC_COMPUTE_KEY, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (buflen != BN_bn2lebinpad(x, buf, buflen)) {
+ GOSTerr(GOST_F_PKEY_GOST_EC_COMPUTE_KEY, ERR_R_BN_LIB);
+ goto err;
+ }
+
+ if (outlen > buflen)
+ outlen = buflen;
+ memcpy(out, buf, outlen);
+ OPENSSL_clear_free(buf, buflen);
+
+ ret = outlen;
+
+ err:
+ EC_POINT_clear_free(tmp);
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ return ret;
+}
+
+int pkey_gost_ec_2020_derive(EVP_PKEY_CTX *ctx, unsigned char *key,
+ size_t *keylen)
+{
+ int ret;
+ size_t outlen;
+ const EC_POINT *pubkey = NULL;
+ EC_KEY *eckey;
+ EVP_PKEY *my_key = EVP_PKEY_CTX_get0_pkey(ctx);
+ EVP_PKEY *peer_key = EVP_PKEY_CTX_get0_peerkey(ctx);
+
+ if (!my_key || !peer_key) {
+ GOSTerr(GOST_F_PKEY_GOST_EC_2020_DERIVE, EC_R_KEYS_NOT_SET);
+ return 0;
+ }
+
+ eckey = EVP_PKEY_get0(my_key);
+
+ if (!key) {
+ const EC_GROUP *group;
+ group = EC_KEY_get0_group(eckey);
+ *keylen = (EC_GROUP_get_degree(group) + 7) / 8;
+ return 1;
+ }
+ pubkey = EC_KEY_get0_public_key(EVP_PKEY_get0(peer_key));
+
+ /*
+ * if *outlen is less than maximum size, the result is truncated.
+ * (is it error or not?)
+ */
+
+ outlen = *keylen;
+
+ ret = pkey_gost_ec_compute_key(key, outlen, pubkey, eckey);
+ if (ret <= 0)
+ return 0;
+ *keylen = ret;
+ return 1;
+}
+
/*
* EVP_PKEY_METHOD callback derive.
* Implements VKO R 34.10-2001/2012 algorithms
int dgst_nid = NID_undef;
if (!data || data->shared_ukm_size == 0) {
- GOSTerr(GOST_F_PKEY_GOST_EC_DERIVE, GOST_R_UKM_NOT_SET);
- return 0;
+ return pkey_gost_ec_2020_derive(ctx, key, keylen);
}
/* VKO */
EVP_PKEY *pubk = EVP_PKEY_CTX_get0_pkey(pctx);
struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(pctx);
int pkey_nid = EVP_PKEY_base_id(pubk);
- ASN1_OBJECT *crypt_params_obj = (pkey_nid == NID_id_GostR3410_2001) ?
+ ASN1_OBJECT *crypt_params_obj = (pkey_nid == NID_id_GostR3410_2001 || pkey_nid == NID_id_GostR3410_2001DH) ?
OBJ_nid2obj(NID_id_Gost28147_89_CryptoPro_A_ParamSet) :
OBJ_nid2obj(NID_id_tc26_gost_28147_param_Z);
const struct gost_cipher_info *param =
int key_is_ephemeral = 1;
gost_ctx cctx;
EVP_PKEY *sec_key = EVP_PKEY_CTX_get0_peerkey(pctx);
+ int res_len = 0;
+
if (data->shared_ukm_size) {
memcpy(ukm, data->shared_ukm, 8);
} else {
goto err;
}
}
- if ((*out_len = i2d_GOST_KEY_TRANSPORT(gkt, out ? &out : NULL)) > 0)
+ res_len = i2d_GOST_KEY_TRANSPORT(gkt, NULL);
+ if (res_len <= 0) {
+ GOSTerr(GOST_F_PKEY_GOST_ECCP_ENCRYPT, ERR_R_ASN1_LIB);
+ goto err;
+ }
+
+ if (out == NULL) {
+ *out_len = res_len;
ret = 1;
+ } else {
+ if ((size_t)res_len > *out_len) {
+ GOSTerr(GOST_F_PKEY_GOST_ECCP_ENCRYPT, GOST_R_INVALID_BUFFER_SIZE);
+ goto err;
+ }
+ if ((*out_len = i2d_GOST_KEY_TRANSPORT(gkt, &out)) > 0)
+ ret = 1;
+ else
+ GOSTerr(GOST_F_PKEY_GOST_ECCP_ENCRYPT, ERR_R_ASN1_LIB);
+ }
+
OPENSSL_cleanse(shared_key, sizeof(shared_key));
GOST_KEY_TRANSPORT_free(gkt);
return ret;
int exp_len = 0, iv_len = 0;
unsigned char *exp_buf = NULL;
int key_is_ephemeral = 0;
+ int res_len = 0;
switch (data->cipher_nid) {
case NID_magma_ctr:
goto err;
}
- if ((*out_len = i2d_PSKeyTransport_gost(pst, out ? &out : NULL)) > 0)
+ res_len = i2d_PSKeyTransport_gost(pst, NULL);
+ if (res_len <= 0) {
+ GOSTerr(GOST_F_PKEY_GOST2018_ENCRYPT, ERR_R_ASN1_LIB);
+ goto err;
+ }
+
+ if (out == NULL) {
+ *out_len = res_len;
ret = 1;
+ } else {
+ if ((size_t)res_len > *out_len) {
+ GOSTerr(GOST_F_PKEY_GOST2018_ENCRYPT, GOST_R_INVALID_BUFFER_SIZE);
+ goto err;
+ }
+ if ((*out_len = i2d_PSKeyTransport_gost(pst, &out)) > 0)
+ ret = 1;
+ else
+ GOSTerr(GOST_F_PKEY_GOST2018_ENCRYPT, ERR_R_ASN1_LIB);
+ }
+
err:
OPENSSL_cleanse(expkeys, sizeof(expkeys));
if (key_is_ephemeral)
EVP_PKEY *eph_key = NULL, *peerkey = NULL;
int dgst_nid = NID_undef;
- if (!key) {
- *key_len = 32;
- return 1;
- }
gkt = d2i_GOST_KEY_TRANSPORT(NULL, (const unsigned char **)&p, in_len);
if (!gkt) {
GOSTerr(GOST_F_PKEY_GOST_ECCP_DECRYPT,
goto err;
}
+ *key_len = 32;
ret = 1;
err:
OPENSSL_cleanse(sharedKey, sizeof(sharedKey));
return -1;
break;
}
- if (!key) {
- *key_len = 32;
- return 1;
- }
pst = d2i_PSKeyTransport_gost(NULL, (const unsigned char **)&p, in_len);
if (!pst) {
o q * Q_eph is not equal to zero point.
*/
+ if (eph_key == NULL || priv == NULL || data == NULL) {
+ GOSTerr(GOST_F_PKEY_GOST2018_DECRYPT,
+ GOST_R_ERROR_COMPUTING_EXPORT_KEYS);
+ ret = 0;
+ goto err;
+ }
+
if (data->shared_ukm_size == 0 && pst->ukm != NULL) {
if (EVP_PKEY_CTX_ctrl(pctx, -1, -1, EVP_PKEY_CTRL_SET_IV,
ASN1_STRING_length(pst->ukm), (void *)ASN1_STRING_get0_data(pst->ukm)) < 0) {
goto err;
}
+ *key_len = 32;
ret = 1;
err:
OPENSSL_cleanse(expkeys, sizeof(expkeys));
size_t *key_len, const unsigned char *in, size_t in_len)
{
struct gost_pmeth_data *gctx = EVP_PKEY_CTX_get_data(pctx);
+
+ if (key == NULL) {
+ *key_len = 32;
+ return 1;
+ }
+
+ if (key != NULL && *key_len < 32) {
+ GOSTerr(GOST_F_PKEY_GOST2018_ENCRYPT, GOST_R_INVALID_BUFFER_SIZE);
+ return 0;
+ }
+
switch (gctx->cipher_nid)
{
case NID_id_Gost28147_89: