aboutsummaryrefslogtreecommitdiff
path: root/src/gnsrecord/gnsrecord_crypto.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gnsrecord/gnsrecord_crypto.c')
-rw-r--r--src/gnsrecord/gnsrecord_crypto.c426
1 files changed, 383 insertions, 43 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 }