]>
Commit | Line | Data |
---|---|---|
c92eade8 | 1 | /* |
59a987b8 TB |
2 | * Copyright (C) 2020 Tobias Brunner |
3 | * HSR Hochschule fuer Technik Rapperswil | |
4 | * | |
c92eade8 SP |
5 | * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc. |
6 | * | |
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
8 | * of this software and associated documentation files (the "Software"), to deal | |
9 | * in the Software without restriction, including without limitation the rights | |
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
11 | * copies of the Software, and to permit persons to whom the Software is | |
12 | * furnished to do so, subject to the following conditions: | |
13 | * | |
14 | * The above copyright notice and this permission notice shall be included in | |
15 | * all copies or substantial portions of the Software. | |
16 | * | |
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
23 | * THE SOFTWARE. | |
24 | */ | |
25 | ||
26 | #include "wolfssl_common.h" | |
27 | ||
59a987b8 | 28 | #if defined(HAVE_CURVE25519) || defined(HAVE_CURVE448) |
c92eade8 SP |
29 | |
30 | #include "wolfssl_x_diffie_hellman.h" | |
31 | ||
32 | #include <utils/debug.h> | |
33 | ||
59a987b8 | 34 | #ifdef HAVE_CURVE25519 |
c92eade8 | 35 | #include <wolfssl/wolfcrypt/curve25519.h> |
59a987b8 TB |
36 | #endif |
37 | #ifdef HAVE_CURVE448 | |
38 | #include <wolfssl/wolfcrypt/curve448.h> | |
39 | #endif | |
40 | ||
c92eade8 SP |
41 | #include <wolfssl/wolfcrypt/fe_operations.h> |
42 | ||
43 | typedef struct private_diffie_hellman_t private_diffie_hellman_t; | |
44 | ||
45 | /** | |
46 | * Private data | |
47 | */ | |
48 | struct private_diffie_hellman_t { | |
49 | /** | |
50 | * Public interface. | |
51 | */ | |
52 | diffie_hellman_t public; | |
53 | ||
54 | /** | |
55 | * Diffie Hellman group number. | |
56 | */ | |
57 | diffie_hellman_group_t group; | |
58 | ||
59 | /** | |
60 | * Private (public) key | |
61 | */ | |
59a987b8 TB |
62 | union { |
63 | #ifdef HAVE_CURVE25519 | |
64 | curve25519_key key25519; | |
65 | #endif | |
66 | #ifdef HAVE_CURVE448 | |
67 | curve448_key key448; | |
68 | #endif | |
69 | } key; | |
c92eade8 SP |
70 | |
71 | /** | |
72 | * Shared secret | |
73 | */ | |
74 | chunk_t shared_secret; | |
c92eade8 SP |
75 | }; |
76 | ||
59a987b8 | 77 | #ifdef HAVE_CURVE25519 |
c92eade8 | 78 | |
59a987b8 | 79 | METHOD(diffie_hellman_t, set_other_public_value_25519, bool, |
c92eade8 SP |
80 | private_diffie_hellman_t *this, chunk_t value) |
81 | { | |
59a987b8 | 82 | word32 len = CURVE25519_KEYSIZE; |
c92eade8 | 83 | curve25519_key pub; |
d3329ee5 | 84 | int ret; |
c92eade8 SP |
85 | |
86 | if (!diffie_hellman_verify_value(this->group, value)) | |
87 | { | |
88 | return FALSE; | |
89 | } | |
90 | ||
91 | ret = wc_curve25519_init(&pub); | |
d3329ee5 | 92 | if (ret != 0) |
c92eade8 SP |
93 | { |
94 | DBG1(DBG_LIB, "%N public key initialization failed", | |
95 | diffie_hellman_group_names, this->group); | |
96 | return FALSE; | |
97 | } | |
98 | ||
99 | ret = wc_curve25519_import_public_ex(value.ptr, value.len, &pub, | |
100 | EC25519_LITTLE_ENDIAN); | |
101 | if (ret != 0) | |
102 | { | |
103 | DBG1(DBG_LIB, "%N public value is malformed", | |
104 | diffie_hellman_group_names, this->group); | |
105 | return FALSE; | |
106 | } | |
107 | ||
108 | chunk_clear(&this->shared_secret); | |
59a987b8 TB |
109 | this->shared_secret = chunk_alloc(len); |
110 | if (wc_curve25519_shared_secret_ex(&this->key.key25519, &pub, | |
111 | this->shared_secret.ptr, &len, EC25519_LITTLE_ENDIAN) != 0) | |
c92eade8 SP |
112 | { |
113 | DBG1(DBG_LIB, "%N shared secret computation failed", | |
114 | diffie_hellman_group_names, this->group); | |
d3329ee5 | 115 | chunk_clear(&this->shared_secret); |
c92eade8 SP |
116 | wc_curve25519_free(&pub); |
117 | return FALSE; | |
118 | } | |
c92eade8 SP |
119 | wc_curve25519_free(&pub); |
120 | return TRUE; | |
121 | } | |
122 | ||
59a987b8 | 123 | METHOD(diffie_hellman_t, get_my_public_value_25519, bool, |
c92eade8 SP |
124 | private_diffie_hellman_t *this, chunk_t *value) |
125 | { | |
126 | word32 len = CURVE25519_KEYSIZE; | |
127 | ||
128 | *value = chunk_alloc(len); | |
59a987b8 | 129 | if (wc_curve25519_export_public_ex(&this->key.key25519, value->ptr, &len, |
c92eade8 SP |
130 | EC25519_LITTLE_ENDIAN) != 0) |
131 | { | |
132 | chunk_free(value); | |
133 | return FALSE; | |
134 | } | |
135 | return TRUE; | |
136 | } | |
137 | ||
59a987b8 | 138 | METHOD(diffie_hellman_t, set_private_value_25519, bool, |
c92eade8 SP |
139 | private_diffie_hellman_t *this, chunk_t value) |
140 | { | |
c92eade8 | 141 | curve25519_key pub; |
d3329ee5 TB |
142 | u_char basepoint[CURVE25519_KEYSIZE] = {9}; |
143 | word32 len = CURVE25519_KEYSIZE; | |
144 | int ret; | |
c92eade8 SP |
145 | |
146 | ret = wc_curve25519_init(&pub); | |
d3329ee5 | 147 | /* create base point for calculating public key */ |
c92eade8 SP |
148 | if (ret == 0) |
149 | { | |
150 | ret = wc_curve25519_import_public_ex(basepoint, CURVE25519_KEYSIZE, | |
151 | &pub, EC25519_LITTLE_ENDIAN); | |
152 | } | |
153 | if (ret == 0) | |
154 | { | |
59a987b8 TB |
155 | ret = wc_curve25519_import_private_ex(value.ptr, value.len, |
156 | &this->key.key25519, EC25519_LITTLE_ENDIAN); | |
157 | } | |
158 | if (ret == 0) | |
159 | { | |
160 | ret = wc_curve25519_shared_secret_ex(&this->key.key25519, &pub, | |
161 | this->key.key25519.p.point, &len, | |
162 | EC25519_LITTLE_ENDIAN); | |
163 | } | |
164 | return ret == 0; | |
165 | } | |
166 | ||
167 | #endif /* HAVE_CURVE25519 */ | |
168 | ||
169 | #ifdef HAVE_CURVE448 | |
170 | ||
171 | METHOD(diffie_hellman_t, set_other_public_value_448, bool, | |
172 | private_diffie_hellman_t *this, chunk_t value) | |
173 | { | |
174 | word32 len = CURVE448_KEY_SIZE; | |
175 | curve448_key pub; | |
176 | int ret; | |
177 | ||
178 | if (!diffie_hellman_verify_value(this->group, value)) | |
179 | { | |
180 | return FALSE; | |
181 | } | |
182 | ||
183 | ret = wc_curve448_init(&pub); | |
184 | if (ret != 0) | |
185 | { | |
186 | DBG1(DBG_LIB, "%N public key initialization failed", | |
187 | diffie_hellman_group_names, this->group); | |
188 | return FALSE; | |
189 | } | |
190 | ||
191 | ret = wc_curve448_import_public_ex(value.ptr, value.len, &pub, | |
192 | EC448_LITTLE_ENDIAN); | |
193 | if (ret != 0) | |
194 | { | |
195 | DBG1(DBG_LIB, "%N public value is malformed", | |
196 | diffie_hellman_group_names, this->group); | |
197 | return FALSE; | |
198 | } | |
199 | ||
200 | chunk_clear(&this->shared_secret); | |
201 | this->shared_secret = chunk_alloc(len); | |
202 | if (wc_curve448_shared_secret_ex(&this->key.key448, &pub, | |
203 | this->shared_secret.ptr, &len, EC448_LITTLE_ENDIAN) != 0) | |
204 | { | |
205 | DBG1(DBG_LIB, "%N shared secret computation failed", | |
206 | diffie_hellman_group_names, this->group); | |
207 | chunk_clear(&this->shared_secret); | |
208 | wc_curve448_free(&pub); | |
209 | return FALSE; | |
210 | } | |
211 | wc_curve448_free(&pub); | |
212 | return TRUE; | |
213 | } | |
214 | ||
215 | METHOD(diffie_hellman_t, get_my_public_value_448, bool, | |
216 | private_diffie_hellman_t *this, chunk_t *value) | |
217 | { | |
218 | word32 len = CURVE448_KEY_SIZE; | |
219 | ||
220 | *value = chunk_alloc(len); | |
221 | if (wc_curve448_export_public_ex(&this->key.key448, value->ptr, &len, | |
222 | EC448_LITTLE_ENDIAN) != 0) | |
223 | { | |
224 | chunk_free(value); | |
225 | return FALSE; | |
226 | } | |
227 | return TRUE; | |
228 | } | |
229 | ||
230 | METHOD(diffie_hellman_t, set_private_value_448, bool, | |
231 | private_diffie_hellman_t *this, chunk_t value) | |
232 | { | |
233 | curve448_key pub; | |
234 | u_char basepoint[CURVE448_KEY_SIZE] = {5}; | |
235 | word32 len = CURVE448_KEY_SIZE; | |
236 | int ret; | |
237 | ||
238 | ret = wc_curve448_init(&pub); | |
239 | /* create base point for calculating public key */ | |
240 | if (ret == 0) | |
241 | { | |
242 | ret = wc_curve448_import_public_ex(basepoint, CURVE448_KEY_SIZE, | |
243 | &pub, EC448_LITTLE_ENDIAN); | |
c92eade8 SP |
244 | } |
245 | if (ret == 0) | |
246 | { | |
59a987b8 TB |
247 | ret = wc_curve448_import_private_ex(value.ptr, value.len, |
248 | &this->key.key448, EC448_LITTLE_ENDIAN); | |
249 | } | |
250 | if (ret == 0) | |
251 | { | |
252 | ret = wc_curve448_shared_secret_ex(&this->key.key448, &pub, | |
253 | this->key.key448.p, &len, | |
254 | EC448_LITTLE_ENDIAN); | |
c92eade8 | 255 | } |
c92eade8 SP |
256 | return ret == 0; |
257 | } | |
258 | ||
59a987b8 TB |
259 | #endif /* HAVE_CURVE448 */ |
260 | ||
c92eade8 SP |
261 | METHOD(diffie_hellman_t, get_shared_secret, bool, |
262 | private_diffie_hellman_t *this, chunk_t *secret) | |
263 | { | |
d3329ee5 | 264 | if (!this->shared_secret.len) |
c92eade8 SP |
265 | { |
266 | return FALSE; | |
267 | } | |
268 | *secret = chunk_clone(this->shared_secret); | |
269 | return TRUE; | |
270 | } | |
271 | ||
272 | METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t, | |
273 | private_diffie_hellman_t *this) | |
274 | { | |
275 | return this->group; | |
276 | } | |
277 | ||
278 | METHOD(diffie_hellman_t, destroy, void, | |
279 | private_diffie_hellman_t *this) | |
280 | { | |
59a987b8 TB |
281 | if (this->group == CURVE_25519) |
282 | { | |
283 | #ifdef HAVE_CURVE25519 | |
284 | wc_curve25519_free(&this->key.key25519); | |
285 | #endif | |
286 | } | |
287 | else if (this->group == CURVE_448) | |
288 | { | |
289 | #ifdef HAVE_CURVE448 | |
290 | wc_curve448_free(&this->key.key448); | |
291 | #endif | |
292 | } | |
c92eade8 SP |
293 | chunk_clear(&this->shared_secret); |
294 | free(this); | |
295 | } | |
296 | ||
297 | /* | |
298 | * Described in header | |
299 | */ | |
300 | diffie_hellman_t *wolfssl_x_diffie_hellman_create(diffie_hellman_group_t group) | |
301 | { | |
302 | private_diffie_hellman_t *this; | |
303 | WC_RNG rng; | |
59a987b8 | 304 | int ret = -1; |
c92eade8 | 305 | |
c92eade8 SP |
306 | INIT(this, |
307 | .public = { | |
308 | .get_shared_secret = _get_shared_secret, | |
c92eade8 SP |
309 | .get_dh_group = _get_dh_group, |
310 | .destroy = _destroy, | |
311 | }, | |
312 | .group = group, | |
313 | ); | |
314 | ||
c92eade8 SP |
315 | if (wc_InitRng(&rng) != 0) |
316 | { | |
d3329ee5 TB |
317 | DBG1(DBG_LIB, "initializing a random number generator failed"); |
318 | destroy(this); | |
c92eade8 SP |
319 | return NULL; |
320 | } | |
59a987b8 TB |
321 | |
322 | if (group == CURVE_25519) | |
323 | { | |
324 | #ifdef HAVE_CURVE25519 | |
325 | this->public.set_other_public_value = _set_other_public_value_25519; | |
326 | this->public.get_my_public_value = _get_my_public_value_25519; | |
327 | this->public.set_private_value = _set_private_value_25519; | |
328 | ||
329 | if (wc_curve25519_init(&this->key.key25519) != 0) | |
330 | { | |
331 | DBG1(DBG_LIB, "initializing key failed"); | |
332 | free(this); | |
333 | return NULL; | |
334 | } | |
335 | ret = wc_curve25519_make_key(&rng, CURVE25519_KEYSIZE, | |
336 | &this->key.key25519); | |
337 | #endif | |
338 | } | |
339 | else if (group == CURVE_448) | |
340 | { | |
341 | #ifdef HAVE_CURVE448 | |
342 | this->public.set_other_public_value = _set_other_public_value_448; | |
343 | this->public.get_my_public_value = _get_my_public_value_448; | |
344 | this->public.set_private_value = _set_private_value_448; | |
345 | ||
346 | if (wc_curve448_init(&this->key.key448) != 0) | |
347 | { | |
348 | DBG1(DBG_LIB, "initializing key failed"); | |
349 | free(this); | |
350 | return NULL; | |
351 | } | |
352 | ret = wc_curve448_make_key(&rng, CURVE448_KEY_SIZE, &this->key.key448); | |
353 | #endif | |
354 | } | |
c92eade8 SP |
355 | wc_FreeRng(&rng); |
356 | if (ret != 0) | |
357 | { | |
d3329ee5 TB |
358 | DBG1(DBG_LIB, "making a key failed"); |
359 | destroy(this); | |
c92eade8 SP |
360 | return NULL; |
361 | } | |
362 | return &this->public; | |
363 | } | |
364 | ||
59a987b8 | 365 | #endif /* HAVE_CURVE25519 || HAVE_CURVE448 */ |