X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fsecretsharing%2Fsecretsharing_api.c;h=6e347f6da9e44dfef058ccdc55ece3d67d4d213c;hb=8a2d1e6aedbf1bc95052e63ac67093b89385b0a1;hp=a44fa2a2fd09e0627bbbc7b5c16fd71479d5daab;hpb=f3a98e004caf91688887a01b5fe2ad3f11813238;p=oweals%2Fgnunet.git diff --git a/src/secretsharing/secretsharing_api.c b/src/secretsharing/secretsharing_api.c index a44fa2a2f..6e347f6da 100644 --- a/src/secretsharing/secretsharing_api.c +++ b/src/secretsharing/secretsharing_api.c @@ -27,12 +27,11 @@ #include "gnunet_util_lib.h" #include "gnunet_secretsharing_service.h" #include "secretsharing.h" +#include #define LOG(kind,...) GNUNET_log_from (kind, "secretsharing-api",__VA_ARGS__) - - /** * Session that will eventually establish a shared secred between * the involved peers and allow encryption and cooperative decryption. @@ -61,6 +60,64 @@ struct GNUNET_SECRETSHARING_Session }; +struct GNUNET_SECRETSHARING_DecryptionHandle +{ + /** + * Client connected to the secretsharing service. + */ + struct GNUNET_CLIENT_Connection *client; + + /** + * Message queue for 'client'. + */ + struct GNUNET_MQ_Handle *mq; + + /** + * Called when the secret sharing is done. + */ + GNUNET_SECRETSHARING_DecryptCallback decrypt_cb; + + /** + * Closure for 'decrypt_cb'. + */ + void *decrypt_cls; +}; + + +/** + * The ElGamal prime field order as libgcrypt mpi. + * Initialized in #init_crypto_constants. + */ +static gcry_mpi_t elgamal_q; + +/** + * Modulus of the prime field used for ElGamal. + * Initialized in #init_crypto_constants. + */ +static gcry_mpi_t elgamal_p; + +/** + * Generator for prime field of order 'elgamal_q'. + * Initialized in #init_crypto_constants. + */ +static gcry_mpi_t elgamal_g; + + +static void +ensure_elgamal_initialized (void) +{ + if (NULL != elgamal_q) + return; /* looks like crypto is already initialized */ + + GNUNET_assert (0 == gcry_mpi_scan (&elgamal_q, GCRYMPI_FMT_HEX, + GNUNET_SECRETSHARING_ELGAMAL_Q_HEX, 0, NULL)); + GNUNET_assert (0 == gcry_mpi_scan (&elgamal_p, GCRYMPI_FMT_HEX, + GNUNET_SECRETSHARING_ELGAMAL_P_HEX, 0, NULL)); + GNUNET_assert (0 == gcry_mpi_scan (&elgamal_g, GCRYMPI_FMT_HEX, + GNUNET_SECRETSHARING_ELGAMAL_G_HEX, 0, NULL)); +} + + static void handle_session_client_error (void *cls, enum GNUNET_MQ_Error error) { @@ -69,18 +126,49 @@ handle_session_client_error (void *cls, enum GNUNET_MQ_Error error) s->secret_ready_cb (s->secret_ready_cls, NULL, NULL, 0, NULL); } + +static void +handle_decrypt_client_error (void *cls, enum GNUNET_MQ_Error error) +{ + struct GNUNET_SECRETSHARING_DecryptionHandle *dh = cls; + + dh->decrypt_cb (dh->decrypt_cls, NULL); +} + + static void handle_secret_ready (void *cls, const struct GNUNET_MessageHeader *msg) { - struct GNUNET_SECRETSHARING_Session *s = cls; + struct GNUNET_SECRETSHARING_Session *session = cls; + struct GNUNET_SECRETSHARING_Share *share; const struct GNUNET_SECRETSHARING_SecretReadyMessage *m = (const void *) msg; + size_t share_size; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "got secret ready message of size %u\n", + ntohs (m->header.size)); + + share_size = ntohs (m->header.size) - sizeof *m; + + share = GNUNET_SECRETSHARING_share_read (&m[1], share_size, NULL); - s->secret_ready_cb (s->secret_ready_cls, - NULL, - &m->public_key, - ntohs (m->num_secret_peers), + session->secret_ready_cb (session->secret_ready_cls, + share, /* FIXME */ + &share->public_key, + share->num_peers, (struct GNUNET_PeerIdentity *) &m[1]); + GNUNET_SECRETSHARING_session_destroy (session); +} + + +void +GNUNET_SECRETSHARING_session_destroy (struct GNUNET_SECRETSHARING_Session *session) +{ + GNUNET_MQ_destroy (session->mq); + session->mq = NULL; + GNUNET_CLIENT_disconnect (session->client); + session->client = NULL; + GNUNET_free (session); } @@ -89,6 +177,7 @@ GNUNET_SECRETSHARING_create_session (const struct GNUNET_CONFIGURATION_Handle *c unsigned int num_peers, const struct GNUNET_PeerIdentity *peers, const struct GNUNET_HashCode *session_id, + struct GNUNET_TIME_Absolute start, struct GNUNET_TIME_Absolute deadline, unsigned int threshold, GNUNET_SECRETSHARING_SecretReadyCallback cb, @@ -113,13 +202,211 @@ GNUNET_SECRETSHARING_create_session (const struct GNUNET_CONFIGURATION_Handle *c handle_session_client_error, s); GNUNET_assert (NULL != s->mq); - ev = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_GENERATE); + ev = GNUNET_MQ_msg_extra (msg, + num_peers * sizeof (struct GNUNET_PeerIdentity), + GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_GENERATE); + msg->threshold = htons (threshold); + msg->num_peers = htons (num_peers); + msg->session_id = *session_id; + msg->start = GNUNET_TIME_absolute_hton (start); + msg->deadline = GNUNET_TIME_absolute_hton (deadline); + memcpy (&msg[1], peers, num_peers * sizeof (struct GNUNET_PeerIdentity)); + GNUNET_MQ_send (s->mq, ev); - LOG (GNUNET_ERROR_TYPE_DEBUG, "secretsharing session created\n"); + LOG (GNUNET_ERROR_TYPE_DEBUG, "secretsharing session created with %u peers\n", + num_peers); return s; +} + +static void +handle_decrypt_done (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_SECRETSHARING_DecryptionHandle *dh = cls; + const struct GNUNET_SECRETSHARING_DecryptResponseMessage *m = + (const void *) msg; + + const struct GNUNET_SECRETSHARING_Plaintext *plaintext; + + if (m->success == 0) + plaintext = NULL; + else + plaintext = (void *) &m->plaintext; + + dh->decrypt_cb (dh->decrypt_cls, plaintext); + + GNUNET_SECRETSHARING_decrypt_cancel (dh); +} + + +/** + * Publish the given ciphertext for decryption. Once a sufficient (>=k) number of peers has + * published the same value, it will be decrypted. + * + * When the operation is canceled, the decrypt_cb is not called anymore, but the calling + * peer may already have irrevocably contributed his share for the decryption of the value. + * + * @param share our secret share to use for decryption + * @param ciphertext ciphertext to publish in order to decrypt it (if enough peers agree) + * @param decrypt_cb callback called once the decryption succeeded + * @param decrypt_cb_cls closure for @a decrypt_cb + * @return handle to cancel the operation + */ +struct GNUNET_SECRETSHARING_DecryptionHandle * +GNUNET_SECRETSHARING_decrypt (const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_SECRETSHARING_Share *share, + const struct GNUNET_SECRETSHARING_Ciphertext *ciphertext, + struct GNUNET_TIME_Absolute start, + struct GNUNET_TIME_Absolute deadline, + GNUNET_SECRETSHARING_DecryptCallback decrypt_cb, + void *decrypt_cb_cls) +{ + struct GNUNET_SECRETSHARING_DecryptionHandle *s; + struct GNUNET_MQ_Envelope *ev; + struct GNUNET_SECRETSHARING_DecryptRequestMessage *msg; + static const struct GNUNET_MQ_MessageHandler mq_handlers[] = { + {handle_decrypt_done, GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_DECRYPT_DONE, 0}, + GNUNET_MQ_HANDLERS_END + }; + size_t share_size; + + + s = GNUNET_new (struct GNUNET_SECRETSHARING_DecryptionHandle); + s->client = GNUNET_CLIENT_connect ("secretsharing", cfg); + s->decrypt_cb = decrypt_cb; + s->decrypt_cls = decrypt_cb_cls; + GNUNET_assert (NULL != s->client); + + s->mq = GNUNET_MQ_queue_for_connection_client (s->client, mq_handlers, + handle_decrypt_client_error, s); + GNUNET_assert (NULL != s->mq); + + GNUNET_assert (GNUNET_OK == GNUNET_SECRETSHARING_share_write (share, NULL, 0, &share_size)); + + ev = GNUNET_MQ_msg_extra (msg, + share_size, + GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_DECRYPT); + + GNUNET_assert (GNUNET_OK == GNUNET_SECRETSHARING_share_write (share, &msg[1], share_size, NULL)); + + msg->start = GNUNET_TIME_absolute_hton (start); + msg->deadline = GNUNET_TIME_absolute_hton (deadline); + msg->ciphertext = *ciphertext; + + GNUNET_MQ_send (s->mq, ev); + + LOG (GNUNET_ERROR_TYPE_DEBUG, "decrypt session created\n"); + return s; +} + + +int +GNUNET_SECRETSHARING_plaintext_generate_i (struct GNUNET_SECRETSHARING_Plaintext *plaintext, + int64_t exponent) +{ + int negative; + gcry_mpi_t x; + + ensure_elgamal_initialized (); + + GNUNET_assert (NULL != (x = gcry_mpi_new (0))); + + negative = GNUNET_NO; + if (exponent < 0) + { + negative = GNUNET_YES; + exponent = -exponent; + } + + gcry_mpi_set_ui (x, exponent); + + gcry_mpi_powm (x, elgamal_g, x, elgamal_p); + + if (GNUNET_YES == negative) + { + int res; + res = gcry_mpi_invm (x, x, elgamal_p); + if (0 == res) + return GNUNET_SYSERR; + } + + GNUNET_CRYPTO_mpi_print_unsigned (plaintext, sizeof (struct GNUNET_SECRETSHARING_Plaintext), x); + + return GNUNET_OK; +} + + +/** + * Encrypt a value. This operation is executed locally, no communication is + * necessary. + * + * This is a helper function, encryption can be done soley with a session's public key + * and the crypto system parameters. + * + * @param public_key public key to use for decryption + * @param message message to encrypt + * @param message_size number of bytes in @a message + * @param result_ciphertext pointer to store the resulting ciphertext + * @return #GNUNET_YES on succes, #GNUNET_SYSERR if the message is invalid (invalid range) + */ +int +GNUNET_SECRETSHARING_encrypt (const struct GNUNET_SECRETSHARING_PublicKey *public_key, + const struct GNUNET_SECRETSHARING_Plaintext *plaintext, + struct GNUNET_SECRETSHARING_Ciphertext *result_ciphertext) +{ + /* pubkey */ + gcry_mpi_t h; + /* nonce */ + gcry_mpi_t y; + /* plaintext message */ + gcry_mpi_t m; + /* temp value */ + gcry_mpi_t tmp; + + ensure_elgamal_initialized (); + + GNUNET_assert (NULL != (h = gcry_mpi_new (0))); + GNUNET_assert (NULL != (y = gcry_mpi_new (0))); + GNUNET_assert (NULL != (tmp = gcry_mpi_new (0))); + + GNUNET_CRYPTO_mpi_scan_unsigned (&h, public_key, sizeof *public_key); + GNUNET_CRYPTO_mpi_scan_unsigned (&m, plaintext, sizeof *plaintext); + + // Randomize y such that 0 < y < elgamal_q. + // The '- 1' is necessary as bitlength(q) = bitlength(p) - 1. + do + { + gcry_mpi_randomize (y, GNUNET_SECRETSHARING_ELGAMAL_BITS - 1, GCRY_WEAK_RANDOM); + } while ((gcry_mpi_cmp_ui (y, 0) == 0) || (gcry_mpi_cmp (y, elgamal_q) >= 0)); + + // tmp <- g^y + gcry_mpi_powm (tmp, elgamal_g, y, elgamal_p); + // write tmp to c1 + GNUNET_CRYPTO_mpi_print_unsigned (&result_ciphertext->c1_bits, + GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, tmp); + + // tmp <- h^y + gcry_mpi_powm (tmp, h, y, elgamal_p); + // tmp <- tmp * m + gcry_mpi_mulm (tmp, tmp, m, elgamal_p); + // write tmp to c2 + GNUNET_CRYPTO_mpi_print_unsigned (&result_ciphertext->c2_bits, + GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, tmp); + + return GNUNET_OK; +} + + +void +GNUNET_SECRETSHARING_decrypt_cancel (struct GNUNET_SECRETSHARING_DecryptionHandle *h) +{ + GNUNET_MQ_destroy (h->mq); + h->mq = NULL; + GNUNET_CLIENT_disconnect (h->client); + h->client = NULL; + GNUNET_free (h); }