diff options
Diffstat (limited to 'src/contrib/service/secretsharing/secretsharing_api.c')
-rw-r--r-- | src/contrib/service/secretsharing/secretsharing_api.c | 492 |
1 files changed, 492 insertions, 0 deletions
diff --git a/src/contrib/service/secretsharing/secretsharing_api.c b/src/contrib/service/secretsharing/secretsharing_api.c new file mode 100644 index 000000000..595af751f --- /dev/null +++ b/src/contrib/service/secretsharing/secretsharing_api.c | |||
@@ -0,0 +1,492 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2012, 2016 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your 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 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file secretsharing/secretsharing_api.c | ||
23 | * @brief | ||
24 | * @author Florian Dold | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_util_lib.h" | ||
28 | #include "gnunet_secretsharing_service.h" | ||
29 | #include "secretsharing.h" | ||
30 | #include <gcrypt.h> | ||
31 | |||
32 | |||
33 | #define LOG(kind, ...) GNUNET_log_from (kind, "secretsharing-api", __VA_ARGS__) | ||
34 | |||
35 | /** | ||
36 | * Session that will eventually establish a shared secred between | ||
37 | * the involved peers and allow encryption and cooperative decryption. | ||
38 | */ | ||
39 | struct GNUNET_SECRETSHARING_Session | ||
40 | { | ||
41 | /** | ||
42 | * Message queue for @e client. | ||
43 | */ | ||
44 | struct GNUNET_MQ_Handle *mq; | ||
45 | |||
46 | /** | ||
47 | * Called when the secret sharing is done. | ||
48 | */ | ||
49 | GNUNET_SECRETSHARING_SecretReadyCallback secret_ready_cb; | ||
50 | |||
51 | /** | ||
52 | * Closure for @e secret_ready_cb. | ||
53 | */ | ||
54 | void *secret_ready_cls; | ||
55 | }; | ||
56 | |||
57 | |||
58 | /** | ||
59 | * Handle to cancel a cooperative decryption operation. | ||
60 | */ | ||
61 | struct GNUNET_SECRETSHARING_DecryptionHandle | ||
62 | { | ||
63 | /** | ||
64 | * Message queue for @e client. | ||
65 | */ | ||
66 | struct GNUNET_MQ_Handle *mq; | ||
67 | |||
68 | /** | ||
69 | * Called when the secret sharing is done. | ||
70 | */ | ||
71 | GNUNET_SECRETSHARING_DecryptCallback decrypt_cb; | ||
72 | |||
73 | /** | ||
74 | * Closure for @e decrypt_cb. | ||
75 | */ | ||
76 | void *decrypt_cls; | ||
77 | }; | ||
78 | |||
79 | |||
80 | /** | ||
81 | * The ElGamal prime field order as libgcrypt mpi. | ||
82 | * Initialized in #init_crypto_constants. | ||
83 | */ | ||
84 | static gcry_mpi_t elgamal_q; | ||
85 | |||
86 | /** | ||
87 | * Modulus of the prime field used for ElGamal. | ||
88 | * Initialized in #init_crypto_constants. | ||
89 | */ | ||
90 | static gcry_mpi_t elgamal_p; | ||
91 | |||
92 | /** | ||
93 | * Generator for prime field of order 'elgamal_q'. | ||
94 | * Initialized in #init_crypto_constants. | ||
95 | */ | ||
96 | static gcry_mpi_t elgamal_g; | ||
97 | |||
98 | |||
99 | /** | ||
100 | * Function to initialize #elgamal_q, #elgamal_p and #elgamal_g. | ||
101 | */ | ||
102 | static void | ||
103 | ensure_elgamal_initialized (void) | ||
104 | { | ||
105 | if (NULL != elgamal_q) | ||
106 | return; /* looks like crypto is already initialized */ | ||
107 | |||
108 | GNUNET_assert (0 == gcry_mpi_scan (&elgamal_q, GCRYMPI_FMT_HEX, | ||
109 | GNUNET_SECRETSHARING_ELGAMAL_Q_HEX, 0, | ||
110 | NULL)); | ||
111 | GNUNET_assert (0 == gcry_mpi_scan (&elgamal_p, GCRYMPI_FMT_HEX, | ||
112 | GNUNET_SECRETSHARING_ELGAMAL_P_HEX, 0, | ||
113 | NULL)); | ||
114 | GNUNET_assert (0 == gcry_mpi_scan (&elgamal_g, GCRYMPI_FMT_HEX, | ||
115 | GNUNET_SECRETSHARING_ELGAMAL_G_HEX, 0, | ||
116 | NULL)); | ||
117 | } | ||
118 | |||
119 | |||
120 | /** | ||
121 | * Callback invoked when there is an error communicating with | ||
122 | * the service. Notifies the application about the error. | ||
123 | * | ||
124 | * @param cls the `struct GNUNET_SECRETSHARING_Session` | ||
125 | * @param error error code | ||
126 | */ | ||
127 | static void | ||
128 | handle_session_client_error (void *cls, | ||
129 | enum GNUNET_MQ_Error error) | ||
130 | { | ||
131 | struct GNUNET_SECRETSHARING_Session *s = cls; | ||
132 | |||
133 | s->secret_ready_cb (s->secret_ready_cls, NULL, NULL, 0, NULL); | ||
134 | GNUNET_SECRETSHARING_session_destroy (s); | ||
135 | } | ||
136 | |||
137 | |||
138 | /** | ||
139 | * Callback invoked when there is an error communicating with | ||
140 | * the service. Notifies the application about the error. | ||
141 | * | ||
142 | * @param cls the `struct GNUNET_SECRETSHARING_DecryptionHandle` | ||
143 | * @param error error code | ||
144 | */ | ||
145 | static void | ||
146 | handle_decrypt_client_error (void *cls, | ||
147 | enum GNUNET_MQ_Error error) | ||
148 | { | ||
149 | struct GNUNET_SECRETSHARING_DecryptionHandle *dh = cls; | ||
150 | |||
151 | dh->decrypt_cb (dh->decrypt_cls, NULL); | ||
152 | GNUNET_SECRETSHARING_decrypt_cancel (dh); | ||
153 | } | ||
154 | |||
155 | |||
156 | /** | ||
157 | * Handler invoked with the final result message from | ||
158 | * secret sharing. Decodes the message and passes the | ||
159 | * result to the application. | ||
160 | * | ||
161 | * @param cls the `struct GNUNET_SECRETSHARING_Session` | ||
162 | * @param m message with the result | ||
163 | */ | ||
164 | static int | ||
165 | check_secret_ready (void *cls, | ||
166 | const struct GNUNET_SECRETSHARING_SecretReadyMessage *m) | ||
167 | { | ||
168 | /* FIXME: actually check m is well-formed here! */ | ||
169 | return GNUNET_OK; | ||
170 | } | ||
171 | |||
172 | |||
173 | /** | ||
174 | * Handler invoked with the final result message from | ||
175 | * secret sharing. Decodes the message and passes the | ||
176 | * result to the application. | ||
177 | * | ||
178 | * @param cls the `struct GNUNET_SECRETSHARING_Session` | ||
179 | * @param m message with the result | ||
180 | */ | ||
181 | static void | ||
182 | handle_secret_ready (void *cls, | ||
183 | const struct GNUNET_SECRETSHARING_SecretReadyMessage *m) | ||
184 | { | ||
185 | struct GNUNET_SECRETSHARING_Session *s = cls; | ||
186 | struct GNUNET_SECRETSHARING_Share *share; | ||
187 | size_t share_size; | ||
188 | |||
189 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
190 | "Got secret ready message of size %u\n", | ||
191 | ntohs (m->header.size)); | ||
192 | share_size = ntohs (m->header.size) - sizeof(struct | ||
193 | GNUNET_SECRETSHARING_SecretReadyMessage); | ||
194 | |||
195 | share = GNUNET_SECRETSHARING_share_read (&m[1], | ||
196 | share_size, | ||
197 | NULL); | ||
198 | GNUNET_assert (NULL != share); // FIXME: this can fail! | ||
199 | // should have been checked in #check_secret_ready! | ||
200 | // FIXME: below we never check &m[1] is valid! | ||
201 | // FIXME: do we leak 'share' here? | ||
202 | s->secret_ready_cb (s->secret_ready_cls, | ||
203 | share, /* FIXME */ | ||
204 | &share->public_key, | ||
205 | share->num_peers, | ||
206 | (const struct GNUNET_PeerIdentity *) &m[1]); | ||
207 | |||
208 | GNUNET_SECRETSHARING_session_destroy (s); | ||
209 | } | ||
210 | |||
211 | |||
212 | /** | ||
213 | * Destroy a secret sharing session. | ||
214 | * The secret ready callback will not be called. | ||
215 | * | ||
216 | * @param s session to destroy | ||
217 | */ | ||
218 | void | ||
219 | GNUNET_SECRETSHARING_session_destroy (struct GNUNET_SECRETSHARING_Session *s) | ||
220 | { | ||
221 | GNUNET_MQ_destroy (s->mq); | ||
222 | s->mq = NULL; | ||
223 | GNUNET_free (s); | ||
224 | } | ||
225 | |||
226 | |||
227 | /** | ||
228 | * Create a session that will eventually establish a shared secret | ||
229 | * with the other peers. | ||
230 | * | ||
231 | * @param cfg configuration to use | ||
232 | * @param num_peers number of peers in @a peers | ||
233 | * @param peers array of peers that we will share secrets with, can optionally contain the local peer | ||
234 | * @param session_id unique session id | ||
235 | * @param start When should all peers be available for sharing the secret? | ||
236 | * Random number generation can take place before the start time. | ||
237 | * @param deadline point in time where the session must be established; taken as hint | ||
238 | * by underlying consensus sessions | ||
239 | * @param threshold minimum number of peers that must cooperate to decrypt a value | ||
240 | * @param cb called when the secret has been established | ||
241 | * @param cls closure for @a cb | ||
242 | */ | ||
243 | struct GNUNET_SECRETSHARING_Session * | ||
244 | GNUNET_SECRETSHARING_create_session (const struct | ||
245 | GNUNET_CONFIGURATION_Handle *cfg, | ||
246 | unsigned int num_peers, | ||
247 | const struct GNUNET_PeerIdentity *peers, | ||
248 | const struct GNUNET_HashCode *session_id, | ||
249 | struct GNUNET_TIME_Absolute start, | ||
250 | struct GNUNET_TIME_Absolute deadline, | ||
251 | unsigned int threshold, | ||
252 | GNUNET_SECRETSHARING_SecretReadyCallback cb, | ||
253 | void *cls) | ||
254 | { | ||
255 | struct GNUNET_SECRETSHARING_Session *s | ||
256 | = GNUNET_new (struct GNUNET_SECRETSHARING_Session); | ||
257 | struct GNUNET_MQ_MessageHandler mq_handlers[] = { | ||
258 | GNUNET_MQ_hd_var_size (secret_ready, | ||
259 | GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_SECRET_READY, | ||
260 | struct GNUNET_SECRETSHARING_SecretReadyMessage, | ||
261 | s), | ||
262 | GNUNET_MQ_handler_end () | ||
263 | }; | ||
264 | struct GNUNET_MQ_Envelope *ev; | ||
265 | struct GNUNET_SECRETSHARING_CreateMessage *msg; | ||
266 | |||
267 | s->mq = GNUNET_CLIENT_connect (cfg, | ||
268 | "secretsharing", | ||
269 | mq_handlers, | ||
270 | &handle_session_client_error, | ||
271 | s); | ||
272 | if (NULL == s->mq) | ||
273 | { | ||
274 | /* secretsharing not configured correctly */ | ||
275 | GNUNET_break (0); | ||
276 | GNUNET_free (s); | ||
277 | return NULL; | ||
278 | } | ||
279 | s->secret_ready_cb = cb; | ||
280 | s->secret_ready_cls = cls; | ||
281 | ev = GNUNET_MQ_msg_extra (msg, | ||
282 | num_peers * sizeof(struct GNUNET_PeerIdentity), | ||
283 | GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_GENERATE); | ||
284 | |||
285 | msg->threshold = htons (threshold); | ||
286 | msg->num_peers = htons (num_peers); | ||
287 | msg->session_id = *session_id; | ||
288 | msg->start = GNUNET_TIME_absolute_hton (start); | ||
289 | msg->deadline = GNUNET_TIME_absolute_hton (deadline); | ||
290 | GNUNET_memcpy (&msg[1], peers, num_peers * sizeof(struct | ||
291 | GNUNET_PeerIdentity)); | ||
292 | |||
293 | GNUNET_MQ_send (s->mq, ev); | ||
294 | |||
295 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
296 | "Secretsharing session created with %u peers\n", | ||
297 | num_peers); | ||
298 | return s; | ||
299 | } | ||
300 | |||
301 | |||
302 | static void | ||
303 | handle_decrypt_done (void *cls, | ||
304 | const struct | ||
305 | GNUNET_SECRETSHARING_DecryptResponseMessage *m) | ||
306 | { | ||
307 | struct GNUNET_SECRETSHARING_DecryptionHandle *dh = cls; | ||
308 | const struct GNUNET_SECRETSHARING_Plaintext *plaintext; | ||
309 | |||
310 | if (m->success == 0) | ||
311 | plaintext = NULL; | ||
312 | else | ||
313 | plaintext = (void *) &m->plaintext; | ||
314 | dh->decrypt_cb (dh->decrypt_cls, plaintext); | ||
315 | GNUNET_SECRETSHARING_decrypt_cancel (dh); | ||
316 | } | ||
317 | |||
318 | |||
319 | struct GNUNET_SECRETSHARING_DecryptionHandle * | ||
320 | GNUNET_SECRETSHARING_decrypt (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
321 | struct GNUNET_SECRETSHARING_Share *share, | ||
322 | const struct | ||
323 | GNUNET_SECRETSHARING_Ciphertext *ciphertext, | ||
324 | struct GNUNET_TIME_Absolute start, | ||
325 | struct GNUNET_TIME_Absolute deadline, | ||
326 | GNUNET_SECRETSHARING_DecryptCallback decrypt_cb, | ||
327 | void *decrypt_cb_cls) | ||
328 | { | ||
329 | struct GNUNET_SECRETSHARING_DecryptionHandle *s | ||
330 | = GNUNET_new (struct GNUNET_SECRETSHARING_DecryptionHandle); | ||
331 | struct GNUNET_MQ_MessageHandler mq_handlers[] = { | ||
332 | GNUNET_MQ_hd_fixed_size (decrypt_done, | ||
333 | GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_DECRYPT_DONE, | ||
334 | struct GNUNET_SECRETSHARING_DecryptResponseMessage, | ||
335 | s), | ||
336 | GNUNET_MQ_handler_end () | ||
337 | }; | ||
338 | struct GNUNET_MQ_Envelope *ev; | ||
339 | struct GNUNET_SECRETSHARING_DecryptRequestMessage *msg; | ||
340 | size_t share_size; | ||
341 | |||
342 | s->decrypt_cb = decrypt_cb; | ||
343 | s->decrypt_cls = decrypt_cb_cls; | ||
344 | s->mq = GNUNET_CLIENT_connect (cfg, | ||
345 | "secretsharing", | ||
346 | mq_handlers, | ||
347 | &handle_decrypt_client_error, | ||
348 | s); | ||
349 | if (NULL == s->mq) | ||
350 | { | ||
351 | GNUNET_free (s); | ||
352 | return NULL; | ||
353 | } | ||
354 | GNUNET_assert (GNUNET_OK == | ||
355 | GNUNET_SECRETSHARING_share_write (share, NULL, 0, | ||
356 | &share_size)); | ||
357 | |||
358 | ev = GNUNET_MQ_msg_extra (msg, | ||
359 | share_size, | ||
360 | GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_DECRYPT); | ||
361 | |||
362 | GNUNET_assert (GNUNET_OK == | ||
363 | GNUNET_SECRETSHARING_share_write (share, | ||
364 | &msg[1], | ||
365 | share_size, | ||
366 | NULL)); | ||
367 | |||
368 | msg->start = GNUNET_TIME_absolute_hton (start); | ||
369 | msg->deadline = GNUNET_TIME_absolute_hton (deadline); | ||
370 | msg->ciphertext = *ciphertext; | ||
371 | |||
372 | GNUNET_MQ_send (s->mq, ev); | ||
373 | |||
374 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
375 | "decrypt session created\n"); | ||
376 | return s; | ||
377 | } | ||
378 | |||
379 | |||
380 | int | ||
381 | GNUNET_SECRETSHARING_plaintext_generate_i (struct | ||
382 | GNUNET_SECRETSHARING_Plaintext * | ||
383 | plaintext, | ||
384 | int64_t exponent) | ||
385 | { | ||
386 | int negative; | ||
387 | gcry_mpi_t x; | ||
388 | |||
389 | ensure_elgamal_initialized (); | ||
390 | |||
391 | GNUNET_assert (NULL != (x = gcry_mpi_new (0))); | ||
392 | |||
393 | negative = GNUNET_NO; | ||
394 | if (exponent < 0) | ||
395 | { | ||
396 | negative = GNUNET_YES; | ||
397 | exponent = -exponent; | ||
398 | } | ||
399 | |||
400 | gcry_mpi_set_ui (x, exponent); | ||
401 | |||
402 | gcry_mpi_powm (x, elgamal_g, x, elgamal_p); | ||
403 | |||
404 | if (GNUNET_YES == negative) | ||
405 | { | ||
406 | int res; | ||
407 | res = gcry_mpi_invm (x, x, elgamal_p); | ||
408 | if (0 == res) | ||
409 | return GNUNET_SYSERR; | ||
410 | } | ||
411 | |||
412 | GNUNET_CRYPTO_mpi_print_unsigned (plaintext, | ||
413 | sizeof(struct | ||
414 | GNUNET_SECRETSHARING_Plaintext), | ||
415 | x); | ||
416 | |||
417 | return GNUNET_OK; | ||
418 | } | ||
419 | |||
420 | |||
421 | int | ||
422 | GNUNET_SECRETSHARING_encrypt (const struct | ||
423 | GNUNET_SECRETSHARING_PublicKey *public_key, | ||
424 | const struct | ||
425 | GNUNET_SECRETSHARING_Plaintext *plaintext, | ||
426 | struct GNUNET_SECRETSHARING_Ciphertext * | ||
427 | result_ciphertext) | ||
428 | { | ||
429 | /* pubkey */ | ||
430 | gcry_mpi_t h; | ||
431 | /* nonce */ | ||
432 | gcry_mpi_t y; | ||
433 | /* plaintext message */ | ||
434 | gcry_mpi_t m; | ||
435 | /* temp value */ | ||
436 | gcry_mpi_t tmp; | ||
437 | |||
438 | ensure_elgamal_initialized (); | ||
439 | |||
440 | GNUNET_assert (NULL != (h = gcry_mpi_new (0))); | ||
441 | GNUNET_assert (NULL != (y = gcry_mpi_new (0))); | ||
442 | GNUNET_assert (NULL != (tmp = gcry_mpi_new (0))); | ||
443 | |||
444 | GNUNET_CRYPTO_mpi_scan_unsigned (&h, public_key, sizeof *public_key); | ||
445 | GNUNET_CRYPTO_mpi_scan_unsigned (&m, plaintext, sizeof *plaintext); | ||
446 | |||
447 | // Randomize y such that 0 < y < elgamal_q. | ||
448 | // The '- 1' is necessary as bitlength(q) = bitlength(p) - 1. | ||
449 | do | ||
450 | { | ||
451 | gcry_mpi_randomize (y, GNUNET_SECRETSHARING_ELGAMAL_BITS - 1, | ||
452 | GCRY_WEAK_RANDOM); | ||
453 | } | ||
454 | while ((gcry_mpi_cmp_ui (y, 0) == 0) || (gcry_mpi_cmp (y, elgamal_q) >= 0)); | ||
455 | |||
456 | // tmp <- g^y | ||
457 | gcry_mpi_powm (tmp, elgamal_g, y, elgamal_p); | ||
458 | // write tmp to c1 | ||
459 | GNUNET_CRYPTO_mpi_print_unsigned (&result_ciphertext->c1_bits, | ||
460 | GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, tmp); | ||
461 | |||
462 | // tmp <- h^y | ||
463 | gcry_mpi_powm (tmp, h, y, elgamal_p); | ||
464 | // tmp <- tmp * m | ||
465 | gcry_mpi_mulm (tmp, tmp, m, elgamal_p); | ||
466 | // write tmp to c2 | ||
467 | GNUNET_CRYPTO_mpi_print_unsigned (&result_ciphertext->c2_bits, | ||
468 | GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, tmp); | ||
469 | |||
470 | return GNUNET_OK; | ||
471 | } | ||
472 | |||
473 | |||
474 | /** | ||
475 | * Cancel a decryption. | ||
476 | * | ||
477 | * The decrypt_cb is not called anymore, but the calling | ||
478 | * peer may already have irrevocably contributed its share for the decryption of the value. | ||
479 | * | ||
480 | * @param dh to cancel | ||
481 | */ | ||
482 | void | ||
483 | GNUNET_SECRETSHARING_decrypt_cancel (struct | ||
484 | GNUNET_SECRETSHARING_DecryptionHandle *dh) | ||
485 | { | ||
486 | GNUNET_MQ_destroy (dh->mq); | ||
487 | dh->mq = NULL; | ||
488 | GNUNET_free (dh); | ||
489 | } | ||
490 | |||
491 | |||
492 | /* end of secretsharing_api.c */ | ||