cleanup: add timed_auth module for ping_ids

This commit is contained in:
zugz (tox) 2019-09-07 00:00:01 +00:00
parent 7cee48d9c4
commit 97acb39c1f
No known key found for this signature in database
GPG Key ID: 6F2BDA289D04F249
9 changed files with 157 additions and 36 deletions

View File

@ -272,6 +272,8 @@ set(toxcore_SOURCES
toxcore/TCP_connection.h toxcore/TCP_connection.h
toxcore/TCP_server.c toxcore/TCP_server.c
toxcore/TCP_server.h toxcore/TCP_server.h
toxcore/timed_auth.c
toxcore/timed_auth.h
toxcore/tox_api.c toxcore/tox_api.c
toxcore/tox.c toxcore/tox.c
toxcore/tox_dispatch.c toxcore/tox_dispatch.c

View File

@ -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( cc_library(
name = "ping_array", name = "ping_array",
srcs = ["ping_array.c"], srcs = ["ping_array.c"],
@ -427,6 +438,7 @@ cc_library(
":ccompat", ":ccompat",
":mono_time", ":mono_time",
":onion", ":onion",
":timed_auth",
":util", ":util",
], ],
) )

View File

@ -45,6 +45,8 @@ libtoxcore_la_SOURCES = ../third_party/cmp/cmp.c \
../toxcore/network.c \ ../toxcore/network.c \
../toxcore/crypto_core.h \ ../toxcore/crypto_core.h \
../toxcore/crypto_core.c \ ../toxcore/crypto_core.c \
../toxcore/timed_auth.h \
../toxcore/timed_auth.c \
../toxcore/ping_array.h \ ../toxcore/ping_array.h \
../toxcore/ping_array.c \ ../toxcore/ping_array.c \
../toxcore/net_crypto.h \ ../toxcore/net_crypto.h \

View File

