aboutsummaryrefslogtreecommitdiff
path: root/src/util/crypto_ecc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/crypto_ecc.c')
-rw-r--r--src/util/crypto_ecc.c727
1 files changed, 431 insertions, 296 deletions
diff --git a/src/util/crypto_ecc.c b/src/util/crypto_ecc.c
index 2561ab2e6..a93512e38 100644
--- a/src/util/crypto_ecc.c
+++ b/src/util/crypto_ecc.c
@@ -4,7 +4,7 @@
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your 7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version. 8 option) any later version.
9 9
10 GNUnet is distributed in the hope that it will be useful, but 10 GNUnet is distributed in the hope that it will be useful, but
@@ -30,6 +30,12 @@
30 30
31#define EXTRA_CHECKS ALLOW_EXTRA_CHECKS 31#define EXTRA_CHECKS ALLOW_EXTRA_CHECKS
32 32
33/**
34 * Name of the curve we are using. Note that we have hard-coded
35 * structs that use 256 bits, so using a bigger curve will require
36 * changes that break stuff badly. The name of the curve given here
37 * must be agreed by all peers and be supported by libgcrypt.
38 */
33#define CURVE "NIST P-256" 39#define CURVE "NIST P-256"
34 40
35#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 41#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
@@ -47,28 +53,14 @@
47 53
48 54
49/** 55/**
50 * The private information of an ECC private key.
51 */
52struct GNUNET_CRYPTO_EccPrivateKey
53{
54
55 /**
56 * Libgcrypt S-expression for the ECC key.
57 */
58 gcry_sexp_t sexp;
59};
60
61
62/**
63 * Free memory occupied by ECC key 56 * Free memory occupied by ECC key
64 * 57 *
65 * @param privatekey pointer to the memory to free 58 * @param priv pointer to the memory to free
66 */ 59 */
67void 60void
68GNUNET_CRYPTO_ecc_key_free (struct GNUNET_CRYPTO_EccPrivateKey *privatekey) 61GNUNET_CRYPTO_ecc_key_free (struct GNUNET_CRYPTO_EccPrivateKey *priv)
69{ 62{
70 gcry_sexp_release (privatekey->sexp); 63 GNUNET_free (priv);
71 GNUNET_free (privatekey);
72} 64}
73 65
74 66
@@ -133,6 +125,141 @@ key_from_sexp (gcry_mpi_t * array, gcry_sexp_t sexp, const char *topname,
133 125
134 126
135/** 127/**
128 * If target != size, move target bytes to the end of the size-sized
129 * buffer and zero out the first target-size bytes.
130 *
131 * @param buf original buffer
132 * @param size number of bytes in the buffer
133 * @param target target size of the buffer
134 */
135static void
136adjust (unsigned char *buf,
137 size_t size,
138 size_t target)
139{
140 if (size < target)
141 {
142 memmove (&buf[target - size], buf, size);
143 memset (buf, 0, target - size);
144 }
145}
146
147
148/**
149 * Output the given MPI value to the given buffer.
150 *
151 * @param buf where to output to
152 * @param size number of bytes in buf
153 * @param val value to write to buf
154 */
155static void
156mpi_print (unsigned char *buf,
157 size_t size,
158 gcry_mpi_t val)
159{
160 size_t rsize;
161
162 rsize = size;
163 GNUNET_assert (0 ==
164 gcry_mpi_print (GCRYMPI_FMT_USG, buf, rsize, &rsize,
165 val));
166 adjust (buf, rsize, size);
167}
168
169
170/**
171 * Convert data buffer into MPI value.
172 *
173 * @param result where to store MPI value (allocated)
174 * @param data raw data (GCRYMPI_FMT_USG)
175 * @param size number of bytes in data
176 */
177static void
178mpi_scan (gcry_mpi_t *result,
179 const unsigned char *data,
180 size_t size)
181{
182 int rc;
183
184 if (0 != (rc = gcry_mpi_scan (result,
185 GCRYMPI_FMT_USG,
186 data, size, &size)))
187 {
188 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
189 GNUNET_assert (0);
190 }
191}
192
193
194/**
195 * Convert the given private key from the network format to the
196 * S-expression that can be used by libgcrypt.
197 *
198 * @param priv private key to decode
199 * @return NULL on error
200 */
201static gcry_sexp_t
202decode_private_key (const struct GNUNET_CRYPTO_EccPrivateKey *priv)
203{
204 gcry_sexp_t result;
205 gcry_mpi_t d;
206 size_t erroff;
207 int rc;
208
209 mpi_scan (&d,
210 priv->d,
211 sizeof (priv->d));
212 rc = gcry_sexp_build (&result, &erroff,
213 "(private-key(ecdsa(curve \"" CURVE "\")(d %m)))",
214 d);
215 gcry_mpi_release (d);
216 if (0 != rc)
217 {
218 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc); /* erroff gives more info */
219 GNUNET_assert (0);
220 }
221#if EXTRA_CHECKS
222 if (0 != (rc = gcry_pk_testkey (result)))
223 {
224 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
225 GNUNET_assert (0);
226 }
227#endif
228 return result;
229}
230
231
232/**
233 * Initialize public key struct from the respective point
234 * on the curve.
235 *
236 * @param q point on curve
237 * @param pub public key struct to initialize
238 * @param ctx context to use for ECC operations
239 */
240static void
241point_to_public_key (gcry_mpi_point_t q,
242 gcry_ctx_t ctx,
243 struct GNUNET_CRYPTO_EccPublicKey *pub)
244{
245 gcry_mpi_t q_x;
246 gcry_mpi_t q_y;
247
248 q_x = gcry_mpi_new (256);
249 q_y = gcry_mpi_new (256);
250 if (gcry_mpi_ec_get_affine (q_x, q_y, q, ctx))
251 {
252 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "get_affine failed", 0);
253 return;
254 }
255 mpi_print (pub->q_x, sizeof (pub->q_x), q_x);
256 mpi_print (pub->q_y, sizeof (pub->q_y), q_y);
257 gcry_mpi_release (q_x);
258 gcry_mpi_release (q_y);
259}
260
261
262/**
136 * Extract the public key for the given private key. 263 * Extract the public key for the given private key.
137 * 264 *
138 * @param priv the private key 265 * @param priv the private key
@@ -140,26 +267,25 @@ key_from_sexp (gcry_mpi_t * array, gcry_sexp_t sexp, const char *topname,
140 */ 267 */
141void 268void
142GNUNET_CRYPTO_ecc_key_get_public (const struct GNUNET_CRYPTO_EccPrivateKey *priv, 269GNUNET_CRYPTO_ecc_key_get_public (const struct GNUNET_CRYPTO_EccPrivateKey *priv,
143 struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *pub) 270 struct GNUNET_CRYPTO_EccPublicKey *pub)
144{ 271{
145 gcry_mpi_t skey; 272 gcry_sexp_t sexp;
146 size_t size; 273 gcry_ctx_t ctx;
274 gcry_mpi_point_t q;
147 int rc; 275 int rc;
148 276
149 memset (pub, 0, sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded)); 277 sexp = decode_private_key (priv);
150 rc = key_from_sexp (&skey, priv->sexp, "public-key", "q"); 278 GNUNET_assert (NULL != sexp);
151 if (rc) 279 if (0 != (rc = gcry_mpi_ec_new (&ctx, sexp, NULL)))
152 rc = key_from_sexp (&skey, priv->sexp, "private-key", "q"); 280 {
153 if (rc) 281 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_new", rc); /* erroff gives more info */
154 rc = key_from_sexp (&skey, priv->sexp, "ecc", "q"); 282 return;
155 GNUNET_assert (0 == rc); 283 }
156 pub->size = htons (sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded)); 284 gcry_sexp_release (sexp);
157 size = GNUNET_CRYPTO_ECC_MAX_PUBLIC_KEY_LENGTH; 285 q = gcry_mpi_ec_get_point ("q", ctx, 0);
158 GNUNET_assert (0 == 286 point_to_public_key (q, ctx, pub);
159 gcry_mpi_print (GCRYMPI_FMT_USG, pub->key, size, &size, 287 gcry_ctx_release (ctx);
160 skey)); 288 gcry_mpi_point_release (q);
161 pub->len = htons (size);
162 gcry_mpi_release (skey);
163} 289}
164 290
165 291
@@ -170,10 +296,10 @@ GNUNET_CRYPTO_ecc_key_get_public (const struct GNUNET_CRYPTO_EccPrivateKey *priv
170 * @return string representing 'pub' 296 * @return string representing 'pub'
171 */ 297 */
172char * 298char *
173GNUNET_CRYPTO_ecc_public_key_to_string (const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *pub) 299GNUNET_CRYPTO_ecc_public_key_to_string (const struct GNUNET_CRYPTO_EccPublicKey *pub)
174{ 300{
175 char *pubkeybuf; 301 char *pubkeybuf;
176 size_t keylen = (sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded)) * 8; 302 size_t keylen = (sizeof (struct GNUNET_CRYPTO_EccPublicKey)) * 8;
177 char *end; 303 char *end;
178 304
179 if (keylen % 5 > 0) 305 if (keylen % 5 > 0)
@@ -181,7 +307,7 @@ GNUNET_CRYPTO_ecc_public_key_to_string (const struct GNUNET_CRYPTO_EccPublicKeyB
181 keylen /= 5; 307 keylen /= 5;
182 pubkeybuf = GNUNET_malloc (keylen + 1); 308 pubkeybuf = GNUNET_malloc (keylen + 1);
183 end = GNUNET_STRINGS_data_to_string ((unsigned char *) pub, 309 end = GNUNET_STRINGS_data_to_string ((unsigned char *) pub,
184 sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded), 310 sizeof (struct GNUNET_CRYPTO_EccPublicKey),
185 pubkeybuf, 311 pubkeybuf,
186 keylen); 312 keylen);
187 if (NULL == end) 313 if (NULL == end)
@@ -205,9 +331,9 @@ GNUNET_CRYPTO_ecc_public_key_to_string (const struct GNUNET_CRYPTO_EccPublicKeyB
205int 331int
206GNUNET_CRYPTO_ecc_public_key_from_string (const char *enc, 332GNUNET_CRYPTO_ecc_public_key_from_string (const char *enc,
207 size_t enclen, 333 size_t enclen,
208 struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *pub) 334 struct GNUNET_CRYPTO_EccPublicKey *pub)
209{ 335{
210 size_t keylen = (sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded)) * 8; 336 size_t keylen = (sizeof (struct GNUNET_CRYPTO_EccPublicKey)) * 8;
211 337
212 if (keylen % 5 > 0) 338 if (keylen % 5 > 0)
213 keylen += 5 - keylen % 5; 339 keylen += 5 - keylen % 5;
@@ -217,10 +343,7 @@ GNUNET_CRYPTO_ecc_public_key_from_string (const char *enc,
217 343
218 if (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, enclen, 344 if (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, enclen,
219 pub, 345 pub,
220 sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded))) 346 sizeof (struct GNUNET_CRYPTO_EccPublicKey)))
221 return GNUNET_SYSERR;
222 if ( (ntohs (pub->size) != sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded)) ||
223 (ntohs (pub->len) > GNUNET_CRYPTO_ECC_SIGNATURE_DATA_ENCODING_LENGTH) )
224 return GNUNET_SYSERR; 347 return GNUNET_SYSERR;
225 return GNUNET_OK; 348 return GNUNET_OK;
226} 349}
@@ -230,137 +353,46 @@ GNUNET_CRYPTO_ecc_public_key_from_string (const char *enc,
230 * Convert the given public key from the network format to the 353 * Convert the given public key from the network format to the
231 * S-expression that can be used by libgcrypt. 354 * S-expression that can be used by libgcrypt.
232 * 355 *
233 * @param publicKey public key to decode 356 * @param pub public key to decode
234 * @return NULL on error 357 * @return NULL on error
235 */ 358 */
236static gcry_sexp_t 359static gcry_sexp_t
237decode_public_key (const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *publicKey) 360decode_public_key (const struct GNUNET_CRYPTO_EccPublicKey *pub)
238{ 361{
239 gcry_sexp_t result; 362 gcry_sexp_t pub_sexp;
240 gcry_mpi_t q; 363 gcry_mpi_t q_x;
241 size_t size; 364 gcry_mpi_t q_y;
242 size_t erroff; 365 gcry_mpi_point_t q;
366 gcry_ctx_t ctx;
243 int rc; 367 int rc;
244 368
245 if (ntohs (publicKey->len) > GNUNET_CRYPTO_ECC_SIGNATURE_DATA_ENCODING_LENGTH) 369 mpi_scan (&q_x, pub->q_x, sizeof (pub->q_x));
246 { 370 mpi_scan (&q_y, pub->q_y, sizeof (pub->q_y));
247 GNUNET_break (0); 371 q = gcry_mpi_point_new (256);
248 return NULL; 372 gcry_mpi_point_set (q, q_x, q_y, GCRYMPI_CONST_ONE);
249 } 373 gcry_mpi_release (q_x);
250 size = ntohs (publicKey->len); 374 gcry_mpi_release (q_y);
251 if (0 != (rc = gcry_mpi_scan (&q, GCRYMPI_FMT_USG, publicKey->key, size, &size)))
252 {
253 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
254 return NULL;
255 }
256
257 rc = gcry_sexp_build (&result, &erroff,
258 "(public-key(ecdsa(curve \"" CURVE "\")(q %m)))",
259 q);
260 gcry_mpi_release (q);
261 if (0 != rc)
262 {
263 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc); /* erroff gives more info */
264 return NULL;
265 }
266#if EXTRA_CHECKS
267 if (0 != (rc = gcry_pk_testkey (result)))
268 {
269 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
270 gcry_sexp_release (result);
271 return NULL;
272 }
273#endif
274 return result;
275}
276
277
278/**
279 * Encode the private key in a format suitable for
280 * storing it into a file.
281 *
282 * @param key key to encode
283 * @return encoding of the private key.
284 * The first 4 bytes give the size of the array, as usual.
285 */
286struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded *
287GNUNET_CRYPTO_ecc_encode_key (const struct GNUNET_CRYPTO_EccPrivateKey *key)
288{
289 struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded *retval;
290 char buf[65536];
291 uint16_t be;
292 size_t size;
293
294#if EXTRA_CHECKS
295 if (0 != gcry_pk_testkey (key->sexp))
296 {
297 GNUNET_break (0);
298 return NULL;
299 }
300#endif
301 size = gcry_sexp_sprint (key->sexp,
302 GCRYSEXP_FMT_DEFAULT,
303 &buf[2], sizeof (buf) - sizeof (uint16_t));
304 if (0 == size)
305 {
306 GNUNET_break (0);
307 return NULL;
308 }
309 GNUNET_assert (size < 65536 - sizeof (uint16_t));
310 be = htons ((uint16_t) size + (sizeof (be)));
311 memcpy (buf, &be, sizeof (be));
312 size += sizeof (be);
313 retval = GNUNET_malloc (size);
314 memcpy (retval, buf, size);
315 return retval;
316}
317
318
319/**
320 * Decode the private key from the file-format back
321 * to the "normal", internal format.
322 *
323 * @param buf the buffer where the private key data is stored
324 * @param len the length of the data in 'buffer'
325 * @param validate GNUNET_YES to validate that the key is well-formed,
326 * GNUNET_NO if the key comes from a totally trusted source
327 * and validation is considered too expensive
328 * @return NULL on error
329 */
330struct GNUNET_CRYPTO_EccPrivateKey *
331GNUNET_CRYPTO_ecc_decode_key (const char *buf,
332 size_t len,
333 int validate)
334{
335 struct GNUNET_CRYPTO_EccPrivateKey *ret;
336 uint16_t be;
337 gcry_sexp_t sexp;
338 int rc;
339 size_t erroff;
340 375
341 if (len < sizeof (uint16_t)) 376 /* create basic ECC context */
342 return NULL; 377 if (0 != (rc = gcry_mpi_ec_new (&ctx, NULL, CURVE)))
343 memcpy (&be, buf, sizeof (be));
344 if (len < ntohs (be))
345 return NULL;
346 len = ntohs (be);
347 if (0 != (rc = gcry_sexp_sscan (&sexp,
348 &erroff,
349 &buf[2],
350 len - sizeof (uint16_t))))
351 { 378 {
352 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_scan", rc); 379 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_new", rc); /* erroff gives more info */
380 gcry_mpi_point_release (q);
353 return NULL; 381 return NULL;
354 } 382 }
355 if ( (GNUNET_YES == validate) && 383 /* initialize 'ctx' with 'q' */
356 (0 != (rc = gcry_pk_testkey (sexp))) ) 384 gcry_mpi_ec_set_point ("q", q, ctx);
385 gcry_mpi_point_release (q);
386
387 /* convert 'ctx' to 'sexp' */
388 if (0 != (rc = gcry_pubkey_get_sexp (&pub_sexp, GCRY_PK_GET_PUBKEY, ctx)))
357 { 389 {
358 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc); 390 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_from_context", rc);
391 gcry_ctx_release (ctx);
359 return NULL; 392 return NULL;
360 } 393 }
361 ret = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccPrivateKey)); 394 gcry_ctx_release (ctx);
362 ret->sexp = sexp; 395 return pub_sexp;
363 return ret;
364} 396}
365 397
366 398
@@ -372,9 +404,10 @@ GNUNET_CRYPTO_ecc_decode_key (const char *buf,
372struct GNUNET_CRYPTO_EccPrivateKey * 404struct GNUNET_CRYPTO_EccPrivateKey *
373GNUNET_CRYPTO_ecc_key_create () 405GNUNET_CRYPTO_ecc_key_create ()
374{ 406{
375 struct GNUNET_CRYPTO_EccPrivateKey *ret; 407 struct GNUNET_CRYPTO_EccPrivateKey *priv;
376 gcry_sexp_t s_key; 408 gcry_sexp_t priv_sexp;
377 gcry_sexp_t s_keyparam; 409 gcry_sexp_t s_keyparam;
410 gcry_mpi_t d;
378 int rc; 411 int rc;
379 412
380 if (0 != (rc = gcry_sexp_build (&s_keyparam, NULL, 413 if (0 != (rc = gcry_sexp_build (&s_keyparam, NULL,
@@ -383,7 +416,7 @@ GNUNET_CRYPTO_ecc_key_create ()
383 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc); 416 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
384 return NULL; 417 return NULL;
385 } 418 }
386 if (0 != (rc = gcry_pk_genkey (&s_key, s_keyparam))) 419 if (0 != (rc = gcry_pk_genkey (&priv_sexp, s_keyparam)))
387 { 420 {
388 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc); 421 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
389 gcry_sexp_release (s_keyparam); 422 gcry_sexp_release (s_keyparam);
@@ -391,16 +424,24 @@ GNUNET_CRYPTO_ecc_key_create ()
391 } 424 }
392 gcry_sexp_release (s_keyparam); 425 gcry_sexp_release (s_keyparam);
393#if EXTRA_CHECKS 426#if EXTRA_CHECKS
394 if (0 != (rc = gcry_pk_testkey (s_key))) 427 if (0 != (rc = gcry_pk_testkey (priv_sexp)))
395 { 428 {
396 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc); 429 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
397 gcry_sexp_release (s_key); 430 gcry_sexp_release (priv_sexp);
398 return NULL; 431 return NULL;
399 } 432 }
400#endif 433#endif
401 ret = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccPrivateKey)); 434 if (0 != (rc = key_from_sexp (&d, priv_sexp, "private-key", "d")))
402 ret->sexp = s_key; 435 {
403 return ret; 436 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
437 gcry_sexp_release (priv_sexp);
438 return NULL;
439 }
440 gcry_sexp_release (priv_sexp);
441 priv = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccPrivateKey));
442 mpi_print (priv->d, sizeof (priv->d), d);
443 gcry_mpi_release (d);
444 return priv;
404} 445}
405 446
406 447
@@ -438,15 +479,11 @@ short_wait ()
438struct GNUNET_CRYPTO_EccPrivateKey * 479struct GNUNET_CRYPTO_EccPrivateKey *
439GNUNET_CRYPTO_ecc_key_create_from_file (const char *filename) 480GNUNET_CRYPTO_ecc_key_create_from_file (const char *filename)
440{ 481{
441 struct GNUNET_CRYPTO_EccPrivateKey *ret; 482 struct GNUNET_CRYPTO_EccPrivateKey *priv;
442 struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded *enc;
443 uint16_t len;
444 struct GNUNET_DISK_FileHandle *fd; 483 struct GNUNET_DISK_FileHandle *fd;
445 unsigned int cnt; 484 unsigned int cnt;
446 int ec; 485 int ec;
447 uint64_t fs; 486 uint64_t fs;
448 struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded pub;
449 struct GNUNET_PeerIdentity pid;
450 487
451 if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (filename)) 488 if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (filename))
452 return NULL; 489 return NULL;
@@ -479,7 +516,7 @@ GNUNET_CRYPTO_ecc_key_create_from_file (const char *filename)
479 516
480 while (GNUNET_YES != 517 while (GNUNET_YES !=
481 GNUNET_DISK_file_lock (fd, 0, 518 GNUNET_DISK_file_lock (fd, 0,
482 sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded), 519 sizeof (struct GNUNET_CRYPTO_EccPrivateKey),
483 GNUNET_YES)) 520 GNUNET_YES))
484 { 521 {
485 short_wait (); 522 short_wait ();
@@ -493,23 +530,17 @@ GNUNET_CRYPTO_ecc_key_create_from_file (const char *filename)
493 } 530 }
494 LOG (GNUNET_ERROR_TYPE_INFO, 531 LOG (GNUNET_ERROR_TYPE_INFO,
495 _("Creating a new private key. This may take a while.\n")); 532 _("Creating a new private key. This may take a while.\n"));
496 ret = GNUNET_CRYPTO_ecc_key_create (); 533 priv = GNUNET_CRYPTO_ecc_key_create ();
497 GNUNET_assert (ret != NULL); 534 GNUNET_assert (NULL != priv);
498 enc = GNUNET_CRYPTO_ecc_encode_key (ret); 535 GNUNET_assert (sizeof (*priv) ==
499 GNUNET_assert (enc != NULL); 536 GNUNET_DISK_file_write (fd, priv, sizeof (*priv)));
500 GNUNET_assert (ntohs (enc->size) ==
501 GNUNET_DISK_file_write (fd, enc, ntohs (enc->size)));
502 GNUNET_free (enc);
503
504 GNUNET_DISK_file_sync (fd); 537 GNUNET_DISK_file_sync (fd);
505 if (GNUNET_YES != 538 if (GNUNET_YES !=
506 GNUNET_DISK_file_unlock (fd, 0, 539 GNUNET_DISK_file_unlock (fd, 0,
507 sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded))) 540 sizeof (struct GNUNET_CRYPTO_EccPrivateKey)))
508 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename); 541 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
509 GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd)); 542 GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
510 GNUNET_CRYPTO_ecc_key_get_public (ret, &pub); 543 return priv;
511 GNUNET_CRYPTO_hash (&pub, sizeof (pub), &pid.hashPubKey);
512 return ret;
513 } 544 }
514 /* key file exists already, read it! */ 545 /* key file exists already, read it! */
515 fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ, 546 fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
@@ -524,7 +555,7 @@ GNUNET_CRYPTO_ecc_key_create_from_file (const char *filename)
524 { 555 {
525 if (GNUNET_YES != 556 if (GNUNET_YES !=
526 GNUNET_DISK_file_lock (fd, 0, 557 GNUNET_DISK_file_lock (fd, 0,
527 sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded), 558 sizeof (struct GNUNET_CRYPTO_EccPrivateKey),
528 GNUNET_NO)) 559 GNUNET_NO))
529 { 560 {
530 if (0 == ++cnt % 60) 561 if (0 == ++cnt % 60)
@@ -546,7 +577,7 @@ GNUNET_CRYPTO_ecc_key_create_from_file (const char *filename)
546 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", filename); 577 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", filename);
547 if (GNUNET_YES != 578 if (GNUNET_YES !=
548 GNUNET_DISK_file_unlock (fd, 0, 579 GNUNET_DISK_file_unlock (fd, 0,
549 sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded))) 580 sizeof (struct GNUNET_CRYPTO_EccPrivateKey)))
550 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename); 581 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
551 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd)); 582 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd));
552 583
@@ -554,13 +585,13 @@ GNUNET_CRYPTO_ecc_key_create_from_file (const char *filename)
554 } 585 }
555 if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES)) 586 if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
556 fs = 0; 587 fs = 0;
557 if (fs < sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded)) 588 if (fs < sizeof (struct GNUNET_CRYPTO_EccPrivateKey))
558 { 589 {
559 /* maybe we got the read lock before the key generating 590 /* maybe we got the read lock before the key generating
560 * process had a chance to get the write lock; give it up! */ 591 * process had a chance to get the write lock; give it up! */
561 if (GNUNET_YES != 592 if (GNUNET_YES !=
562 GNUNET_DISK_file_unlock (fd, 0, 593 GNUNET_DISK_file_unlock (fd, 0,
563 sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded))) 594 sizeof (struct GNUNET_CRYPTO_EccPrivateKey)))
564 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename); 595 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
565 if (0 == ++cnt % 10) 596 if (0 == ++cnt % 10)
566 { 597 {
@@ -568,7 +599,7 @@ GNUNET_CRYPTO_ecc_key_create_from_file (const char *filename)
568 _ 599 _
569 ("When trying to read key file `%s' I found %u bytes but I need at least %u.\n"), 600 ("When trying to read key file `%s' I found %u bytes but I need at least %u.\n"),
570 filename, (unsigned int) fs, 601 filename, (unsigned int) fs,
571 (unsigned int) sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded)); 602 (unsigned int) sizeof (struct GNUNET_CRYPTO_EccPrivateKey));
572 LOG (GNUNET_ERROR_TYPE_ERROR, 603 LOG (GNUNET_ERROR_TYPE_ERROR,
573 _ 604 _
574 ("This may be ok if someone is currently generating a key.\n")); 605 ("This may be ok if someone is currently generating a key.\n"));
@@ -578,33 +609,15 @@ GNUNET_CRYPTO_ecc_key_create_from_file (const char *filename)
578 } 609 }
579 break; 610 break;
580 } 611 }
581 enc = GNUNET_malloc (fs); 612 fs = sizeof (struct GNUNET_CRYPTO_EccPrivateKey);
582 GNUNET_assert (fs == GNUNET_DISK_file_read (fd, enc, fs)); 613 priv = GNUNET_malloc (fs);
583 len = ntohs (enc->size); 614 GNUNET_assert (fs == GNUNET_DISK_file_read (fd, priv, fs));
584 ret = NULL;
585 if ((len > fs) ||
586 (NULL == (ret = GNUNET_CRYPTO_ecc_decode_key ((char *) enc, len, GNUNET_YES))))
587 {
588 LOG (GNUNET_ERROR_TYPE_ERROR,
589 _("File `%s' does not contain a valid private key. Deleting it.\n"),
590 filename);
591 if (0 != UNLINK (filename))
592 {
593 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", filename);
594 }
595 }
596 GNUNET_free (enc);
597 if (GNUNET_YES != 615 if (GNUNET_YES !=
598 GNUNET_DISK_file_unlock (fd, 0, 616 GNUNET_DISK_file_unlock (fd, 0,
599 sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded))) 617 sizeof (struct GNUNET_CRYPTO_EccPrivateKey)))
600 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename); 618 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
601 GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd)); 619 GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
602 if (ret != NULL) 620 return priv;
603 {
604 GNUNET_CRYPTO_ecc_key_get_public (ret, &pub);
605 GNUNET_CRYPTO_hash (&pub, sizeof (pub), &pid.hashPubKey);
606 }
607 return ret;
608} 621}
609 622
610 623
@@ -618,15 +631,15 @@ GNUNET_CRYPTO_ecc_key_create_from_file (const char *filename)
618struct GNUNET_CRYPTO_EccPrivateKey * 631struct GNUNET_CRYPTO_EccPrivateKey *
619GNUNET_CRYPTO_ecc_key_create_from_configuration (const struct GNUNET_CONFIGURATION_Handle *cfg) 632GNUNET_CRYPTO_ecc_key_create_from_configuration (const struct GNUNET_CONFIGURATION_Handle *cfg)
620{ 633{
621 struct GNUNET_CRYPTO_EccPrivateKey *pk; 634 struct GNUNET_CRYPTO_EccPrivateKey *priv;
622 char *fn; 635 char *fn;
623 636
624 if (GNUNET_OK != 637 if (GNUNET_OK !=
625 GNUNET_CONFIGURATION_get_value_filename (cfg, "PEER", "PRIVATE_KEY", &fn)) 638 GNUNET_CONFIGURATION_get_value_filename (cfg, "PEER", "PRIVATE_KEY", &fn))
626 return NULL; 639 return NULL;
627 pk = GNUNET_CRYPTO_ecc_key_create_from_file (fn); 640 priv = GNUNET_CRYPTO_ecc_key_create_from_file (fn);
628 GNUNET_free (fn); 641 GNUNET_free (fn);
629 return pk; 642 return priv;
630} 643}
631 644
632 645
@@ -642,13 +655,13 @@ void
642GNUNET_CRYPTO_ecc_setup_key (const char *cfg_name) 655GNUNET_CRYPTO_ecc_setup_key (const char *cfg_name)
643{ 656{
644 struct GNUNET_CONFIGURATION_Handle *cfg; 657 struct GNUNET_CONFIGURATION_Handle *cfg;
645 struct GNUNET_CRYPTO_EccPrivateKey *pk; 658 struct GNUNET_CRYPTO_EccPrivateKey *priv;
646 659
647 cfg = GNUNET_CONFIGURATION_create (); 660 cfg = GNUNET_CONFIGURATION_create ();
648 (void) GNUNET_CONFIGURATION_load (cfg, cfg_name); 661 (void) GNUNET_CONFIGURATION_load (cfg, cfg_name);
649 pk = GNUNET_CRYPTO_ecc_key_create_from_configuration (cfg); 662 priv = GNUNET_CRYPTO_ecc_key_create_from_configuration (cfg);
650 if (NULL != pk) 663 if (NULL != priv)
651 GNUNET_CRYPTO_ecc_key_free (pk); 664 GNUNET_CRYPTO_ecc_key_free (priv);
652 GNUNET_CONFIGURATION_destroy (cfg); 665 GNUNET_CONFIGURATION_destroy (cfg);
653} 666}
654 667
@@ -665,18 +678,18 @@ int
665GNUNET_CRYPTO_get_host_identity (const struct GNUNET_CONFIGURATION_Handle *cfg, 678GNUNET_CRYPTO_get_host_identity (const struct GNUNET_CONFIGURATION_Handle *cfg,
666 struct GNUNET_PeerIdentity *dst) 679 struct GNUNET_PeerIdentity *dst)
667{ 680{
668 struct GNUNET_CRYPTO_EccPrivateKey *my_private_key; 681 struct GNUNET_CRYPTO_EccPrivateKey *priv;
669 struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded my_public_key; 682 struct GNUNET_CRYPTO_EccPublicKey pub;
670 683
671 if (NULL == (my_private_key = GNUNET_CRYPTO_ecc_key_create_from_configuration (cfg))) 684 if (NULL == (priv = GNUNET_CRYPTO_ecc_key_create_from_configuration (cfg)))
672 { 685 {
673 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 686 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
674 _("Could not load peer's private key\n")); 687 _("Could not load peer's private key\n"));
675 return GNUNET_SYSERR; 688 return GNUNET_SYSERR;
676 } 689 }
677 GNUNET_CRYPTO_ecc_key_get_public (my_private_key, &my_public_key); 690 GNUNET_CRYPTO_ecc_key_get_public (priv, &pub);
678 GNUNET_CRYPTO_ecc_key_free (my_private_key); 691 GNUNET_CRYPTO_ecc_key_free (priv);
679 GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key), &dst->hashPubKey); 692 GNUNET_CRYPTO_hash (&pub, sizeof (pub), &dst->hashPubKey);
680 return GNUNET_OK; 693 return GNUNET_OK;
681} 694}
682 695
@@ -692,24 +705,19 @@ static gcry_sexp_t
692data_to_pkcs1 (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose) 705data_to_pkcs1 (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
693{ 706{
694 struct GNUNET_CRYPTO_ShortHashCode hc; 707 struct GNUNET_CRYPTO_ShortHashCode hc;
695 size_t bufSize;
696 gcry_sexp_t data; 708 gcry_sexp_t data;
709 int rc;
697 710
698 GNUNET_CRYPTO_short_hash (purpose, ntohl (purpose->size), &hc); 711 GNUNET_CRYPTO_short_hash (purpose, ntohl (purpose->size), &hc);
699#define FORMATSTRING "(4:data(5:flags3:raw)(5:value32:01234567890123456789012345678901))" 712 if (0 != (rc = gcry_sexp_build (&data, NULL,
700 bufSize = strlen (FORMATSTRING) + 1; 713 "(data(flags rfc6979)(hash %s %b))",
714 "sha256",
715 sizeof (hc),
716 &hc)))
701 { 717 {
702 char buff[bufSize]; 718 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
703 719 return NULL;
704 memcpy (buff, FORMATSTRING, bufSize);
705 memcpy (&buff
706 [bufSize -
707 strlen
708 ("01234567890123456789012345678901))")
709 - 1], &hc, sizeof (struct GNUNET_CRYPTO_ShortHashCode));
710 GNUNET_assert (0 == gcry_sexp_new (&data, buff, bufSize, 0));
711 } 720 }
712#undef FORMATSTRING
713 return data; 721 return data;
714} 722}
715 723
@@ -717,44 +725,49 @@ data_to_pkcs1 (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
717/** 725/**
718 * Sign a given block. 726 * Sign a given block.
719 * 727 *
720 * @param key private key to use for the signing 728 * @param priv private key to use for the signing
721 * @param purpose what to sign (size, purpose) 729 * @param purpose what to sign (size, purpose)
722 * @param sig where to write the signature 730 * @param sig where to write the signature
723 * @return GNUNET_SYSERR on error, GNUNET_OK on success 731 * @return GNUNET_SYSERR on error, GNUNET_OK on success
724 */ 732 */
725int 733int
726GNUNET_CRYPTO_ecc_sign (const struct GNUNET_CRYPTO_EccPrivateKey *key, 734GNUNET_CRYPTO_ecc_sign (const struct GNUNET_CRYPTO_EccPrivateKey *priv,
727 const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose, 735 const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
728 struct GNUNET_CRYPTO_EccSignature *sig) 736 struct GNUNET_CRYPTO_EccSignature *sig)
729{ 737{
730 gcry_sexp_t result; 738 gcry_sexp_t priv_sexp;
739 gcry_sexp_t sig_sexp;
731 gcry_sexp_t data; 740 gcry_sexp_t data;
732 size_t ssize;
733 int rc; 741 int rc;
742 gcry_mpi_t rs[2];
734 743
744 priv_sexp = decode_private_key (priv);
735 data = data_to_pkcs1 (purpose); 745 data = data_to_pkcs1 (purpose);
736 if (0 != (rc = gcry_pk_sign (&result, data, key->sexp))) 746 if (0 != (rc = gcry_pk_sign (&sig_sexp, data, priv_sexp)))
737 { 747 {
738 LOG (GNUNET_ERROR_TYPE_WARNING, 748 LOG (GNUNET_ERROR_TYPE_WARNING,
739 _("ECC signing failed at %s:%d: %s\n"), __FILE__, 749 _("ECC signing failed at %s:%d: %s\n"), __FILE__,
740 __LINE__, gcry_strerror (rc)); 750 __LINE__, gcry_strerror (rc));
741 gcry_sexp_release (data); 751 gcry_sexp_release (data);
752 gcry_sexp_release (priv_sexp);
742 return GNUNET_SYSERR; 753 return GNUNET_SYSERR;
743 } 754 }
755 gcry_sexp_release (priv_sexp);
744 gcry_sexp_release (data); 756 gcry_sexp_release (data);
745 ssize = gcry_sexp_sprint (result, 757
746 GCRYSEXP_FMT_DEFAULT, 758 /* extract 'r' and 's' values from sexpression 'sig_sexp' and store in
747 sig->sexpr, 759 'signature' */
748 GNUNET_CRYPTO_ECC_SIGNATURE_DATA_ENCODING_LENGTH); 760 if (0 != (rc = key_from_sexp (rs, sig_sexp, "sig-val", "rs")))
749 if (0 == ssize)
750 { 761 {
751 GNUNET_break (0); 762 GNUNET_break (0);
763 gcry_sexp_release (sig_sexp);
752 return GNUNET_SYSERR; 764 return GNUNET_SYSERR;
753 } 765 }
754 sig->size = htons ((uint16_t) (ssize + sizeof (uint16_t))); 766 gcry_sexp_release (sig_sexp);
755 /* padd with zeros */ 767 mpi_print (sig->r, sizeof (sig->r), rs[0]);
756 memset (&sig->sexpr[ssize], 0, GNUNET_CRYPTO_ECC_SIGNATURE_DATA_ENCODING_LENGTH - ssize); 768 mpi_print (sig->s, sizeof (sig->s), rs[1]);
757 gcry_sexp_release (result); 769 gcry_mpi_release (rs[0]);
770 gcry_mpi_release (rs[1]);
758 return GNUNET_OK; 771 return GNUNET_OK;
759} 772}
760 773
@@ -765,7 +778,7 @@ GNUNET_CRYPTO_ecc_sign (const struct GNUNET_CRYPTO_EccPrivateKey *key,
765 * @param purpose what is the purpose that the signature should have? 778 * @param purpose what is the purpose that the signature should have?
766 * @param validate block to validate (size, purpose, data) 779 * @param validate block to validate (size, purpose, data)
767 * @param sig signature that is being validated 780 * @param sig signature that is being validated
768 * @param publicKey public key of the signer 781 * @param pub public key of the signer
769 * @returns GNUNET_OK if ok, GNUNET_SYSERR if invalid 782 * @returns GNUNET_OK if ok, GNUNET_SYSERR if invalid
770 */ 783 */
771int 784int
@@ -773,36 +786,43 @@ GNUNET_CRYPTO_ecc_verify (uint32_t purpose,
773 const struct GNUNET_CRYPTO_EccSignaturePurpose 786 const struct GNUNET_CRYPTO_EccSignaturePurpose
774 *validate, 787 *validate,
775 const struct GNUNET_CRYPTO_EccSignature *sig, 788 const struct GNUNET_CRYPTO_EccSignature *sig,
776 const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded 789 const struct GNUNET_CRYPTO_EccPublicKey *pub)
777 *publicKey)
778{ 790{
779 gcry_sexp_t data; 791 gcry_sexp_t data;
780 gcry_sexp_t sigdata; 792 gcry_sexp_t sig_sexpr;
781 size_t size; 793 gcry_sexp_t pub_sexpr;
782 gcry_sexp_t psexp;
783 size_t erroff; 794 size_t erroff;
784 int rc; 795 int rc;
796 gcry_mpi_t r;
797 gcry_mpi_t s;
785 798
786 if (purpose != ntohl (validate->purpose)) 799 if (purpose != ntohl (validate->purpose))
787 return GNUNET_SYSERR; /* purpose mismatch */ 800 return GNUNET_SYSERR; /* purpose mismatch */
788 size = ntohs (sig->size); 801
789 if ( (size < sizeof (uint16_t)) || 802 /* build s-expression for signature */
790 (size > GNUNET_CRYPTO_ECC_SIGNATURE_DATA_ENCODING_LENGTH - sizeof (uint16_t)) ) 803 mpi_scan (&r, sig->r, sizeof (sig->r));
791 return GNUNET_SYSERR; /* size out of range */ 804 mpi_scan (&s, sig->s, sizeof (sig->s));
805 if (0 != (rc = gcry_sexp_build (&sig_sexpr, &erroff, "(sig-val(ecdsa(r %m)(s %m)))",
806 r, s)))
807 {
808 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
809 gcry_mpi_release (r);
810 gcry_mpi_release (s);
811 return GNUNET_SYSERR;
812 }
813 gcry_mpi_release (r);
814 gcry_mpi_release (s);
792 data = data_to_pkcs1 (validate); 815 data = data_to_pkcs1 (validate);
793 GNUNET_assert (0 == 816 if (! (pub_sexpr = decode_public_key (pub)))
794 gcry_sexp_sscan (&sigdata, &erroff,
795 sig->sexpr, size - sizeof (uint16_t)));
796 if (! (psexp = decode_public_key (publicKey)))
797 { 817 {
798 gcry_sexp_release (data); 818 gcry_sexp_release (data);
799 gcry_sexp_release (sigdata); 819 gcry_sexp_release (sig_sexpr);
800 return GNUNET_SYSERR; 820 return GNUNET_SYSERR;
801 } 821 }
802 rc = gcry_pk_verify (sigdata, data, psexp); 822 rc = gcry_pk_verify (sig_sexpr, data, pub_sexpr);
803 gcry_sexp_release (psexp); 823 gcry_sexp_release (pub_sexpr);
804 gcry_sexp_release (data); 824 gcry_sexp_release (data);
805 gcry_sexp_release (sigdata); 825 gcry_sexp_release (sig_sexpr);
806 if (0 != rc) 826 if (0 != rc)
807 { 827 {
808 LOG (GNUNET_ERROR_TYPE_WARNING, 828 LOG (GNUNET_ERROR_TYPE_WARNING,
@@ -817,14 +837,14 @@ GNUNET_CRYPTO_ecc_verify (uint32_t purpose,
817/** 837/**
818 * Derive key material from a public and a private ECC key. 838 * Derive key material from a public and a private ECC key.
819 * 839 *
820 * @param key private key to use for the ECDH (x) 840 * @param priv private key to use for the ECDH (x)
821 * @param pub public key to use for the ECDY (yG) 841 * @param pub public key to use for the ECDH (yG)
822 * @param key_material where to write the key material (xyG) 842 * @param key_material where to write the key material (xyG)
823 * @return GNUNET_SYSERR on error, GNUNET_OK on success 843 * @return GNUNET_SYSERR on error, GNUNET_OK on success
824 */ 844 */
825int 845int
826GNUNET_CRYPTO_ecc_ecdh (const struct GNUNET_CRYPTO_EccPrivateKey *key, 846GNUNET_CRYPTO_ecc_ecdh (const struct GNUNET_CRYPTO_EccPrivateKey *priv,
827 const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *pub, 847 const struct GNUNET_CRYPTO_EccPublicKey *pub,
828 struct GNUNET_HashCode *key_material) 848 struct GNUNET_HashCode *key_material)
829{ 849{
830 size_t slen; 850 size_t slen;
@@ -835,36 +855,29 @@ GNUNET_CRYPTO_ecc_ecdh (const struct GNUNET_CRYPTO_EccPrivateKey *key,
835 gcry_mpi_point_t q; 855 gcry_mpi_point_t q;
836 gcry_mpi_t d; 856 gcry_mpi_t d;
837 gcry_ctx_t ctx; 857 gcry_ctx_t ctx;
838 gcry_sexp_t psexp; 858 gcry_sexp_t pub_sexpr;
859 gcry_sexp_t ecdh_sexp;
839 gcry_mpi_t result_x; 860 gcry_mpi_t result_x;
840 gcry_mpi_t result_y; 861 gcry_mpi_t result_y;
841 862
842 /* first, extract the q = dP value from the public key */ 863 /* first, extract the q = dP value from the public key */
843 if (! (psexp = decode_public_key (pub))) 864 if (! (pub_sexpr = decode_public_key (pub)))
844 return GNUNET_SYSERR; 865 return GNUNET_SYSERR;
845 if (0 != (rc = gcry_mpi_ec_new (&ctx, psexp, NULL))) 866 if (0 != (rc = gcry_mpi_ec_new (&ctx, pub_sexpr, NULL)))
846 { 867 {
847 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_new", rc); /* erroff gives more info */ 868 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_new", rc); /* erroff gives more info */
848 return GNUNET_SYSERR; 869 return GNUNET_SYSERR;
849 } 870 }
850 gcry_sexp_release (psexp); 871 gcry_sexp_release (pub_sexpr);
851 q = gcry_mpi_ec_get_point ("q", ctx, 0); 872 q = gcry_mpi_ec_get_point ("q", ctx, 0);
852 gcry_ctx_release (ctx); 873 gcry_ctx_release (ctx);
853 874
854 /* second, extract the d value from our private key */ 875 /* second, extract the d value from our private key */
855 rc = key_from_sexp (&d, key->sexp, "private-key", "d"); 876 mpi_scan (&d, priv->d, sizeof (priv->d));
856 if (rc)
857 rc = key_from_sexp (&d, key->sexp, "ecc", "d");
858 if (0 != rc)
859 {
860 GNUNET_break (0);
861 gcry_mpi_point_release (q);
862 return GNUNET_SYSERR;
863 }
864 877
865 /* create a new context for definitively the correct curve; 878 /* create a new context for definitively the correct curve;
866 theoretically the 'public_key' might not use the right curve */ 879 theoretically the 'public_key' might not use the right curve */
867 if (0 != (rc = gcry_mpi_ec_new (&ctx, NULL, "NIST P-256"))) 880 if (0 != (rc = gcry_mpi_ec_new (&ctx, NULL, CURVE)))
868 { 881 {
869 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_new", rc); /* erroff gives more info */ 882 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_new", rc); /* erroff gives more info */
870 gcry_mpi_release (d); 883 gcry_mpi_release (d);
@@ -891,7 +904,7 @@ GNUNET_CRYPTO_ecc_ecdh (const struct GNUNET_CRYPTO_EccPrivateKey *key,
891 } 904 }
892 gcry_mpi_point_release (result); 905 gcry_mpi_point_release (result);
893 gcry_ctx_release (ctx); 906 gcry_ctx_release (ctx);
894 if (0 != (rc = gcry_sexp_build (&psexp, &erroff, 907 if (0 != (rc = gcry_sexp_build (&ecdh_sexp, &erroff,
895 "(dh-shared-secret (x %m)(y %m))", 908 "(dh-shared-secret (x %m)(y %m))",
896 result_x, 909 result_x,
897 result_y))) 910 result_y)))
@@ -903,13 +916,135 @@ GNUNET_CRYPTO_ecc_ecdh (const struct GNUNET_CRYPTO_EccPrivateKey *key,
903 } 916 }
904 gcry_mpi_release (result_x); 917 gcry_mpi_release (result_x);
905 gcry_mpi_release (result_y); 918 gcry_mpi_release (result_y);
906 slen = gcry_sexp_sprint (psexp, GCRYSEXP_FMT_DEFAULT, sdata_buf, sizeof (sdata_buf)); 919 slen = gcry_sexp_sprint (ecdh_sexp,
920 GCRYSEXP_FMT_DEFAULT,
921 sdata_buf, sizeof (sdata_buf));
907 GNUNET_assert (0 != slen); 922 GNUNET_assert (0 != slen);
908 gcry_sexp_release (psexp); 923 gcry_sexp_release (ecdh_sexp);
909 /* finally, get a string of the resulting S-expression and hash it to generate the key material */ 924 /* finally, get a string of the resulting S-expression and hash it
925 to generate the key material */
910 GNUNET_CRYPTO_hash (sdata_buf, slen, key_material); 926 GNUNET_CRYPTO_hash (sdata_buf, slen, key_material);
911 return GNUNET_OK; 927 return GNUNET_OK;
912} 928}
913 929
914 930
931/**
932 * Derive the 'h' value for key derivation, where
933 * 'h = H(l,P)'.
934 *
935 * @param pub public key for deriviation
936 * @param label label for deriviation
937 * @return h value
938 */
939static gcry_mpi_t
940derive_h (const struct GNUNET_CRYPTO_EccPublicKey *pub,
941 const char *label)
942{
943 gcry_mpi_t h;
944 struct GNUNET_HashCode hc;
945
946 GNUNET_CRYPTO_kdf (&hc, sizeof (hc),
947 "key-derivation", strlen ("key-derivation"),
948 pub, sizeof (*pub),
949 label, sizeof (label),
950 NULL, 0);
951 mpi_scan (&h, (unsigned char *) &hc, sizeof (hc));
952 return h;
953}
954
955
956/**
957 * Derive a private key from a given private key and a label.
958 * Essentially calculates a private key 'd = H(l,P) * x mod n'
959 * where n is the size of the ECC group and P is the public
960 * key associated with the private key 'd'.
961 *
962 * @param priv original private key
963 * @param label label to use for key deriviation
964 * @return derived private key
965 */
966struct GNUNET_CRYPTO_EccPrivateKey *
967GNUNET_CRYPTO_ecc_key_derive (const struct GNUNET_CRYPTO_EccPrivateKey *priv,
968 const char *label)
969{
970 struct GNUNET_CRYPTO_EccPublicKey pub;
971 struct GNUNET_CRYPTO_EccPrivateKey *ret;
972 gcry_mpi_t h;
973 gcry_mpi_t x;
974 gcry_mpi_t d;
975 gcry_mpi_t n;
976 int rc;
977
978 GNUNET_CRYPTO_ecc_key_get_public (priv, &pub);
979 h = derive_h (&pub, label);
980 mpi_scan (&x, priv->d, sizeof (priv->d));
981 /* initialize 'n' from P-256; hex copied from libgcrypt code */
982 if (0 != (rc = gcry_mpi_scan (&n, GCRYMPI_FMT_HEX,
983 "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 0, NULL)))
984 {
985 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
986 gcry_mpi_release (h);
987 return NULL;
988 }
989 d = gcry_mpi_new (256);
990 gcry_mpi_mulm (d, h, x, n);
991 gcry_mpi_release (h);
992 gcry_mpi_release (x);
993 gcry_mpi_release (n);
994 ret = GNUNET_new (struct GNUNET_CRYPTO_EccPrivateKey);
995 mpi_print (ret->d, sizeof (ret->d), d);
996 gcry_mpi_release (d);
997 return ret;
998}
999
1000
1001/**
1002 * Derive a public key from a given public key and a label.
1003 * Essentially calculates a public key 'V = H(l,P) * P'.
1004 *
1005 * @param pub original public key
1006 * @param label label to use for key deriviation
1007 * @param result where to write the derived public key
1008 */
1009void
1010GNUNET_CRYPTO_ecc_public_key_derive (const struct GNUNET_CRYPTO_EccPublicKey *pub,
1011 const char *label,
1012 struct GNUNET_CRYPTO_EccPublicKey *result)
1013{
1014 gcry_mpi_t h;
1015 gcry_ctx_t ctx;
1016 gcry_mpi_t q_x;
1017 gcry_mpi_t q_y;
1018 gcry_mpi_point_t q;
1019 gcry_mpi_point_t v;
1020 int rc;
1021
1022 h = derive_h (pub, label);
1023 mpi_scan (&q_x, pub->q_x, sizeof (pub->q_x));
1024 mpi_scan (&q_y, pub->q_y, sizeof (pub->q_y));
1025 q = gcry_mpi_point_new (256);
1026 gcry_mpi_point_set (q, q_x, q_y, GCRYMPI_CONST_ONE);
1027 gcry_mpi_release (q_x);
1028 gcry_mpi_release (q_y);
1029
1030 /* create basic ECC context */
1031 if (0 != (rc = gcry_mpi_ec_new (&ctx, NULL, CURVE)))
1032 {
1033 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_new", rc);
1034 gcry_mpi_point_release (q);
1035 gcry_mpi_release (h);
1036 return;
1037 }
1038 v = gcry_mpi_point_new (256);
1039 /* we could calculate 'h mod n' here first, but hopefully
1040 libgcrypt is smart enough to do that for us... */
1041 gcry_mpi_ec_mul (v, h, q, ctx);
1042 gcry_mpi_release (h);
1043 gcry_mpi_point_release (q);
1044 point_to_public_key (v, ctx, result);
1045 gcry_mpi_point_release (v);
1046 gcry_ctx_release (ctx);
1047}
1048
1049
915/* end of crypto_ecc.c */ 1050/* end of crypto_ecc.c */