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