diff options
Diffstat (limited to 'src/secretsharing/secretsharing_api.c')
-rw-r--r-- | src/secretsharing/secretsharing_api.c | 518 |
1 files changed, 0 insertions, 518 deletions
diff --git a/src/secretsharing/secretsharing_api.c b/src/secretsharing/secretsharing_api.c deleted file mode 100644 index 98f800c95..000000000 --- a/src/secretsharing/secretsharing_api.c +++ /dev/null | |||
@@ -1,518 +0,0 @@ | |||
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 | /** | ||
320 | * Publish the given ciphertext for decryption. Once a sufficient (>=k) number of peers has | ||
321 | * published the same value, it will be decrypted. | ||
322 | * | ||
323 | * When the operation is canceled, the decrypt_cb is not called anymore, but the calling | ||
324 | * peer may already have irrevocably contributed its share for the decryption of the value. | ||
325 | * | ||
326 | * @param share our secret share to use for decryption | ||
327 | * @param ciphertext ciphertext to publish in order to decrypt it (if enough peers agree) | ||
328 | * @param decrypt_cb callback called once the decryption succeeded | ||
329 | * @param decrypt_cb_cls closure for @a decrypt_cb | ||
330 | * @return handle to cancel the operation | ||
331 | */ | ||
332 | struct GNUNET_SECRETSHARING_DecryptionHandle * | ||
333 | GNUNET_SECRETSHARING_decrypt (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
334 | struct GNUNET_SECRETSHARING_Share *share, | ||
335 | const struct | ||
336 | GNUNET_SECRETSHARING_Ciphertext *ciphertext, | ||
337 | struct GNUNET_TIME_Absolute start, | ||
338 | struct GNUNET_TIME_Absolute deadline, | ||
339 | GNUNET_SECRETSHARING_DecryptCallback decrypt_cb, | ||
340 | void *decrypt_cb_cls) | ||
341 | { | ||
342 | struct GNUNET_SECRETSHARING_DecryptionHandle *s | ||
343 | = GNUNET_new (struct GNUNET_SECRETSHARING_DecryptionHandle); | ||
344 | struct GNUNET_MQ_MessageHandler mq_handlers[] = { | ||
345 | GNUNET_MQ_hd_fixed_size (decrypt_done, | ||
346 | GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_DECRYPT_DONE, | ||
347 | struct GNUNET_SECRETSHARING_DecryptResponseMessage, | ||
348 | s), | ||
349 | GNUNET_MQ_handler_end () | ||
350 | }; | ||
351 | struct GNUNET_MQ_Envelope *ev; | ||
352 | struct GNUNET_SECRETSHARING_DecryptRequestMessage *msg; | ||
353 | size_t share_size; | ||
354 | |||
355 | s->decrypt_cb = decrypt_cb; | ||
356 | s->decrypt_cls = decrypt_cb_cls; | ||
357 | s->mq = GNUNET_CLIENT_connect (cfg, | ||
358 | "secretsharing", | ||
359 | mq_handlers, | ||
360 | &handle_decrypt_client_error, | ||
361 | s); | ||
362 | if (NULL == s->mq) | ||
363 | { | ||
364 | GNUNET_free (s); | ||
365 | return NULL; | ||
366 | } | ||
367 | GNUNET_assert (GNUNET_OK == | ||
368 | GNUNET_SECRETSHARING_share_write (share, NULL, 0, | ||
369 | &share_size)); | ||
370 | |||
371 | ev = GNUNET_MQ_msg_extra (msg, | ||
372 | share_size, | ||
373 | GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_DECRYPT); | ||
374 | |||
375 | GNUNET_assert (GNUNET_OK == | ||
376 | GNUNET_SECRETSHARING_share_write (share, | ||
377 | &msg[1], | ||
378 | share_size, | ||
379 | NULL)); | ||
380 | |||
381 | msg->start = GNUNET_TIME_absolute_hton (start); | ||
382 | msg->deadline = GNUNET_TIME_absolute_hton (deadline); | ||
383 | msg->ciphertext = *ciphertext; | ||
384 | |||
385 | GNUNET_MQ_send (s->mq, ev); | ||
386 | |||
387 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
388 | "decrypt session created\n"); | ||
389 | return s; | ||
390 | } | ||
391 | |||
392 | |||
393 | int | ||
394 | GNUNET_SECRETSHARING_plaintext_generate_i (struct | ||
395 | GNUNET_SECRETSHARING_Plaintext * | ||
396 | plaintext, | ||
397 | int64_t exponent) | ||
398 | { | ||
399 | int negative; | ||
400 | gcry_mpi_t x; | ||
401 | |||
402 | ensure_elgamal_initialized (); | ||
403 | |||
404 | GNUNET_assert (NULL != (x = gcry_mpi_new (0))); | ||
405 | |||
406 | negative = GNUNET_NO; | ||
407 | if (exponent < 0) | ||
408 | { | ||
409 | negative = GNUNET_YES; | ||
410 | exponent = -exponent; | ||
411 | } | ||
412 | |||
413 | gcry_mpi_set_ui (x, exponent); | ||
414 | |||
415 | gcry_mpi_powm (x, elgamal_g, x, elgamal_p); | ||
416 | |||
417 | if (GNUNET_YES == negative) | ||
418 | { | ||
419 | int res; | ||
420 | res = gcry_mpi_invm (x, x, elgamal_p); | ||
421 | if (0 == res) | ||
422 | return GNUNET_SYSERR; | ||
423 | } | ||
424 | |||
425 | GNUNET_CRYPTO_mpi_print_unsigned (plaintext, | ||
426 | sizeof(struct | ||
427 | GNUNET_SECRETSHARING_Plaintext), | ||
428 | x); | ||
429 | |||
430 | return GNUNET_OK; | ||
431 | } | ||
432 | |||
433 | |||
434 | /** | ||
435 | * Encrypt a value. This operation is executed locally, no communication is | ||
436 | * necessary. | ||
437 | * | ||
438 | * This is a helper function, encryption can be done solely with a session's public key | ||
439 | * and the crypto system parameters. | ||
440 | * | ||
441 | * @param public_key public key to use for decryption | ||
442 | * @param message message to encrypt | ||
443 | * @param message_size number of bytes in @a message | ||
444 | * @param result_ciphertext pointer to store the resulting ciphertext | ||
445 | * @return #GNUNET_YES on success, #GNUNET_SYSERR if the message is invalid (invalid range) | ||
446 | */ | ||
447 | int | ||
448 | GNUNET_SECRETSHARING_encrypt (const struct | ||
449 | GNUNET_SECRETSHARING_PublicKey *public_key, | ||
450 | const struct | ||
451 | GNUNET_SECRETSHARING_Plaintext *plaintext, | ||
452 | struct GNUNET_SECRETSHARING_Ciphertext * | ||
453 | result_ciphertext) | ||
454 | { | ||
455 | /* pubkey */ | ||
456 | gcry_mpi_t h; | ||
457 | /* nonce */ | ||
458 | gcry_mpi_t y; | ||
459 | /* plaintext message */ | ||
460 | gcry_mpi_t m; | ||
461 | /* temp value */ | ||
462 | gcry_mpi_t tmp; | ||
463 | |||
464 | ensure_elgamal_initialized (); | ||
465 | |||
466 | GNUNET_assert (NULL != (h = gcry_mpi_new (0))); | ||
467 | GNUNET_assert (NULL != (y = gcry_mpi_new (0))); | ||
468 | GNUNET_assert (NULL != (tmp = gcry_mpi_new (0))); | ||
469 | |||
470 | GNUNET_CRYPTO_mpi_scan_unsigned (&h, public_key, sizeof *public_key); | ||
471 | GNUNET_CRYPTO_mpi_scan_unsigned (&m, plaintext, sizeof *plaintext); | ||
472 | |||
473 | // Randomize y such that 0 < y < elgamal_q. | ||
474 | // The '- 1' is necessary as bitlength(q) = bitlength(p) - 1. | ||
475 | do | ||
476 | { | ||
477 | gcry_mpi_randomize (y, GNUNET_SECRETSHARING_ELGAMAL_BITS - 1, | ||
478 | GCRY_WEAK_RANDOM); | ||
479 | } | ||
480 | while ((gcry_mpi_cmp_ui (y, 0) == 0) || (gcry_mpi_cmp (y, elgamal_q) >= 0)); | ||
481 | |||
482 | // tmp <- g^y | ||
483 | gcry_mpi_powm (tmp, elgamal_g, y, elgamal_p); | ||
484 | // write tmp to c1 | ||
485 | GNUNET_CRYPTO_mpi_print_unsigned (&result_ciphertext->c1_bits, | ||
486 | GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, tmp); | ||
487 | |||
488 | // tmp <- h^y | ||
489 | gcry_mpi_powm (tmp, h, y, elgamal_p); | ||
490 | // tmp <- tmp * m | ||
491 | gcry_mpi_mulm (tmp, tmp, m, elgamal_p); | ||
492 | // write tmp to c2 | ||
493 | GNUNET_CRYPTO_mpi_print_unsigned (&result_ciphertext->c2_bits, | ||
494 | GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, tmp); | ||
495 | |||
496 | return GNUNET_OK; | ||
497 | } | ||
498 | |||
499 | |||
500 | /** | ||
501 | * Cancel a decryption. | ||
502 | * | ||
503 | * The decrypt_cb is not called anymore, but the calling | ||
504 | * peer may already have irrevocably contributed its share for the decryption of the value. | ||
505 | * | ||
506 | * @param dh to cancel | ||
507 | */ | ||
508 | void | ||
509 | GNUNET_SECRETSHARING_decrypt_cancel (struct | ||
510 | GNUNET_SECRETSHARING_DecryptionHandle *dh) | ||
511 | { | ||
512 | GNUNET_MQ_destroy (dh->mq); | ||
513 | dh->mq = NULL; | ||
514 | GNUNET_free (dh); | ||
515 | } | ||
516 | |||
517 | |||
518 | /* end of secretsharing_api.c */ | ||