1*f0865ec9SKyle Evans /* 2*f0865ec9SKyle Evans * Copyright (C) 2021 - This file is part of libecc project 3*f0865ec9SKyle Evans * 4*f0865ec9SKyle Evans * Authors: 5*f0865ec9SKyle Evans * Ryad BENADJILA <ryadbenadjila@gmail.com> 6*f0865ec9SKyle Evans * Arnaud EBALARD <arnaud.ebalard@ssi.gouv.fr> 7*f0865ec9SKyle Evans * 8*f0865ec9SKyle Evans * This software is licensed under a dual BSD and GPL v2 license. 9*f0865ec9SKyle Evans * See LICENSE file at the root folder of the project. 10*f0865ec9SKyle Evans */ 11*f0865ec9SKyle Evans #include <libecc/lib_ecc_config.h> 12*f0865ec9SKyle Evans #if defined(WITH_ECCCDH) 13*f0865ec9SKyle Evans 14*f0865ec9SKyle Evans #include <libecc/ecdh/ecccdh.h> 15*f0865ec9SKyle Evans 16*f0865ec9SKyle Evans /* 17*f0865ec9SKyle Evans * This module implements the "Elliptic Curve Cryptography Cofactor Diffie-Hellman (ECC CDH) 18*f0865ec9SKyle Evans * Primitive" as described in section 5.7.1.2 of the NIST SP 800-56A Rev. 3 standard. 19*f0865ec9SKyle Evans * 20*f0865ec9SKyle Evans */ 21*f0865ec9SKyle Evans 22*f0865ec9SKyle Evans /* 23*f0865ec9SKyle Evans * Get the size of the shared secret associated to the curve parameters. 24*f0865ec9SKyle Evans */ 25*f0865ec9SKyle Evans int ecccdh_shared_secret_size(const ec_params *params, u8 *size) 26*f0865ec9SKyle Evans { 27*f0865ec9SKyle Evans int ret; 28*f0865ec9SKyle Evans 29*f0865ec9SKyle Evans MUST_HAVE((params != NULL) && (size != NULL), ret, err); 30*f0865ec9SKyle Evans MUST_HAVE((BYTECEIL(params->ec_fp.p_bitlen) <= 255), ret, err); 31*f0865ec9SKyle Evans 32*f0865ec9SKyle Evans (*size) = (u8)(BYTECEIL(params->ec_fp.p_bitlen)); 33*f0865ec9SKyle Evans ret = 0; 34*f0865ec9SKyle Evans 35*f0865ec9SKyle Evans err: 36*f0865ec9SKyle Evans return ret; 37*f0865ec9SKyle Evans } 38*f0865ec9SKyle Evans 39*f0865ec9SKyle Evans /* 40*f0865ec9SKyle Evans * Get the size of the serialized public key associated to the curve parameters. 41*f0865ec9SKyle Evans */ 42*f0865ec9SKyle Evans int ecccdh_serialized_pub_key_size(const ec_params *params, u8 *size) 43*f0865ec9SKyle Evans { 44*f0865ec9SKyle Evans int ret; 45*f0865ec9SKyle Evans 46*f0865ec9SKyle Evans MUST_HAVE((params != NULL) && (size != NULL), ret, err); 47*f0865ec9SKyle Evans MUST_HAVE(((2 * BYTECEIL(params->ec_fp.p_bitlen)) <= 255), ret, err); 48*f0865ec9SKyle Evans 49*f0865ec9SKyle Evans (*size) = (u8)(2 * BYTECEIL(params->ec_fp.p_bitlen)); 50*f0865ec9SKyle Evans ret = 0; 51*f0865ec9SKyle Evans 52*f0865ec9SKyle Evans err: 53*f0865ec9SKyle Evans return ret; 54*f0865ec9SKyle Evans } 55*f0865ec9SKyle Evans 56*f0865ec9SKyle Evans 57*f0865ec9SKyle Evans /* 58*f0865ec9SKyle Evans * Initialize ECCCDH public key from an initialized private key. 59*f0865ec9SKyle Evans */ 60*f0865ec9SKyle Evans int ecccdh_init_pub_key(ec_pub_key *out_pub, const ec_priv_key *in_priv) 61*f0865ec9SKyle Evans { 62*f0865ec9SKyle Evans prj_pt_src_t G; 63*f0865ec9SKyle Evans int ret, cmp; 64*f0865ec9SKyle Evans nn_src_t q; 65*f0865ec9SKyle Evans 66*f0865ec9SKyle Evans MUST_HAVE((out_pub != NULL), ret, err); 67*f0865ec9SKyle Evans 68*f0865ec9SKyle Evans /* Zero init public key to be generated */ 69*f0865ec9SKyle Evans ret = local_memset(out_pub, 0, sizeof(ec_pub_key)); EG(ret, err); 70*f0865ec9SKyle Evans 71*f0865ec9SKyle Evans ret = priv_key_check_initialized_and_type(in_priv, ECCCDH); EG(ret, err); 72*f0865ec9SKyle Evans q = &(in_priv->params->ec_gen_order); 73*f0865ec9SKyle Evans 74*f0865ec9SKyle Evans /* Sanity check on key compliance */ 75*f0865ec9SKyle Evans MUST_HAVE((!nn_cmp(&(in_priv->x), q, &cmp)) && (cmp < 0), ret, err); 76*f0865ec9SKyle Evans 77*f0865ec9SKyle Evans /* Y = xG */ 78*f0865ec9SKyle Evans G = &(in_priv->params->ec_gen); 79*f0865ec9SKyle Evans /* Use blinding when computing point scalar multiplication */ 80*f0865ec9SKyle Evans ret = prj_pt_mul_blind(&(out_pub->y), &(in_priv->x), G); EG(ret, err); 81*f0865ec9SKyle Evans 82*f0865ec9SKyle Evans out_pub->key_type = ECCCDH; 83*f0865ec9SKyle Evans out_pub->params = in_priv->params; 84*f0865ec9SKyle Evans out_pub->magic = PUB_KEY_MAGIC; 85*f0865ec9SKyle Evans 86*f0865ec9SKyle Evans err: 87*f0865ec9SKyle Evans return ret; 88*f0865ec9SKyle Evans } 89*f0865ec9SKyle Evans 90*f0865ec9SKyle Evans /* 91*f0865ec9SKyle Evans * Generate a key pair for ECCCDH given curve parameters as input. 92*f0865ec9SKyle Evans */ 93*f0865ec9SKyle Evans int ecccdh_gen_key_pair(ec_key_pair *kp, const ec_params *params) 94*f0865ec9SKyle Evans { 95*f0865ec9SKyle Evans int ret; 96*f0865ec9SKyle Evans 97*f0865ec9SKyle Evans MUST_HAVE((kp != NULL) && (params != NULL), ret, err); 98*f0865ec9SKyle Evans 99*f0865ec9SKyle Evans /* Use our generic key pair generation primitive */ 100*f0865ec9SKyle Evans kp->priv_key.magic = PRIV_KEY_MAGIC; 101*f0865ec9SKyle Evans kp->priv_key.key_type = ECCCDH; 102*f0865ec9SKyle Evans kp->priv_key.params = params; 103*f0865ec9SKyle Evans ret = generic_gen_priv_key(&(kp->priv_key)); EG(ret, err); 104*f0865ec9SKyle Evans 105*f0865ec9SKyle Evans /* Then, derive the public key */ 106*f0865ec9SKyle Evans ret = ecccdh_init_pub_key(&(kp->pub_key), &(kp->priv_key)); 107*f0865ec9SKyle Evans 108*f0865ec9SKyle Evans err: 109*f0865ec9SKyle Evans /* If we have failed our generation, uninitialize 110*f0865ec9SKyle Evans * the key pair. 111*f0865ec9SKyle Evans */ 112*f0865ec9SKyle Evans if(ret && (kp != NULL)){ 113*f0865ec9SKyle Evans IGNORE_RET_VAL(local_memset(kp, 0, sizeof(ec_key_pair))); 114*f0865ec9SKyle Evans } 115*f0865ec9SKyle Evans return ret; 116*f0865ec9SKyle Evans } 117*f0865ec9SKyle Evans 118*f0865ec9SKyle Evans /* 119*f0865ec9SKyle Evans * Create a key pair from a serialized private key. 120*f0865ec9SKyle Evans */ 121*f0865ec9SKyle Evans 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) 122*f0865ec9SKyle Evans { 123*f0865ec9SKyle Evans int ret; 124*f0865ec9SKyle Evans 125*f0865ec9SKyle Evans MUST_HAVE((kp != NULL), ret, err); 126*f0865ec9SKyle Evans 127*f0865ec9SKyle Evans /* Use our import primitive */ 128*f0865ec9SKyle Evans ret = ec_priv_key_import_from_buf(&(kp->priv_key), params, priv_key_buf, priv_key_buf_len, ECCCDH); EG(ret, err); 129*f0865ec9SKyle Evans 130*f0865ec9SKyle Evans /* Now derive the public key from the private one */ 131*f0865ec9SKyle Evans ret = ecccdh_init_pub_key(&(kp->pub_key), &(kp->priv_key)); 132*f0865ec9SKyle Evans 133*f0865ec9SKyle Evans err: 134*f0865ec9SKyle Evans return ret; 135*f0865ec9SKyle Evans } 136*f0865ec9SKyle Evans 137*f0865ec9SKyle Evans /* 138*f0865ec9SKyle Evans * Serialize our public key in a buffer. 139*f0865ec9SKyle Evans */ 140*f0865ec9SKyle Evans int ecccdh_serialize_pub_key(const ec_pub_key *our_pub_key, u8 *buf, u8 buf_len) 141*f0865ec9SKyle Evans { 142*f0865ec9SKyle Evans int ret, iszero; 143*f0865ec9SKyle Evans 144*f0865ec9SKyle Evans /* Sanity check */ 145*f0865ec9SKyle Evans ret = pub_key_check_initialized_and_type(our_pub_key, ECCCDH); EG(ret, err); 146*f0865ec9SKyle Evans 147*f0865ec9SKyle Evans /* Reject the point at infinity */ 148*f0865ec9SKyle Evans ret = prj_pt_iszero(&(our_pub_key->y), &iszero); EG(ret, err); 149*f0865ec9SKyle Evans MUST_HAVE((!iszero), ret, err); 150*f0865ec9SKyle Evans 151*f0865ec9SKyle Evans /* Export our public key as an affine point 152*f0865ec9SKyle Evans * NOTE: sanity checks on buf_len are performed in the lower layers. 153*f0865ec9SKyle Evans */ 154*f0865ec9SKyle Evans ret = ec_pub_key_export_to_aff_buf(our_pub_key, buf, buf_len); 155*f0865ec9SKyle Evans 156*f0865ec9SKyle Evans err: 157*f0865ec9SKyle Evans return ret; 158*f0865ec9SKyle Evans } 159*f0865ec9SKyle Evans 160*f0865ec9SKyle Evans /* 161*f0865ec9SKyle Evans * Derive the ECCCDH shared secret and store it in a buffer given the peer 162*f0865ec9SKyle Evans * public key and our private key. 163*f0865ec9SKyle Evans * 164*f0865ec9SKyle Evans * The shared_secret_len length MUST be exactly equal to the expected shared secret size: 165*f0865ec9SKyle Evans * the function fails otherwise. 166*f0865ec9SKyle Evans */ 167*f0865ec9SKyle Evans 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) 168*f0865ec9SKyle Evans { 169*f0865ec9SKyle Evans int ret, iszero, isone; 170*f0865ec9SKyle Evans ec_pub_key peer_pub_key; 171*f0865ec9SKyle Evans prj_pt_t Q; 172*f0865ec9SKyle Evans nn_src_t cofactor; 173*f0865ec9SKyle Evans u8 expected_shared_secret_len; 174*f0865ec9SKyle Evans peer_pub_key.magic = WORD(0); 175*f0865ec9SKyle Evans 176*f0865ec9SKyle Evans /* Sanity checks */ 177*f0865ec9SKyle Evans MUST_HAVE((shared_secret != NULL), ret, err); 178*f0865ec9SKyle Evans ret = priv_key_check_initialized_and_type(our_priv_key, ECCCDH); EG(ret, err); 179*f0865ec9SKyle Evans 180*f0865ec9SKyle Evans /* Try to import the peer public key. 181*f0865ec9SKyle Evans * NOTE: the check that this public key is indeed on the curve is performed in the lower layer 182*f0865ec9SKyle Evans * functions. 183*f0865ec9SKyle Evans */ 184*f0865ec9SKyle Evans 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); 185*f0865ec9SKyle Evans Q = &(peer_pub_key.y); 186*f0865ec9SKyle Evans 187*f0865ec9SKyle Evans cofactor = &(our_priv_key->params->ec_gen_cofactor); 188*f0865ec9SKyle Evans ret = nn_isone(cofactor, &isone); EG(ret, err); 189*f0865ec9SKyle Evans if(!isone){ 190*f0865ec9SKyle Evans /* Perform a cofactor multiplication if necessary. 191*f0865ec9SKyle Evans * NOTE: since the cofactor and the base point are public, we perform an unprotected 192*f0865ec9SKyle Evans * scalar multiplication here. 193*f0865ec9SKyle Evans */ 194*f0865ec9SKyle Evans ret = _prj_pt_unprotected_mult(Q, cofactor, Q); EG(ret, err); 195*f0865ec9SKyle Evans } 196*f0865ec9SKyle Evans 197*f0865ec9SKyle Evans /* 198*f0865ec9SKyle Evans * Reject the point at infinity or low order point as input as a trivial wrong public key. 199*f0865ec9SKyle Evans * This would be rejected in any case by the check post scalar multiplication below, but we 200*f0865ec9SKyle Evans * do not want to use and possibly leak the secret scalar if not necessary! 201*f0865ec9SKyle Evans */ 202*f0865ec9SKyle Evans ret = prj_pt_iszero(Q, &iszero); EG(ret, err); 203*f0865ec9SKyle Evans MUST_HAVE((!iszero), ret, err); 204*f0865ec9SKyle Evans 205*f0865ec9SKyle Evans /* Compute the shared secret using scalar multiplication */ 206*f0865ec9SKyle Evans #ifdef USE_SIG_BLINDING 207*f0865ec9SKyle Evans ret = prj_pt_mul_blind(Q, &(our_priv_key->x), Q); EG(ret, err); 208*f0865ec9SKyle Evans #else 209*f0865ec9SKyle Evans ret = prj_pt_mul(Q, &(our_priv_key->x), Q); EG(ret, err); 210*f0865ec9SKyle Evans #endif 211*f0865ec9SKyle Evans 212*f0865ec9SKyle Evans /* NOTE: scalar multiplication primitive checks that the resulting point is on 213*f0865ec9SKyle Evans * the curve. 214*f0865ec9SKyle Evans */ 215*f0865ec9SKyle Evans /* Reject the point at infinity */ 216*f0865ec9SKyle Evans ret = prj_pt_iszero(Q, &iszero); EG(ret, err); 217*f0865ec9SKyle Evans MUST_HAVE((!iszero), ret, err); 218*f0865ec9SKyle Evans 219*f0865ec9SKyle Evans /* Get the unique affine representation of the resulting point */ 220*f0865ec9SKyle Evans ret = prj_pt_unique(Q, Q); EG(ret, err); 221*f0865ec9SKyle Evans /* Now export the X coordinate as the shared secret in the output buffer */ 222*f0865ec9SKyle Evans ret = ecccdh_shared_secret_size(our_priv_key->params, &expected_shared_secret_len); EG(ret, err); 223*f0865ec9SKyle Evans MUST_HAVE((shared_secret_len == expected_shared_secret_len), ret, err); 224*f0865ec9SKyle Evans ret = fp_export_to_buf(shared_secret, shared_secret_len, &(Q->X)); 225*f0865ec9SKyle Evans 226*f0865ec9SKyle Evans err: 227*f0865ec9SKyle Evans PTR_NULLIFY(Q); 228*f0865ec9SKyle Evans PTR_NULLIFY(cofactor); 229*f0865ec9SKyle Evans /* Uninit local peer pub key and zeroize intermediate computations */ 230*f0865ec9SKyle Evans IGNORE_RET_VAL(local_memset(&peer_pub_key, 0, sizeof(ec_pub_key))); 231*f0865ec9SKyle Evans 232*f0865ec9SKyle Evans return ret; 233*f0865ec9SKyle Evans } 234*f0865ec9SKyle Evans 235*f0865ec9SKyle Evans #else /* !defined(WITH_ECCCDH) */ 236*f0865ec9SKyle Evans 237*f0865ec9SKyle Evans /* 238*f0865ec9SKyle Evans * Dummy definition to avoid the empty translation unit ISO C warning 239*f0865ec9SKyle Evans */ 240*f0865ec9SKyle Evans typedef int dummy; 241*f0865ec9SKyle Evans 242*f0865ec9SKyle Evans #endif /* WITH_ECCCDH */ 243