sensor: proof-of-work and signing library functions
[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
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    * Buffer of the complete message to calculate the pow for
42    */
43   void *buf;
44
45   /**
46    * Size of buf
47    */
48   size_t buf_size;
49
50   /**
51    * Proof-of-work number
52    */
53   uint64_t pow;
54
55   /**
56    * Private key to be used for signing
57    */
58   struct GNUNET_CRYPTO_EddsaPrivateKey private_key;
59
60   /**
61    * Number of leading zeros required in the result hash
62    */
63   int matching_bits;
64
65   /**
66    * Callback function to call with the result
67    */
68   GNUNET_SENSOR_UTIL_pow_callback callback;
69
70   /**
71    * Closure for callback
72    */
73   void *callback_cls;
74
75   /**
76    * Task that calculates the proof-of-work
77    */
78   GNUNET_SCHEDULER_TaskIdentifier calculate_pow_task;
79
80 };
81
82
83 /**
84  * Calculate the scrypt hash
85  */
86 static void
87 pow_hash (const void *buf, size_t buf_len, struct GNUNET_HashCode *result)
88 {
89   GNUNET_break (0 ==
90                 gcry_kdf_derive (buf, buf_len, GCRY_KDF_SCRYPT,
91                                  1 /* subalgo */ ,
92                                  "gnunet-sensor-util-proof-of-work",
93                                  strlen ("gnunet-sensor-util-proof-of-work"), 2
94                                  /* iterations; keep cost of individual op small */
95                                  , sizeof (struct GNUNET_HashCode), result));
96 }
97
98
99 /**
100  * Count the leading zeroes in hash.
101  *
102  * @param hash to count leading zeros in
103  * @return the number of leading zero bits.
104  */
105 static unsigned int
106 count_leading_zeroes (const struct GNUNET_HashCode *hash)
107 {
108   unsigned int hash_count;
109
110   hash_count = 0;
111   while ((0 == GNUNET_CRYPTO_hash_get_bit (hash, hash_count)))
112     hash_count++;
113   return hash_count;
114 }
115
116
117 /**
118  * Check if the given proof-of-work is valid
119  */
120 static int
121 check_pow (void *msg, size_t msg_size, uint64_t pow, int matching_bits)
122 {
123   char buf[msg_size + sizeof (pow)] GNUNET_ALIGN;
124   struct GNUNET_HashCode result;
125
126   memcpy (buf, &pow, sizeof (pow));
127   memcpy (&buf[sizeof (pow)], msg, msg_size);
128   pow_hash (buf, sizeof (buf), &result);
129   return (count_leading_zeroes (&result) >=
130           matching_bits) ? GNUNET_YES : GNUNET_NO;
131 }
132
133
134 /**
135  * Task that checks if pow is correct, otherwise increments and reschedules itself
136  */
137 static void
138 calculate_pow (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
139 {
140   struct GNUNET_SENSOR_crypto_pow_context *cx = cls;
141   struct GNUNET_SENSOR_crypto_pow_block *result_block;
142   GNUNET_SENSOR_UTIL_pow_callback callback;
143   void *callback_cls;
144   int sign_result;
145
146   if (GNUNET_YES ==
147       check_pow (cx->buf, cx->buf_size, cx->pow, cx->matching_bits))
148   {
149     cx->calculate_pow_task = GNUNET_SCHEDULER_NO_TASK;
150     result_block =
151         GNUNET_malloc (sizeof (struct GNUNET_SENSOR_crypto_pow_block) +
152                        cx->buf_size);
153     result_block->purpose.purpose =
154         GNUNET_SIGNATURE_PURPOSE_SENSOR_ANOMALY_REPORT;
155     result_block->purpose.size =
156         sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + cx->buf_size;
157     memcpy (&result_block[1], cx->buf, cx->buf_size);
158     sign_result =
159         GNUNET_CRYPTO_eddsa_sign (&cx->private_key, &result_block->purpose,
160                                   &result_block->signature);
161     callback = cx->callback;
162     callback_cls = cx->callback_cls;
163     GNUNET_SENSOR_crypto_pow_sign_cancel (cx);
164     if (NULL != callback)
165       callback (callback_cls, (GNUNET_OK == sign_result) ? result_block : NULL);
166   }
167   cx->pow++;
168   cx->calculate_pow_task = GNUNET_SCHEDULER_add_now (&calculate_pow, cx);
169 }
170
171
172 /**
173  * Cancel an operation started by #GNUNET_SENSOR_crypto_pow_sign().
174  * Call only before callback function passed to #GNUNET_SENSOR_crypto_pow_sign()
175  * is called with the result.
176  */
177 void
178 GNUNET_SENSOR_crypto_pow_sign_cancel (struct GNUNET_SENSOR_crypto_pow_context
179                                       *cx)
180 {
181   if (NULL != cx->buf)
182   {
183     GNUNET_free (cx->buf);
184     cx->buf = NULL;
185   }
186   GNUNET_free (cx);
187 }
188
189
190 /**
191  * Calculate proof-of-work and sign a message.
192  * The result of all operations will be returned via the callback passed to this
193  * function. Note that the payload (msg) is copied to the result block.
194  *
195  * @param msg Message to calculate pow and sign
196  * @param msg_size size of msg
197  * @param timestamp Timestamp to add to the message to protect against replay attacks
198  * @param public_key Public key of the origin peer, to protect against redirect attacks
199  * @param private_key Private key of the origin peer to sign the result
200  * @param matching_bits Number of leading zeros required in the result hash
201  * @param callback Callback function to call with the result
202  * @param callback_cls Closure for callback
203  * @return Operation context
204  */
205 struct GNUNET_SENSOR_crypto_pow_context *
206 GNUNET_SENSOR_crypto_pow_sign (void *msg, size_t msg_size,
207                                struct GNUNET_TIME_Absolute *timestamp,
208                                struct GNUNET_CRYPTO_EddsaPublicKey *public_key,
209                                struct GNUNET_CRYPTO_EddsaPrivateKey
210                                *private_key, int matching_bits,
211                                GNUNET_SENSOR_UTIL_pow_callback callback,
212                                void *callback_cls)
213 {
214   struct GNUNET_SENSOR_crypto_pow_context *cx;
215   void *buf;
216   size_t buf_size;
217
218   buf_size = msg_size + sizeof (*timestamp) + sizeof (*public_key);
219   buf = GNUNET_malloc (buf_size);
220   cx = GNUNET_new (struct GNUNET_SENSOR_crypto_pow_context);
221
222   cx->buf = buf;
223   cx->buf_size = buf_size;
224   cx->pow = 0;
225   cx->private_key = *private_key;
226   cx->matching_bits = matching_bits;
227   cx->callback = callback;
228   cx->callback_cls = callback_cls;
229   cx->calculate_pow_task = GNUNET_SCHEDULER_add_now (&calculate_pow, cx);
230   return cx;
231 }
232
233
234 /**
235  * Verify that proof-of-work and signature in the given block are valid.
236  * If all valid, a pointer to the payload within the block is set and the size
237  * of the payload is returned.
238  *
239  * @param block The block received and needs to be verified
240  * @param matching_bits Number of leading zeros in the hash used to verify pow
241  * @param public_key Public key of the peer that sent this block
242  * @param payload Where to store the pointer to the payload
243  * @return Size of the payload
244  */
245 size_t
246 GNUNET_SENSOR_crypto_verify_pow_sign (struct GNUNET_SENSOR_crypto_pow_block *
247                                       block, int matching_bits,
248                                       struct GNUNET_CRYPTO_EddsaPublicKey *
249                                       public_key, void **payload)
250 {
251   void *msg;
252   size_t msg_size;
253
254   /* Check signature */
255   if (GNUNET_OK !=
256       GNUNET_CRYPTO_eddsa_verify (block->purpose.purpose, &block->purpose,
257                                   &block->signature, public_key))
258   {
259     LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid signature.\n");
260     return 0;
261   }
262   /* Check pow */
263   msg = &block[1];
264   msg_size =
265       block->purpose.size - sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose);
266   if (GNUNET_NO == check_pow (msg, msg_size, block->pow, matching_bits))
267   {
268     LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid proof-of-work.\n");
269     return 0;
270   }
271   *payload = msg;
272   return msg_size;
273 }