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 LOG (GNUNET_ERROR_TYPE_DEBUG, "Msg size: %" PRIu64 ".\n", msg_size);
132 memcpy (buf, &pow, sizeof (pow));
133 memcpy (&buf[sizeof (pow)], msg, msg_size);
134 pow_hash (buf, sizeof (buf), &result);
135 return (count_leading_zeroes (&result) >=
136 matching_bits) ? GNUNET_YES : GNUNET_NO;
141 * Task that checks if pow is correct, otherwise increments and reschedules itself
144 calculate_pow (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
146 struct GNUNET_SENSOR_crypto_pow_context *cx = cls;
147 struct GNUNET_SENSOR_crypto_pow_block *result_block;
148 GNUNET_SENSOR_UTIL_pow_callback callback;
153 check_pow (&cx->timestamp,
154 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey) +
155 sizeof (struct GNUNET_TIME_Absolute) + cx->msg_size, cx->pow,
158 cx->calculate_pow_task = GNUNET_SCHEDULER_NO_TASK;
160 GNUNET_malloc (sizeof (struct GNUNET_SENSOR_crypto_pow_block) +
162 result_block->msg_size = cx->msg_size;
163 result_block->pow = cx->pow;
164 result_block->timestamp = cx->timestamp;
165 result_block->public_key = cx->public_key;
166 result_block->purpose.purpose =
167 htonl (GNUNET_SIGNATURE_PURPOSE_SENSOR_ANOMALY_REPORT);
168 result_block->purpose.size =
169 htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
170 sizeof (struct GNUNET_TIME_Absolute) +
171 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey) + cx->msg_size);
172 memcpy (&result_block[1], &cx[1], cx->msg_size);
174 GNUNET_CRYPTO_eddsa_sign (&cx->private_key, &result_block->purpose,
175 &result_block->signature);
176 callback = cx->callback;
177 callback_cls = cx->callback_cls;
178 GNUNET_SENSOR_crypto_pow_sign_cancel (cx);
179 if (NULL != callback)
180 callback (callback_cls, (GNUNET_OK == sign_result) ? result_block : NULL);
184 cx->calculate_pow_task = GNUNET_SCHEDULER_add_now (&calculate_pow, cx);
189 * Cancel an operation started by #GNUNET_SENSOR_crypto_pow_sign().
190 * Call only before callback function passed to #GNUNET_SENSOR_crypto_pow_sign()
191 * is called with the result.
194 GNUNET_SENSOR_crypto_pow_sign_cancel (struct GNUNET_SENSOR_crypto_pow_context
197 if (GNUNET_SCHEDULER_NO_TASK != cx->calculate_pow_task)
199 GNUNET_SCHEDULER_cancel (cx->calculate_pow_task);
200 cx->calculate_pow_task = GNUNET_SCHEDULER_NO_TASK;
208 * Calculate proof-of-work and sign a message.
209 * The result of all operations will be returned via the callback passed to this
210 * function. Note that the payload (msg) is copied to the result block.
212 * @param msg Message to calculate pow and sign
213 * @param msg_size size of msg
214 * @param timestamp Timestamp to add to the message to protect against replay attacks
215 * @param public_key Public key of the origin peer, to protect against redirect attacks
216 * @param private_key Private key of the origin peer to sign the result
217 * @param matching_bits Number of leading zeros required in the result hash
218 * @param callback Callback function to call with the result
219 * @param callback_cls Closure for callback
220 * @return Operation context
222 struct GNUNET_SENSOR_crypto_pow_context *
223 GNUNET_SENSOR_crypto_pow_sign (void *msg, size_t msg_size,
224 struct GNUNET_TIME_Absolute *timestamp,
225 struct GNUNET_CRYPTO_EddsaPublicKey *public_key,
226 struct GNUNET_CRYPTO_EddsaPrivateKey
227 *private_key, int matching_bits,
228 GNUNET_SENSOR_UTIL_pow_callback callback,
231 struct GNUNET_SENSOR_crypto_pow_context *cx;
233 cx = GNUNET_malloc (sizeof (struct GNUNET_SENSOR_crypto_pow_context) +
236 cx->timestamp = *timestamp;
237 cx->public_key = *public_key;
238 cx->msg_size = msg_size;
239 memcpy (&cx[1], msg, msg_size);
241 cx->private_key = *private_key;
242 cx->matching_bits = matching_bits;
243 cx->callback = callback;
244 cx->callback_cls = callback_cls;
245 cx->calculate_pow_task = GNUNET_SCHEDULER_add_now (&calculate_pow, cx);
251 * Verify that proof-of-work and signature in the given block are valid.
252 * If all valid, a pointer to the payload within the block is set and the size
253 * of the payload is returned.
255 * **VERY IMPORTANT** : You will still need to verify the timestamp yourself.
257 * @param block The block received and needs to be verified
258 * @param matching_bits Number of leading zeros in the hash used to verify pow
259 * @param public_key Public key of the peer that sent this block
260 * @param purpose Expected signing purpose
261 * @param payload Where to store the pointer to the payload
262 * @return Size of the payload
265 GNUNET_SENSOR_crypto_verify_pow_sign (struct GNUNET_SENSOR_crypto_pow_block *
266 block, int matching_bits,
267 struct GNUNET_CRYPTO_EddsaPublicKey *
268 public_key, uint32_t purpose,
271 /* Check public key */
273 memcmp (public_key, &block->public_key,
274 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
276 LOG (GNUNET_ERROR_TYPE_WARNING, "Public key mismatch.\n");
279 /* Check signature */
281 GNUNET_CRYPTO_eddsa_verify (purpose, &block->purpose, &block->signature,
284 LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid signature.\n");
289 check_pow (&block->timestamp,
290 sizeof (struct GNUNET_TIME_Absolute) +
291 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey) + block->msg_size,
292 block->pow, matching_bits))
294 LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid proof-of-work.\n");
297 *payload = &block[1];
298 return block->msg_size;