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 struct GNUNET_SCHEDULER_Task * 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;
151 if (0 == cx->pow % 1000)
152 LOG (GNUNET_ERROR_TYPE_DEBUG, "Checking pow %" PRIu64 ".\n", cx->pow);
154 check_pow (&cx->timestamp,
155 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey) +
156 sizeof (struct GNUNET_TIME_Absolute) + cx->msg_size, cx->pow,
159 LOG (GNUNET_ERROR_TYPE_DEBUG, "Found pow %" PRIu64 ".\n", cx->pow);
160 cx->calculate_pow_task = NULL;
162 GNUNET_malloc (sizeof (struct GNUNET_SENSOR_crypto_pow_block) +
164 result_block->msg_size = cx->msg_size;
165 result_block->pow = cx->pow;
166 result_block->timestamp = cx->timestamp;
167 result_block->public_key = cx->public_key;
168 result_block->purpose.purpose =
169 htonl (GNUNET_SIGNATURE_PURPOSE_SENSOR_ANOMALY_REPORT);
170 result_block->purpose.size =
171 htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
172 sizeof (struct GNUNET_TIME_Absolute) +
173 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey) + cx->msg_size);
174 memcpy (&result_block[1], &cx[1], cx->msg_size);
176 GNUNET_CRYPTO_eddsa_sign (&cx->private_key, &result_block->purpose,
177 &result_block->signature);
178 callback = cx->callback;
179 callback_cls = cx->callback_cls;
180 GNUNET_SENSOR_crypto_pow_sign_cancel (cx);
181 if (NULL != callback)
182 callback (callback_cls, (GNUNET_OK == sign_result) ? result_block : NULL);
183 GNUNET_free (result_block);
187 cx->calculate_pow_task = GNUNET_SCHEDULER_add_now (&calculate_pow, cx);
192 * Cancel an operation started by #GNUNET_SENSOR_crypto_pow_sign().
193 * Call only before callback function passed to #GNUNET_SENSOR_crypto_pow_sign()
194 * is called with the result.
197 GNUNET_SENSOR_crypto_pow_sign_cancel (struct GNUNET_SENSOR_crypto_pow_context
200 if (NULL != cx->calculate_pow_task)
202 GNUNET_SCHEDULER_cancel (cx->calculate_pow_task);
203 cx->calculate_pow_task = NULL;
211 * Calculate proof-of-work and sign a message.
212 * The result of all operations will be returned via the callback passed to this
213 * function. Note that the payload (msg) is copied to the result block.
215 * @param msg Message to calculate pow and sign
216 * @param msg_size size of msg
217 * @param timestamp Timestamp to add to the message to protect against replay attacks
218 * @param public_key Public key of the origin peer, to protect against redirect attacks
219 * @param private_key Private key of the origin peer to sign the result
220 * @param matching_bits Number of leading zeros required in the result hash
221 * @param callback Callback function to call with the result
222 * @param callback_cls Closure for callback
223 * @return Operation context
225 struct GNUNET_SENSOR_crypto_pow_context *
226 GNUNET_SENSOR_crypto_pow_sign (void *msg, size_t msg_size,
227 struct GNUNET_TIME_Absolute *timestamp,
228 struct GNUNET_CRYPTO_EddsaPublicKey *public_key,
229 struct GNUNET_CRYPTO_EddsaPrivateKey
230 *private_key, int matching_bits,
231 GNUNET_SENSOR_UTIL_pow_callback callback,
234 struct GNUNET_SENSOR_crypto_pow_context *cx;
236 cx = GNUNET_malloc (sizeof (struct GNUNET_SENSOR_crypto_pow_context) +
239 cx->timestamp = *timestamp;
240 cx->public_key = *public_key;
241 cx->msg_size = msg_size;
242 memcpy (&cx[1], msg, msg_size);
244 cx->private_key = *private_key;
245 cx->matching_bits = matching_bits;
246 cx->callback = callback;
247 cx->callback_cls = callback_cls;
248 cx->calculate_pow_task = GNUNET_SCHEDULER_add_now (&calculate_pow, cx);
254 * Verify that proof-of-work and signature in the given block are valid.
255 * If all valid, a pointer to the payload within the block is set and the size
256 * of the payload is returned.
258 * **VERY IMPORTANT** : You will still need to verify the timestamp yourself.
260 * @param block The block received and needs to be verified
261 * @param matching_bits Number of leading zeros in the hash used to verify pow
262 * @param public_key Public key of the peer that sent this block
263 * @param payload Where to store the pointer to the payload
264 * @return Size of the payload, 0 on error
267 GNUNET_SENSOR_crypto_verify_pow_sign (struct GNUNET_SENSOR_crypto_pow_block *
268 block, int matching_bits,
269 struct GNUNET_CRYPTO_EddsaPublicKey *
270 public_key, void **payload)
272 /* Check public key */
274 memcmp (public_key, &block->public_key,
275 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
277 LOG (GNUNET_ERROR_TYPE_WARNING, "Public key mismatch.\n");
280 /* Check signature */
282 GNUNET_CRYPTO_eddsa_verify
283 (GNUNET_SIGNATURE_PURPOSE_SENSOR_ANOMALY_REPORT, &block->purpose,
284 &block->signature, public_key))
286 LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid signature.\n");
291 check_pow (&block->timestamp,
292 sizeof (struct GNUNET_TIME_Absolute) +
293 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey) + block->msg_size,
294 block->pow, matching_bits))
296 LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid proof-of-work.\n");
299 *payload = &block[1];
300 return block->msg_size;