2 This file is part of GNUnet.
3 (C) 2009-2013 Christian Grothoff (and other contributing authors)
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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, 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 expire block expiration
76 * @param label the name for the records
77 * @param rd record data
78 * @param rd_count number of records
79 * @return NULL on error (block too large)
81 struct GNUNET_GNSRECORD_Block *
82 GNUNET_GNSRECORD_block_create (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
83 struct GNUNET_TIME_Absolute expire,
85 const struct GNUNET_GNSRECORD_Data *rd,
86 unsigned int rd_count)
88 size_t payload_len = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
89 char payload[sizeof (uint32_t) + payload_len];
90 struct GNUNET_GNSRECORD_Block *block;
91 struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
92 struct GNUNET_CRYPTO_EcdsaPrivateKey *dkey;
93 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
94 struct GNUNET_CRYPTO_SymmetricSessionKey skey;
95 struct GNUNET_GNSRECORD_Data rdc[rd_count];
96 uint32_t rd_count_nbo;
98 struct GNUNET_TIME_Absolute now;
100 if (payload_len > GNUNET_GNSRECORD_MAX_BLOCK_SIZE)
102 /* convert relative to absolute times */
103 now = GNUNET_TIME_absolute_get ();
104 for (i=0;i<rd_count;i++)
107 if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
109 /* encrypted blocks must never have relative expiration times, convert! */
110 rdc[i].flags &= ~GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
111 rdc[i].expiration_time += now.abs_value_us;
115 rd_count_nbo = htonl (rd_count);
116 memcpy (payload, &rd_count_nbo, sizeof (uint32_t));
117 GNUNET_assert (payload_len ==
118 GNUNET_GNSRECORD_records_serialize (rd_count, rdc,
119 payload_len, &payload[sizeof (uint32_t)]));
120 block = GNUNET_malloc (sizeof (struct GNUNET_GNSRECORD_Block) +
121 sizeof (uint32_t) + payload_len);
122 block->purpose.size = htonl (sizeof (uint32_t) + payload_len +
123 sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
124 sizeof (struct GNUNET_TIME_AbsoluteNBO));
125 block->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN);
126 block->expiration_time = GNUNET_TIME_absolute_hton (expire);
127 /* encrypt and sign */
128 dkey = GNUNET_CRYPTO_ecdsa_private_key_derive (key,
131 GNUNET_CRYPTO_ecdsa_key_get_public (dkey,
132 &block->derived_key);
133 GNUNET_CRYPTO_ecdsa_key_get_public (key,
135 derive_block_aes_key (&iv, &skey, label, &pkey);
136 GNUNET_break (payload_len + sizeof (uint32_t) ==
137 GNUNET_CRYPTO_symmetric_encrypt (payload, payload_len + sizeof (uint32_t),
141 GNUNET_CRYPTO_ecdsa_sign (dkey,
156 * Check if a signature is valid. This API is used by the GNS Block
157 * to validate signatures received from the network.
159 * @param block block to verify
160 * @return #GNUNET_OK if the signature is valid
163 GNUNET_GNSRECORD_block_verify (const struct GNUNET_GNSRECORD_Block *block)
165 return GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN,
168 &block->derived_key);
175 * @param block block to decrypt
176 * @param zone_key public key of the zone
177 * @param label the name for the records
178 * @param proc function to call with the result
179 * @param proc_cls closure for proc
180 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the block was
184 GNUNET_GNSRECORD_block_decrypt (const struct GNUNET_GNSRECORD_Block *block,
185 const struct GNUNET_CRYPTO_EcdsaPublicKey *zone_key,
187 GNUNET_GNSRECORD_RecordCallback proc,
190 size_t payload_len = ntohl (block->purpose.size) -
191 sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) -
192 sizeof (struct GNUNET_TIME_AbsoluteNBO);
193 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
194 struct GNUNET_CRYPTO_SymmetricSessionKey skey;
196 if (ntohl (block->purpose.size) <
197 sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
198 sizeof (struct GNUNET_TIME_AbsoluteNBO))
201 return GNUNET_SYSERR;
203 derive_block_aes_key (&iv, &skey, label, zone_key);
205 char payload[payload_len];
208 GNUNET_break (payload_len ==
209 GNUNET_CRYPTO_symmetric_decrypt (&block[1], payload_len,
215 rd_count = ntohl (rd_count);
218 /* limit to sane value */
220 return GNUNET_SYSERR;
223 struct GNUNET_GNSRECORD_Data rd[rd_count];
226 struct GNUNET_TIME_Absolute now;
229 GNUNET_GNSRECORD_records_deserialize (payload_len - sizeof (uint32_t),
230 &payload[sizeof (uint32_t)],
235 return GNUNET_SYSERR;
237 /* hide expired records */
238 now = GNUNET_TIME_absolute_get ();
240 for (i=0;i<rd_count;i++)
242 if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
244 /* encrypted blocks must never have relative expiration times, skip! */
248 if (rd[i].expiration_time >= now.abs_value_us)
257 proc (proc_cls, rd_count, (0 != rd_count) ? rd : NULL);
265 * Calculate the DHT query for a given @a label in a given @a zone.
267 * @param zone private key of the zone
268 * @param label label of the record
269 * @param query hash to use for the query
272 GNUNET_GNSRECORD_query_from_private_key (const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
274 struct GNUNET_HashCode *query)
276 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
278 GNUNET_CRYPTO_ecdsa_key_get_public (zone, &pub);
279 GNUNET_GNSRECORD_query_from_public_key (&pub, label, query);
284 * Calculate the DHT query for a given @a label in a given @a zone.
286 * @param pub public key of the zone
287 * @param label label of the record
288 * @param query hash to use for the query
291 GNUNET_GNSRECORD_query_from_public_key (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
293 struct GNUNET_HashCode *query)
295 struct GNUNET_CRYPTO_EcdsaPublicKey pd;
297 GNUNET_CRYPTO_ecdsa_public_key_derive (pub, label, "gns", &pd);
298 GNUNET_CRYPTO_hash (&pd, sizeof (pd), query);
302 /* end of gnsrecord_crypto.c */