2 This file is part of GNUnet.
3 Copyright (C) 2009-2013, 2018 GNUnet e.V.
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
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
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
29 #include "gnunet_util_lib.h"
30 #include "gnunet_constants.h"
31 #include "gnunet_signatures.h"
32 #include "gnunet_arm_service.h"
33 #include "gnunet_gnsrecord_lib.h"
34 #include "gnunet_dnsparser_lib.h"
35 #include "gnunet_tun_lib.h"
38 #define LOG(kind,...) GNUNET_log_from (kind, "gnsrecord",__VA_ARGS__)
42 * Derive session key and iv from label and public key.
44 * @param iv initialization vector to initialize
45 * @param skey session key to initialize
46 * @param label label to use for KDF
47 * @param pub public key to use for KDF
50 derive_block_aes_key (struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
51 struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
53 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
55 static const char ctx_key[] = "gns-aes-ctx-key";
56 static const char ctx_iv[] = "gns-aes-ctx-iv";
58 GNUNET_CRYPTO_kdf (skey, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey),
59 pub, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
60 label, strlen (label),
61 ctx_key, strlen (ctx_key),
63 GNUNET_CRYPTO_kdf (iv, sizeof (struct GNUNET_CRYPTO_SymmetricInitializationVector),
64 pub, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
65 label, strlen (label),
66 ctx_iv, strlen (ctx_iv),
72 * Sign name and records
74 * @param key the private key
75 * @param pkey associated public key
76 * @param expire block expiration
77 * @param label the name for the records
78 * @param rd record data
79 * @param rd_count number of records
80 * @return NULL on error (block too large)
82 struct GNUNET_GNSRECORD_Block *
83 block_create (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
84 const struct GNUNET_CRYPTO_EcdsaPublicKey *pkey,
85 struct GNUNET_TIME_Absolute expire,
87 const struct GNUNET_GNSRECORD_Data *rd,
88 unsigned int rd_count)
90 size_t payload_len = GNUNET_GNSRECORD_records_get_size (rd_count,
92 char payload[sizeof (uint32_t) + payload_len];
93 struct GNUNET_GNSRECORD_Block *block;
94 struct GNUNET_CRYPTO_EcdsaPrivateKey *dkey;
95 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
96 struct GNUNET_CRYPTO_SymmetricSessionKey skey;
97 struct GNUNET_GNSRECORD_Data rdc[GNUNET_NZL(rd_count)];
98 uint32_t rd_count_nbo;
99 struct GNUNET_TIME_Absolute now;
101 if (payload_len > GNUNET_GNSRECORD_MAX_BLOCK_SIZE)
103 /* convert relative to absolute times */
104 now = GNUNET_TIME_absolute_get ();
105 for (unsigned int i=0;i<rd_count;i++)
108 if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
110 struct GNUNET_TIME_Relative t;
112 /* encrypted blocks must never have relative expiration times, convert! */
113 rdc[i].flags &= ~GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
114 t.rel_value_us = rdc[i].expiration_time;
115 rdc[i].expiration_time = GNUNET_TIME_absolute_add (now, t).abs_value_us;
119 rd_count_nbo = htonl (rd_count);
120 GNUNET_memcpy (payload,
123 GNUNET_assert (payload_len ==
124 GNUNET_GNSRECORD_records_serialize (rd_count,
127 &payload[sizeof (uint32_t)]));
128 block = GNUNET_malloc (sizeof (struct GNUNET_GNSRECORD_Block) +
131 block->purpose.size = htonl (sizeof (uint32_t) +
133 sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
134 sizeof (struct GNUNET_TIME_AbsoluteNBO));
135 block->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN);
136 block->expiration_time = GNUNET_TIME_absolute_hton (expire);
137 /* encrypt and sign */
138 dkey = GNUNET_CRYPTO_ecdsa_private_key_derive (key,
141 GNUNET_CRYPTO_ecdsa_key_get_public (dkey,
142 &block->derived_key);
143 derive_block_aes_key (&iv,
147 GNUNET_break (payload_len + sizeof (uint32_t) ==
148 GNUNET_CRYPTO_symmetric_encrypt (payload,
149 payload_len + sizeof (uint32_t),
154 GNUNET_CRYPTO_ecdsa_sign (dkey,
169 * Sign name and records
171 * @param key the private key
172 * @param expire block expiration
173 * @param label the name for the records
174 * @param rd record data
175 * @param rd_count number of records
176 * @return NULL on error (block too large)
178 struct GNUNET_GNSRECORD_Block *
179 GNUNET_GNSRECORD_block_create (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
180 struct GNUNET_TIME_Absolute expire,
182 const struct GNUNET_GNSRECORD_Data *rd,
183 unsigned int rd_count)
185 struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
187 GNUNET_CRYPTO_ecdsa_key_get_public (key,
189 return block_create (key,
199 * Line in cache mapping private keys to public keys.
206 struct GNUNET_CRYPTO_EcdsaPrivateKey key;
209 * Associated public key.
211 struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
217 * Sign name and records, cache derived public key (also keeps the
218 * private key in static memory, so do not use this function if
219 * keeping the private key in the process'es RAM is a major issue).
221 * @param key the private key
222 * @param expire block expiration
223 * @param label the name for the records
224 * @param rd record data
225 * @param rd_count number of records
226 * @return NULL on error (block too large)
228 struct GNUNET_GNSRECORD_Block *
229 GNUNET_GNSRECORD_block_create2 (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
230 struct GNUNET_TIME_Absolute expire,
232 const struct GNUNET_GNSRECORD_Data *rd,
233 unsigned int rd_count)
236 static struct KeyCacheLine cache[CSIZE];
237 struct KeyCacheLine *line;
239 line = &cache[(*(unsigned int *) key) % CSIZE];
240 if (0 != memcmp (&line->key,
244 /* cache miss, recompute */
246 GNUNET_CRYPTO_ecdsa_key_get_public (key,
250 return block_create (key,
261 * Check if a signature is valid. This API is used by the GNS Block
262 * to validate signatures received from the network.
264 * @param block block to verify
265 * @return #GNUNET_OK if the signature is valid
268 GNUNET_GNSRECORD_block_verify (const struct GNUNET_GNSRECORD_Block *block)
270 return GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN,
273 &block->derived_key);
280 * @param block block to decrypt
281 * @param zone_key public key of the zone
282 * @param label the name for the records
283 * @param proc function to call with the result
284 * @param proc_cls closure for proc
285 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the block was
289 GNUNET_GNSRECORD_block_decrypt (const struct GNUNET_GNSRECORD_Block *block,
290 const struct GNUNET_CRYPTO_EcdsaPublicKey *zone_key,
292 GNUNET_GNSRECORD_RecordCallback proc,
295 size_t payload_len = ntohl (block->purpose.size) -
296 sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) -
297 sizeof (struct GNUNET_TIME_AbsoluteNBO);
298 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
299 struct GNUNET_CRYPTO_SymmetricSessionKey skey;
301 if (ntohl (block->purpose.size) <
302 sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
303 sizeof (struct GNUNET_TIME_AbsoluteNBO))
306 return GNUNET_SYSERR;
308 derive_block_aes_key (&iv,
313 char payload[payload_len];
316 GNUNET_break (payload_len ==
317 GNUNET_CRYPTO_symmetric_decrypt (&block[1], payload_len,
320 GNUNET_memcpy (&rd_count,
323 rd_count = ntohl (rd_count);
326 /* limit to sane value */
328 return GNUNET_SYSERR;
331 struct GNUNET_GNSRECORD_Data rd[GNUNET_NZL(rd_count)];
333 struct GNUNET_TIME_Absolute now;
336 GNUNET_GNSRECORD_records_deserialize (payload_len - sizeof (uint32_t),
337 &payload[sizeof (uint32_t)],
342 return GNUNET_SYSERR;
344 /* hide expired records */
345 now = GNUNET_TIME_absolute_get ();
347 for (unsigned int i=0;i<rd_count;i++)
349 if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
351 /* encrypted blocks must never have relative expiration times, skip! */
356 if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_SHADOW_RECORD))
358 int include_record = GNUNET_YES;
359 /* Shadow record, figure out if we have a not expired active record */
360 for (unsigned int k=0;k<rd_count;k++)
364 if (rd[i].expiration_time < now.abs_value_us)
365 include_record = GNUNET_NO; /* Shadow record is expired */
366 if ( (rd[k].record_type == rd[i].record_type) &&
367 (rd[k].expiration_time >= now.abs_value_us) &&
368 (0 == (rd[k].flags & GNUNET_GNSRECORD_RF_SHADOW_RECORD)) )
370 include_record = GNUNET_NO; /* We have a non-expired, non-shadow record of the same type */
374 if (GNUNET_YES == include_record)
376 rd[i].flags ^= GNUNET_GNSRECORD_RF_SHADOW_RECORD; /* Remove Flag */
382 else if (rd[i].expiration_time >= now.abs_value_us)
384 /* Include this record */
394 (0 != rd_count) ? rd : NULL);
402 * Calculate the DHT query for a given @a label in a given @a zone.
404 * @param zone private key of the zone
405 * @param label label of the record
406 * @param query hash to use for the query
409 GNUNET_GNSRECORD_query_from_private_key (const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
411 struct GNUNET_HashCode *query)
413 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
415 GNUNET_CRYPTO_ecdsa_key_get_public (zone,
417 GNUNET_GNSRECORD_query_from_public_key (&pub,
424 * Calculate the DHT query for a given @a label in a given @a zone.
426 * @param pub public key of the zone
427 * @param label label of the record
428 * @param query hash to use for the query
431 GNUNET_GNSRECORD_query_from_public_key (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
433 struct GNUNET_HashCode *query)
435 struct GNUNET_CRYPTO_EcdsaPublicKey pd;
437 GNUNET_CRYPTO_ecdsa_public_key_derive (pub,
441 GNUNET_CRYPTO_hash (&pd,
447 /* end of gnsrecord_crypto.c */