sensor: test case for proof-of-work + fixes
[oweals/gnunet.git] / src / sensor / sensor_util_lib_crypto.c
1 /*
2      This file is part of GNUnet.
3      (C)
4
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.
9
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.
14
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.
19 */
20
21 /**
22  * @file sensor/sensor_util_lib_crypto.c
23  * @brief senor utilities - crpyto related functions
24  * @author Omar Tarabai
25  */
26 #include <inttypes.h>
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_sensor_util_lib.h"
30 #include "gnunet_signatures.h"
31
32 #define LOG(kind,...) GNUNET_log_from (kind, "sensor-util-crypto",__VA_ARGS__)
33
34 /**
35  * Context of an operation performed by #GNUNET_SENSOR_crypto_pow_sign()
36  */
37 struct GNUNET_SENSOR_crypto_pow_context
38 {
39
40   /**
41    * Proof-of-work value
42    */
43   uint64_t pow;
44
45   /**
46    * Private key to be used for signing
47    */
48   struct GNUNET_CRYPTO_EddsaPrivateKey private_key;
49
50   /**
51    * Number of leading zeros required in the result hash
52    */
53   int matching_bits;
54
55   /**
56    * Callback function to call with the result
57    */
58   GNUNET_SENSOR_UTIL_pow_callback callback;
59
60   /**
61    * Closure for callback
62    */
63   void *callback_cls;
64
65   /**
66    * Task that calculates the proof-of-work
67    */
68   GNUNET_SCHEDULER_TaskIdentifier calculate_pow_task;
69
70   /**
71    * Size of msg (allocated after this struct)
72    */
73   size_t msg_size;
74
75   /**
76    * Timestamp of the message
77    */
78   struct GNUNET_TIME_Absolute timestamp;
79
80   /**
81    * Public key of the peer sending this message
82    */
83   struct GNUNET_CRYPTO_EddsaPublicKey public_key;
84
85 };
86
87
88 /**
89  * Calculate the scrypt hash
90  */
91 static void
92 pow_hash (const void *buf, size_t buf_len, struct GNUNET_HashCode *result)
93 {
94   GNUNET_break (0 ==
95                 gcry_kdf_derive (buf, buf_len, GCRY_KDF_SCRYPT,
96                                  1 /* subalgo */ ,
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));
101 }
102
103
104 /**
105  * Count the leading zeroes in hash.
106  *
107  * @param hash to count leading zeros in
108  * @return the number of leading zero bits.
109  */
110 static unsigned int
111 count_leading_zeroes (const struct GNUNET_HashCode *hash)
112 {
113   unsigned int hash_count;
114
115   hash_count = 0;
116   while ((0 == GNUNET_CRYPTO_hash_get_bit (hash, hash_count)))
117     hash_count++;
118   return hash_count;
119 }
120
121
122 /**
123  * Check if the given proof-of-work is valid
124  */
125 static int
126 check_pow (void *msg, size_t msg_size, uint64_t pow, int matching_bits)
127 {
128   char buf[msg_size + sizeof (pow)] GNUNET_ALIGN;
129   struct GNUNET_HashCode result;
130
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;
137 }
138
139
140 /**
141  * Task that checks if pow is correct, otherwise increments and reschedules itself
142  */
143 static void
144 calculate_pow (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
145 {
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;
149   void *callback_cls;
150   int sign_result;
151
152   if (GNUNET_YES ==
153       check_pow (&cx->timestamp,
154                  sizeof (struct GNUNET_CRYPTO_EddsaPublicKey) +
155                  sizeof (struct GNUNET_TIME_Absolute) + cx->msg_size, cx->pow,
156                  cx->matching_bits))
157   {
158     cx->calculate_pow_task = GNUNET_SCHEDULER_NO_TASK;
159     result_block =
160         GNUNET_malloc (sizeof (struct GNUNET_SENSOR_crypto_pow_block) +
161                        cx->msg_size);
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);
173     sign_result =
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);
181   }
182   cx->pow++;
183   cx->calculate_pow_task = GNUNET_SCHEDULER_add_now (&calculate_pow, cx);
184 }
185
186
187 /**
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.
191  */
192 void
193 GNUNET_SENSOR_crypto_pow_sign_cancel (struct GNUNET_SENSOR_crypto_pow_context
194                                       *cx)
195 {
196   GNUNET_free (cx);
197 }
198
199
200 /**
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.
204  *
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
214  */
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,
222                                void *callback_cls)
223 {
224   struct GNUNET_SENSOR_crypto_pow_context *cx;
225
226   cx = GNUNET_malloc (sizeof (struct GNUNET_SENSOR_crypto_pow_context) +
227                       msg_size);
228
229   cx->timestamp = *timestamp;
230   cx->public_key = *public_key;
231   cx->msg_size = msg_size;
232   memcpy (&cx[1], msg, msg_size);
233   cx->pow = 0;
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);
239   return cx;
240 }
241
242
243 /**
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.
247  *
248  * **VERY IMPORTANT** : You will still need to verify the timestamp yourself.
249  *
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
256  */
257 size_t
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,
262                                       void **payload)
263 {
264   /* Check public key */
265   if (0 != memcmp (public_key, &block->public_key, sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
266   {
267     LOG (GNUNET_ERROR_TYPE_WARNING, "Public key mismatch.\n");
268     return 0;
269   }
270   /* Check signature */
271   if (GNUNET_OK !=
272       GNUNET_CRYPTO_eddsa_verify (purpose, &block->purpose,
273                                   &block->signature, public_key))
274   {
275     LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid signature.\n");
276     return 0;
277   }
278   /* Check pow */
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))
282   {
283     LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid proof-of-work.\n");
284     return 0;
285   }
286   *payload = &block[1];
287   return block->msg_size;
288 }