diff options
-rw-r--r-- | src/util/crypto_ecc_gnsrecord.c | 73 |
1 files changed, 58 insertions, 15 deletions
diff --git a/src/util/crypto_ecc_gnsrecord.c b/src/util/crypto_ecc_gnsrecord.c index bab0ce44a..213f05863 100644 --- a/src/util/crypto_ecc_gnsrecord.c +++ b/src/util/crypto_ecc_gnsrecord.c | |||
@@ -42,20 +42,19 @@ | |||
42 | * @param label label for deriviation | 42 | * @param label label for deriviation |
43 | * @param context additional context to use for HKDF of 'h'; | 43 | * @param context additional context to use for HKDF of 'h'; |
44 | * typically the name of the subsystem/application | 44 | * typically the name of the subsystem/application |
45 | * @return h value | 45 | * @param hc where to write the result |
46 | */ | 46 | */ |
47 | static gcry_mpi_t | 47 | void |
48 | derive_h (const void *pub, | 48 | derive_h (const void *pub, |
49 | size_t pubsize, | 49 | size_t pubsize, |
50 | const char *label, | 50 | const char *label, |
51 | const char *context) | 51 | const char *context, |
52 | struct GNUNET_HashCode *hc) | ||
52 | { | 53 | { |
53 | gcry_mpi_t h; | ||
54 | struct GNUNET_HashCode hc; | ||
55 | static const char *const salt = "key-derivation"; | 54 | static const char *const salt = "key-derivation"; |
56 | 55 | ||
57 | GNUNET_CRYPTO_kdf (&hc, | 56 | GNUNET_CRYPTO_kdf (hc, |
58 | sizeof(hc), | 57 | sizeof(*hc), |
59 | salt, | 58 | salt, |
60 | strlen (salt), | 59 | strlen (salt), |
61 | pub, | 60 | pub, |
@@ -66,8 +65,6 @@ derive_h (const void *pub, | |||
66 | strlen (context), | 65 | strlen (context), |
67 | NULL, | 66 | NULL, |
68 | 0); | 67 | 0); |
69 | GNUNET_CRYPTO_mpi_scan_unsigned (&h, (unsigned char *) &hc, sizeof(hc)); | ||
70 | return h; | ||
71 | } | 68 | } |
72 | 69 | ||
73 | 70 | ||
@@ -193,6 +190,7 @@ GNUNET_CRYPTO_ecdsa_private_key_derive ( | |||
193 | { | 190 | { |
194 | struct GNUNET_CRYPTO_EcdsaPublicKey pub; | 191 | struct GNUNET_CRYPTO_EcdsaPublicKey pub; |
195 | struct GNUNET_CRYPTO_EcdsaPrivateKey *ret; | 192 | struct GNUNET_CRYPTO_EcdsaPrivateKey *ret; |
193 | struct GNUNET_HashCode hc; | ||
196 | uint8_t dc[32]; | 194 | uint8_t dc[32]; |
197 | gcry_mpi_t h; | 195 | gcry_mpi_t h; |
198 | gcry_mpi_t x; | 196 | gcry_mpi_t x; |
@@ -205,7 +203,9 @@ GNUNET_CRYPTO_ecdsa_private_key_derive ( | |||
205 | n = gcry_mpi_ec_get_mpi ("n", ctx, 1); | 203 | n = gcry_mpi_ec_get_mpi ("n", ctx, 1); |
206 | GNUNET_CRYPTO_ecdsa_key_get_public (priv, &pub); | 204 | GNUNET_CRYPTO_ecdsa_key_get_public (priv, &pub); |
207 | 205 | ||
208 | h = derive_h (&pub, sizeof (pub), label, context); | 206 | derive_h (&pub, sizeof (pub), label, context, &hc); |
207 | GNUNET_CRYPTO_mpi_scan_unsigned (&h, (unsigned char *) &hc, sizeof(hc)); | ||
208 | |||
209 | /* Convert to big endian for libgcrypt */ | 209 | /* Convert to big endian for libgcrypt */ |
210 | for (size_t i = 0; i < 32; i++) | 210 | for (size_t i = 0; i < 32; i++) |
211 | dc[i] = priv->d[31 - i]; | 211 | dc[i] = priv->d[31 - i]; |
@@ -234,6 +234,7 @@ GNUNET_CRYPTO_ecdsa_public_key_derive ( | |||
234 | const char *context, | 234 | const char *context, |
235 | struct GNUNET_CRYPTO_EcdsaPublicKey *result) | 235 | struct GNUNET_CRYPTO_EcdsaPublicKey *result) |
236 | { | 236 | { |
237 | struct GNUNET_HashCode hc; | ||
237 | gcry_ctx_t ctx; | 238 | gcry_ctx_t ctx; |
238 | gcry_mpi_t q_y; | 239 | gcry_mpi_t q_y; |
239 | gcry_mpi_t h; | 240 | gcry_mpi_t h; |
@@ -255,7 +256,8 @@ GNUNET_CRYPTO_ecdsa_public_key_derive ( | |||
255 | GNUNET_assert (q); | 256 | GNUNET_assert (q); |
256 | 257 | ||
257 | /* calculate h_mod_n = h % n */ | 258 | /* calculate h_mod_n = h % n */ |
258 | h = derive_h (pub, sizeof (pub), label, context); | 259 | derive_h (pub, sizeof (pub), label, context, &hc); |
260 | GNUNET_CRYPTO_mpi_scan_unsigned (&h, (unsigned char *) &hc, sizeof(hc)); | ||
259 | n = gcry_mpi_ec_get_mpi ("n", ctx, 1); | 261 | n = gcry_mpi_ec_get_mpi ("n", ctx, 1); |
260 | h_mod_n = gcry_mpi_new (256); | 262 | h_mod_n = gcry_mpi_new (256); |
261 | gcry_mpi_mod (h_mod_n, h, n); | 263 | gcry_mpi_mod (h_mod_n, h, n); |
@@ -286,6 +288,7 @@ GNUNET_CRYPTO_eddsa_private_key_derive ( | |||
286 | struct GNUNET_CRYPTO_EddsaPrivateScalar *result) | 288 | struct GNUNET_CRYPTO_EddsaPrivateScalar *result) |
287 | { | 289 | { |
288 | struct GNUNET_CRYPTO_EddsaPublicKey pub; | 290 | struct GNUNET_CRYPTO_EddsaPublicKey pub; |
291 | struct GNUNET_HashCode hc; | ||
289 | uint8_t dc[32]; | 292 | uint8_t dc[32]; |
290 | unsigned char sk[64]; | 293 | unsigned char sk[64]; |
291 | gcry_mpi_t h; | 294 | gcry_mpi_t h; |
@@ -297,20 +300,49 @@ GNUNET_CRYPTO_eddsa_private_key_derive ( | |||
297 | gcry_mpi_t a2; | 300 | gcry_mpi_t a2; |
298 | gcry_ctx_t ctx; | 301 | gcry_ctx_t ctx; |
299 | 302 | ||
303 | /** | ||
304 | * Libsodium does not offer an API with arbitrary arithmetic. | ||
305 | * Hence we have to use libgcrypt here. | ||
306 | */ | ||
300 | GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, "Ed25519")); | 307 | GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, "Ed25519")); |
301 | 308 | ||
309 | /** | ||
310 | * Get our modulo | ||
311 | */ | ||
302 | n = gcry_mpi_ec_get_mpi ("n", ctx, 1); | 312 | n = gcry_mpi_ec_get_mpi ("n", ctx, 1); |
303 | GNUNET_CRYPTO_eddsa_key_get_public (priv, &pub); | 313 | GNUNET_CRYPTO_eddsa_key_get_public (priv, &pub); |
314 | |||
315 | /** | ||
316 | * This is the standard private key expansion in Ed25519. | ||
317 | * The first 32 octets are used as a little-endian private | ||
318 | * scalar. | ||
319 | * We derive this scalar using our "h". | ||
320 | */ | ||
304 | crypto_hash_sha512 (sk, priv->d, 32); | 321 | crypto_hash_sha512 (sk, priv->d, 32); |
305 | sk[0] &= 248; | 322 | sk[0] &= 248; |
306 | sk[31] &= 127; | 323 | sk[31] &= 127; |
307 | sk[31] |= 64; | 324 | sk[31] |= 64; |
308 | h = derive_h (&pub, sizeof (pub), label, context); | 325 | |
326 | /** | ||
327 | * Get h mod n | ||
328 | */ | ||
329 | derive_h (&pub, sizeof (pub), label, context, &hc); | ||
330 | GNUNET_CRYPTO_mpi_scan_unsigned (&h, (unsigned char *) &hc, sizeof(hc)); | ||
331 | |||
309 | h_mod_n = gcry_mpi_new (256); | 332 | h_mod_n = gcry_mpi_new (256); |
310 | gcry_mpi_mod (h_mod_n, h, n); | 333 | gcry_mpi_mod (h_mod_n, h, n); |
311 | /* Convert to big endian for libgcrypt */ | 334 | /* Convert scalar to big endian for libgcrypt */ |
312 | for (size_t i = 0; i < 32; i++) | 335 | for (size_t i = 0; i < 32; i++) |
313 | dc[i] = sk[31 - i]; | 336 | dc[i] = sk[31 - i]; |
337 | |||
338 | /** | ||
339 | * dc now contains the private scalar "a". | ||
340 | * We carefully remove the clamping and derive a'. | ||
341 | * Calculate: | ||
342 | * a1 := a / 8 | ||
343 | * a2 := h * a1 mod n | ||
344 | * a' := a2 * 8 mod n | ||
345 | */ | ||
314 | GNUNET_CRYPTO_mpi_scan_unsigned (&x, dc, sizeof(dc)); // a | 346 | GNUNET_CRYPTO_mpi_scan_unsigned (&x, dc, sizeof(dc)); // a |
315 | a1 = gcry_mpi_new (256); | 347 | a1 = gcry_mpi_new (256); |
316 | gcry_mpi_t eight = gcry_mpi_set_ui (NULL, 8); | 348 | gcry_mpi_t eight = gcry_mpi_set_ui (NULL, 8); |
@@ -318,7 +350,6 @@ GNUNET_CRYPTO_eddsa_private_key_derive ( | |||
318 | a2 = gcry_mpi_new (256); | 350 | a2 = gcry_mpi_new (256); |
319 | gcry_mpi_mulm (a2, h_mod_n, a1, n); // a2 := h * a1 mod n | 351 | gcry_mpi_mulm (a2, h_mod_n, a1, n); // a2 := h * a1 mod n |
320 | d = gcry_mpi_new (256); | 352 | d = gcry_mpi_new (256); |
321 | // gcry_mpi_mulm (d, a2, eight, n); // a' := a2 * 8 mod n | ||
322 | gcry_mpi_mul (d, a2, eight); // a' := a2 * 8 | 353 | gcry_mpi_mul (d, a2, eight); // a' := a2 * 8 |
323 | gcry_mpi_release (h); | 354 | gcry_mpi_release (h); |
324 | gcry_mpi_release (x); | 355 | gcry_mpi_release (x); |
@@ -327,10 +358,19 @@ GNUNET_CRYPTO_eddsa_private_key_derive ( | |||
327 | gcry_mpi_release (a2); | 358 | gcry_mpi_release (a2); |
328 | gcry_ctx_release (ctx); | 359 | gcry_ctx_release (ctx); |
329 | GNUNET_CRYPTO_mpi_print_unsigned (dc, sizeof(dc), d); | 360 | GNUNET_CRYPTO_mpi_print_unsigned (dc, sizeof(dc), d); |
361 | /** | ||
362 | * Note that we copy all of SHA512(d) into the result and | ||
363 | * then overrwrite the derived private scalar. | ||
364 | * This means that we re-use SHA512(d)[32..63] | ||
365 | * FIXME: Do we want to derive this part as well?? | ||
366 | */ | ||
330 | memcpy (result->s, sk, sizeof (sk)); | 367 | memcpy (result->s, sk, sizeof (sk)); |
331 | /* Convert to little endian for libsodium */ | 368 | /* Convert to little endian for libsodium */ |
332 | for (size_t i = 0; i < 32; i++) | 369 | for (size_t i = 0; i < 32; i++) |
333 | result->s[i] = dc[31 - i]; | 370 | result->s[i] = dc[31 - i]; |
371 | /** | ||
372 | * Clamp the scalar | ||
373 | */ | ||
334 | result->s[0] &= 248; | 374 | result->s[0] &= 248; |
335 | result->s[31] &= 127; | 375 | result->s[31] &= 127; |
336 | result->s[31] |= 64; | 376 | result->s[31] |= 64; |
@@ -347,6 +387,7 @@ GNUNET_CRYPTO_eddsa_public_key_derive ( | |||
347 | const char *context, | 387 | const char *context, |
348 | struct GNUNET_CRYPTO_EddsaPublicKey *result) | 388 | struct GNUNET_CRYPTO_EddsaPublicKey *result) |
349 | { | 389 | { |
390 | struct GNUNET_HashCode hc; | ||
350 | gcry_ctx_t ctx; | 391 | gcry_ctx_t ctx; |
351 | gcry_mpi_t q_y; | 392 | gcry_mpi_t q_y; |
352 | gcry_mpi_t h; | 393 | gcry_mpi_t h; |
@@ -368,7 +409,9 @@ GNUNET_CRYPTO_eddsa_public_key_derive ( | |||
368 | GNUNET_assert (q); | 409 | GNUNET_assert (q); |
369 | 410 | ||
370 | /* calculate h_mod_n = h % n */ | 411 | /* calculate h_mod_n = h % n */ |
371 | h = derive_h (pub, sizeof (*pub), label, context); | 412 | derive_h (pub, sizeof (*pub), label, context, &hc); |
413 | GNUNET_CRYPTO_mpi_scan_unsigned (&h, (unsigned char *) &hc, sizeof(hc)); | ||
414 | |||
372 | n = gcry_mpi_ec_get_mpi ("n", ctx, 1); | 415 | n = gcry_mpi_ec_get_mpi ("n", ctx, 1); |
373 | h_mod_n = gcry_mpi_new (256); | 416 | h_mod_n = gcry_mpi_new (256); |
374 | gcry_mpi_mod (h_mod_n, h, n); | 417 | gcry_mpi_mod (h_mod_n, h, n); |