aboutsummaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/util')
-rw-r--r--src/util/.gitignore1
-rw-r--r--src/util/Makefile.am8
-rw-r--r--src/util/crypto_ecc_gnsrecord.c55
-rw-r--r--src/util/crypto_edx25519.c418
-rw-r--r--src/util/crypto_hkdf.c118
-rw-r--r--src/util/crypto_kdf.c61
-rw-r--r--src/util/crypto_rsa.c28
-rw-r--r--src/util/test_crypto_eddsa.c8
-rw-r--r--src/util/test_crypto_edx25519.c326
-rw-r--r--src/util/time.c30
10 files changed, 918 insertions, 135 deletions
diff --git a/src/util/.gitignore b/src/util/.gitignore
index 51eab71db..0e3449fed 100644
--- a/src/util/.gitignore
+++ b/src/util/.gitignore
@@ -36,6 +36,7 @@ test_crypto_ecdh_eddsa
36test_crypto_ecdhe 36test_crypto_ecdhe
37test_crypto_ecdsa 37test_crypto_ecdsa
38test_crypto_eddsa 38test_crypto_eddsa
39test_crypto_edx25519
39test_crypto_hash 40test_crypto_hash
40test_crypto_hash_context 41test_crypto_hash_context
41test_crypto_hkdf 42test_crypto_hkdf
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index 406d42b1e..9cb7da15b 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -66,6 +66,7 @@ libgnunetutil_la_SOURCES = \
66 crypto_ecc_gnsrecord.c \ 66 crypto_ecc_gnsrecord.c \
67 $(DLOG) \ 67 $(DLOG) \
68 crypto_ecc_setup.c \ 68 crypto_ecc_setup.c \
69 crypto_edx25519.c \
69 crypto_hash.c \ 70 crypto_hash.c \
70 crypto_hash_file.c \ 71 crypto_hash_file.c \
71 crypto_hkdf.c \ 72 crypto_hkdf.c \
@@ -297,6 +298,7 @@ check_PROGRAMS = \
297 test_crypto_ecdhe \ 298 test_crypto_ecdhe \
298 test_crypto_ecdh_eddsa \ 299 test_crypto_ecdh_eddsa \
299 test_crypto_ecdh_ecdsa \ 300 test_crypto_ecdh_ecdsa \
301 test_crypto_edx25519 \
300 $(DLOG_TEST) \ 302 $(DLOG_TEST) \
301 test_crypto_hash \ 303 test_crypto_hash \
302 test_crypto_hash_context \ 304 test_crypto_hash_context \
@@ -470,6 +472,12 @@ test_crypto_eddsa_LDADD = \
470 libgnunetutil.la \ 472 libgnunetutil.la \
471 $(LIBGCRYPT_LIBS) 473 $(LIBGCRYPT_LIBS)
472 474
475test_crypto_edx25519_SOURCES = \
476 test_crypto_edx25519.c
477test_crypto_edx25519_LDADD = \
478 libgnunetutil.la \
479 $(LIBGCRYPT_LIBS)
480
473test_crypto_ecc_dlog_SOURCES = \ 481test_crypto_ecc_dlog_SOURCES = \
474 test_crypto_ecc_dlog.c 482 test_crypto_ecc_dlog.c
475test_crypto_ecc_dlog_LDADD = \ 483test_crypto_ecc_dlog_LDADD = \
diff --git a/src/util/crypto_ecc_gnsrecord.c b/src/util/crypto_ecc_gnsrecord.c
index ce41a4699..0ee0570c0 100644
--- a/src/util/crypto_ecc_gnsrecord.c
+++ b/src/util/crypto_ecc_gnsrecord.c
@@ -68,28 +68,15 @@ derive_h (const void *pub,
68} 68}
69 69
70 70
71/** 71enum GNUNET_GenericReturnValue
72 * This is a signature function for EdDSA which takes the 72GNUNET_CRYPTO_eddsa_sign_derived (
73 * secret scalar sk instead of the private seed which is 73 const struct GNUNET_CRYPTO_EddsaPrivateKey *pkey,
74 * usually the case for crypto APIs. We require this functionality 74 const char *label,
75 * in order to use derived private keys for signatures we 75 const char *context,
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, 76 const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
90 struct GNUNET_CRYPTO_EddsaSignature *sig) 77 struct GNUNET_CRYPTO_EddsaSignature *sig)
91{ 78{
92 79 struct GNUNET_CRYPTO_EddsaPrivateScalar priv;
93 crypto_hash_sha512_state hs; 80 crypto_hash_sha512_state hs;
94 unsigned char sk[64]; 81 unsigned char sk[64];
95 unsigned char r[64]; 82 unsigned char r[64];
@@ -98,6 +85,14 @@ GNUNET_CRYPTO_eddsa_sign_with_scalar (
98 unsigned char zk[32]; 85 unsigned char zk[32];
99 unsigned char tmp[32]; 86 unsigned char tmp[32];
100 87
88 /**
89 * Derive the private key
90 */
91 GNUNET_CRYPTO_eddsa_private_key_derive (pkey,
92 label,
93 context,
94 &priv);
95
101 crypto_hash_sha512_init (&hs); 96 crypto_hash_sha512_init (&hs);
102 97
103 /** 98 /**
@@ -108,7 +103,7 @@ GNUNET_CRYPTO_eddsa_sign_with_scalar (
108 * sk[0..31] = h * SHA512 (d)[0..31] 103 * sk[0..31] = h * SHA512 (d)[0..31]
109 * sk[32..63] = SHA512 (d)[32..63] 104 * sk[32..63] = SHA512 (d)[32..63]
110 */ 105 */
111 memcpy (sk, priv->s, 64); 106 memcpy (sk, priv.s, 64);
112 107
113 /** 108 /**
114 * Calculate the derived zone key zk' from the 109 * Calculate the derived zone key zk' from the
@@ -172,8 +167,28 @@ GNUNET_CRYPTO_eddsa_sign_with_scalar (
172 sodium_memzero (sk, sizeof (sk)); 167 sodium_memzero (sk, sizeof (sk));
173 sodium_memzero (r, sizeof (r)); 168 sodium_memzero (r, sizeof (r));
174 sodium_memzero (r_mod, sizeof (r_mod)); 169 sodium_memzero (r_mod, sizeof (r_mod));
170 return GNUNET_OK;
175} 171}
176 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}
177 192
178struct GNUNET_CRYPTO_EcdsaPrivateKey * 193struct GNUNET_CRYPTO_EcdsaPrivateKey *
179GNUNET_CRYPTO_ecdsa_private_key_derive ( 194GNUNET_CRYPTO_ecdsa_private_key_derive (
diff --git a/src/util/crypto_edx25519.c b/src/util/crypto_edx25519.c
new file mode 100644
index 000000000..26b45407e
--- /dev/null
+++ b/src/util/crypto_edx25519.c
@@ -0,0 +1,418 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2022 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_edx25519.c
23 * @brief An variant of EdDSA which allows for iterative derivation of key pairs.
24 * @author Özgür Kesim
25 * @author Christian Grothoff
26 * @author Florian Dold
27 * @author Martin Schanzenbach
28 */
29#include "platform.h"
30#include <gcrypt.h>
31#include <sodium.h>
32#include "gnunet_crypto_lib.h"
33#include "gnunet_strings_lib.h"
34
35#define CURVE "Ed25519"
36
37void
38GNUNET_CRYPTO_edx25519_key_clear (struct GNUNET_CRYPTO_Edx25519PrivateKey *pk)
39{
40 memset (pk, 0, sizeof(struct GNUNET_CRYPTO_Edx25519PrivateKey));
41}
42
43
44void
45GNUNET_CRYPTO_edx25519_key_create_from_seed (
46 const void *seed,
47 size_t seedsize,
48 struct GNUNET_CRYPTO_Edx25519PrivateKey *pk)
49{
50
51 GNUNET_static_assert (sizeof(*pk) == sizeof(struct GNUNET_HashCode));
52 GNUNET_CRYPTO_hash (seed,
53 seedsize,
54 (struct GNUNET_HashCode *) pk);
55
56 /* Clamp the first half of the key. The second half is used in the signature
57 * process. */
58 pk->a[0] &= 248;
59 pk->a[31] &= 127;
60 pk->a[31] |= 64;
61}
62
63
64void
65GNUNET_CRYPTO_edx25519_key_create (
66 struct GNUNET_CRYPTO_Edx25519PrivateKey *pk)
67{
68 char seed[256 / 8];
69 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
70 seed,
71 sizeof (seed));
72 GNUNET_CRYPTO_edx25519_key_create_from_seed (seed,
73 sizeof(seed),
74 pk);
75}
76
77
78void
79GNUNET_CRYPTO_edx25519_key_get_public (
80 const struct GNUNET_CRYPTO_Edx25519PrivateKey *priv,
81 struct GNUNET_CRYPTO_Edx25519PublicKey *pub)
82{
83 crypto_scalarmult_ed25519_base_noclamp (pub->q_y,
84 priv->a);
85}
86
87
88/**
89 * This function operates the basically same way as the signature function for
90 * EdDSA. But instead of expanding a private seed (which is usually the case
91 * for crypto APIs) and using the resulting scalars, it takes the scalars
92 * directly from Edx25519PrivateKey. We require this functionality in order to
93 * use derived private keys for signatures.
94 *
95 * The resulting signature is a standard EdDSA signature
96 * which can be verified using the usual APIs.
97 *
98 * @param priv the private key (containing two scalars .a and .b)
99 * @param purp the signature purpose
100 * @param sig the resulting signature
101 */
102enum GNUNET_GenericReturnValue
103GNUNET_CRYPTO_edx25519_sign_ (
104 const struct GNUNET_CRYPTO_Edx25519PrivateKey *priv,
105 const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
106 struct GNUNET_CRYPTO_Edx25519Signature *sig)
107{
108
109 crypto_hash_sha512_state hs;
110 unsigned char r[64];
111 unsigned char hram[64];
112 unsigned char P[32];
113 unsigned char r_mod[64];
114 unsigned char R[32];
115 unsigned char tmp[32];
116
117 crypto_hash_sha512_init (&hs);
118
119 /**
120 * Calculate the public key P from the private scalar in the key.
121 */
122 crypto_scalarmult_ed25519_base_noclamp (P,
123 priv->a);
124
125 /**
126 * Calculate r:
127 * r = SHA512 (b ∥ M)
128 * where M is our message (purpose).
129 */
130 crypto_hash_sha512_update (&hs,
131 priv->b,
132 sizeof(priv->b));
133 crypto_hash_sha512_update (&hs,
134 (uint8_t*) purpose,
135 ntohl (purpose->size));
136 crypto_hash_sha512_final (&hs,
137 r);
138
139 /**
140 * Temporarily put P into S
141 */
142 memcpy (sig->s, P, 32);
143
144 /**
145 * Reduce the scalar value r
146 */
147 crypto_core_ed25519_scalar_reduce (r_mod, r);
148
149 /**
150 * Calculate R := r * G of the signature
151 */
152 crypto_scalarmult_ed25519_base_noclamp (R, r_mod);
153 memcpy (sig->r, R, sizeof (R));
154
155 /**
156 * Calculate
157 * hram := SHA512 (R ∥ P ∥ M)
158 */
159 crypto_hash_sha512_init (&hs);
160 crypto_hash_sha512_update (&hs, (uint8_t*) sig, 64);
161 crypto_hash_sha512_update (&hs, (uint8_t*) purpose,
162 ntohl (purpose->size));
163 crypto_hash_sha512_final (&hs, hram);
164
165 /**
166 * Reduce the resulting scalar value
167 */
168 unsigned char hram_mod[64];
169 crypto_core_ed25519_scalar_reduce (hram_mod, hram);
170
171 /**
172 * Calculate
173 * S := r + hram * s mod L
174 */
175 crypto_core_ed25519_scalar_mul (tmp, hram_mod, priv->a);
176 crypto_core_ed25519_scalar_add (sig->s, tmp, r_mod);
177
178 sodium_memzero (r, sizeof (r));
179 sodium_memzero (r_mod, sizeof (r_mod));
180
181 return GNUNET_OK;
182}
183
184
185enum GNUNET_GenericReturnValue
186GNUNET_CRYPTO_edx25519_verify_ (
187 uint32_t purpose,
188 const struct GNUNET_CRYPTO_EccSignaturePurpose *validate,
189 const struct GNUNET_CRYPTO_Edx25519Signature *sig,
190 const struct GNUNET_CRYPTO_Edx25519PublicKey *pub)
191{
192 const unsigned char *m = (const void *) validate;
193 size_t mlen = ntohl (validate->size);
194 const unsigned char *s = (const void *) sig;
195
196 int res;
197
198 if (purpose != ntohl (validate->purpose))
199 return GNUNET_SYSERR; /* purpose mismatch */
200
201 res = crypto_sign_verify_detached (s, m, mlen, pub->q_y);
202 return (res == 0) ? GNUNET_OK : GNUNET_SYSERR;
203}
204
205
206/**
207 * Derive the 'h' value for key derivation, where
208 * 'h = H(P ∥ seed) mod n' and 'n' is the size of the cyclic subroup.
209 *
210 * @param pub public key for deriviation
211 * @param seed seed for key the deriviation
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
215 * return h_mod_n (allocated by this function)
216 */
217static gcry_mpi_t
218derive_h_mod_n (
219 const struct GNUNET_CRYPTO_Edx25519PublicKey *pub,
220 const void *seed,
221 size_t seedsize,
222 const gcry_mpi_t n,
223 struct GNUNET_HashCode *phc)
224{
225 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
233 GNUNET_CRYPTO_kdf (phc, sizeof(*phc),
234 salt, strlen (salt),
235 pub, sizeof(*pub),
236 seed, seedsize,
237 NULL, 0);
238
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}
261
262
263void
264GNUNET_CRYPTO_edx25519_private_key_derive (
265 const struct GNUNET_CRYPTO_Edx25519PrivateKey *priv,
266 const void *seed,
267 size_t seedsize,
268 struct GNUNET_CRYPTO_Edx25519PrivateKey *result)
269{
270 struct GNUNET_CRYPTO_Edx25519PublicKey pub;
271 struct GNUNET_HashCode hc;
272 uint8_t a[32];
273 gcry_ctx_t ctx;
274 gcry_mpi_t h_mod_n;
275 gcry_mpi_t x;
276 gcry_mpi_t n;
277 gcry_mpi_t a1;
278 gcry_mpi_t a2;
279 gcry_mpi_t ap; // a'
280
281 GNUNET_CRYPTO_edx25519_key_get_public (priv, &pub);
282
283 /**
284 * Libsodium does not offer an API with arbitrary arithmetic.
285 * Hence we have to use libgcrypt here.
286 */
287 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, "Ed25519"));
288
289 /**
290 * Get our modulo
291 */
292 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
293 GNUNET_assert (NULL != n);
294
295 /**
296 * Get h mod n
297 */
298 h_mod_n = derive_h_mod_n (&pub,
299 seed,
300 seedsize,
301 n,
302 &hc);
303
304 /* Convert priv->a scalar to big endian for libgcrypt */
305 for (size_t i = 0; i < 32; i++)
306 a[i] = priv->a[31 - i];
307
308 /**
309 * dc now contains the private scalar "a".
310 * We carefully remove the clamping and derive a'.
311 * Calculate:
312 * a1 := a / 8
313 * a2 := h * a1 mod n
314 * a' := a2 * 8 mod n
315 */
316 GNUNET_CRYPTO_mpi_scan_unsigned (&x, a, sizeof(a)); // a
317 a1 = gcry_mpi_new (256);
318 gcry_mpi_t eight = gcry_mpi_set_ui (NULL, 8);
319 gcry_mpi_div (a1, NULL, x, eight, 0); // a1 := a / 8
320 a2 = gcry_mpi_new (256);
321 gcry_mpi_mulm (a2, h_mod_n, a1, n); // a2 := h * a1 mod n
322 ap = gcry_mpi_new (256);
323 gcry_mpi_mul (ap, a2, eight); // a' := a2 * 8
324
325#ifdef CHECK_RARE_CASES
326 /* The likelihood for a' == 0 or a' == 1 is neglegible */
327 GNUNET_assert (! gcry_mpi_cmp_ui (ap, 0));
328 GNUNET_assert (! gcry_mpi_cmp_ui (ap, 1));
329#endif
330
331 gcry_mpi_release (h_mod_n);
332 gcry_mpi_release (eight);
333 gcry_mpi_release (x);
334 gcry_mpi_release (n);
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
341 /**
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
344 * generation, the "R" is derived from the same derivation path as "h" and is
345 * not reused.
346 */
347 {
348 crypto_hash_sha256_state hs;
349 crypto_hash_sha256_init (&hs);
350 crypto_hash_sha256_update (&hs, priv->b, sizeof(priv->b));
351 crypto_hash_sha256_update (&hs, (unsigned char*) &hc, sizeof (hc));
352 crypto_hash_sha256_final (&hs, result->b);
353 }
354
355 /* Convert to little endian for libsodium */
356 for (size_t i = 0; i < 32; i++)
357 result->a[i] = a[31 - i];
358
359 sodium_memzero (a, sizeof(a));
360}
361
362
363void
364GNUNET_CRYPTO_edx25519_public_key_derive (
365 const struct GNUNET_CRYPTO_Edx25519PublicKey *pub,
366 const void *seed,
367 size_t seedsize,
368 struct GNUNET_CRYPTO_Edx25519PublicKey *result)
369{
370 gcry_ctx_t ctx;
371 gcry_mpi_t q_y;
372 gcry_mpi_t n;
373 gcry_mpi_t h_mod_n;
374 gcry_mpi_point_t q;
375 gcry_mpi_point_t v;
376
377 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, "Ed25519"));
378
379 /* obtain point 'q' from original public key. The provided 'q' is
380 compressed thus we first store it in the context and then get it
381 back as a (decompresssed) point. */
382 q_y = gcry_mpi_set_opaque_copy (NULL,
383 pub->q_y,
384 8 * sizeof(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}
diff --git a/src/util/crypto_hkdf.c b/src/util/crypto_hkdf.c
index 4e4496819..838e37d8d 100644
--- a/src/util/crypto_hkdf.c
+++ b/src/util/crypto_hkdf.c
@@ -74,16 +74,21 @@
74 * @return HMAC, freed by caller via gcry_md_close/_reset 74 * @return HMAC, freed by caller via gcry_md_close/_reset
75 */ 75 */
76static const void * 76static const void *
77doHMAC (gcry_md_hd_t mac, const void *key, size_t key_len, const void *buf, 77doHMAC (gcry_md_hd_t mac,
78 const void *key,
79 size_t key_len,
80 const void *buf,
78 size_t buf_len) 81 size_t buf_len)
79{ 82{
80 if (GPG_ERR_NO_ERROR != gcry_md_setkey (mac, key, key_len)) 83 if (GPG_ERR_NO_ERROR !=
84 gcry_md_setkey (mac, key, key_len))
81 { 85 {
82 GNUNET_break (0); 86 GNUNET_break (0);
83 return NULL; 87 return NULL;
84 } 88 }
85 gcry_md_write (mac, buf, buf_len); 89 gcry_md_write (mac,
86 90 buf,
91 buf_len);
87 return (const void *) gcry_md_read (mac, 0); 92 return (const void *) gcry_md_read (mac, 0);
88} 93}
89 94
@@ -98,9 +103,13 @@ doHMAC (gcry_md_hd_t mac, const void *key, size_t key_len, const void *buf,
98 * @param prk result buffer (allocated by caller; at least gcry_md_dlen() bytes) 103 * @param prk result buffer (allocated by caller; at least gcry_md_dlen() bytes)
99 * @return #GNUNET_YES on success 104 * @return #GNUNET_YES on success
100 */ 105 */
101static int 106static enum GNUNET_GenericReturnValue
102getPRK (gcry_md_hd_t mac, const void *xts, size_t xts_len, const void *skm, 107getPRK (gcry_md_hd_t mac,
103 size_t skm_len, void *prk) 108 const void *xts,
109 size_t xts_len,
110 const void *skm,
111 size_t skm_len,
112 void *prk)
104{ 113{
105 const void *ret; 114 const void *ret;
106 size_t dlen; 115 size_t dlen;
@@ -114,9 +123,10 @@ getPRK (gcry_md_hd_t mac, const void *xts, size_t xts_len, const void *skm,
114 * salt - optional salt value (a non-secret random value); 123 * salt - optional salt value (a non-secret random value);
115 * if not provided, it is set to a string of HashLen zeros. */ 124 * if not provided, it is set to a string of HashLen zeros. */
116 125
117 if (xts_len == 0) 126 if (0 == xts_len)
118 { 127 {
119 char zero_salt[dlen]; 128 char zero_salt[dlen];
129
120 memset (zero_salt, 0, dlen); 130 memset (zero_salt, 0, dlen);
121 ret = doHMAC (mac, zero_salt, dlen, skm, skm_len); 131 ret = doHMAC (mac, zero_salt, dlen, skm, skm_len);
122 } 132 }
@@ -124,22 +134,23 @@ getPRK (gcry_md_hd_t mac, const void *xts, size_t xts_len, const void *skm,
124 { 134 {
125 ret = doHMAC (mac, xts, xts_len, skm, skm_len); 135 ret = doHMAC (mac, xts, xts_len, skm, skm_len);
126 } 136 }
127 if (ret == NULL) 137 if (NULL == ret)
128 return GNUNET_SYSERR; 138 return GNUNET_SYSERR;
129 GNUNET_memcpy (prk, ret, dlen); 139 GNUNET_memcpy (prk,
130 140 ret,
141 dlen);
131 return GNUNET_YES; 142 return GNUNET_YES;
132} 143}
133 144
134 145
135#if DEBUG_HKDF 146#if DEBUG_HKDF
136static void 147static void
137dump (const char *src, const void *p, unsigned int l) 148dump (const char *src,
149 const void *p,
150 unsigned int l)
138{ 151{
139 unsigned int i;
140
141 printf ("\n%s: ", src); 152 printf ("\n%s: ", src);
142 for (i = 0; i < l; i++) 153 for (unsigned int i = 0; i < l; i++)
143 { 154 {
144 printf ("%2x", (int) ((const unsigned char *) p)[i]); 155 printf ("%2x", (int) ((const unsigned char *) p)[i]);
145 } 156 }
@@ -150,23 +161,16 @@ dump (const char *src, const void *p, unsigned int l)
150#endif 161#endif
151 162
152 163
153/** 164enum GNUNET_GenericReturnValue
154 * @brief Derive key 165GNUNET_CRYPTO_hkdf_v (void *result,
155 * @param result buffer for the derived key, allocated by caller 166 size_t out_len,
156 * @param out_len desired length of the derived key 167 int xtr_algo,
157 * @param xtr_algo hash algorithm for the extraction phase, GCRY_MD_... 168 int prf_algo,
158 * @param prf_algo hash algorithm for the expansion phase, GCRY_MD_... 169 const void *xts,
159 * @param xts salt 170 size_t xts_len,
160 * @param xts_len length of @a xts 171 const void *skm,
161 * @param skm source key material 172 size_t skm_len,
162 * @param skm_len length of @a skm 173 va_list argp)
163 * @param argp va_list of void * & size_t pairs for context chunks
164 * @return #GNUNET_YES on success
165 */
166int
167GNUNET_CRYPTO_hkdf_v (void *result, size_t out_len, int xtr_algo, int prf_algo,
168 const void *xts, size_t xts_len, const void *skm,
169 size_t skm_len, va_list argp)
170{ 174{
171 gcry_md_hd_t xtr; 175 gcry_md_hd_t xtr;
172 gcry_md_hd_t prf; 176 gcry_md_hd_t prf;
@@ -186,10 +190,14 @@ GNUNET_CRYPTO_hkdf_v (void *result, size_t out_len, int xtr_algo, int prf_algo,
186 if (0 == k) 190 if (0 == k)
187 return GNUNET_SYSERR; 191 return GNUNET_SYSERR;
188 if (GPG_ERR_NO_ERROR != 192 if (GPG_ERR_NO_ERROR !=
189 gcry_md_open (&xtr, xtr_algo, GCRY_MD_FLAG_HMAC)) 193 gcry_md_open (&xtr,
194 xtr_algo,
195 GCRY_MD_FLAG_HMAC))
190 return GNUNET_SYSERR; 196 return GNUNET_SYSERR;
191 if (GPG_ERR_NO_ERROR != 197 if (GPG_ERR_NO_ERROR !=
192 gcry_md_open (&prf, prf_algo, GCRY_MD_FLAG_HMAC)) 198 gcry_md_open (&prf,
199 prf_algo,
200 GCRY_MD_FLAG_HMAC))
193 { 201 {
194 gcry_md_close (xtr); 202 gcry_md_close (xtr);
195 return GNUNET_SYSERR; 203 return GNUNET_SYSERR;
@@ -221,7 +229,8 @@ GNUNET_CRYPTO_hkdf_v (void *result, size_t out_len, int xtr_algo, int prf_algo,
221 } 229 }
222 230
223 memset (result, 0, out_len); 231 memset (result, 0, out_len);
224 if (getPRK (xtr, xts, xts_len, skm, skm_len, prk) != GNUNET_YES) 232 if (GNUNET_YES !=
233 getPRK (xtr, xts, xts_len, skm, skm_len, prk))
225 goto hkdf_error; 234 goto hkdf_error;
226#if DEBUG_HKDF 235#if DEBUG_HKDF
227 dump ("PRK", prk, xtr_len); 236 dump ("PRK", prk, xtr_len);
@@ -276,7 +285,7 @@ GNUNET_CRYPTO_hkdf_v (void *result, size_t out_len, int xtr_algo, int prf_algo,
276 dump ("K(i+1)", plain, plain_len); 285 dump ("K(i+1)", plain, plain_len);
277#endif 286#endif
278 hc = doHMAC (prf, prk, xtr_len, plain, plain_len); 287 hc = doHMAC (prf, prk, xtr_len, plain, plain_len);
279 if (hc == NULL) 288 if (NULL == hc)
280 { 289 {
281 GNUNET_free (plain); 290 GNUNET_free (plain);
282 goto hkdf_error; 291 goto hkdf_error;
@@ -327,32 +336,31 @@ hkdf_ok:
327} 336}
328 337
329 338
330/** 339enum GNUNET_GenericReturnValue
331 * @brief Derive key 340GNUNET_CRYPTO_hkdf (void *result,
332 * @param result buffer for the derived key, allocated by caller 341 size_t out_len,
333 * @param out_len desired length of the derived key 342 int xtr_algo,
334 * @param xtr_algo hash algorithm for the extraction phase, GCRY_MD_... 343 int prf_algo,
335 * @param prf_algo hash algorithm for the expansion phase, GCRY_MD_... 344 const void *xts,
336 * @param xts salt 345 size_t xts_len,
337 * @param xts_len length of @a xts 346 const void *skm,
338 * @param skm source key material
339 * @param skm_len length of @a skm
340 * @return #GNUNET_YES on success
341 */
342int
343GNUNET_CRYPTO_hkdf (void *result, size_t out_len, int xtr_algo, int prf_algo,
344 const void *xts, size_t xts_len, const void *skm,
345 size_t skm_len, ...) 347 size_t skm_len, ...)
346{ 348{
347 va_list argp; 349 va_list argp;
348 int ret; 350 enum GNUNET_GenericReturnValue ret;
349 351
350 va_start (argp, skm_len); 352 va_start (argp, skm_len);
351 ret = 353 ret =
352 GNUNET_CRYPTO_hkdf_v (result, out_len, xtr_algo, prf_algo, xts, xts_len, 354 GNUNET_CRYPTO_hkdf_v (result,
353 skm, skm_len, argp); 355 out_len,
356 xtr_algo,
357 prf_algo,
358 xts,
359 xts_len,
360 skm,
361 skm_len,
362 argp);
354 va_end (argp); 363 va_end (argp);
355
356 return ret; 364 return ret;
357} 365}
358 366
diff --git a/src/util/crypto_kdf.c b/src/util/crypto_kdf.c
index 0dc734549..f577e0f7a 100644
--- a/src/util/crypto_kdf.c
+++ b/src/util/crypto_kdf.c
@@ -32,18 +32,8 @@
32 32
33#define LOG(kind, ...) GNUNET_log_from (kind, "util-crypto-kdf", __VA_ARGS__) 33#define LOG(kind, ...) GNUNET_log_from (kind, "util-crypto-kdf", __VA_ARGS__)
34 34
35/** 35
36 * @brief Derive key 36enum GNUNET_GenericReturnValue
37 * @param result buffer for the derived key, allocated by caller
38 * @param out_len desired length of the derived key
39 * @param xts salt
40 * @param xts_len length of @a xts
41 * @param skm source key material
42 * @param skm_len length of @a skm
43 * @param argp va_list of void * & size_t pairs for context chunks
44 * @return #GNUNET_YES on success
45 */
46int
47GNUNET_CRYPTO_kdf_v (void *result, 37GNUNET_CRYPTO_kdf_v (void *result,
48 size_t out_len, 38 size_t out_len,
49 const void *xts, 39 const void *xts,
@@ -62,7 +52,7 @@ GNUNET_CRYPTO_kdf_v (void *result,
62 * hash function." 52 * hash function."
63 * 53 *
64 * http://eprint.iacr.org/2010/264 54 * http://eprint.iacr.org/2010/264
65 */// 55 */
66 return GNUNET_CRYPTO_hkdf_v (result, 56 return GNUNET_CRYPTO_hkdf_v (result,
67 out_len, 57 out_len,
68 GCRY_MD_SHA512, 58 GCRY_MD_SHA512,
@@ -75,18 +65,7 @@ GNUNET_CRYPTO_kdf_v (void *result,
75} 65}
76 66
77 67
78/** 68enum GNUNET_GenericReturnValue
79 * @brief Derive key
80 * @param result buffer for the derived key, allocated by caller
81 * @param out_len desired length of the derived key
82 * @param xts salt
83 * @param xts_len length of @a xts
84 * @param skm source key material
85 * @param skm_len length of @a skm
86 * @param ... void * & size_t pairs for context chunks
87 * @return #GNUNET_YES on success
88 */
89int
90GNUNET_CRYPTO_kdf (void *result, 69GNUNET_CRYPTO_kdf (void *result,
91 size_t out_len, 70 size_t out_len,
92 const void *xts, 71 const void *xts,
@@ -111,18 +90,6 @@ GNUNET_CRYPTO_kdf (void *result,
111} 90}
112 91
113 92
114/**
115 * Deterministically generate a pseudo-random number uniformly from the
116 * integers modulo a libgcrypt mpi.
117 *
118 * @param[out] r MPI value set to the FDH
119 * @param n MPI to work modulo
120 * @param xts salt
121 * @param xts_len length of @a xts
122 * @param skm source key material
123 * @param skm_len length of @a skm
124 * @param ctx context string
125 */
126void 93void
127GNUNET_CRYPTO_kdf_mod_mpi (gcry_mpi_t *r, 94GNUNET_CRYPTO_kdf_mod_mpi (gcry_mpi_t *r,
128 gcry_mpi_t n, 95 gcry_mpi_t n,
@@ -137,32 +104,34 @@ GNUNET_CRYPTO_kdf_mod_mpi (gcry_mpi_t *r,
137 104
138 nbits = gcry_mpi_get_nbits (n); 105 nbits = gcry_mpi_get_nbits (n);
139 /* GNUNET_assert (nbits > 512); */ 106 /* GNUNET_assert (nbits > 512); */
140
141 ctr = 0; 107 ctr = 0;
142 while (1) 108 while (1)
143 { 109 {
144 /* Ain't clear if n is always divisible by 8 */ 110 /* Ain't clear if n is always divisible by 8 */
145 uint8_t buf[ (nbits - 1) / 8 + 1 ]; 111 size_t bsize = (nbits - 1) / 8 + 1;
112 uint8_t buf[bsize];
146 uint16_t ctr_nbo = htons (ctr); 113 uint16_t ctr_nbo = htons (ctr);
147 114
148 rc = GNUNET_CRYPTO_kdf (buf, 115 rc = GNUNET_CRYPTO_kdf (buf,
149 sizeof(buf), 116 bsize,
150 xts, xts_len, 117 xts, xts_len,
151 skm, skm_len, 118 skm, skm_len,
152 ctx, strlen (ctx), 119 ctx, strlen (ctx),
153 &ctr_nbo, sizeof(ctr_nbo), 120 &ctr_nbo, sizeof(ctr_nbo),
154 NULL, 0); 121 NULL, 0);
155 GNUNET_assert (GNUNET_YES == rc); 122 GNUNET_assert (GNUNET_YES == rc);
156
157 rc = gcry_mpi_scan (r, 123 rc = gcry_mpi_scan (r,
158 GCRYMPI_FMT_USG, 124 GCRYMPI_FMT_USG,
159 (const unsigned char *) buf, 125 (const unsigned char *) buf,
160 sizeof(buf), 126 bsize,
161 &rsize); 127 &rsize);
162 GNUNET_assert (0 == rc); /* Allocation error? */ 128 GNUNET_assert (GPG_ERR_NO_ERROR == rc); /* Allocation error? */
163 129 GNUNET_assert (rsize == bsize);
164 gcry_mpi_clear_highbit (*r, nbits); 130 gcry_mpi_clear_highbit (*r,
165 GNUNET_assert (0 == gcry_mpi_test_bit (*r, nbits)); 131 nbits);
132 GNUNET_assert (0 ==
133 gcry_mpi_test_bit (*r,
134 nbits));
166 ++ctr; 135 ++ctr;
167 /* We reject this FDH if either *r > n and retry with another ctr */ 136 /* We reject this FDH if either *r > n and retry with another ctr */
168 if (0 > gcry_mpi_cmp (*r, n)) 137 if (0 > gcry_mpi_cmp (*r, n))
diff --git a/src/util/crypto_rsa.c b/src/util/crypto_rsa.c
index 43e6eedac..4b8e5a5ce 100644
--- a/src/util/crypto_rsa.c
+++ b/src/util/crypto_rsa.c
@@ -497,7 +497,8 @@ GNUNET_CRYPTO_rsa_public_key_decode (const char *buf,
497 * @return True if gcd(r,n) = 1, False means RSA key is malicious 497 * @return True if gcd(r,n) = 1, False means RSA key is malicious
498 */ 498 */
499static int 499static int
500rsa_gcd_validate (gcry_mpi_t r, gcry_mpi_t n) 500rsa_gcd_validate (gcry_mpi_t r,
501 gcry_mpi_t n)
501{ 502{
502 gcry_mpi_t g; 503 gcry_mpi_t g;
503 int t; 504 int t;
@@ -520,29 +521,34 @@ static struct RsaBlindingKey *
520rsa_blinding_key_derive (const struct GNUNET_CRYPTO_RsaPublicKey *pkey, 521rsa_blinding_key_derive (const struct GNUNET_CRYPTO_RsaPublicKey *pkey,
521 const struct GNUNET_CRYPTO_RsaBlindingKeySecret *bks) 522 const struct GNUNET_CRYPTO_RsaBlindingKeySecret *bks)
522{ 523{
523 char *xts = "Blinding KDF extractor HMAC key"; /* Trusts bks' randomness more */ 524 const char *xts = "Blinding KDF extractor HMAC key"; /* Trusts bks' randomness more */
524 struct RsaBlindingKey *blind; 525 struct RsaBlindingKey *blind;
525 gcry_mpi_t n; 526 gcry_mpi_t n;
526 527
527 blind = GNUNET_new (struct RsaBlindingKey); 528 blind = GNUNET_new (struct RsaBlindingKey);
528 GNUNET_assert (NULL != blind);
529 529
530 /* Extract the composite n from the RSA public key */ 530 /* Extract the composite n from the RSA public key */
531 GNUNET_assert (0 == key_from_sexp (&n, pkey->sexp, "rsa", "n")); 531 GNUNET_assert (0 ==
532 key_from_sexp (&n,
533 pkey->sexp,
534 "rsa",
535 "n"));
532 /* Assert that it at least looks like an RSA key */ 536 /* Assert that it at least looks like an RSA key */
533 GNUNET_assert (0 == gcry_mpi_get_flag (n, GCRYMPI_FLAG_OPAQUE)); 537 GNUNET_assert (0 ==
534 538 gcry_mpi_get_flag (n,
539 GCRYMPI_FLAG_OPAQUE));
535 GNUNET_CRYPTO_kdf_mod_mpi (&blind->r, 540 GNUNET_CRYPTO_kdf_mod_mpi (&blind->r,
536 n, 541 n,
537 xts, strlen (xts), 542 xts, strlen (xts),
538 bks, sizeof(*bks), 543 bks, sizeof(*bks),
539 "Blinding KDF"); 544 "Blinding KDF");
540 if (0 == rsa_gcd_validate (blind->r, n)) 545 if (0 == rsa_gcd_validate (blind->r,
546 n))
541 { 547 {
548 gcry_mpi_release (blind->r);
542 GNUNET_free (blind); 549 GNUNET_free (blind);
543 blind = NULL; 550 blind = NULL;
544 } 551 }
545
546 gcry_mpi_release (n); 552 gcry_mpi_release (n);
547 return blind; 553 return blind;
548} 554}
@@ -760,8 +766,9 @@ rsa_full_domain_hash (const struct GNUNET_CRYPTO_RsaPublicKey *pkey,
760 /* We key with the public denomination key as a homage to RSA-PSS by * 766 /* We key with the public denomination key as a homage to RSA-PSS by *
761 * Mihir Bellare and Phillip Rogaway. Doing this lowers the degree * 767 * Mihir Bellare and Phillip Rogaway. Doing this lowers the degree *
762 * of the hypothetical polyomial-time attack on RSA-KTI created by a * 768 * of the hypothetical polyomial-time attack on RSA-KTI created by a *
763 * polynomial-time one-more forgary attack. Yey seeding! */ 769 * polynomial-time one-more forgary attack. Yey seeding! */
764 xts_len = GNUNET_CRYPTO_rsa_public_key_encode (pkey, &xts); 770 xts_len = GNUNET_CRYPTO_rsa_public_key_encode (pkey,
771 &xts);
765 772
766 GNUNET_CRYPTO_kdf_mod_mpi (&r, 773 GNUNET_CRYPTO_kdf_mod_mpi (&r,
767 n, 774 n,
@@ -769,7 +776,6 @@ rsa_full_domain_hash (const struct GNUNET_CRYPTO_RsaPublicKey *pkey,
769 hash, sizeof(*hash), 776 hash, sizeof(*hash),
770 "RSA-FDA FTpsW!"); 777 "RSA-FDA FTpsW!");
771 GNUNET_free (xts); 778 GNUNET_free (xts);
772
773 ok = rsa_gcd_validate (r, n); 779 ok = rsa_gcd_validate (r, n);
774 gcry_mpi_release (n); 780 gcry_mpi_release (n);
775 if (ok) 781 if (ok)
diff --git a/src/util/test_crypto_eddsa.c b/src/util/test_crypto_eddsa.c
index 459619ff2..e9573a307 100644
--- a/src/util/test_crypto_eddsa.c
+++ b/src/util/test_crypto_eddsa.c
@@ -130,9 +130,11 @@ testDeriveSignVerify (void)
130 return GNUNET_SYSERR; 130 return GNUNET_SYSERR;
131 } 131 }
132 132
133 GNUNET_CRYPTO_eddsa_sign_with_scalar (&dpriv, 133 GNUNET_CRYPTO_eddsa_sign_derived (&key,
134 &purp, 134 "test-derive",
135 &sig); 135 "test-CTX",
136 &purp,
137 &sig);
136 if (GNUNET_SYSERR == 138 if (GNUNET_SYSERR ==
137 GNUNET_CRYPTO_eddsa_verify_ (GNUNET_SIGNATURE_PURPOSE_TEST, 139 GNUNET_CRYPTO_eddsa_verify_ (GNUNET_SIGNATURE_PURPOSE_TEST,
138 &purp, 140 &purp,
diff --git a/src/util/test_crypto_edx25519.c b/src/util/test_crypto_edx25519.c
new file mode 100644
index 000000000..ead6f0bb9
--- /dev/null
+++ b/src/util/test_crypto_edx25519.c
@@ -0,0 +1,326 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2022 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/test_crypto_edx25519.c
23 * @brief testcase for ECC public key crypto for edx25519
24 * @author Özgür Kesim
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_signatures.h"
29#include <gcrypt.h>
30
31#define ITER 25
32
33#define KEYFILE "/tmp/test-gnunet-crypto-edx25519.key"
34
35#define PERF GNUNET_YES
36
37
38static struct GNUNET_CRYPTO_Edx25519PrivateKey key;
39
40
41static int
42testSignVerify (void)
43{
44 struct GNUNET_CRYPTO_Edx25519Signature sig;
45 struct GNUNET_CRYPTO_EccSignaturePurpose purp;
46 struct GNUNET_CRYPTO_Edx25519PublicKey pkey;
47 struct GNUNET_TIME_Absolute start;
48 int ok = GNUNET_OK;
49
50 fprintf (stderr, "%s", "W");
51 GNUNET_CRYPTO_edx25519_key_get_public (&key,
52 &pkey);
53 start = GNUNET_TIME_absolute_get ();
54 purp.size = htonl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose));
55 purp.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TEST);
56
57 for (unsigned int i = 0; i < ITER; i++)
58 {
59 fprintf (stderr, "%s", "."); fflush (stderr);
60 if (GNUNET_SYSERR == GNUNET_CRYPTO_edx25519_sign_ (&key,
61 &purp,
62 &sig))
63 {
64 fprintf (stderr,
65 "GNUNET_CRYPTO_edx25519_sign returned SYSERR\n");
66 ok = GNUNET_SYSERR;
67 continue;
68 }
69 if (GNUNET_SYSERR ==
70 GNUNET_CRYPTO_edx25519_verify_ (GNUNET_SIGNATURE_PURPOSE_TEST,
71 &purp,
72 &sig,
73 &pkey))
74 {
75 fprintf (stderr,
76 "GNUNET_CRYPTO_edx25519_verify failed!\n");
77 ok = GNUNET_SYSERR;
78 continue;
79 }
80 if (GNUNET_SYSERR !=
81 GNUNET_CRYPTO_edx25519_verify_ (
82 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
83 &purp,
84 &sig,
85 &pkey))
86 {
87 fprintf (stderr,
88 "GNUNET_CRYPTO_edx25519_verify failed to fail!\n");
89 ok = GNUNET_SYSERR;
90 continue;
91 }
92 }
93 fprintf (stderr, "\n");
94 printf ("%d EdDSA sign/verify operations %s\n",
95 ITER,
96 GNUNET_STRINGS_relative_time_to_string (
97 GNUNET_TIME_absolute_get_duration (start),
98 GNUNET_YES));
99 return ok;
100}
101
102
103static int
104testDeriveSignVerify (void)
105{
106 struct GNUNET_CRYPTO_EccSignaturePurpose purp;
107 struct GNUNET_CRYPTO_Edx25519Signature sig;
108 struct GNUNET_CRYPTO_Edx25519PrivateKey dkey;
109 struct GNUNET_CRYPTO_Edx25519PublicKey pub;
110 struct GNUNET_CRYPTO_Edx25519PublicKey dpub;
111 struct GNUNET_CRYPTO_Edx25519PublicKey dpub2;
112
113 GNUNET_CRYPTO_edx25519_key_get_public (&key, &pub);
114 GNUNET_CRYPTO_edx25519_private_key_derive (&key,
115 "test-derive",
116 sizeof("test-derive"),
117 &dkey);
118 GNUNET_CRYPTO_edx25519_public_key_derive (&pub,
119 "test-derive",
120 sizeof("test-derive"),
121 &dpub);
122 GNUNET_CRYPTO_edx25519_key_get_public (&dkey, &dpub2);
123
124 if (0 != GNUNET_memcmp (&dpub.q_y, &dpub2.q_y))
125 {
126 fprintf (stderr, "key deriviation failed\n");
127 return GNUNET_SYSERR;
128 }
129
130 purp.size = htonl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose));
131 purp.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TEST);
132
133 GNUNET_CRYPTO_edx25519_sign_ (&dkey,
134 &purp,
135 &sig);
136
137 if (GNUNET_SYSERR ==
138 GNUNET_CRYPTO_edx25519_verify_ (GNUNET_SIGNATURE_PURPOSE_TEST,
139 &purp,
140 &sig,
141 &dpub))
142 {
143 fprintf (stderr,
144 "GNUNET_CRYPTO_edx25519_verify failed after derivation!\n");
145 return GNUNET_SYSERR;
146 }
147
148 if (GNUNET_SYSERR !=
149 GNUNET_CRYPTO_edx25519_verify_ (GNUNET_SIGNATURE_PURPOSE_TEST,
150 &purp,
151 &sig,
152 &pub))
153 {
154 fprintf (stderr,
155 "GNUNET_CRYPTO_edx25519_verify failed to fail after derivation!\n");
156 return GNUNET_SYSERR;
157 }
158
159 if (GNUNET_SYSERR !=
160 GNUNET_CRYPTO_edx25519_verify_ (
161 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
162 &purp,
163 &sig,
164 &dpub))
165 {
166 fprintf (stderr,
167 "GNUNET_CRYPTO_edx25519_verify failed to fail after derivation!\n");
168 return GNUNET_SYSERR;
169 }
170 return GNUNET_OK;
171}
172
173
174#if PERF
175static int
176testSignPerformance ()
177{
178 struct GNUNET_CRYPTO_EccSignaturePurpose purp;
179 struct GNUNET_CRYPTO_Edx25519Signature sig;
180 struct GNUNET_CRYPTO_Edx25519PublicKey pkey;
181 struct GNUNET_TIME_Absolute start;
182 int ok = GNUNET_OK;
183
184 purp.size = htonl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose));
185 purp.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TEST);
186 fprintf (stderr, "%s", "W");
187 GNUNET_CRYPTO_edx25519_key_get_public (&key,
188 &pkey);
189 start = GNUNET_TIME_absolute_get ();
190 for (unsigned int i = 0; i < ITER; i++)
191 {
192 fprintf (stderr, "%s", ".");
193 fflush (stderr);
194 if (GNUNET_SYSERR ==
195 GNUNET_CRYPTO_edx25519_sign_ (&key,
196 &purp,
197 &sig))
198 {
199 fprintf (stderr, "%s", "GNUNET_CRYPTO_edx25519_sign returned SYSERR\n");
200 ok = GNUNET_SYSERR;
201 continue;
202 }
203 }
204 fprintf (stderr, "\n");
205 printf ("%d EdDSA sign operations %s\n",
206 ITER,
207 GNUNET_STRINGS_relative_time_to_string (
208 GNUNET_TIME_absolute_get_duration (start),
209 GNUNET_YES));
210 return ok;
211}
212
213
214#endif
215
216
217#if 0 /* not implemented */
218static int
219testCreateFromFile (void)
220{
221 struct GNUNET_CRYPTO_Edx25519PublicKey p1;
222 struct GNUNET_CRYPTO_Edx25519PublicKey p2;
223
224 /* do_create == GNUNET_YES and non-existing file MUST return GNUNET_YES */
225 GNUNET_assert (0 == unlink (KEYFILE) || ENOENT == errno);
226 GNUNET_assert (GNUNET_YES ==
227 GNUNET_CRYPTO_edx25519_key_from_file (KEYFILE,
228 GNUNET_YES,
229 &key));
230 GNUNET_CRYPTO_edx25519_key_get_public (&key,
231 &p1);
232
233 /* do_create == GNUNET_YES and _existing_ file MUST return GNUNET_NO */
234 GNUNET_assert (GNUNET_NO ==
235 GNUNET_CRYPTO_edx25519_key_from_file (KEYFILE,
236 GNUNET_YES,
237 &key));
238 GNUNET_CRYPTO_edx25519_key_get_public (&key,
239 &p2);
240 GNUNET_assert (0 ==
241 GNUNET_memcmp (&p1,
242 &p2));
243
244 /* do_create == GNUNET_NO and non-existing file MUST return GNUNET_SYSERR */
245 GNUNET_assert (0 == unlink (KEYFILE));
246 GNUNET_assert (GNUNET_SYSERR ==
247 GNUNET_CRYPTO_edx25519_key_from_file (KEYFILE,
248 GNUNET_NO,
249 &key));
250 return GNUNET_OK;
251}
252
253
254#endif
255
256
257static void
258perf_keygen (void)
259{
260 struct GNUNET_TIME_Absolute start;
261 struct GNUNET_CRYPTO_Edx25519PrivateKey pk;
262
263 fprintf (stderr, "%s", "W");
264 start = GNUNET_TIME_absolute_get ();
265 for (unsigned int i = 0; i < 10; i++)
266 {
267 fprintf (stderr, ".");
268 fflush (stderr);
269 GNUNET_CRYPTO_edx25519_key_create (&pk);
270 }
271 fprintf (stderr, "\n");
272 printf ("10 EdDSA keys created in %s\n",
273 GNUNET_STRINGS_relative_time_to_string (
274 GNUNET_TIME_absolute_get_duration (start), GNUNET_YES));
275}
276
277
278int
279main (int argc, char *argv[])
280{
281 int failure_count = 0;
282
283 if (! gcry_check_version ("1.6.0"))
284 {
285 fprintf (stderr,
286 "libgcrypt has not the expected version (version %s is required).\n",
287 "1.6.0");
288 return 0;
289 }
290 if (getenv ("GNUNET_GCRYPT_DEBUG"))
291 gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
292 GNUNET_log_setup ("test-crypto-edx25519",
293 "WARNING",
294 NULL);
295 GNUNET_CRYPTO_edx25519_key_create (&key);
296 if (GNUNET_OK != testDeriveSignVerify ())
297 {
298 failure_count++;
299 fprintf (stderr,
300 "\n\n%d TESTS FAILED!\n\n", failure_count);
301 return -1;
302 }
303#if PERF
304 if (GNUNET_OK != testSignPerformance ())
305 failure_count++;
306#endif
307 if (GNUNET_OK != testSignVerify ())
308 failure_count++;
309#if 0 /* not implemented */
310 if (GNUNET_OK != testCreateFromFile ())
311 failure_count++;
312#endif
313 perf_keygen ();
314
315 if (0 != failure_count)
316 {
317 fprintf (stderr,
318 "\n\n%d TESTS FAILED!\n\n",
319 failure_count);
320 return -1;
321 }
322 return 0;
323}
324
325
326/* end of test_crypto_edx25519.c */
diff --git a/src/util/time.c b/src/util/time.c
index 68a6937a0..cf072aebf 100644
--- a/src/util/time.c
+++ b/src/util/time.c
@@ -58,6 +58,22 @@ GNUNET_TIME_get_offset ()
58} 58}
59 59
60 60
61bool
62GNUNET_TIME_absolute_approx_eq (struct GNUNET_TIME_Absolute a1,
63 struct GNUNET_TIME_Absolute a2,
64 struct GNUNET_TIME_Relative t)
65{
66 struct GNUNET_TIME_Relative delta;
67
68 delta = GNUNET_TIME_relative_min (
69 GNUNET_TIME_absolute_get_difference (a1, a2),
70 GNUNET_TIME_absolute_get_difference (a2, a1));
71 return GNUNET_TIME_relative_cmp (delta,
72 <=,
73 t);
74}
75
76
61struct GNUNET_TIME_Timestamp 77struct GNUNET_TIME_Timestamp
62GNUNET_TIME_absolute_to_timestamp (struct GNUNET_TIME_Absolute at) 78GNUNET_TIME_absolute_to_timestamp (struct GNUNET_TIME_Absolute at)
63{ 79{
@@ -370,6 +386,20 @@ GNUNET_TIME_timestamp_min (struct GNUNET_TIME_Timestamp t1,
370} 386}
371 387
372 388
389struct GNUNET_TIME_Absolute
390GNUNET_TIME_absolute_round_down (struct GNUNET_TIME_Absolute at,
391 struct GNUNET_TIME_Relative rt)
392{
393 struct GNUNET_TIME_Absolute ret;
394
395 GNUNET_assert (! GNUNET_TIME_relative_is_zero (rt));
396 ret.abs_value_us
397 = at.abs_value_us
398 - at.abs_value_us % rt.rel_value_us;
399 return ret;
400}
401
402
373struct GNUNET_TIME_Relative 403struct GNUNET_TIME_Relative
374GNUNET_TIME_absolute_get_remaining (struct GNUNET_TIME_Absolute future) 404GNUNET_TIME_absolute_get_remaining (struct GNUNET_TIME_Absolute future)
375{ 405{