#include <libecc/lib_ecc_config.h>
#if defined(WITH_ECCCDH)
#include <libecc/ecdh/ecccdh.h>
int ecccdh_shared_secret_size(const ec_params *params, u8 *size)
{
int ret;
MUST_HAVE((params != NULL) && (size != NULL), ret, err);
MUST_HAVE((BYTECEIL(params->ec_fp.p_bitlen) <= 255), ret, err);
(*size) = (u8)(BYTECEIL(params->ec_fp.p_bitlen));
ret = 0;
err:
return ret;
}
int ecccdh_serialized_pub_key_size(const ec_params *params, u8 *size)
{
int ret;
MUST_HAVE((params != NULL) && (size != NULL), ret, err);
MUST_HAVE(((2 * BYTECEIL(params->ec_fp.p_bitlen)) <= 255), ret, err);
(*size) = (u8)(2 * BYTECEIL(params->ec_fp.p_bitlen));
ret = 0;
err:
return ret;
}
int ecccdh_init_pub_key(ec_pub_key *out_pub, const ec_priv_key *in_priv)
{
prj_pt_src_t G;
int ret, cmp;
nn_src_t q;
MUST_HAVE((out_pub != NULL), ret, err);
ret = local_memset(out_pub, 0, sizeof(ec_pub_key)); EG(ret, err);
ret = priv_key_check_initialized_and_type(in_priv, ECCCDH); EG(ret, err);
q = &(in_priv->params->ec_gen_order);
MUST_HAVE((!nn_cmp(&(in_priv->x), q, &cmp)) && (cmp < 0), ret, err);
G = &(in_priv->params->ec_gen);
ret = prj_pt_mul_blind(&(out_pub->y), &(in_priv->x), G); EG(ret, err);
out_pub->key_type = ECCCDH;
out_pub->params = in_priv->params;
out_pub->magic = PUB_KEY_MAGIC;
err:
return ret;
}
int ecccdh_gen_key_pair(ec_key_pair *kp, const ec_params *params)
{
int ret;
MUST_HAVE((kp != NULL) && (params != NULL), ret, err);
kp->priv_key.magic = PRIV_KEY_MAGIC;
kp->priv_key.key_type = ECCCDH;
kp->priv_key.params = params;
ret = generic_gen_priv_key(&(kp->priv_key)); EG(ret, err);
ret = ecccdh_init_pub_key(&(kp->pub_key), &(kp->priv_key));
err:
if(ret && (kp != NULL)){
IGNORE_RET_VAL(local_memset(kp, 0, sizeof(ec_key_pair)));
}
return ret;
}
int ecccdh_import_key_pair_from_priv_key_buf(ec_key_pair *kp, const ec_params *params, const u8 *priv_key_buf, u8 priv_key_buf_len)
{
int ret;
MUST_HAVE((kp != NULL), ret, err);
ret = ec_priv_key_import_from_buf(&(kp->priv_key), params, priv_key_buf, priv_key_buf_len, ECCCDH); EG(ret, err);
ret = ecccdh_init_pub_key(&(kp->pub_key), &(kp->priv_key));
err:
return ret;
}
int ecccdh_serialize_pub_key(const ec_pub_key *our_pub_key, u8 *buf, u8 buf_len)
{
int ret, iszero;
ret = pub_key_check_initialized_and_type(our_pub_key, ECCCDH); EG(ret, err);
ret = prj_pt_iszero(&(our_pub_key->y), &iszero); EG(ret, err);
MUST_HAVE((!iszero), ret, err);
ret = ec_pub_key_export_to_aff_buf(our_pub_key, buf, buf_len);
err:
return ret;
}
int ecccdh_derive_secret(const ec_priv_key *our_priv_key, const u8 *peer_pub_key_buf, u8 peer_pub_key_buf_len, u8 *shared_secret, u8 shared_secret_len)
{
int ret, iszero, isone;
ec_pub_key peer_pub_key;
prj_pt_t Q;
nn_src_t cofactor;
u8 expected_shared_secret_len;
peer_pub_key.magic = WORD(0);
MUST_HAVE((shared_secret != NULL), ret, err);
ret = priv_key_check_initialized_and_type(our_priv_key, ECCCDH); EG(ret, err);
ret = ec_pub_key_import_from_aff_buf(&peer_pub_key, our_priv_key->params, peer_pub_key_buf, peer_pub_key_buf_len, ECCCDH); EG(ret, err);
Q = &(peer_pub_key.y);
cofactor = &(our_priv_key->params->ec_gen_cofactor);
ret = nn_isone(cofactor, &isone); EG(ret, err);
if(!isone){
ret = _prj_pt_unprotected_mult(Q, cofactor, Q); EG(ret, err);
}
ret = prj_pt_iszero(Q, &iszero); EG(ret, err);
MUST_HAVE((!iszero), ret, err);
#ifdef USE_SIG_BLINDING
ret = prj_pt_mul_blind(Q, &(our_priv_key->x), Q); EG(ret, err);
#else
ret = prj_pt_mul(Q, &(our_priv_key->x), Q); EG(ret, err);
#endif
ret = prj_pt_iszero(Q, &iszero); EG(ret, err);
MUST_HAVE((!iszero), ret, err);
ret = prj_pt_unique(Q, Q); EG(ret, err);
ret = ecccdh_shared_secret_size(our_priv_key->params, &expected_shared_secret_len); EG(ret, err);
MUST_HAVE((shared_secret_len == expected_shared_secret_len), ret, err);
ret = fp_export_to_buf(shared_secret, shared_secret_len, &(Q->X));
err:
PTR_NULLIFY(Q);
PTR_NULLIFY(cofactor);
IGNORE_RET_VAL(local_memset(&peer_pub_key, 0, sizeof(ec_pub_key)));
return ret;
}
#else
typedef int dummy;
#endif