2 This file is part of GNUnet.
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 sensor/sensor_util_lib_crypto.c
23 * @brief senor utilities - crpyto related functions
24 * @author Omar Tarabai
28 #include "gnunet_util_lib.h"
29 #include "gnunet_sensor_util_lib.h"
30 #include "gnunet_signatures.h"
32 #define LOG(kind,...) GNUNET_log_from (kind, "sensor-util-crypto",__VA_ARGS__)
35 * Context of an operation performed by #GNUNET_SENSOR_crypto_pow_sign()
37 struct GNUNET_SENSOR_crypto_pow_context
46 * Private key to be used for signing
48 struct GNUNET_CRYPTO_EddsaPrivateKey private_key;
51 * Number of leading zeros required in the result hash
56 * Callback function to call with the result
58 GNUNET_SENSOR_UTIL_pow_callback callback;
61 * Closure for callback
66 * Task that calculates the proof-of-work
68 GNUNET_SCHEDULER_TaskIdentifier calculate_pow_task;
71 * Size of msg (allocated after this struct)
76 * Timestamp of the message
78 struct GNUNET_TIME_Absolute timestamp;
81 * Public key of the peer sending this message
83 struct GNUNET_CRYPTO_EddsaPublicKey public_key;
89 * Calculate the scrypt hash
92 pow_hash (const void *buf, size_t buf_len, struct GNUNET_HashCode *result)
95 gcry_kdf_derive (buf, buf_len, GCRY_KDF_SCRYPT,
97 "gnunet-sensor-util-proof-of-work",
98 strlen ("gnunet-sensor-util-proof-of-work"), 2
99 /* iterations; keep cost of individual op small */
100 , sizeof (struct GNUNET_HashCode), result));
105 * Count the leading zeroes in hash.
107 * @param hash to count leading zeros in
108 * @return the number of leading zero bits.
111 count_leading_zeroes (const struct GNUNET_HashCode *hash)
113 unsigned int hash_count;
116 while ((0 == GNUNET_CRYPTO_hash_get_bit (hash, hash_count)))
123 * Check if the given proof-of-work is valid
126 check_pow (void *msg, size_t msg_size, uint64_t pow, int matching_bits)
128 char buf[msg_size + sizeof (pow)] GNUNET_ALIGN;
129 struct GNUNET_HashCode result;
131 memcpy (buf, &pow, sizeof (pow));
132 memcpy (&buf[sizeof (pow)], msg, msg_size);
133 pow_hash (buf, sizeof (buf), &result);
134 return (count_leading_zeroes (&result) >=
135 matching_bits) ? GNUNET_YES : GNUNET_NO;
140 * Task that checks if pow is correct, otherwise increments and reschedules itself
143 calculate_pow (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
145 struct GNUNET_SENSOR_crypto_pow_context *cx = cls;
146 struct GNUNET_SENSOR_crypto_pow_block *result_block;
147 GNUNET_SENSOR_UTIL_pow_callback callback;
152 check_pow (&cx->timestamp,
153 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey) +
154 sizeof (struct GNUNET_TIME_Absolute) + cx->msg_size, cx->pow,
157 cx->calculate_pow_task = GNUNET_SCHEDULER_NO_TASK;
159 GNUNET_malloc (sizeof (struct GNUNET_SENSOR_crypto_pow_block) +
161 result_block->msg_size = cx->msg_size;
162 result_block->pow = cx->pow;
163 result_block->timestamp = cx->timestamp;
164 result_block->public_key = cx->public_key;
165 result_block->purpose.purpose =
166 htonl (GNUNET_SIGNATURE_PURPOSE_SENSOR_ANOMALY_REPORT);
167 result_block->purpose.size =
168 htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
169 sizeof (struct GNUNET_TIME_Absolute) +
170 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey) + cx->msg_size);
171 memcpy (&result_block[1], &cx[1], cx->msg_size);
173 GNUNET_CRYPTO_eddsa_sign (&cx->private_key, &result_block->purpose,
174 &result_block->signature);
175 callback = cx->callback;
176 callback_cls = cx->callback_cls;
177 GNUNET_SENSOR_crypto_pow_sign_cancel (cx);
178 if (NULL != callback)
179 callback (callback_cls, (GNUNET_OK == sign_result) ? result_block : NULL);
183 cx->calculate_pow_task = GNUNET_SCHEDULER_add_now (&calculate_pow, cx);
188 * Cancel an operation started by #GNUNET_SENSOR_crypto_pow_sign().
189 * Call only before callback function passed to #GNUNET_SENSOR_crypto_pow_sign()
190 * is called with the result.
193 GNUNET_SENSOR_crypto_pow_sign_cancel (struct GNUNET_SENSOR_crypto_pow_context
196 if (GNUNET_SCHEDULER_NO_TASK != cx->calculate_pow_task)
198 GNUNET_SCHEDULER_cancel (cx->calculate_pow_task);
199 cx->calculate_pow_task = GNUNET_SCHEDULER_NO_TASK;
207 * Calculate proof-of-work and sign a message.
208 * The result of all operations will be returned via the callback passed to this
209 * function. Note that the payload (msg) is copied to the result block.
211 * @param msg Message to calculate pow and sign
212 * @param msg_size size of msg
213 * @param timestamp Timestamp to add to the message to protect against replay attacks
214 * @param public_key Public key of the origin peer, to protect against redirect attacks
215 * @param private_key Private key of the origin peer to sign the result
216 * @param matching_bits Number of leading zeros required in the result hash
217 * @param callback Callback function to call with the result
218 * @param callback_cls Closure for callback
219 * @return Operation context
221 struct GNUNET_SENSOR_crypto_pow_context *
222 GNUNET_SENSOR_crypto_pow_sign (void *msg, size_t msg_size,
223 struct GNUNET_TIME_Absolute *timestamp,
224 struct GNUNET_CRYPTO_EddsaPublicKey *public_key,
225 struct GNUNET_CRYPTO_EddsaPrivateKey
226 *private_key, int matching_bits,
227 GNUNET_SENSOR_UTIL_pow_callback callback,
230 struct GNUNET_SENSOR_crypto_pow_context *cx;
232 cx = GNUNET_malloc (sizeof (struct GNUNET_SENSOR_crypto_pow_context) +
235 cx->timestamp = *timestamp;
236 cx->public_key = *public_key;
237 cx->msg_size = msg_size;
238 memcpy (&cx[1], msg, msg_size);
240 cx->private_key = *private_key;
241 cx->matching_bits = matching_bits;
242 cx->callback = callback;
243 cx->callback_cls = callback_cls;
244 cx->calculate_pow_task = GNUNET_SCHEDULER_add_now (&calculate_pow, cx);
250 * Verify that proof-of-work and signature in the given block are valid.
251 * If all valid, a pointer to the payload within the block is set and the size
252 * of the payload is returned.
254 * **VERY IMPORTANT** : You will still need to verify the timestamp yourself.
256 * @param block The block received and needs to be verified
257 * @param matching_bits Number of leading zeros in the hash used to verify pow
258 * @param public_key Public key of the peer that sent this block
259 * @param payload Where to store the pointer to the payload
260 * @return Size of the payload, 0 on error
263 GNUNET_SENSOR_crypto_verify_pow_sign (struct GNUNET_SENSOR_crypto_pow_block *
264 block, int matching_bits,
265 struct GNUNET_CRYPTO_EddsaPublicKey *
266 public_key, void **payload)
268 /* Check public key */
270 memcmp (public_key, &block->public_key,
271 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
273 LOG (GNUNET_ERROR_TYPE_WARNING, "Public key mismatch.\n");
276 /* Check signature */
278 GNUNET_CRYPTO_eddsa_verify
279 (GNUNET_SIGNATURE_PURPOSE_SENSOR_ANOMALY_REPORT, &block->purpose,
280 &block->signature, public_key))
282 LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid signature.\n");
287 check_pow (&block->timestamp,
288 sizeof (struct GNUNET_TIME_Absolute) +
289 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey) + block->msg_size,
290 block->pow, matching_bits))
292 LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid proof-of-work.\n");
295 *payload = &block[1];
296 return block->msg_size;