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