diff options
Diffstat (limited to 'src/util/crypto_edx25519.c')
-rw-r--r-- | src/util/crypto_edx25519.c | 354 |
1 files changed, 0 insertions, 354 deletions
diff --git a/src/util/crypto_edx25519.c b/src/util/crypto_edx25519.c deleted file mode 100644 index e43c1685b..000000000 --- a/src/util/crypto_edx25519.c +++ /dev/null | |||
@@ -1,354 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2022 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file util/crypto_edx25519.c | ||
23 | * @brief An variant of EdDSA which allows for iterative derivation of key pairs. | ||
24 | * @author Özgür Kesim | ||
25 | * @author Christian Grothoff | ||
26 | * @author Florian Dold | ||
27 | * @author Martin Schanzenbach | ||
28 | */ | ||
29 | #include "platform.h" | ||
30 | #include <gcrypt.h> | ||
31 | #include <sodium.h> | ||
32 | #include "gnunet_crypto_lib.h" | ||
33 | #include "gnunet_strings_lib.h" | ||
34 | |||
35 | #define CURVE "Ed25519" | ||
36 | |||
37 | void | ||
38 | GNUNET_CRYPTO_edx25519_key_clear (struct GNUNET_CRYPTO_Edx25519PrivateKey *pk) | ||
39 | { | ||
40 | memset (pk, 0, sizeof(struct GNUNET_CRYPTO_Edx25519PrivateKey)); | ||
41 | } | ||
42 | |||
43 | |||
44 | void | ||
45 | GNUNET_CRYPTO_edx25519_key_create_from_seed ( | ||
46 | const void *seed, | ||
47 | size_t seedsize, | ||
48 | struct GNUNET_CRYPTO_Edx25519PrivateKey *pk) | ||
49 | { | ||
50 | |||
51 | GNUNET_static_assert (sizeof(*pk) == sizeof(struct GNUNET_HashCode)); | ||
52 | GNUNET_CRYPTO_hash (seed, | ||
53 | seedsize, | ||
54 | (struct GNUNET_HashCode *) pk); | ||
55 | |||
56 | /* Clamp the first half of the key. The second half is used in the signature | ||
57 | * process. */ | ||
58 | pk->a[0] &= 248; | ||
59 | pk->a[31] &= 127; | ||
60 | pk->a[31] |= 64; | ||
61 | } | ||
62 | |||
63 | |||
64 | void | ||
65 | GNUNET_CRYPTO_edx25519_key_create ( | ||
66 | struct GNUNET_CRYPTO_Edx25519PrivateKey *pk) | ||
67 | { | ||
68 | char seed[256 / 8]; | ||
69 | GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, | ||
70 | seed, | ||
71 | sizeof (seed)); | ||
72 | GNUNET_CRYPTO_edx25519_key_create_from_seed (seed, | ||
73 | sizeof(seed), | ||
74 | pk); | ||
75 | } | ||
76 | |||
77 | |||
78 | void | ||
79 | GNUNET_CRYPTO_edx25519_key_get_public ( | ||
80 | const struct GNUNET_CRYPTO_Edx25519PrivateKey *priv, | ||
81 | struct GNUNET_CRYPTO_Edx25519PublicKey *pub) | ||
82 | { | ||
83 | crypto_scalarmult_ed25519_base_noclamp (pub->q_y, | ||
84 | priv->a); | ||
85 | } | ||
86 | |||
87 | |||
88 | /** | ||
89 | * This function operates the basically same way as the signature function for | ||
90 | * EdDSA. But instead of expanding a private seed (which is usually the case | ||
91 | * for crypto APIs) and using the resulting scalars, it takes the scalars | ||
92 | * directly from Edx25519PrivateKey. We require this functionality in order to | ||
93 | * use derived private keys for signatures. | ||
94 | * | ||
95 | * The resulting signature is a standard EdDSA signature | ||
96 | * which can be verified using the usual APIs. | ||
97 | * | ||
98 | * @param priv the private key (containing two scalars .a and .b) | ||
99 | * @param purp the signature purpose | ||
100 | * @param sig the resulting signature | ||
101 | */ | ||
102 | enum GNUNET_GenericReturnValue | ||
103 | GNUNET_CRYPTO_edx25519_sign_ ( | ||
104 | const struct GNUNET_CRYPTO_Edx25519PrivateKey *priv, | ||
105 | const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose, | ||
106 | struct GNUNET_CRYPTO_Edx25519Signature *sig) | ||
107 | { | ||
108 | |||
109 | crypto_hash_sha512_state hs; | ||
110 | unsigned char r[64]; | ||
111 | unsigned char hram[64]; | ||
112 | unsigned char P[32]; | ||
113 | unsigned char r_mod[64]; | ||
114 | unsigned char R[32]; | ||
115 | unsigned char tmp[32]; | ||
116 | |||
117 | crypto_hash_sha512_init (&hs); | ||
118 | |||
119 | /** | ||
120 | * Calculate the public key P from the private scalar in the key. | ||
121 | */ | ||
122 | crypto_scalarmult_ed25519_base_noclamp (P, | ||
123 | priv->a); | ||
124 | |||
125 | /** | ||
126 | * Calculate r: | ||
127 | * r = SHA512 (b ∥ M) | ||
128 | * where M is our message (purpose). | ||
129 | */ | ||
130 | crypto_hash_sha512_update (&hs, | ||
131 | priv->b, | ||
132 | sizeof(priv->b)); | ||
133 | crypto_hash_sha512_update (&hs, | ||
134 | (uint8_t*) purpose, | ||
135 | ntohl (purpose->size)); | ||
136 | crypto_hash_sha512_final (&hs, | ||
137 | r); | ||
138 | |||
139 | /** | ||
140 | * Temporarily put P into S | ||
141 | */ | ||
142 | memcpy (sig->s, P, 32); | ||
143 | |||
144 | /** | ||
145 | * Reduce the scalar value r | ||
146 | */ | ||
147 | crypto_core_ed25519_scalar_reduce (r_mod, r); | ||
148 | |||
149 | /** | ||
150 | * Calculate R := r * G of the signature | ||
151 | */ | ||
152 | crypto_scalarmult_ed25519_base_noclamp (R, r_mod); | ||
153 | memcpy (sig->r, R, sizeof (R)); | ||
154 | |||
155 | /** | ||
156 | * Calculate | ||
157 | * hram := SHA512 (R ∥ P ∥ M) | ||
158 | */ | ||
159 | crypto_hash_sha512_init (&hs); | ||
160 | crypto_hash_sha512_update (&hs, (uint8_t*) sig, 64); | ||
161 | crypto_hash_sha512_update (&hs, (uint8_t*) purpose, | ||
162 | ntohl (purpose->size)); | ||
163 | crypto_hash_sha512_final (&hs, hram); | ||
164 | |||
165 | /** | ||
166 | * Reduce the resulting scalar value | ||
167 | */ | ||
168 | unsigned char hram_mod[64]; | ||
169 | crypto_core_ed25519_scalar_reduce (hram_mod, hram); | ||
170 | |||
171 | /** | ||
172 | * Calculate | ||
173 | * S := r + hram * s mod L | ||
174 | */ | ||
175 | crypto_core_ed25519_scalar_mul (tmp, hram_mod, priv->a); | ||
176 | crypto_core_ed25519_scalar_add (sig->s, tmp, r_mod); | ||
177 | |||
178 | sodium_memzero (r, sizeof (r)); | ||
179 | sodium_memzero (r_mod, sizeof (r_mod)); | ||
180 | |||
181 | return GNUNET_OK; | ||
182 | } | ||
183 | |||
184 | |||
185 | enum GNUNET_GenericReturnValue | ||
186 | GNUNET_CRYPTO_edx25519_verify_ ( | ||
187 | uint32_t purpose, | ||
188 | const struct GNUNET_CRYPTO_EccSignaturePurpose *validate, | ||
189 | const struct GNUNET_CRYPTO_Edx25519Signature *sig, | ||
190 | const struct GNUNET_CRYPTO_Edx25519PublicKey *pub) | ||
191 | { | ||
192 | const unsigned char *m = (const void *) validate; | ||
193 | size_t mlen = ntohl (validate->size); | ||
194 | const unsigned char *s = (const void *) sig; | ||
195 | |||
196 | int res; | ||
197 | |||
198 | if (purpose != ntohl (validate->purpose)) | ||
199 | return GNUNET_SYSERR; /* purpose mismatch */ | ||
200 | |||
201 | res = crypto_sign_verify_detached (s, m, mlen, pub->q_y); | ||
202 | return (res == 0) ? GNUNET_OK : GNUNET_SYSERR; | ||
203 | } | ||
204 | |||
205 | |||
206 | /** | ||
207 | * Derive the 'h' value for key derivation, where | ||
208 | * 'h = H(P ∥ seed) mod n' and 'n' is the size of the cyclic subroup. | ||
209 | * | ||
210 | * @param pub public key for deriviation | ||
211 | * @param seed seed for key the deriviation | ||
212 | * @param seedsize the size of the seed | ||
213 | * @param[out] phc if not NULL, the output of H() will be written into | ||
214 | * return h_mod_n (allocated by this function) | ||
215 | */ | ||
216 | static void | ||
217 | derive_h ( | ||
218 | const struct GNUNET_CRYPTO_Edx25519PublicKey *pub, | ||
219 | const void *seed, | ||
220 | size_t seedsize, | ||
221 | struct GNUNET_HashCode *phc) | ||
222 | { | ||
223 | static const char *const salt = "edx25519-derivation"; | ||
224 | |||
225 | GNUNET_CRYPTO_kdf (/* output*/ | ||
226 | phc, sizeof(*phc), | ||
227 | /* salt */ | ||
228 | seed, seedsize, | ||
229 | /* ikm */ | ||
230 | pub, sizeof(*pub), | ||
231 | /* ctx chunks*/ | ||
232 | salt, strlen (salt), | ||
233 | NULL, 0); | ||
234 | |||
235 | } | ||
236 | |||
237 | |||
238 | void | ||
239 | GNUNET_CRYPTO_edx25519_private_key_derive ( | ||
240 | const struct GNUNET_CRYPTO_Edx25519PrivateKey *priv, | ||
241 | const void *seed, | ||
242 | size_t seedsize, | ||
243 | struct GNUNET_CRYPTO_Edx25519PrivateKey *result) | ||
244 | { | ||
245 | struct GNUNET_CRYPTO_Edx25519PublicKey pub; | ||
246 | struct GNUNET_HashCode hc; | ||
247 | uint8_t a[32]; | ||
248 | uint8_t eight[32] = { 8 }; | ||
249 | uint8_t eight_inv[32]; | ||
250 | uint8_t h[64] = { 0 }; | ||
251 | |||
252 | GNUNET_CRYPTO_edx25519_key_get_public (priv, &pub); | ||
253 | |||
254 | /* Get h mod n */ | ||
255 | derive_h (&pub, | ||
256 | seed, | ||
257 | seedsize, | ||
258 | &hc); | ||
259 | |||
260 | memcpy (h, &hc, 64); | ||
261 | crypto_core_ed25519_scalar_reduce (h, | ||
262 | h); | ||
263 | #ifdef CHECK_RARE_CASES | ||
264 | /** | ||
265 | * Note that the following cases would be problematic: | ||
266 | * 1.) h == 0 mod n | ||
267 | * 2.) h == 1 mod n | ||
268 | * 3.) [h] * P == E | ||
269 | * We assume that the probalities for these cases to occur are neglegible. | ||
270 | */ | ||
271 | { | ||
272 | char zero[32] = { 0 }; | ||
273 | char one[32] = { 1 }; | ||
274 | |||
275 | GNUNET_assert (0 != memcmp (zero, h, 32)); | ||
276 | GNUNET_assert (0 != memcmp (one, h, 32)); | ||
277 | } | ||
278 | #endif | ||
279 | |||
280 | /** | ||
281 | * dc now contains the private scalar "a". | ||
282 | * We carefully remove the clamping and derive a'. | ||
283 | * Calculate: | ||
284 | * a1 := a / 8 | ||
285 | * a2 := h * a1 mod n | ||
286 | * a' := a2 * 8 mod n | ||
287 | */ | ||
288 | |||
289 | GNUNET_assert (0 == crypto_core_ed25519_scalar_invert (eight_inv, | ||
290 | eight)); | ||
291 | |||
292 | crypto_core_ed25519_scalar_mul (a, priv->a, eight_inv); | ||
293 | crypto_core_ed25519_scalar_mul (a, a, h); | ||
294 | crypto_core_ed25519_scalar_mul (a, a, eight); | ||
295 | |||
296 | #ifdef CHECK_RARE_CASES | ||
297 | /* The likelihood for a' == 0 or a' == 1 is neglegible */ | ||
298 | { | ||
299 | char zero[32] = { 0 }; | ||
300 | char one[32] = { 1 }; | ||
301 | |||
302 | GNUNET_assert (0 != memcmp (zero, a, 32)); | ||
303 | GNUNET_assert (0 != memcmp (one, a, 32)); | ||
304 | } | ||
305 | #endif | ||
306 | |||
307 | /* We hash the derived "h" parameter with the other half of the expanded | ||
308 | * private key (that is: priv->b). This ensures that for signature | ||
309 | * generation, the "R" is derived from the same derivation path as "h" and is | ||
310 | * not reused. */ | ||
311 | { | ||
312 | struct GNUNET_HashCode hcb; | ||
313 | struct GNUNET_HashContext *hctx; | ||
314 | |||
315 | hctx = GNUNET_CRYPTO_hash_context_start (); | ||
316 | GNUNET_CRYPTO_hash_context_read (hctx, priv->b, sizeof(priv->b)); | ||
317 | GNUNET_CRYPTO_hash_context_read (hctx, (unsigned char*) &hc, sizeof (hc)); | ||
318 | GNUNET_CRYPTO_hash_context_finish (hctx, &hcb); | ||
319 | |||
320 | /* Truncate result, effectively doing SHA512/256 */ | ||
321 | for (size_t i = 0; i < 32; i++) | ||
322 | result->b[i] = ((unsigned char *) &hcb)[i]; | ||
323 | } | ||
324 | |||
325 | for (size_t i = 0; i < 32; i++) | ||
326 | result->a[i] = a[i]; | ||
327 | |||
328 | sodium_memzero (a, sizeof(a)); | ||
329 | } | ||
330 | |||
331 | |||
332 | void | ||
333 | GNUNET_CRYPTO_edx25519_public_key_derive ( | ||
334 | const struct GNUNET_CRYPTO_Edx25519PublicKey *pub, | ||
335 | const void *seed, | ||
336 | size_t seedsize, | ||
337 | struct GNUNET_CRYPTO_Edx25519PublicKey *result) | ||
338 | { | ||
339 | struct GNUNET_HashCode hc; | ||
340 | uint8_t h[64] = { 0 }; | ||
341 | |||
342 | derive_h (pub, | ||
343 | seed, | ||
344 | seedsize, | ||
345 | &hc); | ||
346 | memcpy (h, | ||
347 | &hc, | ||
348 | 64); | ||
349 | crypto_core_ed25519_scalar_reduce (h, | ||
350 | h); | ||
351 | GNUNET_assert (0 == crypto_scalarmult_ed25519_noclamp (result->q_y, | ||
352 | h, | ||
353 | pub->q_y)); | ||
354 | } | ||