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);
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
201 * Calculate proof-of-work and sign a message.
202 * The result of all operations will be returned via the callback passed to this
203 * function. Note that the payload (msg) is copied to the result block.
205 * @param msg Message to calculate pow and sign
206 * @param msg_size size of msg
207 * @param timestamp Timestamp to add to the message to protect against replay attacks
208 * @param public_key Public key of the origin peer, to protect against redirect attacks
209 * @param private_key Private key of the origin peer to sign the result
210 * @param matching_bits Number of leading zeros required in the result hash
211 * @param callback Callback function to call with the result
212 * @param callback_cls Closure for callback
213 * @return Operation context
215 struct GNUNET_SENSOR_crypto_pow_context *
216 GNUNET_SENSOR_crypto_pow_sign (void *msg, size_t msg_size,
217 struct GNUNET_TIME_Absolute *timestamp,
218 struct GNUNET_CRYPTO_EddsaPublicKey *public_key,
219 struct GNUNET_CRYPTO_EddsaPrivateKey
220 *private_key, int matching_bits,
221 GNUNET_SENSOR_UTIL_pow_callback callback,
224 struct GNUNET_SENSOR_crypto_pow_context *cx;
226 cx = GNUNET_malloc (sizeof (struct GNUNET_SENSOR_crypto_pow_context) +
229 cx->timestamp = *timestamp;
230 cx->public_key = *public_key;
231 cx->msg_size = msg_size;
232 memcpy (&cx[1], msg, msg_size);
234 cx->private_key = *private_key;
235 cx->matching_bits = matching_bits;
236 cx->callback = callback;
237 cx->callback_cls = callback_cls;
238 cx->calculate_pow_task = GNUNET_SCHEDULER_add_now (&calculate_pow, cx);
244 * Verify that proof-of-work and signature in the given block are valid.
245 * If all valid, a pointer to the payload within the block is set and the size
246 * of the payload is returned.
248 * **VERY IMPORTANT** : You will still need to verify the timestamp yourself.
250 * @param block The block received and needs to be verified
251 * @param matching_bits Number of leading zeros in the hash used to verify pow
252 * @param public_key Public key of the peer that sent this block
253 * @param purpose Expected signing purpose
254 * @param payload Where to store the pointer to the payload
255 * @return Size of the payload
258 GNUNET_SENSOR_crypto_verify_pow_sign (struct GNUNET_SENSOR_crypto_pow_block *
259 block, int matching_bits,
260 struct GNUNET_CRYPTO_EddsaPublicKey *
261 public_key, uint32_t purpose,
264 /* Check public key */
265 if (0 != memcmp (public_key, &block->public_key, sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
267 LOG (GNUNET_ERROR_TYPE_WARNING, "Public key mismatch.\n");
270 /* Check signature */
272 GNUNET_CRYPTO_eddsa_verify (purpose, &block->purpose,
273 &block->signature, public_key))
275 LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid signature.\n");
279 if (GNUNET_NO == check_pow (&block->timestamp,
280 sizeof (struct GNUNET_TIME_Absolute) +
281 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey) + block->msg_size, block->pow, matching_bits))
283 LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid proof-of-work.\n");
286 *payload = &block[1];
287 return block->msg_size;