diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/util/crypto_edx25519.c | 198 |
1 files changed, 64 insertions, 134 deletions
diff --git a/src/util/crypto_edx25519.c b/src/util/crypto_edx25519.c index 26b45407e..2a7f75030 100644 --- a/src/util/crypto_edx25519.c +++ b/src/util/crypto_edx25519.c | |||
@@ -210,53 +210,28 @@ GNUNET_CRYPTO_edx25519_verify_ ( | |||
210 | * @param pub public key for deriviation | 210 | * @param pub public key for deriviation |
211 | * @param seed seed for key the deriviation | 211 | * @param seed seed for key the deriviation |
212 | * @param seedsize the size of the seed | 212 | * @param seedsize the size of the seed |
213 | * @param n The value for the modulus 'n' | ||
214 | * @param[out] phc if not NULL, the output of H() will be written into | 213 | * @param[out] phc if not NULL, the output of H() will be written into |
215 | * return h_mod_n (allocated by this function) | 214 | * return h_mod_n (allocated by this function) |
216 | */ | 215 | */ |
217 | static gcry_mpi_t | 216 | static void |
218 | derive_h_mod_n ( | 217 | derive_h ( |
219 | const struct GNUNET_CRYPTO_Edx25519PublicKey *pub, | 218 | const struct GNUNET_CRYPTO_Edx25519PublicKey *pub, |
220 | const void *seed, | 219 | const void *seed, |
221 | size_t seedsize, | 220 | size_t seedsize, |
222 | const gcry_mpi_t n, | ||
223 | struct GNUNET_HashCode *phc) | 221 | struct GNUNET_HashCode *phc) |
224 | { | 222 | { |
225 | static const char *const salt = "edx2559-derivation"; | 223 | static const char *const salt = "edx2559-derivation"; |
226 | struct GNUNET_HashCode hc; | ||
227 | gcry_mpi_t h; | ||
228 | gcry_mpi_t h_mod_n; | ||
229 | |||
230 | if (NULL == phc) | ||
231 | phc = &hc; | ||
232 | 224 | ||
233 | GNUNET_CRYPTO_kdf (phc, sizeof(*phc), | 225 | GNUNET_CRYPTO_kdf (/* output*/ |
234 | salt, strlen (salt), | 226 | phc, sizeof(*phc), |
227 | /* salt */ | ||
235 | pub, sizeof(*pub), | 228 | pub, sizeof(*pub), |
229 | /* ikm */ | ||
236 | seed, seedsize, | 230 | seed, seedsize, |
231 | /* ctx chunks*/ | ||
232 | salt, strlen (salt), | ||
237 | NULL, 0); | 233 | NULL, 0); |
238 | 234 | ||
239 | /* calculate h_mod_n = h % n */ | ||
240 | GNUNET_CRYPTO_mpi_scan_unsigned (&h, | ||
241 | (unsigned char *) phc, | ||
242 | sizeof(*phc)); | ||
243 | h_mod_n = gcry_mpi_new (256); | ||
244 | gcry_mpi_mod (h_mod_n, h, n); | ||
245 | |||
246 | #ifdef CHECK_RARE_CASES | ||
247 | /** | ||
248 | * Note that the following cases would be problematic: | ||
249 | * 1.) h == 0 mod n | ||
250 | * 2.) h == 1 mod n | ||
251 | * 3.) [h] * P == E | ||
252 | * We assume that the probalities for these cases to occur are neglegible. | ||
253 | */ | ||
254 | GNUNET_assert (! gcry_mpi_cmp_ui (h_mod_n, 0)); | ||
255 | GNUNET_assert (! gcry_mpi_cmp_ui (h_mod_n, 1)); | ||
256 | #endif | ||
257 | |||
258 | gcry_mpi_release(h); | ||
259 | return h_mod_n; | ||
260 | } | 235 | } |
261 | 236 | ||
262 | 237 | ||
@@ -270,40 +245,37 @@ GNUNET_CRYPTO_edx25519_private_key_derive ( | |||
270 | struct GNUNET_CRYPTO_Edx25519PublicKey pub; | 245 | struct GNUNET_CRYPTO_Edx25519PublicKey pub; |
271 | struct GNUNET_HashCode hc; | 246 | struct GNUNET_HashCode hc; |
272 | uint8_t a[32]; | 247 | uint8_t a[32]; |
273 | gcry_ctx_t ctx; | 248 | uint8_t eight[32] = { 8 }; |
274 | gcry_mpi_t h_mod_n; | 249 | uint8_t eight_inv[32]; |
275 | gcry_mpi_t x; | 250 | uint8_t h[64] = { 0 }; |
276 | gcry_mpi_t n; | ||
277 | gcry_mpi_t a1; | ||
278 | gcry_mpi_t a2; | ||
279 | gcry_mpi_t ap; // a' | ||
280 | 251 | ||
281 | GNUNET_CRYPTO_edx25519_key_get_public (priv, &pub); | 252 | GNUNET_CRYPTO_edx25519_key_get_public (priv, &pub); |
282 | 253 | ||
283 | /** | 254 | /* Get h mod n */ |
284 | * Libsodium does not offer an API with arbitrary arithmetic. | 255 | derive_h (&pub, |
285 | * Hence we have to use libgcrypt here. | 256 | seed, |
286 | */ | 257 | seedsize, |
287 | GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, "Ed25519")); | 258 | &hc); |
288 | |||
289 | /** | ||
290 | * Get our modulo | ||
291 | */ | ||
292 | n = gcry_mpi_ec_get_mpi ("n", ctx, 1); | ||
293 | GNUNET_assert (NULL != n); | ||
294 | 259 | ||
260 | memcpy (h, &hc, 64); | ||
261 | crypto_core_ed25519_scalar_reduce (h, | ||
262 | h); | ||
263 | #ifdef CHECK_RARE_CASES | ||
295 | /** | 264 | /** |
296 | * Get h mod n | 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. | ||
297 | */ | 270 | */ |
298 | h_mod_n = derive_h_mod_n (&pub, | 271 | { |
299 | seed, | 272 | char zero[32] = { 0 }; |
300 | seedsize, | 273 | char one[32] = { 1 }; |
301 | n, | ||
302 | &hc); | ||
303 | 274 | ||
304 | /* Convert priv->a scalar to big endian for libgcrypt */ | 275 | GNUNET_assert (0 != memcmp (zero, h, 32)); |
305 | for (size_t i = 0; i < 32; i++) | 276 | GNUNET_assert (0 != memcmp (one, h, 32)); |
306 | a[i] = priv->a[31 - i]; | 277 | } |
278 | #endif | ||
307 | 279 | ||
308 | /** | 280 | /** |
309 | * dc now contains the private scalar "a". | 281 | * dc now contains the private scalar "a". |
@@ -313,37 +285,29 @@ GNUNET_CRYPTO_edx25519_private_key_derive ( | |||
313 | * a2 := h * a1 mod n | 285 | * a2 := h * a1 mod n |
314 | * a' := a2 * 8 mod n | 286 | * a' := a2 * 8 mod n |
315 | */ | 287 | */ |
316 | GNUNET_CRYPTO_mpi_scan_unsigned (&x, a, sizeof(a)); // a | 288 | |
317 | a1 = gcry_mpi_new (256); | 289 | GNUNET_assert (0 == crypto_core_ed25519_scalar_invert (eight_inv, |
318 | gcry_mpi_t eight = gcry_mpi_set_ui (NULL, 8); | 290 | eight)); |
319 | gcry_mpi_div (a1, NULL, x, eight, 0); // a1 := a / 8 | 291 | |
320 | a2 = gcry_mpi_new (256); | 292 | crypto_core_ed25519_scalar_mul (a, priv->a, eight_inv); |
321 | gcry_mpi_mulm (a2, h_mod_n, a1, n); // a2 := h * a1 mod n | 293 | crypto_core_ed25519_scalar_mul (a, a, h); |
322 | ap = gcry_mpi_new (256); | 294 | crypto_core_ed25519_scalar_mul (a, a, eight); |
323 | gcry_mpi_mul (ap, a2, eight); // a' := a2 * 8 | ||
324 | 295 | ||
325 | #ifdef CHECK_RARE_CASES | 296 | #ifdef CHECK_RARE_CASES |
326 | /* The likelihood for a' == 0 or a' == 1 is neglegible */ | 297 | /* The likelihood for a' == 0 or a' == 1 is neglegible */ |
327 | GNUNET_assert (! gcry_mpi_cmp_ui (ap, 0)); | 298 | { |
328 | GNUNET_assert (! gcry_mpi_cmp_ui (ap, 1)); | 299 | char zero[32] = { 0 }; |
329 | #endif | 300 | char one[32] = { 1 }; |
330 | 301 | ||
331 | gcry_mpi_release (h_mod_n); | 302 | GNUNET_assert (0 != memcmp (zero, a, 32)); |
332 | gcry_mpi_release (eight); | 303 | GNUNET_assert (0 != memcmp (one, a, 32)); |
333 | gcry_mpi_release (x); | 304 | } |
334 | gcry_mpi_release (n); | 305 | #endif |
335 | gcry_mpi_release (a1); | ||
336 | gcry_mpi_release (a2); | ||
337 | gcry_ctx_release (ctx); | ||
338 | GNUNET_CRYPTO_mpi_print_unsigned (a, sizeof(a), ap); | ||
339 | gcry_mpi_release (ap); | ||
340 | 306 | ||
341 | /** | 307 | /* We hash the derived "h" parameter with the other half of the expanded |
342 | * We hash the derived "h" parameter with the other half of the expanded | ||
343 | * private key (that is: priv->b). This ensures that for signature | 308 | * private key (that is: priv->b). This ensures that for signature |
344 | * generation, the "R" is derived from the same derivation path as "h" and is | 309 | * generation, the "R" is derived from the same derivation path as "h" and is |
345 | * not reused. | 310 | * not reused. */ |
346 | */ | ||
347 | { | 311 | { |
348 | crypto_hash_sha256_state hs; | 312 | crypto_hash_sha256_state hs; |
349 | crypto_hash_sha256_init (&hs); | 313 | crypto_hash_sha256_init (&hs); |
@@ -352,9 +316,8 @@ GNUNET_CRYPTO_edx25519_private_key_derive ( | |||
352 | crypto_hash_sha256_final (&hs, result->b); | 316 | crypto_hash_sha256_final (&hs, result->b); |
353 | } | 317 | } |
354 | 318 | ||
355 | /* Convert to little endian for libsodium */ | ||
356 | for (size_t i = 0; i < 32; i++) | 319 | for (size_t i = 0; i < 32; i++) |
357 | result->a[i] = a[31 - i]; | 320 | result->a[i] = a[i]; |
358 | 321 | ||
359 | sodium_memzero (a, sizeof(a)); | 322 | sodium_memzero (a, sizeof(a)); |
360 | } | 323 | } |
@@ -367,52 +330,19 @@ GNUNET_CRYPTO_edx25519_public_key_derive ( | |||
367 | size_t seedsize, | 330 | size_t seedsize, |
368 | struct GNUNET_CRYPTO_Edx25519PublicKey *result) | 331 | struct GNUNET_CRYPTO_Edx25519PublicKey *result) |
369 | { | 332 | { |
370 | gcry_ctx_t ctx; | 333 | struct GNUNET_HashCode hc; |
371 | gcry_mpi_t q_y; | 334 | uint8_t h[64] = { 0 }; |
372 | gcry_mpi_t n; | 335 | |
373 | gcry_mpi_t h_mod_n; | 336 | derive_h (pub, |
374 | gcry_mpi_point_t q; | 337 | seed, |
375 | gcry_mpi_point_t v; | 338 | seedsize, |
376 | 339 | &hc); | |
377 | GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, "Ed25519")); | 340 | memcpy (h, |
378 | 341 | &hc, | |
379 | /* obtain point 'q' from original public key. The provided 'q' is | 342 | 64); |
380 | compressed thus we first store it in the context and then get it | 343 | crypto_core_ed25519_scalar_reduce (h, |
381 | back as a (decompresssed) point. */ | 344 | h); |
382 | q_y = gcry_mpi_set_opaque_copy (NULL, | 345 | GNUNET_assert (0 == crypto_scalarmult_ed25519_noclamp (result->q_y, |
383 | pub->q_y, | 346 | h, |
384 | 8 * sizeof(pub->q_y)); | 347 | pub->q_y)); |
385 | GNUNET_assert (NULL != q_y); | ||
386 | GNUNET_assert (0 == gcry_mpi_ec_set_mpi ("q", q_y, ctx)); | ||
387 | gcry_mpi_release (q_y); | ||
388 | q = gcry_mpi_ec_get_point ("q", ctx, 0); | ||
389 | GNUNET_assert (q); | ||
390 | |||
391 | /** | ||
392 | * Get h mod n | ||
393 | */ | ||
394 | n = gcry_mpi_ec_get_mpi ("n", ctx, 1); | ||
395 | GNUNET_assert (NULL != n); | ||
396 | GNUNET_assert (NULL != pub); | ||
397 | h_mod_n = derive_h_mod_n (pub, | ||
398 | seed, | ||
399 | seedsize, | ||
400 | n, | ||
401 | NULL /* We don't need hc here */); | ||
402 | |||
403 | /* calculate v = h_mod_n * q */ | ||
404 | v = gcry_mpi_point_new (0); | ||
405 | gcry_mpi_ec_mul (v, h_mod_n, q, ctx); | ||
406 | gcry_mpi_release (h_mod_n); | ||
407 | gcry_mpi_release (n); | ||
408 | gcry_mpi_point_release (q); | ||
409 | |||
410 | /* convert point 'v' to public key that we return */ | ||
411 | GNUNET_assert (0 == gcry_mpi_ec_set_point ("q", v, ctx)); | ||
412 | gcry_mpi_point_release (v); | ||
413 | q_y = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0); | ||
414 | GNUNET_assert (q_y); | ||
415 | GNUNET_CRYPTO_mpi_print_unsigned (result->q_y, sizeof(result->q_y), q_y); | ||
416 | gcry_mpi_release (q_y); | ||
417 | gcry_ctx_release (ctx); | ||
418 | } | 348 | } |