@ -18,6 +18,7 @@
// We use libsodium by default. // We use libsodium by default.
#include <sodium.h> #include <sodium.h>
#else #else
#include <crypto_auth.h>
#include <crypto_box.h> #include <crypto_box.h>
#include <crypto_hash_sha256.h> #include <crypto_hash_sha256.h>
#include <crypto_hash_sha512.h> #include <crypto_hash_sha512.h>
@ -57,6 +58,10 @@ static_assert(CRYPTO_MAC_SIZE == crypto_box_MACBYTES,
"CRYPTO_MAC_SIZE should be equal to crypto_box_MACBYTES"); "CRYPTO_MAC_SIZE should be equal to crypto_box_MACBYTES");
static_assert(CRYPTO_NONCE_SIZE == crypto_box_NONCEBYTES, static_assert(CRYPTO_NONCE_SIZE == crypto_box_NONCEBYTES,
"CRYPTO_NONCE_SIZE should be equal to 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, static_assert(CRYPTO_SHA256_SIZE == crypto_hash_sha256_BYTES,
"CRYPTO_SHA256_SIZE should be equal to crypto_hash_sha256_BYTES"); "CRYPTO_SHA256_SIZE should be equal to crypto_hash_sha256_BYTES");
static_assert(CRYPTO_SHA512_SIZE == crypto_hash_sha512_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); 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) void crypto_sha512(uint8_t *hash, const uint8_t *data, size_t length)
{ {
crypto_hash_sha512(hash, data, length); crypto_hash_sha512(hash, data, length);

View File

@ -125,6 +125,16 @@ const Random *system_random(void);
*/ */
#define EXT_SECRET_KEY_SIZE (ENC_SECRET_KEY_SIZE + SIG_SECRET_KEY_SIZE) #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. * @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() non_null()
void crypto_sha512(uint8_t *hash, const uint8_t *data, size_t length); 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 * @brief Compare 2 public keys of length @ref CRYPTO_PUBLIC_KEY_SIZE, not vulnerable to
* timing attacks. * timing attacks.
@ -390,6 +417,12 @@ bool crypto_memlock(void *data, size_t length);
non_null() non_null()
bool crypto_memunlock(void *data, size_t length); 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 #ifdef __cplusplus
} // extern "C" } // extern "C"
#endif #endif

View File

@ -49,8 +49,7 @@ struct Onion_Announce {
DHT *dht; DHT *dht;
Networking_Core *net; Networking_Core *net;
Onion_Announce_Entry entries[ONION_ANNOUNCE_MAX_ENTRIES]; 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 hmac_key[CRYPTO_HMAC_KEY_SIZE];
uint8_t secret_bytes[CRYPTO_SYMMETRIC_KEY_SIZE];
Shared_Keys shared_keys_recv; 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; 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) uint8_t *onion_announce_entry_public_key(Onion_Announce *onion_a, uint32_t entry)
{ {
return onion_a->entries[entry].public_key; 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; 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 /** @brief check if public key is in entries list
* *
* return -1 if no * 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() 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) uint8_t *response, int index, const uint8_t *packet_public_key, const uint8_t *data_public_key)
{ {
if (index < 0) { if (index < 0) {
response[0] = 0; response[0] = 0;
memcpy(response + 1, ping_id2, ONION_PING_ID_SIZE); memcpy(response + 1, ping_id, ONION_PING_ID_SIZE);
return; return;
} }
if (public_key_eq(onion_a->entries[index].public_key, packet_public_key)) { 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)) { if (!public_key_eq(onion_a->entries[index].data_public_key, data_public_key)) {
response[0] = 0; response[0] = 0;
memcpy(response + 1, ping_id2, ONION_PING_ID_SIZE); memcpy(response + 1, ping_id, ONION_PING_ID_SIZE);
} else { } else {
response[0] = 2; response[0] = 2;
memcpy(response + 1, ping_id2, ONION_PING_ID_SIZE); memcpy(response + 1, ping_id, ONION_PING_ID_SIZE);
} }
} else { } else {
response[0] = 1; response[0] = 1;
@ -466,18 +445,17 @@ static int handle_announce_request_common(
return 1; return 1;
} }
uint8_t ping_id1[ONION_PING_ID_SIZE]; const uint16_t ping_id_data_len = CRYPTO_PUBLIC_KEY_SIZE + sizeof(*source);
generate_ping_id(onion_a, mono_time_get(onion_a->mono_time), packet_public_key, source, ping_id1); uint8_t ping_id_data[CRYPTO_PUBLIC_KEY_SIZE + sizeof(*source)];
memcpy(ping_id_data, packet_public_key, CRYPTO_PUBLIC_KEY_SIZE);
uint8_t ping_id2[ONION_PING_ID_SIZE]; memcpy(ping_id_data + CRYPTO_PUBLIC_KEY_SIZE, source, sizeof(*source));
generate_ping_id(onion_a, mono_time_get(onion_a->mono_time) + PING_ID_TIMEOUT, packet_public_key, source, ping_id2);
const uint8_t *data_public_key = plain + ONION_PING_ID_SIZE + CRYPTO_PUBLIC_KEY_SIZE; const uint8_t *data_public_key = plain + ONION_PING_ID_SIZE + CRYPTO_PUBLIC_KEY_SIZE;
int index; int index;
if (onion_ping_id_eq(ping_id1, plain) if (check_timed_auth(onion_a->mono_time, PING_ID_TIMEOUT, onion_a->hmac_key,
|| onion_ping_id_eq(ping_id2, plain)) { ping_id_data, ping_id_data_len, plain)) {
index = add_to_entries(onion_a, source, packet_public_key, data_public_key, index = add_to_entries(onion_a, source, packet_public_key, data_public_key,
packet + (length - ONION_RETURN_3)); packet + (length - ONION_RETURN_3));
} else { } else {
@ -505,7 +483,11 @@ static int handle_announce_request_common(
return 1; 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; 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_max_size = 0;
onion_a->extra_data_callback = nullptr; onion_a->extra_data_callback = nullptr;
onion_a->extra_data_object = 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, &handle_announce_request, onion_a);
networking_registerhandler(onion_a->net, NET_PACKET_ANNOUNCE_REQUEST_OLD, &handle_announce_request_old, 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, nullptr, nullptr);
networking_registerhandler(onion_a->net, NET_PACKET_ANNOUNCE_REQUEST_OLD, 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); 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); free(onion_a);
} }

View File

@ -11,10 +11,11 @@
#include "logger.h" #include "logger.h"
#include "onion.h" #include "onion.h"
#include "timed_auth.h"
#define ONION_ANNOUNCE_MAX_ENTRIES 160 #define ONION_ANNOUNCE_MAX_ENTRIES 160
#define ONION_ANNOUNCE_TIMEOUT 300 #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_MAX_EXTRA_DATA_SIZE 136
#define ONION_ANNOUNCE_SENDBACK_DATA_LENGTH (sizeof(uint64_t)) #define ONION_ANNOUNCE_SENDBACK_DATA_LENGTH (sizeof(uint64_t))

40
toxcore/timed_auth.c Normal file
View File

@ -0,0 +1,40 @@
/* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright © 2019-2021 The TokTok team.
*/
#include "timed_auth.h"
#include <string.h>
#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;
}

24
toxcore/timed_auth.h Normal file
View File

@ -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