Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/libecc/src/ecdh/ecccdh.c
34889 views
1
/*
2
* Copyright (C) 2021 - This file is part of libecc project
3
*
4
* Authors:
5
* Ryad BENADJILA <[email protected]>
6
* Arnaud EBALARD <[email protected]>
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 */
243
244