gnunet

Main GNUnet Logic
Log | Files | Refs | Submodules | README | LICENSE

commit a7a44991b3c241bf4ab189d91ce0e73b7c6851f1
parent f029ece5c1300c3860ea19d891eae363618ecda3
Author: Jacki <jacki@thejackimonster.de>
Date:   Thu, 20 Nov 2025 02:40:25 +0100

messenger: explit usage of hpke keys for encryption/decryption

Signed-off-by: Jacki <jacki@thejackimonster.de>

Diffstat:
Msrc/include/gnunet_crypto_lib.h | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/include/gnunet_messenger_service.h | 14++++++++++++--
Msrc/lib/util/crypto_hpke.c | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/service/messenger/messenger_api.c | 12++++++++++--
Msrc/service/messenger/messenger_api_message.c | 44++++++++++++++++++++++++++++++++------------
Msrc/service/messenger/messenger_api_message_kind.c | 6++++++
Msrc/service/messenger/messenger_api_room.c | 14+++++++++++++-
7 files changed, 199 insertions(+), 17 deletions(-)

diff --git a/src/include/gnunet_crypto_lib.h b/src/include/gnunet_crypto_lib.h @@ -392,6 +392,17 @@ enum GNUNET_CRYPTO_KeyType }; /** + * Key type for the hpke public key union + */ +enum GNUNET_CRYPTO_HpkeKeyType +{ + /** + * ECDHE hybrid public key encryption. + */ + GNUNET_CRYPTO_HPKE_KEY_TYPE_ECDHE = 1 +}; + +/** * A private key for an identity as per LSD0001. * Note that these types are NOT packed and MUST NOT be used in RPC * messages. Use the respective serialization functions. @@ -4919,6 +4930,58 @@ GNUNET_CRYPTO_blindable_key_get_public (const struct struct GNUNET_CRYPTO_BlindablePublicKey *key); +/** + * Get the compacted length of a #GNUNET_CRYPTO_HpkePublicKey. + * Compacted means that it returns the minimum number of bytes this + * key is long, as opposed to the union structure inside + * #GNUNET_CRYPTO_HpkePublicKey. + * Useful for compact serializations. + * + * @param key the key. + * @return -1 on error, else the compacted length of the key. + */ +ssize_t +GNUNET_CRYPTO_hpke_pk_get_length ( + const struct GNUNET_CRYPTO_HpkePublicKey *key); + +/** + * Reads a #GNUNET_CRYPTO_HpkePublicKey from a compact buffer. + * The buffer has to contain at least the compacted length of + * a #GNUNET_CRYPTO_HpkePublicKey in bytes. + * If the buffer is too small, the function returns -1 as error. + * If the buffer does not contain a valid key, it returns -2 as error. + * + * @param buffer the buffer + * @param len the length of buffer + * @param key the key + * @param the amount of bytes read from the buffer + * @return #GNUNET_SYSERR on error + */ +enum GNUNET_GenericReturnValue +GNUNET_CRYPTO_read_hpke_pk_from_buffer ( + const void *buffer, + size_t len, + struct GNUNET_CRYPTO_HpkePublicKey *key, + size_t *read); + +/** + * Writes a #GNUNET_CRYPTO_HpkePublicKey to a compact buffer. + * The buffer requires space for at least the compacted length of + * a #GNUNET_CRYPTO_HpkePublicKey in bytes. + * If the buffer is too small, the function returns -1 as error. + * If the key is not valid, it returns -2 as error. + * + * @param key the key + * @param buffer the buffer + * @param len the length of buffer + * @return -1 or -2 on error, else the amount of bytes written to the buffer + */ +ssize_t +GNUNET_CRYPTO_write_hpke_pk_to_buffer ( + const struct GNUNET_CRYPTO_HpkePublicKey *key, + void*buffer, + size_t len); + #if 0 /* keep Emacsens' auto-indent happy */ { #endif diff --git a/src/include/gnunet_messenger_service.h b/src/include/gnunet_messenger_service.h @@ -44,9 +44,9 @@ extern "C" { /** * Version number of GNUnet Messenger API. * - * Current version of the Messenger: 0.6 + * Current version of the Messenger: 0.7 */ -#define GNUNET_MESSENGER_VERSION 0x00000006 +#define GNUNET_MESSENGER_VERSION 0x00000007 /** * Identifier of GNUnet MESSENGER Service. @@ -470,6 +470,11 @@ struct GNUNET_MESSENGER_MessageJoin * The senders blindable public key to verify its signatures. */ struct GNUNET_CRYPTO_BlindablePublicKey key; + + /** + * The senders HPKE public key to encrypt private messages with. + */ + struct GNUNET_CRYPTO_HpkePublicKey hpke_key; }; /** @@ -512,6 +517,11 @@ struct GNUNET_MESSENGER_MessageKey * The new blindable public key which replaces the current senders public key. */ struct GNUNET_CRYPTO_BlindablePublicKey key; + + /** + * The new HPKE public key which replaces the current senders HPKE public key. + */ + struct GNUNET_CRYPTO_HpkePublicKey hpke_key; }; /** diff --git a/src/lib/util/crypto_hpke.c b/src/lib/util/crypto_hpke.c @@ -842,11 +842,13 @@ GNUNET_CRYPTO_hpke_pk_to_x25519 (const struct GNUNET_CRYPTO_BlindablePublicKey * if (0 != crypto_sign_ed25519_pk_to_curve25519 (x25519->ecdhe_key.q_y, pk->ecdsa_key.q_y)) return GNUNET_SYSERR; + x25519->type = GNUNET_CRYPTO_HPKE_KEY_TYPE_ECDHE; return GNUNET_OK; case GNUNET_PUBLIC_KEY_TYPE_EDDSA: if (0 != crypto_sign_ed25519_pk_to_curve25519 (x25519->ecdhe_key.q_y, pk->eddsa_key.q_y)) return GNUNET_SYSERR; + x25519->type = GNUNET_CRYPTO_HPKE_KEY_TYPE_ECDHE; return GNUNET_OK; default: return GNUNET_SYSERR; @@ -868,11 +870,13 @@ GNUNET_CRYPTO_hpke_sk_to_x25519 (const struct memcpy (x25519->ecdhe_key.d, sk->ecdsa_key.d, sizeof sk->ecdsa_key.d); + x25519->type = GNUNET_CRYPTO_HPKE_KEY_TYPE_ECDHE; return GNUNET_OK; case GNUNET_PUBLIC_KEY_TYPE_EDDSA: if (0 != crypto_sign_ed25519_sk_to_curve25519 (x25519->ecdhe_key.d, sk->eddsa_key.d)) return GNUNET_SYSERR; + x25519->type = GNUNET_CRYPTO_HPKE_KEY_TYPE_ECDHE; return GNUNET_OK; default: return GNUNET_SYSERR; @@ -880,3 +884,62 @@ GNUNET_CRYPTO_hpke_sk_to_x25519 (const struct return GNUNET_SYSERR; } + + +ssize_t +GNUNET_CRYPTO_hpke_pk_get_length ( + const struct GNUNET_CRYPTO_HpkePublicKey *key) +{ + switch (ntohl (key->type)) + { + case GNUNET_CRYPTO_HPKE_KEY_TYPE_ECDHE: + return sizeof (key->type) + sizeof (key->ecdhe_key); + default: + GNUNET_break (0); + } + return -1; +} + + +enum GNUNET_GenericReturnValue +GNUNET_CRYPTO_read_hpke_pk_from_buffer (const void *buffer, + size_t len, + struct + GNUNET_CRYPTO_HpkePublicKey *key, + size_t *read) +{ + ssize_t length; + if (len < sizeof (key->type)) + return GNUNET_SYSERR; + GNUNET_memcpy (&key->type, + buffer, + sizeof (key->type)); + length = GNUNET_CRYPTO_hpke_pk_get_length (key); + if (len < length) + return GNUNET_SYSERR; + if (length < 0) + return GNUNET_SYSERR; + GNUNET_memcpy (&key->ecdhe_key, + buffer + sizeof (key->type), + length - sizeof (key->type)); + *read = length; + return GNUNET_OK; +} + + +ssize_t +GNUNET_CRYPTO_write_hpke_pk_to_buffer (const struct + GNUNET_CRYPTO_HpkePublicKey *key, + void*buffer, + size_t len) +{ + const ssize_t length = GNUNET_CRYPTO_hpke_pk_get_length (key); + if (len < length) + return -1; + if (length < 0) + return -2; + GNUNET_memcpy (buffer, &(key->type), sizeof (key->type)); + GNUNET_memcpy (buffer + sizeof (key->type), &(key->ecdhe_key), length + - sizeof (key->type)); + return length; +} diff --git a/src/service/messenger/messenger_api.c b/src/service/messenger/messenger_api.c @@ -1104,6 +1104,7 @@ dequeue_message_from_room (void *cls) struct GNUNET_HashCode epoch; struct GNUNET_HashCode hash; struct GNUNET_CRYPTO_BlindablePublicKey pubkey; + struct GNUNET_CRYPTO_HpkePublicKey hpke_key; GNUNET_assert (cls); @@ -1148,7 +1149,10 @@ dequeue_message_from_room (void *cls) GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_blindable_key_get_public ( &key, &pubkey)); - if (GNUNET_YES == encrypt_message (transcript, &pubkey)) + GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_hpke_pk_to_x25519 ( + &pubkey, &hpke_key)); + + if (GNUNET_YES == encrypt_message (transcript, &hpke_key)) { struct GNUNET_HashCode other; send_message_to_room (room, transcript, &key, &epoch, &other); @@ -1531,6 +1535,7 @@ send_message_to_room_with_key (struct GNUNET_MESSENGER_Room *room, { struct GNUNET_MESSENGER_Message *transcript; const struct GNUNET_CRYPTO_BlindablePublicKey *pubkey; + struct GNUNET_CRYPTO_HpkePublicKey hpke_key; const char *handle_name; char *original_name; @@ -1564,7 +1569,10 @@ skip_naming: if (0 != GNUNET_memcmp (pubkey, public_key)) transcript = transcribe_message (message, public_key); - if (GNUNET_YES != encrypt_message (message, public_key)) + GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_hpke_pk_to_x25519 ( + pubkey, &hpke_key)); + + if (GNUNET_YES != encrypt_message (message, &hpke_key)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Sending message aborted: Encryption failed!\n"); diff --git a/src/service/messenger/messenger_api_message.c b/src/service/messenger/messenger_api_message.c @@ -486,12 +486,14 @@ get_message_body_size (enum GNUNET_MESSENGER_MessageKind kind, { case GNUNET_MESSENGER_KIND_JOIN: length += GNUNET_CRYPTO_blindable_pk_get_length (&(body->join.key)); + length += GNUNET_CRYPTO_hpke_pk_get_length (&(body->join.hpke_key)); break; case GNUNET_MESSENGER_KIND_NAME: length += (body->name.name ? strlen (body->name.name) : 0); break; case GNUNET_MESSENGER_KIND_KEY: length += GNUNET_CRYPTO_blindable_pk_get_length (&(body->key.key)); + length += GNUNET_CRYPTO_hpke_pk_get_length (&(body->key.hpke_key)); break; case GNUNET_MESSENGER_KIND_TEXT: length += (body->text.text ? strlen (body->text.text) : 0); @@ -634,6 +636,15 @@ calc_padded_length (uint16_t length) offset += result; \ } while (0) +#define encode_step_hpke_key(dst, offset, src, length) do { \ + ssize_t result = GNUNET_CRYPTO_write_hpke_pk_to_buffer ( \ + src, dst + offset, length - offset); \ + if (result < 0) \ + GNUNET_break (0); \ + else \ + offset += result; \ +} while (0) + #define encode_step_signature(dst, offset, src, length) do { \ ssize_t result = GNUNET_CRYPTO_write_blinded_key_signature_to_buffer ( \ src, dst + offset, length - offset); \ @@ -664,6 +675,7 @@ encode_message_body (enum GNUNET_MESSENGER_MessageKind kind, case GNUNET_MESSENGER_KIND_JOIN: encode_step (buffer, offset, &(body->join.epoch)); encode_step_key (buffer, offset, &(body->join.key), length); + encode_step_hpke_key (buffer, offset, &(body->join.hpke_key), length); break; case GNUNET_MESSENGER_KIND_LEAVE: encode_step (buffer, offset, &(body->leave.epoch)); @@ -678,6 +690,7 @@ encode_message_body (enum GNUNET_MESSENGER_MessageKind kind, break; case GNUNET_MESSENGER_KIND_KEY: encode_step_key (buffer, offset, &(body->key.key), length); + encode_step_hpke_key (buffer, offset, &(body->key.hpke_key), length); break; case GNUNET_MESSENGER_KIND_PEER: encode_step (buffer, offset, &(body->peer.peer)); @@ -930,6 +943,17 @@ encode_short_message (const struct GNUNET_MESSENGER_ShortMessage *message, offset += read; \ } while (0) +#define decode_step_hpke_key(src, offset, dst, length) do { \ + enum GNUNET_GenericReturnValue result; \ + size_t read; \ + result = GNUNET_CRYPTO_read_hpke_pk_from_buffer ( \ + src + offset, length - offset, dst, &read); \ + if (GNUNET_SYSERR == result) \ + GNUNET_break (0); \ + else \ + offset += read; \ +} while (0) + static uint16_t decode_message_body (enum GNUNET_MESSENGER_MessageKind *kind, struct GNUNET_MESSENGER_MessageBody *body, @@ -969,6 +993,7 @@ decode_message_body (enum GNUNET_MESSENGER_MessageKind *kind, case GNUNET_MESSENGER_KIND_JOIN: decode_step (buffer, offset, &(body->join.epoch)); decode_step_key (buffer, offset, &(body->join.key), length); + decode_step_hpke_key (buffer, offset, &(body->join.hpke_key), length); break; case GNUNET_MESSENGER_KIND_LEAVE: decode_step (buffer, offset, &(body->leave.epoch)); @@ -981,6 +1006,7 @@ decode_message_body (enum GNUNET_MESSENGER_MessageKind *kind, break; case GNUNET_MESSENGER_KIND_KEY: decode_step_key (buffer, offset, &(body->key.key), length); + decode_step_hpke_key (buffer, offset, &(body->key.hpke_key), length); break; case GNUNET_MESSENGER_KIND_PEER: decode_step (buffer, offset, &(body->peer.peer)); @@ -1549,15 +1575,14 @@ verify_message_by_key (const struct GNUNET_MESSENGER_Message *message, enum GNUNET_GenericReturnValue encrypt_message (struct GNUNET_MESSENGER_Message *message, - const struct GNUNET_CRYPTO_BlindablePublicKey *key) + const struct GNUNET_CRYPTO_HpkePublicKey *hpke_key) { - struct GNUNET_CRYPTO_HpkePublicKey hpke_key; enum GNUNET_GenericReturnValue result; struct GNUNET_MESSENGER_ShortMessage shortened; uint16_t length, padded_length, encoded_length; uint8_t *data; - GNUNET_assert ((message) && (key)); + GNUNET_assert ((message) && (hpke_key)); if (GNUNET_YES == is_service_message (message)) return GNUNET_NO; @@ -1573,8 +1598,6 @@ encrypt_message (struct GNUNET_MESSENGER_Message *message, message->body.privacy.data = GNUNET_malloc (padded_length); message->body.privacy.length = padded_length; - GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_hpke_pk_to_x25519 (key, - &hpke_key)); encoded_length = (padded_length - encryption_overhead); GNUNET_assert (padded_length == encoded_length + encryption_overhead); @@ -1584,7 +1607,7 @@ encrypt_message (struct GNUNET_MESSENGER_Message *message, encode_short_message (&shortened, encoded_length, (char *) data); - if (GNUNET_OK != GNUNET_CRYPTO_hpke_seal_oneshot (&hpke_key, + if (GNUNET_OK != GNUNET_CRYPTO_hpke_seal_oneshot (hpke_key, (const uint8_t*) "messenger", strlen ("messenger"), @@ -1612,14 +1635,13 @@ cleanup: enum GNUNET_GenericReturnValue decrypt_message (struct GNUNET_MESSENGER_Message *message, - const struct GNUNET_CRYPTO_BlindablePrivateKey *key) + const struct GNUNET_CRYPTO_HpkePrivateKey *hpke_key) { - struct GNUNET_CRYPTO_HpkePrivateKey hpke_key; enum GNUNET_GenericReturnValue result; uint16_t padded_length, encoded_length; uint8_t *data; - GNUNET_assert ((message) && (key) && + GNUNET_assert ((message) && (hpke_key) && (GNUNET_MESSENGER_KIND_PRIVATE == message->header.kind)); padded_length = message->body.privacy.length; @@ -1632,8 +1654,6 @@ decrypt_message (struct GNUNET_MESSENGER_Message *message, return GNUNET_NO; } - GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_hpke_sk_to_x25519 (key, - &hpke_key)); encoded_length = (padded_length - encryption_overhead); GNUNET_assert (padded_length == encoded_length + encryption_overhead); @@ -1642,7 +1662,7 @@ decrypt_message (struct GNUNET_MESSENGER_Message *message, data = GNUNET_malloc (encoded_length); if (GNUNET_OK != - GNUNET_CRYPTO_hpke_open_oneshot (&hpke_key, + GNUNET_CRYPTO_hpke_open_oneshot (hpke_key, (uint8_t*) "messenger", strlen ("messenger"), NULL, 0, diff --git a/src/service/messenger/messenger_api_message_kind.c b/src/service/messenger/messenger_api_message_kind.c @@ -47,6 +47,9 @@ create_message_join (const struct GNUNET_CRYPTO_BlindablePrivateKey *key) GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_blindable_key_get_public ( key, &(message->body.join.key))); + GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_hpke_pk_to_x25519 ( + &(message->body.join.key), &(message->body.join.hpke_key))); + return message; } @@ -102,6 +105,9 @@ create_message_key (const struct GNUNET_CRYPTO_BlindablePrivateKey *key) GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_blindable_key_get_public ( key, &(message->body.key.key))); + GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_hpke_pk_to_x25519 ( + &(message->body.key.key), &(message->body.key.hpke_key))); + return message; } diff --git a/src/service/messenger/messenger_api_room.c b/src/service/messenger/messenger_api_room.c @@ -1369,6 +1369,8 @@ handle_private_message (struct GNUNET_MESSENGER_Room *room, struct GNUNET_MESSENGER_RoomMessageEntry *entry) { struct GNUNET_MESSENGER_Message *private_message; + const struct GNUNET_CRYPTO_BlindablePrivateKey *key; + struct GNUNET_CRYPTO_HpkePrivateKey hpke_key; GNUNET_assert ((room) && (hash) && (entry)); @@ -1377,13 +1379,23 @@ handle_private_message (struct GNUNET_MESSENGER_Room *room, if (! private_message) return; + key = get_handle_key (room->handle); + + if (! key) + return; + + GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_hpke_sk_to_x25519 ( + key, &hpke_key)); + if (GNUNET_YES != decrypt_message ( - private_message, get_handle_key (room->handle))) + private_message, &hpke_key)) { destroy_message (private_message); private_message = NULL; } + memset (&hpke_key, 0, sizeof (hpke_key)); + if (! private_message) return;