aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Schanzenbach <mschanzenbach@posteo.de>2021-05-01 22:05:15 +0200
committerMartin Schanzenbach <mschanzenbach@posteo.de>2021-05-02 10:39:55 +0200
commit572f4d6f7b19dec42d571829384ac9cd356bb092 (patch)
treecbe8bf3ae413a1aa3b71beffcbe7ce9bb83fe03f /src
parentca3ebf1e59eb00ad101ba8b26e5185db4d785610 (diff)
downloadgnunet-572f4d6f7b19dec42d571829384ac9cd356bb092.tar.gz
gnunet-572f4d6f7b19dec42d571829384ac9cd356bb092.zip
GNS: Add EDKEY support.
GNS and GNSRECORD can now handle EdDSA keys in addition to the existing ECDSA scheme. See also LSD0001.
Diffstat (limited to 'src')
-rw-r--r--src/gnsrecord/gnsrecord_crypto.c426
-rw-r--r--src/gnsrecord/gnsrecord_misc.c17
-rw-r--r--src/gnsrecord/gnsrecord_serialization.c3
-rw-r--r--src/gnsrecord/test_gnsrecord_crypto.c36
-rw-r--r--src/include/gnunet_crypto_lib.h78
-rw-r--r--src/include/gnunet_gnsrecord_lib.h33
-rw-r--r--src/util/Makefile.am1
-rw-r--r--src/util/crypto_ecc.c129
-rw-r--r--src/util/crypto_ecc_gnsrecord.c351
9 files changed, 889 insertions, 185 deletions
diff --git a/src/gnsrecord/gnsrecord_crypto.c b/src/gnsrecord/gnsrecord_crypto.c
index 9c551a936..289f0e885 100644
--- a/src/gnsrecord/gnsrecord_crypto.c
+++ b/src/gnsrecord/gnsrecord_crypto.c
@@ -64,7 +64,6 @@ ecdsa_symmetric_decrypt (
64} 64}
65 65
66 66
67
68ssize_t 67ssize_t
69ecdsa_symmetric_encrypt ( 68ecdsa_symmetric_encrypt (
70 const void *block, 69 const void *block,
@@ -92,6 +91,34 @@ ecdsa_symmetric_encrypt (
92} 91}
93 92
94 93
94enum GNUNET_GenericReturnValue
95eddsa_symmetric_decrypt (
96 const void *block,
97 size_t size,
98 const unsigned char *key,
99 const unsigned char *nonce,
100 void *result)
101{
102 if (0 != crypto_secretbox_open_easy (result, block, size, nonce, key))
103 {
104 return GNUNET_SYSERR;
105 }
106 return GNUNET_OK;
107}
108
109
110enum GNUNET_GenericReturnValue
111eddsa_symmetric_encrypt (
112 const void *block,
113 size_t size,
114 const unsigned char *key,
115 const unsigned char *nonce,
116 void *result)
117{
118 crypto_secretbox_easy (result, block, size, nonce, key);
119 return GNUNET_OK;
120}
121
95 122
96/** 123/**
97 * Derive session key and iv from label and public key. 124 * Derive session key and iv from label and public key.
@@ -131,6 +158,42 @@ derive_block_aes_key (unsigned char *ctr,
131 158
132 159
133/** 160/**
161 * Derive session key and iv from label and public key.
162 *
163 * @param nonce initialization vector to initialize
164 * @param skey session key to initialize
165 * @param label label to use for KDF
166 * @param pub public key to use for KDF
167 */
168static void
169derive_block_xsalsa_key (unsigned char *nonce,
170 unsigned char *key,
171 const char *label,
172 uint64_t exp,
173 const struct GNUNET_CRYPTO_EddsaPublicKey *pub)
174{
175 static const char ctx_key[] = "gns-aes-ctx-key";
176 static const char ctx_iv[] = "gns-aes-ctx-iv";
177
178 GNUNET_CRYPTO_kdf (key, crypto_secretbox_KEYBYTES,
179 ctx_key, strlen (ctx_key),
180 pub, sizeof(struct GNUNET_CRYPTO_EddsaPublicKey),
181 label, strlen (label),
182 NULL, 0);
183 memset (nonce, 0, crypto_secretbox_NONCEBYTES);
184 /** 16 byte nonce **/
185 GNUNET_CRYPTO_kdf (nonce, (crypto_secretbox_NONCEBYTES - sizeof (exp)),
186 ctx_iv, strlen (ctx_iv),
187 pub, sizeof(struct GNUNET_CRYPTO_EddsaPublicKey),
188 label, strlen (label),
189 NULL, 0);
190 /** Expiration time 64 bit. **/
191 memcpy (nonce + (crypto_secretbox_NONCEBYTES - sizeof (exp)),
192 &exp, sizeof (exp));
193}
194
195
196/**
134 * Sign name and records 197 * Sign name and records
135 * 198 *
136 * @param key the private key 199 * @param key the private key
@@ -246,6 +309,119 @@ block_create_ecdsa (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
246 309
247 310
248/** 311/**
312 * Sign name and records (EDDSA version)
313 *
314 * @param key the private key
315 * @param pkey associated public key
316 * @param expire block expiration
317 * @param label the name for the records
318 * @param rd record data
319 * @param rd_count number of records
320 * @return NULL on error (block too large)
321 */
322static struct GNUNET_GNSRECORD_Block *
323block_create_eddsa (const struct GNUNET_CRYPTO_EddsaPrivateKey *key,
324 const struct GNUNET_CRYPTO_EddsaPublicKey *pkey,
325 struct GNUNET_TIME_Absolute expire,
326 const char *label,
327 const struct GNUNET_GNSRECORD_Data *rd,
328 unsigned int rd_count)
329{
330 ssize_t payload_len = GNUNET_GNSRECORD_records_get_size (rd_count,
331 rd);
332 struct GNUNET_GNSRECORD_Block *block;
333 struct GNUNET_GNSRECORD_EddsaBlock *edblock;
334 struct GNUNET_CRYPTO_EddsaPrivateScalar dkey;
335 unsigned char nonce[crypto_secretbox_NONCEBYTES];
336 unsigned char skey[crypto_secretbox_KEYBYTES];
337 struct GNUNET_GNSRECORD_Data rdc[GNUNET_NZL (rd_count)];
338 uint32_t rd_count_nbo;
339 struct GNUNET_TIME_Absolute now;
340
341 if (payload_len < 0)
342 {
343 GNUNET_break (0);
344 return NULL;
345 }
346 if (payload_len > GNUNET_GNSRECORD_MAX_BLOCK_SIZE)
347 {
348 GNUNET_break (0);
349 return NULL;
350 }
351 /* convert relative to absolute times */
352 now = GNUNET_TIME_absolute_get ();
353 for (unsigned int i = 0; i < rd_count; i++)
354 {
355 rdc[i] = rd[i];
356 if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
357 {
358 struct GNUNET_TIME_Relative t;
359
360 /* encrypted blocks must never have relative expiration times, convert! */
361 rdc[i].flags &= ~GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
362 t.rel_value_us = rdc[i].expiration_time;
363 rdc[i].expiration_time = GNUNET_TIME_absolute_add (now, t).abs_value_us;
364 }
365 }
366 /* serialize */
367 rd_count_nbo = htonl (rd_count);
368 {
369 char payload[sizeof(uint32_t) + payload_len];
370
371 GNUNET_memcpy (payload,
372 &rd_count_nbo,
373 sizeof(uint32_t));
374 GNUNET_assert (payload_len ==
375 GNUNET_GNSRECORD_records_serialize (rd_count,
376 rdc,
377 payload_len,
378 &payload[sizeof(uint32_t)
379 ]));
380 block = GNUNET_malloc (sizeof(struct GNUNET_GNSRECORD_Block)
381 + sizeof(uint32_t)
382 + payload_len
383 + crypto_secretbox_MACBYTES);
384 edblock = &block->eddsa_block;
385 block->type = htonl (GNUNET_GNSRECORD_TYPE_EDKEY);
386 edblock->purpose.size = htonl (sizeof(uint32_t)
387 + payload_len
388 + sizeof(struct
389 GNUNET_CRYPTO_EccSignaturePurpose)
390 + sizeof(struct GNUNET_TIME_AbsoluteNBO)
391 + crypto_secretbox_MACBYTES);
392 edblock->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN);
393 edblock->expiration_time = GNUNET_TIME_absolute_hton (expire);
394 /* encrypt and sign */
395 GNUNET_CRYPTO_eddsa_private_key_derive (key,
396 label,
397 "gns",
398 &dkey);
399 // FIXME: We may want a key_get_public_from_private_scalar function
400 struct GNUNET_CRYPTO_EddsaPublicKey test;
401 crypto_scalarmult_ed25519_base_noclamp (test.q_y,
402 dkey.s);
403 edblock->derived_key = test;
404 derive_block_xsalsa_key (nonce,
405 skey,
406 label,
407 edblock->expiration_time.abs_value_us__,
408 pkey);
409 GNUNET_break (GNUNET_OK ==
410 eddsa_symmetric_encrypt (payload,
411 payload_len
412 + sizeof(uint32_t),
413 skey,
414 nonce,
415 &edblock[1]));
416 }
417 GNUNET_CRYPTO_eddsa_sign_with_scalar (&dkey,
418 &edblock->purpose,
419 &edblock->signature);
420 return block;
421}
422
423
424/**
249 * Sign name and records 425 * Sign name and records
250 * 426 *
251 * @param key the private key 427 * @param key the private key
@@ -263,6 +439,7 @@ GNUNET_GNSRECORD_block_create (const struct GNUNET_IDENTITY_PrivateKey *key,
263 unsigned int rd_count) 439 unsigned int rd_count)
264{ 440{
265 struct GNUNET_CRYPTO_EcdsaPublicKey pkey; 441 struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
442 struct GNUNET_CRYPTO_EddsaPublicKey edkey;
266 443
267 switch (ntohl (key->type)) 444 switch (ntohl (key->type))
268 { 445 {
@@ -275,6 +452,15 @@ GNUNET_GNSRECORD_block_create (const struct GNUNET_IDENTITY_PrivateKey *key,
275 label, 452 label,
276 rd, 453 rd,
277 rd_count); 454 rd_count);
455 case GNUNET_GNSRECORD_TYPE_EDKEY:
456 GNUNET_CRYPTO_eddsa_key_get_public (&key->eddsa_key,
457 &edkey);
458 return block_create_eddsa (&key->eddsa_key,
459 &edkey,
460 expire,
461 label,
462 rd,
463 rd_count);
278 default: 464 default:
279 GNUNET_assert (0); 465 GNUNET_assert (0);
280 } 466 }
@@ -319,33 +505,45 @@ GNUNET_GNSRECORD_block_create2 (const struct GNUNET_IDENTITY_PrivateKey *pkey,
319 unsigned int rd_count) 505 unsigned int rd_count)
320{ 506{
321 const struct GNUNET_CRYPTO_EcdsaPrivateKey *key; 507 const struct GNUNET_CRYPTO_EcdsaPrivateKey *key;
508 struct GNUNET_CRYPTO_EddsaPublicKey edpubkey;
322 509
323 if (GNUNET_IDENTITY_TYPE_ECDSA != ntohl (pkey->type)) 510 if (GNUNET_IDENTITY_TYPE_ECDSA == ntohl (pkey->type))
324 { 511 {
325 return NULL; // FIXME 512 key = &pkey->ecdsa_key;
326 }
327 key = &pkey->ecdsa_key;
328#define CSIZE 64 513#define CSIZE 64
329 static struct KeyCacheLine cache[CSIZE]; 514 static struct KeyCacheLine cache[CSIZE];
330 struct KeyCacheLine *line; 515 struct KeyCacheLine *line;
331 516
332 line = &cache[(*(unsigned int *) key) % CSIZE]; 517 line = &cache[(*(unsigned int *) key) % CSIZE];
333 if (0 != memcmp (&line->key, 518 if (0 != memcmp (&line->key,
334 key, 519 key,
335 sizeof(*key))) 520 sizeof(*key)))
521 {
522 /* cache miss, recompute */
523 line->key = *key;
524 GNUNET_CRYPTO_ecdsa_key_get_public (key,
525 &line->pkey);
526 }
527#undef CSIZE
528 return block_create_ecdsa (key,
529 &line->pkey,
530 expire,
531 label,
532 rd,
533 rd_count);
534 }
535 else if (GNUNET_IDENTITY_TYPE_EDDSA == ntohl (pkey->type))
336 { 536 {
337 /* cache miss, recompute */ 537 GNUNET_CRYPTO_eddsa_key_get_public (&pkey->eddsa_key,
338 line->key = *key; 538 &edpubkey);
339 GNUNET_CRYPTO_ecdsa_key_get_public (key, 539 return block_create_eddsa (&pkey->eddsa_key,
340 &line->pkey); 540 &edpubkey,
541 expire,
542 label,
543 rd,
544 rd_count);
341 } 545 }
342#undef CSIZE 546 return NULL;
343 return block_create_ecdsa (key,
344 &line->pkey,
345 expire,
346 label,
347 rd,
348 rd_count);
349} 547}
350 548
351 549
@@ -359,21 +557,23 @@ GNUNET_GNSRECORD_block_create2 (const struct GNUNET_IDENTITY_PrivateKey *pkey,
359enum GNUNET_GenericReturnValue 557enum GNUNET_GenericReturnValue
360GNUNET_GNSRECORD_block_verify (const struct GNUNET_GNSRECORD_Block *block) 558GNUNET_GNSRECORD_block_verify (const struct GNUNET_GNSRECORD_Block *block)
361{ 559{
362 const struct GNUNET_CRYPTO_EcdsaPublicKey *key; 560 switch (ntohl (block->type))
363 const struct GNUNET_GNSRECORD_EcdsaBlock *ecblock;
364
365 if (GNUNET_GNSRECORD_TYPE_PKEY != ntohl (block->type))
366 { 561 {
367 GNUNET_break (0); 562 case GNUNET_GNSRECORD_TYPE_PKEY:
563 return GNUNET_CRYPTO_ecdsa_verify_ (
564 GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN,
565 &block->ecdsa_block.purpose,
566 &block->ecdsa_block.signature,
567 &block->ecdsa_block.derived_key);
568 case GNUNET_GNSRECORD_TYPE_EDKEY:
569 return GNUNET_CRYPTO_eddsa_verify_ (
570 GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN,
571 &block->eddsa_block.purpose,
572 &block->eddsa_block.signature,
573 &block->eddsa_block.derived_key);
574 default:
368 return GNUNET_NO; 575 return GNUNET_NO;
369 } 576 }
370 ecblock = &block->ecdsa_block;
371 key = &ecblock->derived_key;
372
373 return GNUNET_CRYPTO_ecdsa_verify_ (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN,
374 &ecblock->purpose,
375 &ecblock->signature,
376 key);
377} 577}
378 578
379 579
@@ -505,6 +705,134 @@ block_decrypt_ecdsa (const struct GNUNET_GNSRECORD_EcdsaBlock *block,
505} 705}
506 706
507 707
708enum GNUNET_GenericReturnValue
709block_decrypt_eddsa (const struct GNUNET_GNSRECORD_EddsaBlock *block,
710 const struct
711 GNUNET_CRYPTO_EddsaPublicKey *zone_key,
712 const char *label,
713 GNUNET_GNSRECORD_RecordCallback proc,
714 void *proc_cls)
715{
716 size_t payload_len = ntohl (block->purpose.size)
717 - sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
718 - sizeof(struct GNUNET_TIME_AbsoluteNBO);
719 unsigned char nonce[crypto_secretbox_NONCEBYTES];
720 unsigned char key[crypto_secretbox_KEYBYTES];
721
722 if (ntohl (block->purpose.size) <
723 sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
724 + sizeof(struct GNUNET_TIME_AbsoluteNBO))
725 {
726 GNUNET_break_op (0);
727 return GNUNET_SYSERR;
728 }
729 derive_block_xsalsa_key (nonce,
730 key,
731 label,
732 block->expiration_time.abs_value_us__,
733 zone_key);
734 {
735 char payload[payload_len];
736 uint32_t rd_count;
737
738 GNUNET_break (GNUNET_OK ==
739 eddsa_symmetric_decrypt (&block[1], payload_len,
740 key, nonce,
741 payload));
742 GNUNET_memcpy (&rd_count,
743 payload,
744 sizeof(uint32_t));
745 rd_count = ntohl (rd_count);
746 if (rd_count > 2048)
747 {
748 /* limit to sane value */
749 GNUNET_break_op (0);
750 return GNUNET_SYSERR;
751 }
752 {
753 struct GNUNET_GNSRECORD_Data rd[GNUNET_NZL (rd_count)];
754 unsigned int j;
755 struct GNUNET_TIME_Absolute now;
756
757 if (GNUNET_OK !=
758 GNUNET_GNSRECORD_records_deserialize (payload_len - sizeof(uint32_t),
759 &payload[sizeof(uint32_t)],
760 rd_count,
761 rd))
762 {
763 GNUNET_break_op (0);
764 return GNUNET_SYSERR;
765 }
766 /* hide expired records */
767 now = GNUNET_TIME_absolute_get ();
768 j = 0;
769 for (unsigned int i = 0; i < rd_count; i++)
770 {
771 if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
772 {
773 /* encrypted blocks must never have relative expiration times, skip! */
774 GNUNET_break_op (0);
775 continue;
776 }
777
778 if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_SHADOW_RECORD))
779 {
780 int include_record = GNUNET_YES;
781 /* Shadow record, figure out if we have a not expired active record */
782 for (unsigned int k = 0; k < rd_count; k++)
783 {
784 if (k == i)
785 continue;
786 if (rd[i].expiration_time < now.abs_value_us)
787 include_record = GNUNET_NO; /* Shadow record is expired */
788 if ((rd[k].record_type == rd[i].record_type) &&
789 (rd[k].expiration_time >= now.abs_value_us) &&
790 (0 == (rd[k].flags & GNUNET_GNSRECORD_RF_SHADOW_RECORD)))
791 {
792 include_record = GNUNET_NO; /* We have a non-expired, non-shadow record of the same type */
793 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
794 "Ignoring shadow record\n");
795 break;
796 }
797 }
798 if (GNUNET_YES == include_record)
799 {
800 rd[i].flags ^= GNUNET_GNSRECORD_RF_SHADOW_RECORD; /* Remove Flag */
801 if (j != i)
802 rd[j] = rd[i];
803 j++;
804 }
805 }
806 else if (rd[i].expiration_time >= now.abs_value_us)
807 {
808 /* Include this record */
809 if (j != i)
810 rd[j] = rd[i];
811 j++;
812 }
813 else
814 {
815 struct GNUNET_TIME_Absolute at;
816
817 at.abs_value_us = rd[i].expiration_time;
818 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
819 "Excluding record that expired %s (%llu ago)\n",
820 GNUNET_STRINGS_absolute_time_to_string (at),
821 (unsigned long long) rd[i].expiration_time
822 - now.abs_value_us);
823 }
824 }
825 rd_count = j;
826 if (NULL != proc)
827 proc (proc_cls,
828 rd_count,
829 (0 != rd_count) ? rd : NULL);
830 }
831 }
832 return GNUNET_OK;
833}
834
835
508/** 836/**
509 * Decrypt block. 837 * Decrypt block.
510 * 838 *
@@ -524,17 +852,17 @@ GNUNET_GNSRECORD_block_decrypt (const struct GNUNET_GNSRECORD_Block *block,
524 GNUNET_GNSRECORD_RecordCallback proc, 852 GNUNET_GNSRECORD_RecordCallback proc,
525 void *proc_cls) 853 void *proc_cls)
526{ 854{
527 const struct GNUNET_CRYPTO_EcdsaPublicKey *key; 855 switch (ntohl (zone_key->type))
528
529 if (GNUNET_IDENTITY_TYPE_ECDSA != ntohl (zone_key->type))
530 { 856 {
531 return GNUNET_NO; 857 case GNUNET_IDENTITY_TYPE_ECDSA:
858 return block_decrypt_ecdsa (&block->ecdsa_block,
859 &zone_key->ecdsa_key, label, proc, proc_cls);
860 case GNUNET_IDENTITY_TYPE_EDDSA:
861 return block_decrypt_eddsa (&block->eddsa_block,
862 &zone_key->eddsa_key, label, proc, proc_cls);
863 default:
864 return GNUNET_SYSERR;
532 } 865 }
533 key = &zone_key->ecdsa_key;
534
535 return block_decrypt_ecdsa (&block->ecdsa_block,
536 key, label, proc, proc_cls);
537
538} 866}
539 867
540 868
@@ -555,6 +883,7 @@ GNUNET_GNSRECORD_query_from_private_key (const struct
555 switch (ntohl (zone->type)) 883 switch (ntohl (zone->type))
556 { 884 {
557 case GNUNET_GNSRECORD_TYPE_PKEY: 885 case GNUNET_GNSRECORD_TYPE_PKEY:
886 case GNUNET_GNSRECORD_TYPE_EDKEY:
558 887
559 GNUNET_IDENTITY_key_get_public (zone, 888 GNUNET_IDENTITY_key_get_public (zone,
560 &pub); 889 &pub);
@@ -570,6 +899,7 @@ GNUNET_GNSRECORD_query_from_private_key (const struct
570 899
571/** 900/**
572 * Calculate the DHT query for a given @a label in a given @a zone. 901 * Calculate the DHT query for a given @a label in a given @a zone.
902 * FIXME: We may want to plugin-ize this at some point.
573 * 903 *
574 * @param pub public key of the zone 904 * @param pub public key of the zone
575 * @param label label of the record 905 * @param label label of the record
@@ -595,6 +925,16 @@ GNUNET_GNSRECORD_query_from_public_key (const struct
595 sizeof (pd.ecdsa_key), 925 sizeof (pd.ecdsa_key),
596 query); 926 query);
597 break; 927 break;
928 case GNUNET_GNSRECORD_TYPE_EDKEY:
929 pd.type = pub->type;
930 GNUNET_CRYPTO_eddsa_public_key_derive (&pub->eddsa_key,
931 label,
932 "gns",
933 &pd.eddsa_key);
934 GNUNET_CRYPTO_hash (&pd.eddsa_key,
935 sizeof (pd.eddsa_key),
936 query);
937 break;
598 default: 938 default:
599 GNUNET_assert (0); 939 GNUNET_assert (0);
600 } 940 }
diff --git a/src/gnsrecord/gnsrecord_misc.c b/src/gnsrecord/gnsrecord_misc.c
index b907eed27..2fe315bd8 100644
--- a/src/gnsrecord/gnsrecord_misc.c
+++ b/src/gnsrecord/gnsrecord_misc.c
@@ -338,6 +338,12 @@ GNUNET_GNSRECORD_block_get_size (const struct GNUNET_GNSRECORD_Block *block)
338 + ntohl (block->ecdsa_block.purpose.size) /* Length of signed data */ 338 + ntohl (block->ecdsa_block.purpose.size) /* Length of signed data */
339 - sizeof (block->ecdsa_block.purpose); /* Purpose already in EcdsaBlock */ 339 - sizeof (block->ecdsa_block.purpose); /* Purpose already in EcdsaBlock */
340 break; 340 break;
341 case GNUNET_GNSRECORD_TYPE_EDKEY:
342 return sizeof (uint32_t) /* zone type */
343 + sizeof (block->eddsa_block) /* EddsaBlock */
344 + ntohl (block->eddsa_block.purpose.size) /* Length of signed data */
345 - sizeof (block->ecdsa_block.purpose); /* Purpose already in EcdsaBlock */
346
341 default: 347 default:
342 return 0; 348 return 0;
343 } 349 }
@@ -354,6 +360,8 @@ GNUNET_GNSRECORD_block_get_expiration (const struct
354 { 360 {
355 case GNUNET_GNSRECORD_TYPE_PKEY: 361 case GNUNET_GNSRECORD_TYPE_PKEY:
356 return GNUNET_TIME_absolute_ntoh (block->ecdsa_block.expiration_time); 362 return GNUNET_TIME_absolute_ntoh (block->ecdsa_block.expiration_time);
363 case GNUNET_GNSRECORD_TYPE_EDKEY:
364 return GNUNET_TIME_absolute_ntoh (block->eddsa_block.expiration_time);
357 default: 365 default:
358 GNUNET_break (0); /* Hopefully we never get here, but we might */ 366 GNUNET_break (0); /* Hopefully we never get here, but we might */
359 } 367 }
@@ -373,6 +381,11 @@ GNUNET_GNSRECORD_query_from_block (const struct GNUNET_GNSRECORD_Block *block,
373 sizeof (block->ecdsa_block.derived_key), 381 sizeof (block->ecdsa_block.derived_key),
374 query); 382 query);
375 return GNUNET_OK; 383 return GNUNET_OK;
384 case GNUNET_GNSRECORD_TYPE_EDKEY:
385 GNUNET_CRYPTO_hash (&block->eddsa_block.derived_key,
386 sizeof (block->eddsa_block.derived_key),
387 query);
388 return GNUNET_OK;
376 default: 389 default:
377 return GNUNET_SYSERR; 390 return GNUNET_SYSERR;
378 } 391 }
@@ -394,6 +407,10 @@ GNUNET_GNSRECORD_record_to_identity_key (const struct GNUNET_GNSRECORD_Data *rd,
394 key->type = htonl (rd->record_type); 407 key->type = htonl (rd->record_type);
395 memcpy (&key->ecdsa_key, rd->data, sizeof (key->ecdsa_key)); 408 memcpy (&key->ecdsa_key, rd->data, sizeof (key->ecdsa_key));
396 return GNUNET_OK; 409 return GNUNET_OK;
410 case GNUNET_GNSRECORD_TYPE_EDKEY:
411 key->type = htonl (rd->record_type);
412 memcpy (&key->eddsa_key, rd->data, sizeof (key->eddsa_key));
413 return GNUNET_OK;
397 default: 414 default:
398 return GNUNET_SYSERR; 415 return GNUNET_SYSERR;
399 } 416 }
diff --git a/src/gnsrecord/gnsrecord_serialization.c b/src/gnsrecord/gnsrecord_serialization.c
index 42665e662..cb6957605 100644
--- a/src/gnsrecord/gnsrecord_serialization.c
+++ b/src/gnsrecord/gnsrecord_serialization.c
@@ -124,7 +124,8 @@ GNUNET_GNSRECORD_records_get_size (unsigned int rd_count,
124 return -1; 124 return -1;
125 } 125 }
126 // Do not pad PKEY 126 // Do not pad PKEY
127 if (GNUNET_GNSRECORD_TYPE_PKEY == rd->record_type) 127 if ((GNUNET_GNSRECORD_TYPE_PKEY == rd->record_type) ||
128 (GNUNET_GNSRECORD_TYPE_EDKEY == rd->record_type))
128 return ret; 129 return ret;
129 /** 130 /**
130 * Efficiently round up to the next 131 * Efficiently round up to the next
diff --git a/src/gnsrecord/test_gnsrecord_crypto.c b/src/gnsrecord/test_gnsrecord_crypto.c
index d541f3076..9394f562d 100644
--- a/src/gnsrecord/test_gnsrecord_crypto.c
+++ b/src/gnsrecord/test_gnsrecord_crypto.c
@@ -92,29 +92,22 @@ rd_decrypt_cb (void *cls,
92 res = 0; 92 res = 0;
93} 93}
94 94
95
96static void 95static void
97run (void *cls, 96test_with_type (struct GNUNET_IDENTITY_PrivateKey *privkey)
98 char *const *args,
99 const char *cfgfile,
100 const struct GNUNET_CONFIGURATION_Handle *cfg)
101{ 97{
102 struct GNUNET_GNSRECORD_Block *block; 98 struct GNUNET_GNSRECORD_Block *block;
103 struct GNUNET_IDENTITY_PublicKey pubkey; 99 struct GNUNET_IDENTITY_PublicKey pubkey;
104 struct GNUNET_HashCode query_pub; 100 struct GNUNET_HashCode query_pub;
105 struct GNUNET_HashCode query_priv; 101 struct GNUNET_HashCode query_priv;
106 struct GNUNET_TIME_Absolute expire = GNUNET_TIME_absolute_get (); 102 struct GNUNET_TIME_Absolute expire = GNUNET_TIME_absolute_get ();
107 struct GNUNET_IDENTITY_PrivateKey privkey;
108 103
109 104
110 privkey.type = htonl (GNUNET_GNSRECORD_TYPE_PKEY);
111 GNUNET_CRYPTO_ecdsa_key_create (&privkey.ecdsa_key);
112 /* get public key */ 105 /* get public key */
113 GNUNET_IDENTITY_key_get_public (&privkey, 106 GNUNET_IDENTITY_key_get_public (privkey,
114 &pubkey); 107 &pubkey);
115 108
116 /* test query derivation */ 109 /* test query derivation */
117 GNUNET_GNSRECORD_query_from_private_key (&privkey, 110 GNUNET_GNSRECORD_query_from_private_key (privkey,
118 "testlabel", 111 "testlabel",
119 &query_priv); 112 &query_priv);
120 GNUNET_GNSRECORD_query_from_public_key (&pubkey, 113 GNUNET_GNSRECORD_query_from_public_key (&pubkey,
@@ -129,7 +122,7 @@ run (void *cls,
129 122
130 /* Create block */ 123 /* Create block */
131 GNUNET_assert (NULL != (block = 124 GNUNET_assert (NULL != (block =
132 GNUNET_GNSRECORD_block_create (&privkey, 125 GNUNET_GNSRECORD_block_create (privkey,
133 expire, 126 expire,
134 s_name, 127 s_name,
135 s_rd, 128 s_rd,
@@ -146,6 +139,27 @@ run (void *cls,
146} 139}
147 140
148 141
142
143static void
144run (void *cls,
145 char *const *args,
146 const char *cfgfile,
147 const struct GNUNET_CONFIGURATION_Handle *cfg)
148{
149 struct GNUNET_IDENTITY_PrivateKey privkey;
150 struct GNUNET_IDENTITY_PrivateKey privkey_ed;
151
152
153 privkey.type = htonl (GNUNET_GNSRECORD_TYPE_PKEY);
154 GNUNET_CRYPTO_ecdsa_key_create (&privkey.ecdsa_key);
155 test_with_type (&privkey);
156
157 privkey_ed.type = htonl (GNUNET_GNSRECORD_TYPE_EDKEY);
158 GNUNET_CRYPTO_eddsa_key_create (&privkey_ed.eddsa_key);
159 test_with_type(&privkey_ed);
160}
161
162
149int 163int
150main (int argc, char *argv[]) 164main (int argc, char *argv[])
151{ 165{
diff --git a/src/include/gnunet_crypto_lib.h b/src/include/gnunet_crypto_lib.h
index 43cdfdfac..a334b50d0 100644
--- a/src/include/gnunet_crypto_lib.h
+++ b/src/include/gnunet_crypto_lib.h
@@ -275,6 +275,19 @@ struct GNUNET_CRYPTO_EddsaPrivateKey
275 275
276 276
277/** 277/**
278 * Private ECC scalar encoded for transmission. To be used only for EdDSA
279 * signatures.
280 */
281struct GNUNET_CRYPTO_EddsaPrivateScalar
282{
283 /**
284 * s is the expandedprivate 512-bit scalar of a private key.
285 */
286 unsigned char s[512 / 8];
287};
288
289
290/**
278 * @brief type for session keys 291 * @brief type for session keys
279 */ 292 */
280struct GNUNET_CRYPTO_SymmetricSessionKey 293struct GNUNET_CRYPTO_SymmetricSessionKey
@@ -1907,6 +1920,71 @@ GNUNET_CRYPTO_ecdsa_public_key_derive (
1907 1920
1908 1921
1909/** 1922/**
1923 * @ingroup crypto
1924 * Derive a private scalar from a given private key and a label.
1925 * Essentially calculates a private key 'h = H(l,P) * d mod n'
1926 * where n is the size of the ECC group and P is the public
1927 * key associated with the private key 'd'.
1928 * The result is the derived private _scalar_, not the private
1929 * key as for EdDSA we cannot derive before we hash the
1930 * private key.
1931 *
1932 * @param priv original private key
1933 * @param label label to use for key deriviation
1934 * @param context additional context to use for HKDF of 'h';
1935 * typically the name of the subsystem/application
1936 * @param result derived private scalar
1937 */
1938void
1939GNUNET_CRYPTO_eddsa_private_key_derive (
1940 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
1941 const char *label,
1942 const char *context,
1943 struct GNUNET_CRYPTO_EddsaPrivateScalar *result);
1944
1945
1946/**
1947 * @ingroup crypto
1948 * Derive a public key from a given public key and a label.
1949 * Essentially calculates a public key 'V = H(l,P) * P'.
1950 *
1951 * @param pub original public key
1952 * @param label label to use for key deriviation
1953 * @param context additional context to use for HKDF of 'h'.
1954 * typically the name of the subsystem/application
1955 * @param result where to write the derived public key
1956 */
1957void
1958GNUNET_CRYPTO_eddsa_public_key_derive (
1959 const struct GNUNET_CRYPTO_EddsaPublicKey *pub,
1960 const char *label,
1961 const char *context,
1962 struct GNUNET_CRYPTO_EddsaPublicKey *result);
1963
1964
1965/**
1966 * This is a signature function for EdDSA which takes the
1967 * secret scalar sk instead of the private seed which is
1968 * usually the case for crypto APIs. We require this functionality
1969 * in order to use derived private keys for signatures we
1970 * cannot calculate the inverse of a sk to find the seed
1971 * efficiently.
1972 *
1973 * The resulting signature is a standard EdDSA signature
1974 * which can be verified using the usual APIs.
1975 *
1976 * @param sk the secret scalar
1977 * @param purp the signature purpose
1978 * @param sig the resulting signature
1979 */
1980void
1981GNUNET_CRYPTO_eddsa_sign_with_scalar (
1982 const struct GNUNET_CRYPTO_EddsaPrivateScalar *priv,
1983 const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
1984 struct GNUNET_CRYPTO_EddsaSignature *sig);
1985
1986
1987/**
1910 * Output the given MPI value to the given buffer in network 1988 * Output the given MPI value to the given buffer in network
1911 * byte order. The MPI @a val may not be negative. 1989 * byte order. The MPI @a val may not be negative.
1912 * 1990 *
diff --git a/src/include/gnunet_gnsrecord_lib.h b/src/include/gnunet_gnsrecord_lib.h
index 61cbac2ca..5afb3f253 100644
--- a/src/include/gnunet_gnsrecord_lib.h
+++ b/src/include/gnunet_gnsrecord_lib.h
@@ -197,6 +197,37 @@ struct GNUNET_GNSRECORD_EcdsaBlock
197 /* followed by encrypted data */ 197 /* followed by encrypted data */
198}; 198};
199 199
200
201/**
202 * Information we have in an encrypted block with record data (i.e. in the DHT).
203 */
204struct GNUNET_GNSRECORD_EddsaBlock
205{
206 /**
207 * Derived key used for signing; hash of this is the query.
208 */
209 struct GNUNET_CRYPTO_EddsaPublicKey derived_key;
210
211 /**
212 * Signature of the block.
213 */
214 struct GNUNET_CRYPTO_EddsaSignature signature;
215
216 /**
217 * Number of bytes signed; also specifies the number of bytes
218 * of encrypted data that follow.
219 */
220 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
221
222 /**
223 * Expiration time of the block.
224 */
225 struct GNUNET_TIME_AbsoluteNBO expiration_time;
226
227 /* followed by encrypted data */
228};
229
230
200struct GNUNET_GNSRECORD_Block 231struct GNUNET_GNSRECORD_Block
201{ 232{
202 uint32_t type; 233 uint32_t type;
@@ -204,7 +235,7 @@ struct GNUNET_GNSRECORD_Block
204 union 235 union
205 { 236 {
206 struct GNUNET_GNSRECORD_EcdsaBlock ecdsa_block; 237 struct GNUNET_GNSRECORD_EcdsaBlock ecdsa_block;
207 //struct GNUNET_GNSRECORD_EddsaBlock eddsa_block; 238 struct GNUNET_GNSRECORD_EddsaBlock eddsa_block;
208 }; 239 };
209}; 240};
210 241
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index 72fd37bde..09620aee0 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -61,6 +61,7 @@ libgnunetutil_la_SOURCES = \
61 crypto_symmetric.c \ 61 crypto_symmetric.c \
62 crypto_crc.c \ 62 crypto_crc.c \
63 crypto_ecc.c \ 63 crypto_ecc.c \
64 crypto_ecc_gnsrecord.c \
64 $(DLOG) \ 65 $(DLOG) \
65 crypto_ecc_setup.c \ 66 crypto_ecc_setup.c \
66 crypto_hash.c \ 67 crypto_hash.c \
diff --git a/src/util/crypto_ecc.c b/src/util/crypto_ecc.c
index efbf2ee17..5b1b579ec 100644
--- a/src/util/crypto_ecc.c
+++ b/src/util/crypto_ecc.c
@@ -714,135 +714,6 @@ GNUNET_CRYPTO_ecc_ecdh (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
714} 714}
715 715
716 716
717/**
718 * Derive the 'h' value for key derivation, where
719 * 'h = H(l,P)'.
720 *
721 * @param pub public key for deriviation
722 * @param label label for deriviation
723 * @param context additional context to use for HKDF of 'h';
724 * typically the name of the subsystem/application
725 * @return h value
726 */
727static gcry_mpi_t
728derive_h (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
729 const char *label,
730 const char *context)
731{
732 gcry_mpi_t h;
733 struct GNUNET_HashCode hc;
734 static const char *const salt = "key-derivation";
735
736 GNUNET_CRYPTO_kdf (&hc,
737 sizeof(hc),
738 salt,
739 strlen (salt),
740 pub,
741 sizeof(*pub),
742 label,
743 strlen (label),
744 context,
745 strlen (context),
746 NULL,
747 0);
748 GNUNET_CRYPTO_mpi_scan_unsigned (&h, (unsigned char *) &hc, sizeof(hc));
749 return h;
750}
751
752
753struct GNUNET_CRYPTO_EcdsaPrivateKey *
754GNUNET_CRYPTO_ecdsa_private_key_derive (
755 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
756 const char *label,
757 const char *context)
758{
759 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
760 struct GNUNET_CRYPTO_EcdsaPrivateKey *ret;
761 uint8_t dc[32];
762 gcry_mpi_t h;
763 gcry_mpi_t x;
764 gcry_mpi_t d;
765 gcry_mpi_t n;
766 gcry_ctx_t ctx;
767
768 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
769
770 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
771 GNUNET_CRYPTO_ecdsa_key_get_public (priv, &pub);
772
773 h = derive_h (&pub, label, context);
774 /* Convert to big endian for libgcrypt */
775 for (size_t i = 0; i < 32; i++)
776 dc[i] = priv->d[31 - i];
777 GNUNET_CRYPTO_mpi_scan_unsigned (&x, dc, sizeof(dc));
778 d = gcry_mpi_new (256);
779 gcry_mpi_mulm (d, h, x, n);
780 gcry_mpi_release (h);
781 gcry_mpi_release (x);
782 gcry_mpi_release (n);
783 gcry_ctx_release (ctx);
784 ret = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
785 GNUNET_CRYPTO_mpi_print_unsigned (dc, sizeof(dc), d);
786 /* Convert to big endian for libgcrypt */
787 for (size_t i = 0; i < 32; i++)
788 ret->d[i] = dc[31 - i];
789 sodium_memzero (dc, sizeof(dc));
790 gcry_mpi_release (d);
791 return ret;
792}
793
794
795void
796GNUNET_CRYPTO_ecdsa_public_key_derive (
797 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
798 const char *label,
799 const char *context,
800 struct GNUNET_CRYPTO_EcdsaPublicKey *result)
801{
802 gcry_ctx_t ctx;
803 gcry_mpi_t q_y;
804 gcry_mpi_t h;
805 gcry_mpi_t n;
806 gcry_mpi_t h_mod_n;
807 gcry_mpi_point_t q;
808 gcry_mpi_point_t v;
809
810 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
811
812 /* obtain point 'q' from original public key. The provided 'q' is
813 compressed thus we first store it in the context and then get it
814 back as a (decompresssed) point. */
815 q_y = gcry_mpi_set_opaque_copy (NULL, pub->q_y, 8 * sizeof(pub->q_y));
816 GNUNET_assert (NULL != q_y);
817 GNUNET_assert (0 == gcry_mpi_ec_set_mpi ("q", q_y, ctx));
818 gcry_mpi_release (q_y);
819 q = gcry_mpi_ec_get_point ("q", ctx, 0);
820 GNUNET_assert (q);
821
822 /* calculate h_mod_n = h % n */
823 h = derive_h (pub, label, context);
824 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
825 h_mod_n = gcry_mpi_new (256);
826 gcry_mpi_mod (h_mod_n, h, n);
827 /* calculate v = h_mod_n * q */
828 v = gcry_mpi_point_new (0);
829 gcry_mpi_ec_mul (v, h_mod_n, q, ctx);
830 gcry_mpi_release (h_mod_n);
831 gcry_mpi_release (h);
832 gcry_mpi_release (n);
833 gcry_mpi_point_release (q);
834
835 /* convert point 'v' to public key that we return */
836 GNUNET_assert (0 == gcry_mpi_ec_set_point ("q", v, ctx));
837 gcry_mpi_point_release (v);
838 q_y = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
839 GNUNET_assert (q_y);
840 GNUNET_CRYPTO_mpi_print_unsigned (result->q_y, sizeof(result->q_y), q_y);
841 gcry_mpi_release (q_y);
842 gcry_ctx_release (ctx);
843}
844
845
846enum GNUNET_GenericReturnValue 717enum GNUNET_GenericReturnValue
847GNUNET_CRYPTO_eddsa_ecdh (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv, 718GNUNET_CRYPTO_eddsa_ecdh (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
848 const struct GNUNET_CRYPTO_EcdhePublicKey *pub, 719 const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
diff --git a/src/util/crypto_ecc_gnsrecord.c b/src/util/crypto_ecc_gnsrecord.c
new file mode 100644
index 000000000..6689a21f1
--- /dev/null
+++ b/src/util/crypto_ecc_gnsrecord.c
@@ -0,0 +1,351 @@
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 * @return h value
46 */
47static gcry_mpi_t
48derive_h (const void *pub,
49 size_t pubsize,
50 const char *label,
51 const char *context)
52{
53 gcry_mpi_t h;
54 struct GNUNET_HashCode hc;
55 static const char *const salt = "key-derivation";
56
57 GNUNET_CRYPTO_kdf (&hc,
58 sizeof(hc),
59 salt,
60 strlen (salt),
61 pub,
62 pubsize,
63 label,
64 strlen (label),
65 context,
66 strlen (context),
67 NULL,
68 0);
69 GNUNET_CRYPTO_mpi_scan_unsigned (&h, (unsigned char *) &hc, sizeof(hc));
70 return h;
71}
72
73
74/**
75 * This is a signature function for EdDSA which takes the
76 * secret scalar sk instead of the private seed which is
77 * usually the case for crypto APIs. We require this functionality
78 * in order to use derived private keys for signatures we
79 * cannot calculate the inverse of a sk to find the seed
80 * efficiently.
81 *
82 * The resulting signature is a standard EdDSA signature
83 * which can be verified using the usual APIs.
84 *
85 * @param sk the secret scalar
86 * @param purp the signature purpose
87 * @param sig the resulting signature
88 */
89void
90GNUNET_CRYPTO_eddsa_sign_with_scalar (
91 const struct GNUNET_CRYPTO_EddsaPrivateScalar *priv,
92 const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
93 struct GNUNET_CRYPTO_EddsaSignature *sig)
94{
95
96 crypto_hash_sha512_state hs;
97 unsigned char az[64];
98 unsigned char nonce[64];
99 unsigned char hram[64];
100 unsigned char R[32];
101 unsigned char pk[32];
102
103 crypto_hash_sha512_init (&hs);
104
105 // crypto_hash_sha512 (az, sk, 32); DO NOT EXPAND, WE HAVE A KEY
106 memcpy (az, priv->s, 64);
107 crypto_scalarmult_ed25519_base_noclamp (pk,
108 priv->s);
109 crypto_hash_sha512_update (&hs, az + 32, 32);
110
111 crypto_hash_sha512_update (&hs, (uint8_t*) purpose, ntohl (purpose->size));
112 crypto_hash_sha512_final (&hs, nonce);
113
114 // This effectively creates R || A in sig
115 memcpy (sig->s, pk, 32);
116
117 unsigned char nonce_mod[64];
118 crypto_core_ed25519_scalar_reduce (nonce_mod, nonce);
119 // nonce == r; r * G == R
120 crypto_scalarmult_ed25519_base_noclamp (R, nonce_mod);
121 memcpy (sig->r, R, sizeof (R));
122
123 // SHA512 (R | A | M) == k
124 crypto_hash_sha512_init (&hs);
125 crypto_hash_sha512_update (&hs, (uint8_t*) sig, 64);
126 crypto_hash_sha512_update (&hs, (uint8_t*) purpose,
127 ntohl (purpose->size));
128 crypto_hash_sha512_final (&hs, hram);
129
130 unsigned char hram_mod[64];
131 crypto_core_ed25519_scalar_reduce (hram_mod, hram);
132 az[0] &= 248;
133 az[31] &= 127;
134 az[31] |= 64;
135
136 unsigned char tmp[32];
137 // r + k * s mod L == S
138 crypto_core_ed25519_scalar_mul (tmp, hram_mod, az);
139 crypto_core_ed25519_scalar_add (sig->s, tmp, nonce_mod);
140
141 sodium_memzero (az, sizeof az);
142 sodium_memzero (nonce, sizeof nonce);
143}
144
145
146struct GNUNET_CRYPTO_EcdsaPrivateKey *
147GNUNET_CRYPTO_ecdsa_private_key_derive (
148 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
149 const char *label,
150 const char *context)
151{
152 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
153 struct GNUNET_CRYPTO_EcdsaPrivateKey *ret;
154 uint8_t dc[32];
155 gcry_mpi_t h;
156 gcry_mpi_t x;
157 gcry_mpi_t d;
158 gcry_mpi_t n;
159 gcry_ctx_t ctx;
160
161 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
162
163 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
164 GNUNET_CRYPTO_ecdsa_key_get_public (priv, &pub);
165
166 h = derive_h (&pub, sizeof (pub), label, context);
167 /* Convert to big endian for libgcrypt */
168 for (size_t i = 0; i < 32; i++)
169 dc[i] = priv->d[31 - i];
170 GNUNET_CRYPTO_mpi_scan_unsigned (&x, dc, sizeof(dc));
171 d = gcry_mpi_new (256);
172 gcry_mpi_mulm (d, h, x, n);
173 gcry_mpi_release (h);
174 gcry_mpi_release (x);
175 gcry_mpi_release (n);
176 gcry_ctx_release (ctx);
177 ret = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
178 GNUNET_CRYPTO_mpi_print_unsigned (dc, sizeof(dc), d);
179 /* Convert to big endian for libgcrypt */
180 for (size_t i = 0; i < 32; i++)
181 ret->d[i] = dc[31 - i];
182 sodium_memzero (dc, sizeof(dc));
183 gcry_mpi_release (d);
184 return ret;
185}
186
187
188void
189GNUNET_CRYPTO_ecdsa_public_key_derive (
190 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
191 const char *label,
192 const char *context,
193 struct GNUNET_CRYPTO_EcdsaPublicKey *result)
194{
195 gcry_ctx_t ctx;
196 gcry_mpi_t q_y;
197 gcry_mpi_t h;
198 gcry_mpi_t n;
199 gcry_mpi_t h_mod_n;
200 gcry_mpi_point_t q;
201 gcry_mpi_point_t v;
202
203 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
204
205 /* obtain point 'q' from original public key. The provided 'q' is
206 compressed thus we first store it in the context and then get it
207 back as a (decompresssed) point. */
208 q_y = gcry_mpi_set_opaque_copy (NULL, pub->q_y, 8 * sizeof(pub->q_y));
209 GNUNET_assert (NULL != q_y);
210 GNUNET_assert (0 == gcry_mpi_ec_set_mpi ("q", q_y, ctx));
211 gcry_mpi_release (q_y);
212 q = gcry_mpi_ec_get_point ("q", ctx, 0);
213 GNUNET_assert (q);
214
215 /* calculate h_mod_n = h % n */
216 h = derive_h (pub, sizeof (pub), label, context);
217 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
218 h_mod_n = gcry_mpi_new (256);
219 gcry_mpi_mod (h_mod_n, h, n);
220 /* calculate v = h_mod_n * q */
221 v = gcry_mpi_point_new (0);
222 gcry_mpi_ec_mul (v, h_mod_n, q, ctx);
223 gcry_mpi_release (h_mod_n);
224 gcry_mpi_release (h);
225 gcry_mpi_release (n);
226 gcry_mpi_point_release (q);
227
228 /* convert point 'v' to public key that we return */
229 GNUNET_assert (0 == gcry_mpi_ec_set_point ("q", v, ctx));
230 gcry_mpi_point_release (v);
231 q_y = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
232 GNUNET_assert (q_y);
233 GNUNET_CRYPTO_mpi_print_unsigned (result->q_y, sizeof(result->q_y), q_y);
234 gcry_mpi_release (q_y);
235 gcry_ctx_release (ctx);
236}
237
238
239void
240GNUNET_CRYPTO_eddsa_private_key_derive (
241 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
242 const char *label,
243 const char *context,
244 struct GNUNET_CRYPTO_EddsaPrivateScalar *result)
245{
246 struct GNUNET_CRYPTO_EddsaPublicKey pub;
247 uint8_t dc[32];
248 unsigned char sk[64];
249 gcry_mpi_t h;
250 gcry_mpi_t h_mod_n;
251 gcry_mpi_t x;
252 gcry_mpi_t d;
253 gcry_mpi_t n;
254 gcry_mpi_t a1;
255 gcry_mpi_t a2;
256 gcry_ctx_t ctx;
257
258 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, "Ed25519"));
259
260 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
261 GNUNET_CRYPTO_eddsa_key_get_public (priv, &pub);
262 crypto_hash_sha512 (sk, priv->d, 32);
263 sk[0] &= 248;
264 sk[31] &= 127;
265 sk[31] |= 64;
266 h = derive_h (&pub, sizeof (pub), label, context);
267 h_mod_n = gcry_mpi_new (256);
268 gcry_mpi_mod (h_mod_n, h, n);
269 /* Convert to big endian for libgcrypt */
270 for (size_t i = 0; i < 32; i++)
271 dc[i] = sk[31 - i];
272 GNUNET_CRYPTO_mpi_scan_unsigned (&x, dc, sizeof(dc)); // a
273 a1 = gcry_mpi_new (256);
274 gcry_mpi_t eight = gcry_mpi_set_ui (NULL, 8);
275 gcry_mpi_div (a1, NULL, x, eight, 0); // a1 := a / 8
276 a2 = gcry_mpi_new (256);
277 gcry_mpi_mulm (a2, h_mod_n, a1, n); // a2 := h * a1 mod n
278 d = gcry_mpi_new (256);
279 // gcry_mpi_mulm (d, a2, eight, n); // a' := a2 * 8 mod n
280 gcry_mpi_mul (d, a2, eight); // a' := a2 * 8
281 gcry_mpi_release (h);
282 gcry_mpi_release (x);
283 gcry_mpi_release (n);
284 gcry_mpi_release (a1);
285 gcry_mpi_release (a2);
286 gcry_ctx_release (ctx);
287 GNUNET_CRYPTO_mpi_print_unsigned (dc, sizeof(dc), d);
288 memcpy (result->s, sk, sizeof (sk));
289 /* Convert to little endian for libsodium */
290 for (size_t i = 0; i < 32; i++)
291 result->s[i] = dc[31 - i];
292 result->s[0] &= 248;
293 result->s[31] &= 127;
294 result->s[31] |= 64;
295
296 sodium_memzero (dc, sizeof(dc));
297 gcry_mpi_release (d);
298}
299
300
301void
302GNUNET_CRYPTO_eddsa_public_key_derive (
303 const struct GNUNET_CRYPTO_EddsaPublicKey *pub,
304 const char *label,
305 const char *context,
306 struct GNUNET_CRYPTO_EddsaPublicKey *result)
307{
308 gcry_ctx_t ctx;
309 gcry_mpi_t q_y;
310 gcry_mpi_t h;
311 gcry_mpi_t n;
312 gcry_mpi_t h_mod_n;
313 gcry_mpi_point_t q;
314 gcry_mpi_point_t v;
315
316 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, "Ed25519"));
317
318 /* obtain point 'q' from original public key. The provided 'q' is
319 compressed thus we first store it in the context and then get it
320 back as a (decompresssed) point. */
321 q_y = gcry_mpi_set_opaque_copy (NULL, pub->q_y, 8 * sizeof(pub->q_y));
322 GNUNET_assert (NULL != q_y);
323 GNUNET_assert (0 == gcry_mpi_ec_set_mpi ("q", q_y, ctx));
324 gcry_mpi_release (q_y);
325 q = gcry_mpi_ec_get_point ("q", ctx, 0);
326 GNUNET_assert (q);
327
328 /* calculate h_mod_n = h % n */
329 h = derive_h (pub, sizeof (*pub), label, context);
330 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
331 h_mod_n = gcry_mpi_new (256);
332 gcry_mpi_mod (h_mod_n, h, n);
333
334 /* calculate v = h_mod_n * q */
335 v = gcry_mpi_point_new (0);
336 gcry_mpi_ec_mul (v, h_mod_n, q, ctx);
337 gcry_mpi_release (h_mod_n);
338 gcry_mpi_release (h);
339 gcry_mpi_release (n);
340 gcry_mpi_point_release (q);
341
342 /* convert point 'v' to public key that we return */
343 GNUNET_assert (0 == gcry_mpi_ec_set_point ("q", v, ctx));
344 gcry_mpi_point_release (v);
345 q_y = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
346 GNUNET_assert (q_y);
347 GNUNET_CRYPTO_mpi_print_unsigned (result->q_y, sizeof(result->q_y), q_y);
348 gcry_mpi_release (q_y);
349 gcry_ctx_release (ctx);
350
351}