aboutsummaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2022-04-19 14:43:30 +0200
committerFlorian Dold <florian@dold.me>2022-04-19 14:44:56 +0200
commit0487df9a041ac7ecde00d4ea4c6a204eaab06e70 (patch)
tree9a85d7fa3952e43a76be908b2d749d0aa44dec4d /src/util
parent25e750421bba1f921fc9e285db4a04d23c852796 (diff)
downloadgnunet-0487df9a041ac7ecde00d4ea4c6a204eaab06e70.tar.gz
gnunet-0487df9a041ac7ecde00d4ea4c6a204eaab06e70.zip
edx25519: use libsodium, tweak KDF call
Diffstat (limited to 'src/util')
-rw-r--r--src/util/crypto_edx25519.c198
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 */
217static gcry_mpi_t 216static void
218derive_h_mod_n ( 217derive_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}