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.c997
1 files changed, 0 insertions, 997 deletions
diff --git a/src/gnsrecord/gnsrecord_crypto.c b/src/gnsrecord/gnsrecord_crypto.c
deleted file mode 100644
index b5e8be82b..000000000
--- a/src/gnsrecord/gnsrecord_crypto.c
+++ /dev/null
@@ -1,997 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2013, 2018 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 gnsrecord/gnsrecord_crypto.c
23 * @brief API for GNS record-related crypto
24 * @author Martin Schanzenbach
25 * @author Matthias Wachs
26 * @author Christian Grothoff
27 */
28#include "gnsrecord_crypto.h"
29
30#define LOG(kind, ...) GNUNET_log_from (kind, "gnsrecord", __VA_ARGS__)
31
32ssize_t
33ecdsa_symmetric_decrypt (
34 const void *block,
35 size_t size,
36 const unsigned char *key,
37 const unsigned char *ctr,
38 void *result)
39{
40 gcry_cipher_hd_t handle;
41 int rc;
42
43 GNUNET_assert (0 == gcry_cipher_open (&handle, GCRY_CIPHER_AES256,
44 GCRY_CIPHER_MODE_CTR, 0));
45 rc = gcry_cipher_setkey (handle,
46 key,
47 GNUNET_CRYPTO_AES_KEY_LENGTH);
48 GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY));
49 rc = gcry_cipher_setctr (handle,
50 ctr,
51 GNUNET_CRYPTO_AES_KEY_LENGTH / 2);
52 GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY));
53 GNUNET_assert (0 == gcry_cipher_decrypt (handle, result, size, block, size));
54 gcry_cipher_close (handle);
55 return size;
56}
57
58
59ssize_t
60ecdsa_symmetric_encrypt (
61 const void *block,
62 size_t size,
63 const unsigned char *key,
64 const unsigned char *ctr,
65 void *result)
66{
67 gcry_cipher_hd_t handle;
68 int rc;
69
70 GNUNET_assert (0 == gcry_cipher_open (&handle, GCRY_CIPHER_AES256,
71 GCRY_CIPHER_MODE_CTR, 0));
72 rc = gcry_cipher_setkey (handle,
73 key,
74 GNUNET_CRYPTO_AES_KEY_LENGTH);
75 GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY));
76 rc = gcry_cipher_setctr (handle,
77 ctr,
78 GNUNET_CRYPTO_AES_KEY_LENGTH / 2);
79 GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY));
80 GNUNET_assert (0 == gcry_cipher_encrypt (handle, result, size, block, size));
81 gcry_cipher_close (handle);
82 return size;
83}
84
85
86enum GNUNET_GenericReturnValue
87eddsa_symmetric_decrypt (
88 const void *block,
89 size_t size,
90 const unsigned char *key,
91 const unsigned char *nonce,
92 void *result)
93{
94 ssize_t ctlen = size - crypto_secretbox_MACBYTES;
95 if (ctlen < 0)
96 return GNUNET_SYSERR;
97 if (0 != crypto_secretbox_open_detached (result,
98 ((unsigned char*) block) + crypto_secretbox_MACBYTES, // Ciphertext
99 block, // Tag
100 ctlen,
101 nonce, key))
102 {
103 return GNUNET_SYSERR;
104 }
105 return GNUNET_OK;
106}
107
108
109enum GNUNET_GenericReturnValue
110eddsa_symmetric_encrypt (
111 const void *block,
112 size_t size,
113 const unsigned char *key,
114 const unsigned char *nonce,
115 void *result)
116{
117 if (size > crypto_secretbox_MESSAGEBYTES_MAX)
118 return GNUNET_SYSERR;
119 crypto_secretbox_detached (result + crypto_secretbox_MACBYTES, // Ciphertext
120 result, // TAG
121 block, size, nonce, key);
122 return GNUNET_OK;
123}
124
125
126void
127GNR_derive_block_aes_key (unsigned char *ctr,
128 unsigned char *key,
129 const char *label,
130 uint64_t exp,
131 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
132{
133 static const char ctx_key[] = "gns-aes-ctx-key";
134 static const char ctx_iv[] = "gns-aes-ctx-iv";
135
136 GNUNET_CRYPTO_kdf (key, GNUNET_CRYPTO_AES_KEY_LENGTH,
137 ctx_key, strlen (ctx_key),
138 pub, sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey),
139 label, strlen (label),
140 NULL, 0);
141 memset (ctr, 0, GNUNET_CRYPTO_AES_KEY_LENGTH / 2);
142 /** 4 byte nonce **/
143 GNUNET_CRYPTO_kdf (ctr, 4,
144 ctx_iv, strlen (ctx_iv),
145 pub, sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey),
146 label, strlen (label),
147 NULL, 0);
148 /** Expiration time 64 bit. **/
149 memcpy (ctr + 4, &exp, sizeof (exp));
150 /** Set counter part to 1 **/
151 ctr[15] |= 0x01;
152}
153
154
155void
156GNR_derive_block_xsalsa_key (unsigned char *nonce,
157 unsigned char *key,
158 const char *label,
159 uint64_t exp,
160 const struct GNUNET_CRYPTO_EddsaPublicKey *pub)
161{
162 static const char ctx_key[] = "gns-xsalsa-ctx-key";
163 static const char ctx_iv[] = "gns-xsalsa-ctx-iv";
164
165 GNUNET_CRYPTO_kdf (key, crypto_secretbox_KEYBYTES,
166 ctx_key, strlen (ctx_key),
167 pub, sizeof(struct GNUNET_CRYPTO_EddsaPublicKey),
168 label, strlen (label),
169 NULL, 0);
170 memset (nonce, 0, crypto_secretbox_NONCEBYTES);
171 /** 16 byte nonce **/
172 GNUNET_CRYPTO_kdf (nonce, (crypto_secretbox_NONCEBYTES - sizeof (exp)),
173 ctx_iv, strlen (ctx_iv),
174 pub, sizeof(struct GNUNET_CRYPTO_EddsaPublicKey),
175 label, strlen (label),
176 NULL, 0);
177 /** Expiration time 64 bit. **/
178 memcpy (nonce + (crypto_secretbox_NONCEBYTES - sizeof (exp)),
179 &exp, sizeof (exp));
180}
181
182
183static ssize_t
184block_get_size_ecdsa (const struct GNUNET_GNSRECORD_Data *rd,
185 unsigned int rd_count)
186{
187 ssize_t len;
188
189 len = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
190 if (len < 0)
191 return -1;
192 len += sizeof(struct GNUNET_GNSRECORD_Block);
193 return len;
194}
195
196
197/**
198 * Sign name and records
199 *
200 * @param key the private key
201 * @param pkey associated public key
202 * @param expire block expiration
203 * @param label the name for the records
204 * @param rd record data
205 * @param rd_count number of records
206 * @param block the block result. Must be allocated sufficiently.
207 * @return GNUNET_SYSERR on error (otherwise GNUNET_OK)
208 */
209static enum GNUNET_GenericReturnValue
210block_create_ecdsa (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
211 const struct GNUNET_CRYPTO_EcdsaPublicKey *pkey,
212 struct GNUNET_TIME_Absolute expire,
213 const char *label,
214 const struct GNUNET_GNSRECORD_Data *rd,
215 unsigned int rd_count,
216 struct GNUNET_GNSRECORD_Block **block)
217{
218 ssize_t payload_len = GNUNET_GNSRECORD_records_get_size (rd_count,
219 rd);
220 struct GNUNET_GNSRECORD_EcdsaBlock *ecblock;
221 struct GNRBlockPS *gnr_block;
222 unsigned char ctr[GNUNET_CRYPTO_AES_KEY_LENGTH / 2];
223 unsigned char skey[GNUNET_CRYPTO_AES_KEY_LENGTH];
224 struct GNUNET_GNSRECORD_Data rdc[GNUNET_NZL (rd_count)];
225 struct GNUNET_TIME_Absolute now;
226
227 if (payload_len < 0)
228 {
229 GNUNET_break (0);
230 return GNUNET_SYSERR;
231 }
232 if (payload_len > GNUNET_GNSRECORD_MAX_BLOCK_SIZE)
233 {
234 GNUNET_break (0);
235 return GNUNET_SYSERR;
236 }
237 /* convert relative to absolute times */
238 now = GNUNET_TIME_absolute_get ();
239 for (unsigned int i = 0; i < rd_count; i++)
240 {
241 rdc[i] = rd[i];
242 if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
243 {
244 struct GNUNET_TIME_Relative t;
245
246 /* encrypted blocks must never have relative expiration times, convert! */
247 rdc[i].flags &= ~GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
248 t.rel_value_us = rdc[i].expiration_time;
249 rdc[i].expiration_time = GNUNET_TIME_absolute_add (now, t).abs_value_us;
250 }
251 }
252 /* serialize */
253 *block = GNUNET_malloc (sizeof (struct GNUNET_GNSRECORD_Block) + payload_len);
254 (*block)->size = htonl(sizeof (struct GNUNET_GNSRECORD_Block) + payload_len);
255 {
256 char payload[payload_len];
257
258 GNUNET_assert (payload_len ==
259 GNUNET_GNSRECORD_records_serialize (rd_count,
260 rdc,
261 payload_len,
262 payload));
263 gnr_block = GNUNET_malloc (sizeof (struct GNRBlockPS) + payload_len);
264 ecblock = &(*block)->ecdsa_block;
265 (*block)->type = htonl (GNUNET_GNSRECORD_TYPE_PKEY);
266 gnr_block->purpose.size = htonl (sizeof(struct GNRBlockPS) + payload_len);
267 gnr_block->purpose.purpose =
268 htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN);
269 gnr_block->expiration_time = GNUNET_TIME_absolute_hton (expire);
270 ecblock->expiration_time = gnr_block->expiration_time;
271 /* encrypt and sign */
272 GNUNET_CRYPTO_ecdsa_public_key_derive (pkey,
273 label,
274 "gns",
275 &ecblock->derived_key);
276 GNR_derive_block_aes_key (ctr,
277 skey,
278 label,
279 ecblock->expiration_time.abs_value_us__,
280 pkey);
281 GNUNET_assert (payload_len ==
282 ecdsa_symmetric_encrypt (payload,
283 payload_len,
284 skey,
285 ctr,
286 &ecblock[1]));
287 GNUNET_memcpy (&gnr_block[1], &ecblock[1], payload_len);
288 }
289 if (GNUNET_OK !=
290 GNUNET_CRYPTO_ecdsa_sign_derived (key,
291 label,
292 "gns",
293 &gnr_block->purpose,
294 &ecblock->signature))
295 {
296 GNUNET_break (0);
297 GNUNET_free (*block);
298 GNUNET_free (gnr_block);
299 return GNUNET_SYSERR;
300 }
301 GNUNET_free (gnr_block);
302 return GNUNET_OK;
303}
304
305static ssize_t
306block_get_size_eddsa (const struct GNUNET_GNSRECORD_Data *rd,
307 unsigned int rd_count)
308{
309 ssize_t len;
310
311 len = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
312 if (len < 0)
313 return -1;
314 len += sizeof(struct GNUNET_GNSRECORD_Block);
315 len += crypto_secretbox_MACBYTES;
316 return len;
317}
318
319
320/**
321 * Sign name and records (EDDSA version)
322 *
323 * @param key the private key
324 * @param pkey associated public key
325 * @param expire block expiration
326 * @param label the name for the records
327 * @param rd record data
328 * @param rd_count number of records
329 * @param block where to store the block. Must be allocated sufficiently.
330 * @return GNUNET_SYSERR on error (otherwise GNUNET_OK)
331 */
332enum GNUNET_GenericReturnValue
333block_create_eddsa (const struct GNUNET_CRYPTO_EddsaPrivateKey *key,
334 const struct GNUNET_CRYPTO_EddsaPublicKey *pkey,
335 struct GNUNET_TIME_Absolute expire,
336 const char *label,
337 const struct GNUNET_GNSRECORD_Data *rd,
338 unsigned int rd_count,
339 struct GNUNET_GNSRECORD_Block **block)
340{
341 ssize_t payload_len = GNUNET_GNSRECORD_records_get_size (rd_count,
342 rd);
343 struct GNUNET_GNSRECORD_EddsaBlock *edblock;
344 struct GNRBlockPS *gnr_block;
345 unsigned char nonce[crypto_secretbox_NONCEBYTES];
346 unsigned char skey[crypto_secretbox_KEYBYTES];
347 struct GNUNET_GNSRECORD_Data rdc[GNUNET_NZL (rd_count)];
348 struct GNUNET_TIME_Absolute now;
349
350 if (payload_len < 0)
351 {
352 GNUNET_break (0);
353 return GNUNET_SYSERR;
354 }
355 if (payload_len > GNUNET_GNSRECORD_MAX_BLOCK_SIZE)
356 {
357 GNUNET_break (0);
358 return GNUNET_SYSERR;
359 }
360 /* convert relative to absolute times */
361 now = GNUNET_TIME_absolute_get ();
362 for (unsigned int i = 0; i < rd_count; i++)
363 {
364 rdc[i] = rd[i];
365 if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
366 {
367 struct GNUNET_TIME_Relative t;
368
369 /* encrypted blocks must never have relative expiration times, convert! */
370 rdc[i].flags &= ~GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
371 t.rel_value_us = rdc[i].expiration_time;
372 rdc[i].expiration_time = GNUNET_TIME_absolute_add (now, t).abs_value_us;
373 }
374 }
375 /* serialize */
376 *block = GNUNET_malloc (sizeof (struct GNUNET_GNSRECORD_Block)
377 + payload_len + crypto_secretbox_MACBYTES);
378 (*block)->size = htonl(sizeof (struct GNUNET_GNSRECORD_Block)
379 + payload_len + crypto_secretbox_MACBYTES);
380 {
381 char payload[payload_len];
382
383 GNUNET_assert (payload_len ==
384 GNUNET_GNSRECORD_records_serialize (rd_count,
385 rdc,
386 payload_len,
387 payload));
388 gnr_block = GNUNET_malloc (sizeof (struct GNRBlockPS)
389 + payload_len
390 + crypto_secretbox_MACBYTES);
391 edblock = &(*block)->eddsa_block;
392 (*block)->type = htonl (GNUNET_GNSRECORD_TYPE_EDKEY);
393 gnr_block->purpose.size =
394 htonl (sizeof(struct GNRBlockPS)
395 + payload_len
396 + crypto_secretbox_MACBYTES);
397 gnr_block->purpose.purpose =
398 htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN);
399 gnr_block->expiration_time = GNUNET_TIME_absolute_hton (expire);
400 edblock->expiration_time = gnr_block->expiration_time;
401 /* encrypt and sign */
402 GNUNET_CRYPTO_eddsa_public_key_derive (pkey,
403 label,
404 "gns",
405 &edblock->derived_key);
406 GNR_derive_block_xsalsa_key (nonce,
407 skey,
408 label,
409 edblock->expiration_time.abs_value_us__,
410 pkey);
411 GNUNET_assert (GNUNET_OK ==
412 eddsa_symmetric_encrypt (payload,
413 payload_len,
414 skey,
415 nonce,
416 &edblock[1]));
417 GNUNET_memcpy (&gnr_block[1], &edblock[1],
418 payload_len + crypto_secretbox_MACBYTES);
419
420 GNUNET_CRYPTO_eddsa_sign_derived (key,
421 label,
422 "gns",
423 &gnr_block->purpose,
424 &edblock->signature);
425 }
426 return GNUNET_OK;
427}
428
429ssize_t
430GNUNET_GNSRECORD_block_calculate_size (const struct
431 GNUNET_IDENTITY_PrivateKey *key,
432 const struct GNUNET_GNSRECORD_Data *rd,
433 unsigned int rd_count)
434{
435 struct GNUNET_IDENTITY_PublicKey pkey;
436 ssize_t res = -1;
437
438 GNUNET_IDENTITY_key_get_public (key,
439 &pkey);
440 switch (ntohl (key->type))
441 {
442 case GNUNET_GNSRECORD_TYPE_PKEY:
443 res = block_get_size_ecdsa (rd, rd_count);
444 break;
445 case GNUNET_GNSRECORD_TYPE_EDKEY:
446 res = block_get_size_eddsa (rd, rd_count);
447 break;
448 default:
449 GNUNET_assert (0);
450 }
451 return res;
452
453}
454
455enum GNUNET_GenericReturnValue
456GNUNET_GNSRECORD_block_create (const struct GNUNET_IDENTITY_PrivateKey *key,
457 struct GNUNET_TIME_Absolute expire,
458 const char *label,
459 const struct GNUNET_GNSRECORD_Data *rd,
460 unsigned int rd_count,
461 struct GNUNET_GNSRECORD_Block **result)
462{
463 struct GNUNET_IDENTITY_PublicKey pkey;
464 enum GNUNET_GenericReturnValue res = GNUNET_SYSERR;
465 char *norm_label;
466
467 GNUNET_IDENTITY_key_get_public (key,
468 &pkey);
469 norm_label = GNUNET_GNSRECORD_string_normalize (label);
470
471 switch (ntohl (key->type))
472 {
473 case GNUNET_GNSRECORD_TYPE_PKEY:
474 res = block_create_ecdsa (&key->ecdsa_key,
475 &pkey.ecdsa_key,
476 expire,
477 norm_label,
478 rd,
479 rd_count,
480 result);
481 break;
482 case GNUNET_GNSRECORD_TYPE_EDKEY:
483 res = block_create_eddsa (&key->eddsa_key,
484 &pkey.eddsa_key,
485 expire,
486 norm_label,
487 rd,
488 rd_count,
489 result);
490 break;
491 default:
492 GNUNET_assert (0);
493 }
494 GNUNET_free (norm_label);
495 return res;
496}
497
498
499/**
500 * Line in cache mapping private keys to public keys.
501 */
502struct KeyCacheLine
503{
504 /**
505 * A private key.
506 */
507 struct GNUNET_CRYPTO_EcdsaPrivateKey key;
508
509 /**
510 * Associated public key.
511 */
512 struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
513};
514
515
516enum GNUNET_GenericReturnValue
517GNUNET_GNSRECORD_block_create2 (const struct GNUNET_IDENTITY_PrivateKey *pkey,
518 struct GNUNET_TIME_Absolute expire,
519 const char *label,
520 const struct GNUNET_GNSRECORD_Data *rd,
521 unsigned int rd_count,
522 struct GNUNET_GNSRECORD_Block **result)
523{
524 const struct GNUNET_CRYPTO_EcdsaPrivateKey *key;
525 struct GNUNET_CRYPTO_EddsaPublicKey edpubkey;
526 enum GNUNET_GenericReturnValue res = GNUNET_SYSERR;
527 char *norm_label;
528
529 norm_label = GNUNET_GNSRECORD_string_normalize (label);
530
531 if (GNUNET_IDENTITY_TYPE_ECDSA == ntohl (pkey->type))
532 {
533 key = &pkey->ecdsa_key;
534#define CSIZE 64
535 static struct KeyCacheLine cache[CSIZE];
536 struct KeyCacheLine *line;
537
538 line = &cache[(*(unsigned int *) key) % CSIZE];
539 if (0 != memcmp (&line->key,
540 key,
541 sizeof(*key)))
542 {
543 /* cache miss, recompute */
544 line->key = *key;
545 GNUNET_CRYPTO_ecdsa_key_get_public (key,
546 &line->pkey);
547 }
548#undef CSIZE
549 res = block_create_ecdsa (key,
550 &line->pkey,
551 expire,
552 norm_label,
553 rd,
554 rd_count,
555 result);
556 }
557 else if (GNUNET_IDENTITY_TYPE_EDDSA == ntohl (pkey->type))
558 {
559 GNUNET_CRYPTO_eddsa_key_get_public (&pkey->eddsa_key,
560 &edpubkey);
561 res = block_create_eddsa (&pkey->eddsa_key,
562 &edpubkey,
563 expire,
564 norm_label,
565 rd,
566 rd_count,
567 result);
568 }
569 GNUNET_free (norm_label);
570 return res;
571}
572
573
574/**
575 * Check if a signature is valid. This API is used by the GNS Block
576 * to validate signatures received from the network.
577 *
578 * @param block block to verify
579 * @return #GNUNET_OK if the signature is valid
580 */
581enum GNUNET_GenericReturnValue
582GNUNET_GNSRECORD_block_verify (const struct GNUNET_GNSRECORD_Block *block)
583{
584 struct GNRBlockPS *purp;
585 size_t payload_len = ntohl (block->size)
586 - sizeof (struct GNUNET_GNSRECORD_Block);
587 enum GNUNET_GenericReturnValue res = GNUNET_NO;
588 purp = GNUNET_malloc (sizeof (struct GNRBlockPS) + payload_len);
589 purp->purpose.size = htonl (sizeof (struct GNRBlockPS) + payload_len);
590 purp->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN);
591 GNUNET_memcpy (&purp[1],
592 &block[1],
593 payload_len);
594 switch (ntohl (block->type))
595 {
596 case GNUNET_GNSRECORD_TYPE_PKEY:
597 purp->expiration_time = block->ecdsa_block.expiration_time;
598 res = GNUNET_CRYPTO_ecdsa_verify_ (
599 GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN,
600 &purp->purpose,
601 &block->ecdsa_block.signature,
602 &block->ecdsa_block.derived_key);
603 break;
604 case GNUNET_GNSRECORD_TYPE_EDKEY:
605 purp->expiration_time = block->eddsa_block.expiration_time;
606 res = GNUNET_CRYPTO_eddsa_verify_ (
607 GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN,
608 &purp->purpose,
609 &block->eddsa_block.signature,
610 &block->eddsa_block.derived_key);
611 break;
612 default:
613 res = GNUNET_NO;
614 }
615 GNUNET_free (purp);
616 return res;
617}
618
619
620enum GNUNET_GenericReturnValue
621block_decrypt_ecdsa (const struct GNUNET_GNSRECORD_Block *block,
622 const struct
623 GNUNET_CRYPTO_EcdsaPublicKey *zone_key,
624 const char *label,
625 GNUNET_GNSRECORD_RecordCallback proc,
626 void *proc_cls)
627{
628 size_t payload_len = ntohl (block->size) - sizeof (struct
629 GNUNET_GNSRECORD_Block);
630 unsigned char ctr[GNUNET_CRYPTO_AES_KEY_LENGTH / 2];
631 unsigned char key[GNUNET_CRYPTO_AES_KEY_LENGTH];
632
633 if (ntohl (block->size) <
634 sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
635 + sizeof(struct GNUNET_TIME_AbsoluteNBO))
636 {
637 GNUNET_break_op (0);
638 return GNUNET_SYSERR;
639 }
640 GNR_derive_block_aes_key (ctr,
641 key,
642 label,
643 block->ecdsa_block.expiration_time.abs_value_us__,
644 zone_key);
645 {
646 char payload[payload_len];
647 unsigned int rd_count;
648
649 GNUNET_assert (payload_len ==
650 ecdsa_symmetric_decrypt (&block[1], payload_len,
651 key, ctr,
652 payload));
653 rd_count = GNUNET_GNSRECORD_records_deserialize_get_size (payload_len,
654 payload);
655 if (rd_count > 2048)
656 {
657 /* limit to sane value */
658 GNUNET_break_op (0);
659 return GNUNET_SYSERR;
660 }
661 {
662 struct GNUNET_GNSRECORD_Data rd[GNUNET_NZL (rd_count)];
663 unsigned int j;
664 struct GNUNET_TIME_Absolute now;
665
666 if (GNUNET_OK !=
667 GNUNET_GNSRECORD_records_deserialize (payload_len,
668 payload,
669 rd_count,
670 rd))
671 {
672 GNUNET_break_op (0);
673 return GNUNET_SYSERR;
674 }
675 /* hide expired records */
676 now = GNUNET_TIME_absolute_get ();
677 j = 0;
678 for (unsigned int i = 0; i < rd_count; i++)
679 {
680 if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
681 {
682 /* encrypted blocks must never have relative expiration times, skip! */
683 GNUNET_break_op (0);
684 continue;
685 }
686
687 if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_SHADOW_RECORD))
688 {
689 int include_record = GNUNET_YES;
690 /* Shadow record, figure out if we have a not expired active record */
691 for (unsigned int k = 0; k < rd_count; k++)
692 {
693 if (k == i)
694 continue;
695 if (rd[i].expiration_time < now.abs_value_us)
696 include_record = GNUNET_NO; /* Shadow record is expired */
697 if ((rd[k].record_type == rd[i].record_type) &&
698 (rd[k].expiration_time >= now.abs_value_us) &&
699 (0 == (rd[k].flags & GNUNET_GNSRECORD_RF_SHADOW_RECORD)))
700 {
701 include_record = GNUNET_NO; /* We have a non-expired, non-shadow record of the same type */
702 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
703 "Ignoring shadow record\n");
704 break;
705 }
706 }
707 if (GNUNET_YES == include_record)
708 {
709 rd[i].flags ^= GNUNET_GNSRECORD_RF_SHADOW_RECORD; /* Remove Flag */
710 if (j != i)
711 rd[j] = rd[i];
712 j++;
713 }
714 }
715 else if (rd[i].expiration_time >= now.abs_value_us)
716 {
717 /* Include this record */
718 if (j != i)
719 rd[j] = rd[i];
720 j++;
721 }
722 else
723 {
724 struct GNUNET_TIME_Absolute at;
725
726 at.abs_value_us = rd[i].expiration_time;
727 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
728 "Excluding record that expired %s (%llu ago)\n",
729 GNUNET_STRINGS_absolute_time_to_string (at),
730 (unsigned long long) rd[i].expiration_time
731 - now.abs_value_us);
732 }
733 }
734 rd_count = j;
735 if (NULL != proc)
736 proc (proc_cls,
737 rd_count,
738 (0 != rd_count) ? rd : NULL);
739 }
740 }
741 return GNUNET_OK;
742}
743
744
745enum GNUNET_GenericReturnValue
746block_decrypt_eddsa (const struct GNUNET_GNSRECORD_Block *block,
747 const struct
748 GNUNET_CRYPTO_EddsaPublicKey *zone_key,
749 const char *label,
750 GNUNET_GNSRECORD_RecordCallback proc,
751 void *proc_cls)
752{
753 size_t payload_len = ntohl (block->size) - sizeof (struct
754 GNUNET_GNSRECORD_Block);
755 unsigned char nonce[crypto_secretbox_NONCEBYTES];
756 unsigned char key[crypto_secretbox_KEYBYTES];
757
758 if (ntohl (block->size) <
759 sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
760 + sizeof(struct GNUNET_TIME_AbsoluteNBO))
761 {
762 GNUNET_break_op (0);
763 return GNUNET_SYSERR;
764 }
765 GNR_derive_block_xsalsa_key (nonce,
766 key,
767 label,
768 block->eddsa_block.expiration_time.abs_value_us__,
769 zone_key);
770 {
771 char payload[payload_len];
772 unsigned int rd_count;
773
774 GNUNET_assert (GNUNET_OK ==
775 eddsa_symmetric_decrypt (&block[1], payload_len,
776 key, nonce,
777 payload));
778 payload_len -= crypto_secretbox_MACBYTES;
779 rd_count = GNUNET_GNSRECORD_records_deserialize_get_size (payload_len,
780 payload);
781 if (rd_count > 2048)
782 {
783 /* limit to sane value */
784 GNUNET_break_op (0);
785 return GNUNET_SYSERR;
786 }
787 {
788 struct GNUNET_GNSRECORD_Data rd[GNUNET_NZL (rd_count)];
789 unsigned int j;
790 struct GNUNET_TIME_Absolute now;
791
792 if (GNUNET_OK !=
793 GNUNET_GNSRECORD_records_deserialize (payload_len,
794 payload,
795 rd_count,
796 rd))
797 {
798 GNUNET_break_op (0);
799 return GNUNET_SYSERR;
800 }
801 /* hide expired records */
802 now = GNUNET_TIME_absolute_get ();
803 j = 0;
804 for (unsigned int i = 0; i < rd_count; i++)
805 {
806 if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
807 {
808 /* encrypted blocks must never have relative expiration times, skip! */
809 GNUNET_break_op (0);
810 continue;
811 }
812
813 if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_SHADOW_RECORD))
814 {
815 int include_record = GNUNET_YES;
816 /* Shadow record, figure out if we have a not expired active record */
817 for (unsigned int k = 0; k < rd_count; k++)
818 {
819 if (k == i)
820 continue;
821 if (rd[i].expiration_time < now.abs_value_us)
822 include_record = GNUNET_NO; /* Shadow record is expired */
823 if ((rd[k].record_type == rd[i].record_type) &&
824 (rd[k].expiration_time >= now.abs_value_us) &&
825 (0 == (rd[k].flags & GNUNET_GNSRECORD_RF_SHADOW_RECORD)))
826 {
827 include_record = GNUNET_NO; /* We have a non-expired, non-shadow record of the same type */
828 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
829 "Ignoring shadow record\n");
830 break;
831 }
832 }
833 if (GNUNET_YES == include_record)
834 {
835 rd[i].flags ^= GNUNET_GNSRECORD_RF_SHADOW_RECORD; /* Remove Flag */
836 if (j != i)
837 rd[j] = rd[i];
838 j++;
839 }
840 }
841 else if (rd[i].expiration_time >= now.abs_value_us)
842 {
843 /* Include this record */
844 if (j != i)
845 rd[j] = rd[i];
846 j++;
847 }
848 else
849 {
850 struct GNUNET_TIME_Absolute at;
851
852 at.abs_value_us = rd[i].expiration_time;
853 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
854 "Excluding record that expired %s (%llu ago)\n",
855 GNUNET_STRINGS_absolute_time_to_string (at),
856 (unsigned long long) rd[i].expiration_time
857 - now.abs_value_us);
858 }
859 }
860 rd_count = j;
861 if (NULL != proc)
862 proc (proc_cls,
863 rd_count,
864 (0 != rd_count) ? rd : NULL);
865 }
866 }
867 return GNUNET_OK;
868}
869
870
871/**
872 * Decrypt block.
873 *
874 * @param block block to decrypt
875 * @param zone_key public key of the zone
876 * @param label the name for the records
877 * @param proc function to call with the result
878 * @param proc_cls closure for proc
879 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the block was
880 * not well-formed
881 */
882enum GNUNET_GenericReturnValue
883GNUNET_GNSRECORD_block_decrypt (const struct GNUNET_GNSRECORD_Block *block,
884 const struct
885 GNUNET_IDENTITY_PublicKey *zone_key,
886 const char *label,
887 GNUNET_GNSRECORD_RecordCallback proc,
888 void *proc_cls)
889{
890 enum GNUNET_GenericReturnValue res = GNUNET_SYSERR;
891 char *norm_label;
892
893 norm_label = GNUNET_GNSRECORD_string_normalize (label);
894 switch (ntohl (zone_key->type))
895 {
896 case GNUNET_IDENTITY_TYPE_ECDSA:
897 res = block_decrypt_ecdsa (block,
898 &zone_key->ecdsa_key, norm_label, proc,
899 proc_cls);
900 break;
901 case GNUNET_IDENTITY_TYPE_EDDSA:
902 res = block_decrypt_eddsa (block,
903 &zone_key->eddsa_key, norm_label, proc,
904 proc_cls);
905 break;
906 default:
907 res = GNUNET_SYSERR;
908 }
909 GNUNET_free (norm_label);
910 return res;
911}
912
913
914/**
915 * Calculate the DHT query for a given @a label in a given @a zone.
916 *
917 * @param zone private key of the zone
918 * @param label label of the record
919 * @param query hash to use for the query
920 */
921void
922GNUNET_GNSRECORD_query_from_private_key (const struct
923 GNUNET_IDENTITY_PrivateKey *zone,
924 const char *label,
925 struct GNUNET_HashCode *query)
926{
927 char *norm_label;
928 struct GNUNET_IDENTITY_PublicKey pub;
929
930 norm_label = GNUNET_GNSRECORD_string_normalize (label);
931 switch (ntohl (zone->type))
932 {
933 case GNUNET_GNSRECORD_TYPE_PKEY:
934 case GNUNET_GNSRECORD_TYPE_EDKEY:
935
936 GNUNET_IDENTITY_key_get_public (zone,
937 &pub);
938 GNUNET_GNSRECORD_query_from_public_key (&pub,
939 norm_label,
940 query);
941 break;
942 default:
943 GNUNET_assert (0);
944 }
945 GNUNET_free (norm_label);
946}
947
948
949/**
950 * Calculate the DHT query for a given @a label in a given @a zone.
951 * FIXME: We may want to plugin-ize this at some point.
952 *
953 * @param pub public key of the zone
954 * @param label label of the record
955 * @param query hash to use for the query
956 */
957void
958GNUNET_GNSRECORD_query_from_public_key (const struct
959 GNUNET_IDENTITY_PublicKey *pub,
960 const char *label,
961 struct GNUNET_HashCode *query)
962{
963 char *norm_label;
964 struct GNUNET_IDENTITY_PublicKey pd;
965
966 norm_label = GNUNET_GNSRECORD_string_normalize (label);
967
968 switch (ntohl (pub->type))
969 {
970 case GNUNET_GNSRECORD_TYPE_PKEY:
971 pd.type = pub->type;
972 GNUNET_CRYPTO_ecdsa_public_key_derive (&pub->ecdsa_key,
973 norm_label,
974 "gns",
975 &pd.ecdsa_key);
976 GNUNET_CRYPTO_hash (&pd.ecdsa_key,
977 sizeof (pd.ecdsa_key),
978 query);
979 break;
980 case GNUNET_GNSRECORD_TYPE_EDKEY:
981 pd.type = pub->type;
982 GNUNET_CRYPTO_eddsa_public_key_derive (&pub->eddsa_key,
983 norm_label,
984 "gns",
985 &(pd.eddsa_key));
986 GNUNET_CRYPTO_hash (&pd.eddsa_key,
987 sizeof (pd.eddsa_key),
988 query);
989 break;
990 default:
991 GNUNET_assert (0);
992 }
993 GNUNET_free (norm_label);
994}
995
996
997/* end of gnsrecord_crypto.c */