aboutsummaryrefslogtreecommitdiff
path: root/src/util/crypto_ecc_gnsrecord.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/crypto_ecc_gnsrecord.c')
-rw-r--r--src/util/crypto_ecc_gnsrecord.c460
1 files changed, 0 insertions, 460 deletions
diff --git a/src/util/crypto_ecc_gnsrecord.c b/src/util/crypto_ecc_gnsrecord.c
deleted file mode 100644
index 0ee0570c0..000000000
--- a/src/util/crypto_ecc_gnsrecord.c
+++ /dev/null
@@ -1,460 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013, 2015 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_ecc_gnsrecord.c
23 * @brief public key cryptography (ECC) for GNS records (LSD0001)
24 * @author Christian Grothoff
25 * @author Florian Dold
26 * @author Martin Schanzenbach
27 */
28#include "platform.h"
29#include <gcrypt.h>
30#include <sodium.h>
31#include "gnunet_crypto_lib.h"
32#include "gnunet_strings_lib.h"
33
34#define CURVE "Ed25519"
35
36/**
37 * Derive the 'h' value for key derivation, where
38 * 'h = H(l,P)'.
39 *
40 * @param pub public key for deriviation
41 * @param pubsize the size of the public key
42 * @param label label for deriviation
43 * @param context additional context to use for HKDF of 'h';
44 * typically the name of the subsystem/application
45 * @param hc where to write the result
46 */
47void
48derive_h (const void *pub,
49 size_t pubsize,
50 const char *label,
51 const char *context,
52 struct GNUNET_HashCode *hc)
53{
54 static const char *const salt = "key-derivation";
55
56 GNUNET_CRYPTO_kdf (hc,
57 sizeof(*hc),
58 salt,
59 strlen (salt),
60 pub,
61 pubsize,
62 label,
63 strlen (label),
64 context,
65 strlen (context),
66 NULL,
67 0);
68}
69
70
71enum GNUNET_GenericReturnValue
72GNUNET_CRYPTO_eddsa_sign_derived (
73 const struct GNUNET_CRYPTO_EddsaPrivateKey *pkey,
74 const char *label,
75 const char *context,
76 const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
77 struct GNUNET_CRYPTO_EddsaSignature *sig)
78{
79 struct GNUNET_CRYPTO_EddsaPrivateScalar priv;
80 crypto_hash_sha512_state hs;
81 unsigned char sk[64];
82 unsigned char r[64];
83 unsigned char hram[64];
84 unsigned char R[32];
85 unsigned char zk[32];
86 unsigned char tmp[32];
87
88 /**
89 * Derive the private key
90 */
91 GNUNET_CRYPTO_eddsa_private_key_derive (pkey,
92 label,
93 context,
94 &priv);
95
96 crypto_hash_sha512_init (&hs);
97
98 /**
99 * Instead of expanding the private here, we already
100 * have the secret scalar as input. Use it.
101 * Note that sk is not plain SHA512 (d).
102 * sk[0..31] contains the derived private scalar
103 * sk[0..31] = h * SHA512 (d)[0..31]
104 * sk[32..63] = SHA512 (d)[32..63]
105 */
106 memcpy (sk, priv.s, 64);
107
108 /**
109 * Calculate the derived zone key zk' from the
110 * derived private scalar.
111 */
112 crypto_scalarmult_ed25519_base_noclamp (zk,
113 sk);
114
115 /**
116 * Calculate r:
117 * r = SHA512 (sk[32..63] | M)
118 * where M is our message (purpose).
119 * Note that sk[32..63] is the other half of the
120 * expansion from the original, non-derived private key
121 * "d".
122 */
123 crypto_hash_sha512_update (&hs, sk + 32, 32);
124 crypto_hash_sha512_update (&hs, (uint8_t*) purpose, ntohl (purpose->size));
125 crypto_hash_sha512_final (&hs, r);
126
127 /**
128 * Temporarily put zk into S
129 */
130 memcpy (sig->s, zk, 32);
131
132 /**
133 * Reduce the scalar value r
134 */
135 unsigned char r_mod[64];
136 crypto_core_ed25519_scalar_reduce (r_mod, r);
137
138 /**
139 * Calculate R := r * G of the signature
140 */
141 crypto_scalarmult_ed25519_base_noclamp (R, r_mod);
142 memcpy (sig->r, R, sizeof (R));
143
144 /**
145 * Calculate
146 * hram := SHA512 (R | zk' | M)
147 */
148 crypto_hash_sha512_init (&hs);
149 crypto_hash_sha512_update (&hs, (uint8_t*) sig, 64);
150 crypto_hash_sha512_update (&hs, (uint8_t*) purpose,
151 ntohl (purpose->size));
152 crypto_hash_sha512_final (&hs, hram);
153
154 /**
155 * Reduce the resulting scalar value
156 */
157 unsigned char hram_mod[64];
158 crypto_core_ed25519_scalar_reduce (hram_mod, hram);
159
160 /**
161 * Calculate
162 * S := r + hram * s mod L
163 */
164 crypto_core_ed25519_scalar_mul (tmp, hram_mod, sk);
165 crypto_core_ed25519_scalar_add (sig->s, tmp, r_mod);
166
167 sodium_memzero (sk, sizeof (sk));
168 sodium_memzero (r, sizeof (r));
169 sodium_memzero (r_mod, sizeof (r_mod));
170 return GNUNET_OK;
171}
172
173enum GNUNET_GenericReturnValue
174GNUNET_CRYPTO_ecdsa_sign_derived (
175 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
176 const char *label,
177 const char *context,
178 const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
179 struct GNUNET_CRYPTO_EcdsaSignature *sig)
180{
181 struct GNUNET_CRYPTO_EcdsaPrivateKey *key;
182 enum GNUNET_GenericReturnValue res;
183 key = GNUNET_CRYPTO_ecdsa_private_key_derive (priv,
184 label,
185 context);
186 res = GNUNET_CRYPTO_ecdsa_sign_ (key,
187 purpose,
188 sig);
189 GNUNET_free (key);
190 return res;
191}
192
193struct GNUNET_CRYPTO_EcdsaPrivateKey *
194GNUNET_CRYPTO_ecdsa_private_key_derive (
195 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
196 const char *label,
197 const char *context)
198{
199 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
200 struct GNUNET_CRYPTO_EcdsaPrivateKey *ret;
201 struct GNUNET_HashCode hc;
202 uint8_t dc[32];
203 gcry_mpi_t h;
204 gcry_mpi_t x;
205 gcry_mpi_t d;
206 gcry_mpi_t n;
207 gcry_ctx_t ctx;
208
209 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
210
211 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
212 GNUNET_CRYPTO_ecdsa_key_get_public (priv, &pub);
213
214 derive_h (&pub, sizeof (pub), label, context, &hc);
215 GNUNET_CRYPTO_mpi_scan_unsigned (&h, (unsigned char *) &hc, sizeof(hc));
216
217 /* Convert to big endian for libgcrypt */
218 for (size_t i = 0; i < 32; i++)
219 dc[i] = priv->d[31 - i];
220 GNUNET_CRYPTO_mpi_scan_unsigned (&x, dc, sizeof(dc));
221 d = gcry_mpi_new (256);
222 gcry_mpi_mulm (d, h, x, n);
223 gcry_mpi_release (h);
224 gcry_mpi_release (x);
225 gcry_mpi_release (n);
226 gcry_ctx_release (ctx);
227 ret = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
228 GNUNET_CRYPTO_mpi_print_unsigned (dc, sizeof(dc), d);
229 /* Convert to big endian for libgcrypt */
230 for (size_t i = 0; i < 32; i++)
231 ret->d[i] = dc[31 - i];
232 sodium_memzero (dc, sizeof(dc));
233 gcry_mpi_release (d);
234 return ret;
235}
236
237
238void
239GNUNET_CRYPTO_ecdsa_public_key_derive (
240 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
241 const char *label,
242 const char *context,
243 struct GNUNET_CRYPTO_EcdsaPublicKey *result)
244{
245 struct GNUNET_HashCode hc;
246 gcry_ctx_t ctx;
247 gcry_mpi_t q_y;
248 gcry_mpi_t h;
249 gcry_mpi_t n;
250 gcry_mpi_t h_mod_n;
251 gcry_mpi_point_t q;
252 gcry_mpi_point_t v;
253
254 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
255
256 /* obtain point 'q' from original public key. The provided 'q' is
257 compressed thus we first store it in the context and then get it
258 back as a (decompresssed) point. */
259 q_y = gcry_mpi_set_opaque_copy (NULL, pub->q_y, 8 * sizeof(pub->q_y));
260 GNUNET_assert (NULL != q_y);
261 GNUNET_assert (0 == gcry_mpi_ec_set_mpi ("q", q_y, ctx));
262 gcry_mpi_release (q_y);
263 q = gcry_mpi_ec_get_point ("q", ctx, 0);
264 GNUNET_assert (q);
265
266 /* calculate h_mod_n = h % n */
267 derive_h (pub, sizeof (*pub), label, context, &hc);
268 GNUNET_CRYPTO_mpi_scan_unsigned (&h, (unsigned char *) &hc, sizeof(hc));
269 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
270 h_mod_n = gcry_mpi_new (256);
271 gcry_mpi_mod (h_mod_n, h, n);
272 /* calculate v = h_mod_n * q */
273 v = gcry_mpi_point_new (0);
274 gcry_mpi_ec_mul (v, h_mod_n, q, ctx);
275 gcry_mpi_release (h_mod_n);
276 gcry_mpi_release (h);
277 gcry_mpi_release (n);
278 gcry_mpi_point_release (q);
279
280 /* convert point 'v' to public key that we return */
281 GNUNET_assert (0 == gcry_mpi_ec_set_point ("q", v, ctx));
282 gcry_mpi_point_release (v);
283 q_y = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
284 GNUNET_assert (q_y);
285 GNUNET_CRYPTO_mpi_print_unsigned (result->q_y, sizeof(result->q_y), q_y);
286 gcry_mpi_release (q_y);
287 gcry_ctx_release (ctx);
288}
289
290
291void
292GNUNET_CRYPTO_eddsa_private_key_derive (
293 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
294 const char *label,
295 const char *context,
296 struct GNUNET_CRYPTO_EddsaPrivateScalar *result)
297{
298 struct GNUNET_CRYPTO_EddsaPublicKey pub;
299 struct GNUNET_HashCode hc;
300 uint8_t dc[32];
301 unsigned char sk[64];
302 gcry_mpi_t h;
303 gcry_mpi_t h_mod_n;
304 gcry_mpi_t x;
305 gcry_mpi_t d;
306 gcry_mpi_t n;
307 gcry_mpi_t a1;
308 gcry_mpi_t a2;
309 gcry_ctx_t ctx;
310
311 /**
312 * Libsodium does not offer an API with arbitrary arithmetic.
313 * Hence we have to use libgcrypt here.
314 */
315 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, "Ed25519"));
316
317 /**
318 * Get our modulo
319 */
320 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
321 GNUNET_CRYPTO_eddsa_key_get_public (priv, &pub);
322
323 /**
324 * This is the standard private key expansion in Ed25519.
325 * The first 32 octets are used as a little-endian private
326 * scalar.
327 * We derive this scalar using our "h".
328 */
329 crypto_hash_sha512 (sk, priv->d, 32);
330 sk[0] &= 248;
331 sk[31] &= 127;
332 sk[31] |= 64;
333
334 /**
335 * Get h mod n
336 */
337 derive_h (&pub, sizeof (pub), label, context, &hc);
338 GNUNET_CRYPTO_mpi_scan_unsigned (&h, (unsigned char *) &hc, sizeof(hc));
339 h_mod_n = gcry_mpi_new (256);
340 gcry_mpi_mod (h_mod_n, h, n);
341 /* Convert scalar to big endian for libgcrypt */
342 for (size_t i = 0; i < 32; i++)
343 dc[i] = sk[31 - i];
344
345 /**
346 * dc now contains the private scalar "a".
347 * We carefully remove the clamping and derive a'.
348 * Calculate:
349 * a1 := a / 8
350 * a2 := h * a1 mod n
351 * a' := a2 * 8 mod n
352 */
353 GNUNET_CRYPTO_mpi_scan_unsigned (&x, dc, sizeof(dc)); // a
354 a1 = gcry_mpi_new (256);
355 gcry_mpi_t eight = gcry_mpi_set_ui (NULL, 8);
356 gcry_mpi_div (a1, NULL, x, eight, 0); // a1 := a / 8
357 a2 = gcry_mpi_new (256);
358 gcry_mpi_mulm (a2, h_mod_n, a1, n); // a2 := h * a1 mod n
359 d = gcry_mpi_new (256);
360 gcry_mpi_mul (d, a2, eight); // a' := a2 * 8
361 gcry_mpi_release (h);
362 gcry_mpi_release (x);
363 gcry_mpi_release (n);
364 gcry_mpi_release (a1);
365 gcry_mpi_release (a2);
366 gcry_ctx_release (ctx);
367 GNUNET_CRYPTO_mpi_print_unsigned (dc, sizeof(dc), d);
368 /**
369 * We hash the derived "h" parameter with the
370 * other half of the expanded private key. This ensures
371 * that for signature generation, the "R" is derived from
372 * the same derivation path as "h" and is not reused.
373 */
374 crypto_hash_sha256_state hs;
375 crypto_hash_sha256_init (&hs);
376 crypto_hash_sha256_update (&hs, sk + 32, 32);
377 crypto_hash_sha256_update (&hs, (unsigned char*) &hc, sizeof (hc));
378 crypto_hash_sha256_final (&hs, result->s + 32);
379 //memcpy (result->s, sk, sizeof (sk));
380 /* Convert to little endian for libsodium */
381 for (size_t i = 0; i < 32; i++)
382 result->s[i] = dc[31 - i];
383
384 sodium_memzero (dc, sizeof(dc));
385 gcry_mpi_release (d);
386}
387
388
389void
390GNUNET_CRYPTO_eddsa_public_key_derive (
391 const struct GNUNET_CRYPTO_EddsaPublicKey *pub,
392 const char *label,
393 const char *context,
394 struct GNUNET_CRYPTO_EddsaPublicKey *result)
395{
396 struct GNUNET_HashCode hc;
397 gcry_ctx_t ctx;
398 gcry_mpi_t q_y;
399 gcry_mpi_t h;
400 gcry_mpi_t n;
401 gcry_mpi_t h_mod_n;
402 gcry_mpi_point_t q;
403 gcry_mpi_point_t v;
404
405 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, "Ed25519"));
406
407 /* obtain point 'q' from original public key. The provided 'q' is
408 compressed thus we first store it in the context and then get it
409 back as a (decompresssed) point. */
410 q_y = gcry_mpi_set_opaque_copy (NULL, pub->q_y, 8 * sizeof(pub->q_y));
411 GNUNET_assert (NULL != q_y);
412 GNUNET_assert (0 == gcry_mpi_ec_set_mpi ("q", q_y, ctx));
413 gcry_mpi_release (q_y);
414 q = gcry_mpi_ec_get_point ("q", ctx, 0);
415 GNUNET_assert (q);
416
417 /* calculate h_mod_n = h % n */
418 derive_h (pub, sizeof (*pub), label, context, &hc);
419 GNUNET_CRYPTO_mpi_scan_unsigned (&h, (unsigned char *) &hc, sizeof(hc));
420
421 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
422 h_mod_n = gcry_mpi_new (256);
423 gcry_mpi_mod (h_mod_n, h, n);
424
425 /* calculate v = h_mod_n * q */
426 v = gcry_mpi_point_new (0);
427 gcry_mpi_ec_mul (v, h_mod_n, q, ctx);
428 gcry_mpi_release (h_mod_n);
429 gcry_mpi_release (h);
430 gcry_mpi_release (n);
431 gcry_mpi_point_release (q);
432
433 /* convert point 'v' to public key that we return */
434 GNUNET_assert (0 == gcry_mpi_ec_set_point ("q", v, ctx));
435 gcry_mpi_point_release (v);
436 q_y = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
437 GNUNET_assert (q_y);
438 GNUNET_CRYPTO_mpi_print_unsigned (result->q_y, sizeof(result->q_y), q_y);
439 gcry_mpi_release (q_y);
440 gcry_ctx_release (ctx);
441
442}
443
444
445void
446GNUNET_CRYPTO_eddsa_key_get_public_from_scalar (
447 const struct GNUNET_CRYPTO_EddsaPrivateScalar *priv,
448 struct GNUNET_CRYPTO_EddsaPublicKey *pkey)
449{
450 unsigned char sk[32];
451
452 memcpy (sk, priv->s, 32);
453
454 /**
455 * Calculate the derived zone key zk' from the
456 * derived private scalar.
457 */
458 crypto_scalarmult_ed25519_base_noclamp (pkey->q_y,
459 sk);
460}