From 97acb39c1fd4ec05421729295e969d762b63cd01 Mon Sep 17 00:00:00 2001 From: "zugz (tox)" Date: Sat, 7 Sep 2019 00:00:01 +0000 Subject: [PATCH] cleanup: add timed_auth module for ping_ids --- CMakeLists.txt | 2 ++ toxcore/BUILD.bazel | 12 +++++++++ toxcore/Makefile.inc | 2 ++ toxcore/crypto_core.c | 22 ++++++++++++++++ toxcore/crypto_core.h | 33 ++++++++++++++++++++++++ toxcore/onion_announce.c | 55 +++++++++++++++------------------------- toxcore/onion_announce.h | 3 ++- toxcore/timed_auth.c | 40 +++++++++++++++++++++++++++++ toxcore/timed_auth.h | 24 ++++++++++++++++++ 9 files changed, 157 insertions(+), 36 deletions(-) create mode 100644 toxcore/timed_auth.c create mode 100644 toxcore/timed_auth.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d9f08b48..7ff0818b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -272,6 +272,8 @@ set(toxcore_SOURCES toxcore/TCP_connection.h toxcore/TCP_server.c toxcore/TCP_server.h + toxcore/timed_auth.c + toxcore/timed_auth.h toxcore/tox_api.c toxcore/tox.c toxcore/tox_dispatch.c diff --git a/toxcore/BUILD.bazel b/toxcore/BUILD.bazel index 09030255..964fbeab 100644 --- a/toxcore/BUILD.bazel +++ b/toxcore/BUILD.bazel @@ -216,6 +216,17 @@ cc_test( ], ) +cc_library( + name = "timed_auth", + srcs = ["timed_auth.c"], + hdrs = ["timed_auth.h"], + deps = [ + ":ccompat", + ":crypto_core", + ":mono_time", + ], +) + cc_library( name = "ping_array", srcs = ["ping_array.c"], @@ -427,6 +438,7 @@ cc_library( ":ccompat", ":mono_time", ":onion", + ":timed_auth", ":util", ], ) diff --git a/toxcore/Makefile.inc b/toxcore/Makefile.inc index 513b4c49..7c00ffff 100644 --- a/toxcore/Makefile.inc +++ b/toxcore/Makefile.inc @@ -45,6 +45,8 @@ libtoxcore_la_SOURCES = ../third_party/cmp/cmp.c \ ../toxcore/network.c \ ../toxcore/crypto_core.h \ ../toxcore/crypto_core.c \ + ../toxcore/timed_auth.h \ + ../toxcore/timed_auth.c \ ../toxcore/ping_array.h \ ../toxcore/ping_array.c \ ../toxcore/net_crypto.h \ diff --git a/toxcore/crypto_core.c b/toxcore/crypto_core.c index cf9fa368..b0bca7b4 100644 --- a/toxcore/crypto_core.c +++ b/toxcore/crypto_core.c @@ -18,6 +18,7 @@ // We use libsodium by default. #include #else +#include #include #include #include @@ -57,6 +58,10 @@ static_assert(CRYPTO_MAC_SIZE == crypto_box_MACBYTES, "CRYPTO_MAC_SIZE should be equal to crypto_box_MACBYTES"); static_assert(CRYPTO_NONCE_SIZE == crypto_box_NONCEBYTES, "CRYPTO_NONCE_SIZE should be equal to crypto_box_NONCEBYTES"); +static_assert(CRYPTO_HMAC_SIZE == crypto_auth_BYTES, + "CRYPTO_HMAC_SIZE should be equal to crypto_auth_BYTES"); +static_assert(CRYPTO_HMAC_KEY_SIZE == crypto_auth_KEYBYTES, + "CRYPTO_HMAC_KEY_SIZE should be equal to crypto_auth_KEYBYTES"); static_assert(CRYPTO_SHA256_SIZE == crypto_hash_sha256_BYTES, "CRYPTO_SHA256_SIZE should be equal to crypto_hash_sha256_BYTES"); static_assert(CRYPTO_SHA512_SIZE == crypto_hash_sha512_BYTES, @@ -445,6 +450,23 @@ void crypto_sha256(uint8_t *hash, const uint8_t *data, size_t length) crypto_hash_sha256(hash, data, length); } +void new_hmac_key(const Random *rng, uint8_t *key) +{ + random_bytes(rng, key, CRYPTO_HMAC_KEY_SIZE); +} + +void crypto_hmac(uint8_t auth[CRYPTO_HMAC_SIZE], const uint8_t key[CRYPTO_HMAC_KEY_SIZE], const uint8_t *data, + size_t length) +{ + crypto_auth(auth, data, length, key); +} + +bool crypto_hmac_verify(const uint8_t auth[CRYPTO_HMAC_SIZE], const uint8_t key[CRYPTO_HMAC_KEY_SIZE], + const uint8_t *data, size_t length) +{ + return (crypto_auth_verify(auth, data, length, key) == 0); +} + void crypto_sha512(uint8_t *hash, const uint8_t *data, size_t length) { crypto_hash_sha512(hash, data, length); diff --git a/toxcore/crypto_core.h b/toxcore/crypto_core.h index b9b2893d..1b984cb6 100644 --- a/toxcore/crypto_core.h +++ b/toxcore/crypto_core.h @@ -125,6 +125,16 @@ const Random *system_random(void); */ #define EXT_SECRET_KEY_SIZE (ENC_SECRET_KEY_SIZE + SIG_SECRET_KEY_SIZE) +/** + * @brief The number of bytes in an HMAC authenticator. + */ +#define CRYPTO_HMAC_SIZE 32 + +/** + * @brief The number of bytes in an HMAC secret key. + */ +#define CRYPTO_HMAC_KEY_SIZE 32 + /** * @brief A `bzero`-like function which won't be optimised away by the compiler. * @@ -147,6 +157,23 @@ void crypto_sha256(uint8_t *hash, const uint8_t *data, size_t length); non_null() void crypto_sha512(uint8_t *hash, const uint8_t *data, size_t length); +/** + * @brief Compute an HMAC authenticator (32 bytes). + * + * @param auth Resulting authenticator. + * @param key Secret key, as generated by `new_hmac_key()`. + */ +non_null() +void crypto_hmac(uint8_t auth[CRYPTO_HMAC_SIZE], const uint8_t key[CRYPTO_HMAC_KEY_SIZE], const uint8_t *data, + size_t length); + +/** + * @brief Verify an HMAC authenticator. + */ +non_null() +bool crypto_hmac_verify(const uint8_t auth[CRYPTO_HMAC_SIZE], const uint8_t key[CRYPTO_HMAC_KEY_SIZE], + const uint8_t *data, size_t length); + /** * @brief Compare 2 public keys of length @ref CRYPTO_PUBLIC_KEY_SIZE, not vulnerable to * timing attacks. @@ -390,6 +417,12 @@ bool crypto_memlock(void *data, size_t length); non_null() bool crypto_memunlock(void *data, size_t length); +/** + * @brief Generate a random secret HMAC key. + */ +non_null() +void new_hmac_key(const Random *rng, uint8_t key[CRYPTO_HMAC_KEY_SIZE]); + #ifdef __cplusplus } // extern "C" #endif diff --git a/toxcore/onion_announce.c b/toxcore/onion_announce.c index fa8122bc..7d97517c 100644 --- a/toxcore/onion_announce.c +++ b/toxcore/onion_announce.c @@ -49,8 +49,7 @@ struct Onion_Announce { DHT *dht; Networking_Core *net; Onion_Announce_Entry entries[ONION_ANNOUNCE_MAX_ENTRIES]; - /* This is CRYPTO_SYMMETRIC_KEY_SIZE long just so we can use new_symmetric_key() to fill it */ - uint8_t secret_bytes[CRYPTO_SYMMETRIC_KEY_SIZE]; + uint8_t hmac_key[CRYPTO_HMAC_KEY_SIZE]; Shared_Keys shared_keys_recv; @@ -67,12 +66,6 @@ void onion_announce_extra_data_callback(Onion_Announce *onion_a, uint16_t extra_ onion_a->extra_data_object = extra_data_object; } -non_null() -static bool onion_ping_id_eq(const uint8_t *a, const uint8_t *b) -{ - return pk_equal(a, b); -} - uint8_t *onion_announce_entry_public_key(Onion_Announce *onion_a, uint32_t entry) { return onion_a->entries[entry].public_key; @@ -256,20 +249,6 @@ int send_data_request(const Networking_Core *net, const Random *rng, const Onion return 0; } -/** Generate a ping_id and put it in ping_id */ -non_null() -static void generate_ping_id(const Onion_Announce *onion_a, uint64_t ping_time, const uint8_t *public_key, - const IP_Port *ret_ip_port, uint8_t *ping_id) -{ - ping_time /= PING_ID_TIMEOUT; - uint8_t data[CRYPTO_SYMMETRIC_KEY_SIZE + sizeof(ping_time) + CRYPTO_PUBLIC_KEY_SIZE + sizeof(IP_Port)]; - memcpy(data, onion_a->secret_bytes, CRYPTO_SYMMETRIC_KEY_SIZE); - memcpy(data + CRYPTO_SYMMETRIC_KEY_SIZE, &ping_time, sizeof(ping_time)); - memcpy(data + CRYPTO_SYMMETRIC_KEY_SIZE + sizeof(ping_time), public_key, CRYPTO_PUBLIC_KEY_SIZE); - memcpy(data + CRYPTO_SYMMETRIC_KEY_SIZE + sizeof(ping_time) + CRYPTO_PUBLIC_KEY_SIZE, ret_ip_port, sizeof(IP_Port)); - crypto_sha256(ping_id, data, sizeof(data)); -} - /** @brief check if public key is in entries list * * return -1 if no @@ -400,22 +379,22 @@ static int add_to_entries(Onion_Announce *onion_a, const IP_Port *ret_ip_port, c } non_null() -static void make_announce_payload_helper(const Onion_Announce *onion_a, const uint8_t *ping_id2, +static void make_announce_payload_helper(const Onion_Announce *onion_a, const uint8_t *ping_id, uint8_t *response, int index, const uint8_t *packet_public_key, const uint8_t *data_public_key) { if (index < 0) { response[0] = 0; - memcpy(response + 1, ping_id2, ONION_PING_ID_SIZE); + memcpy(response + 1, ping_id, ONION_PING_ID_SIZE); return; } if (public_key_eq(onion_a->entries[index].public_key, packet_public_key)) { if (!public_key_eq(onion_a->entries[index].data_public_key, data_public_key)) { response[0] = 0; - memcpy(response + 1, ping_id2, ONION_PING_ID_SIZE); + memcpy(response + 1, ping_id, ONION_PING_ID_SIZE); } else { response[0] = 2; - memcpy(response + 1, ping_id2, ONION_PING_ID_SIZE); + memcpy(response + 1, ping_id, ONION_PING_ID_SIZE); } } else { response[0] = 1; @@ -466,18 +445,17 @@ static int handle_announce_request_common( return 1; } - uint8_t ping_id1[ONION_PING_ID_SIZE]; - generate_ping_id(onion_a, mono_time_get(onion_a->mono_time), packet_public_key, source, ping_id1); - - uint8_t ping_id2[ONION_PING_ID_SIZE]; - generate_ping_id(onion_a, mono_time_get(onion_a->mono_time) + PING_ID_TIMEOUT, packet_public_key, source, ping_id2); + const uint16_t ping_id_data_len = CRYPTO_PUBLIC_KEY_SIZE + sizeof(*source); + uint8_t ping_id_data[CRYPTO_PUBLIC_KEY_SIZE + sizeof(*source)]; + memcpy(ping_id_data, packet_public_key, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(ping_id_data + CRYPTO_PUBLIC_KEY_SIZE, source, sizeof(*source)); const uint8_t *data_public_key = plain + ONION_PING_ID_SIZE + CRYPTO_PUBLIC_KEY_SIZE; int index; - if (onion_ping_id_eq(ping_id1, plain) - || onion_ping_id_eq(ping_id2, plain)) { + if (check_timed_auth(onion_a->mono_time, PING_ID_TIMEOUT, onion_a->hmac_key, + ping_id_data, ping_id_data_len, plain)) { index = add_to_entries(onion_a, source, packet_public_key, data_public_key, packet + (length - ONION_RETURN_3)); } else { @@ -505,7 +483,11 @@ static int handle_announce_request_common( return 1; } - make_announce_payload_helper(onion_a, ping_id2, response, index, packet_public_key, data_public_key); + uint8_t ping_id[TIMED_AUTH_SIZE]; + generate_timed_auth(onion_a->mono_time, PING_ID_TIMEOUT, onion_a->hmac_key, + ping_id_data, ping_id_data_len, ping_id); + + make_announce_payload_helper(onion_a, ping_id, response, index, packet_public_key, data_public_key); int nodes_length = 0; @@ -670,7 +652,7 @@ Onion_Announce *new_onion_announce(const Logger *log, const Random *rng, const M onion_a->extra_data_max_size = 0; onion_a->extra_data_callback = nullptr; onion_a->extra_data_object = nullptr; - new_symmetric_key(rng, onion_a->secret_bytes); + new_hmac_key(rng, onion_a->hmac_key); networking_registerhandler(onion_a->net, NET_PACKET_ANNOUNCE_REQUEST, &handle_announce_request, onion_a); networking_registerhandler(onion_a->net, NET_PACKET_ANNOUNCE_REQUEST_OLD, &handle_announce_request_old, onion_a); @@ -691,5 +673,8 @@ void kill_onion_announce(Onion_Announce *onion_a) networking_registerhandler(onion_a->net, NET_PACKET_ANNOUNCE_REQUEST, nullptr, nullptr); networking_registerhandler(onion_a->net, NET_PACKET_ANNOUNCE_REQUEST_OLD, nullptr, nullptr); networking_registerhandler(onion_a->net, NET_PACKET_ONION_DATA_REQUEST, nullptr, nullptr); + + crypto_memzero(onion_a->hmac_key, CRYPTO_HMAC_KEY_SIZE); + free(onion_a); } diff --git a/toxcore/onion_announce.h b/toxcore/onion_announce.h index 231daacf..8cf1f495 100644 --- a/toxcore/onion_announce.h +++ b/toxcore/onion_announce.h @@ -11,10 +11,11 @@ #include "logger.h" #include "onion.h" +#include "timed_auth.h" #define ONION_ANNOUNCE_MAX_ENTRIES 160 #define ONION_ANNOUNCE_TIMEOUT 300 -#define ONION_PING_ID_SIZE CRYPTO_SHA256_SIZE +#define ONION_PING_ID_SIZE TIMED_AUTH_SIZE #define ONION_MAX_EXTRA_DATA_SIZE 136 #define ONION_ANNOUNCE_SENDBACK_DATA_LENGTH (sizeof(uint64_t)) diff --git a/toxcore/timed_auth.c b/toxcore/timed_auth.c new file mode 100644 index 00000000..afe283ac --- /dev/null +++ b/toxcore/timed_auth.c @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later + * Copyright © 2019-2021 The TokTok team. + */ +#include "timed_auth.h" + +#include + +#include "ccompat.h" + +static void create_timed_auth_to_hash(const Mono_Time *mono_time, uint16_t timeout, bool previous, const uint8_t *data, + uint16_t length, uint8_t *to_hash) +{ + const uint64_t t = (mono_time_get(mono_time) / timeout) - previous; + memcpy(to_hash, &t, sizeof(t)); + memcpy(to_hash + sizeof(t), data, length); +} + +void generate_timed_auth(const Mono_Time *mono_time, uint16_t timeout, const uint8_t *key, + const uint8_t *data, uint16_t length, uint8_t *timed_auth) +{ + VLA(uint8_t, to_hash, sizeof(uint64_t) + length); + create_timed_auth_to_hash(mono_time, timeout, false, data, length, to_hash); + crypto_hmac(timed_auth, key, to_hash, SIZEOF_VLA(to_hash)); +} + +bool check_timed_auth(const Mono_Time *mono_time, uint16_t timeout, const uint8_t *key, const uint8_t *data, + uint16_t length, const uint8_t *timed_auth) +{ + VLA(uint8_t, to_hash, sizeof(uint64_t) + length); + + for (uint8_t i = 0; i < 2; ++i) { + create_timed_auth_to_hash(mono_time, timeout, i, data, length, to_hash); + + if (crypto_hmac_verify(timed_auth, key, to_hash, SIZEOF_VLA(to_hash))) { + return true; + } + } + + return false; +} diff --git a/toxcore/timed_auth.h b/toxcore/timed_auth.h new file mode 100644 index 00000000..f936f4d1 --- /dev/null +++ b/toxcore/timed_auth.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later + * Copyright © 2019-2021 The TokTok team. + */ +#ifndef C_TOXCORE_TOXCORE_TIMED_AUTH_H +#define C_TOXCORE_TOXCORE_TIMED_AUTH_H + +#include "crypto_core.h" +#include "mono_time.h" + +#define TIMED_AUTH_SIZE CRYPTO_HMAC_SIZE + +/* Put timed authentication code of data in timed_auth. */ +void generate_timed_auth(const Mono_Time *mono_time, uint16_t timeout, const uint8_t *key, + const uint8_t *data, uint16_t length, uint8_t *timed_auth); + +/* Check timed_auth. This succeeds if timed_auth was generated by + * generate_timed_auth at most timeout seconds ago, and fails if at least + * `2*timeout` seconds ago. + * + * return true on success, false otherwise. + */ +bool check_timed_auth(const Mono_Time *mono_time, uint16_t timeout, const uint8_t *key, const uint8_t *data, + uint16_t length, const uint8_t *timed_auth); +#endif