xref: /freebsd/crypto/libecc/src/ecdh/ecccdh.c (revision f0865ec9906d5a18fa2a3b61381f22ce16e606ad)
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  */
ecccdh_shared_secret_size(const ec_params * params,u8 * size)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  */
ecccdh_serialized_pub_key_size(const ec_params * params,u8 * size)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  */
ecccdh_init_pub_key(ec_pub_key * out_pub,const ec_priv_key * in_priv)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  */
ecccdh_gen_key_pair(ec_key_pair * kp,const ec_params * params)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  */
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)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  */
ecccdh_serialize_pub_key(const ec_pub_key * our_pub_key,u8 * buf,u8 buf_len)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  */
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)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