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:
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;