mirror of
https://github.com/irungentoo/toxcore.git
synced 2024-03-22 13:30:51 +08:00
cleanup: add timed_auth module for ping_ids
This commit is contained in:
parent
7cee48d9c4
commit
97acb39c1f
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
],
|
||||
)
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
// We use libsodium by default.
|
||||
#include <sodium.h>
|
||||
#else
|
||||
#include <crypto_auth.h>
|
||||
#include <crypto_box.h>
|
||||
#include <crypto_hash_sha256.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");
|
||||
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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
|
|
40
toxcore/timed_auth.c
Normal file
40
toxcore/timed_auth.c
Normal 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
24
toxcore/timed_auth.h
Normal 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
|
Loading…
Reference in New Issue
Block a user