mirror of
https://github.com/irungentoo/toxcore.git
synced 2024-03-22 13:30:51 +08:00
refactor: re-implement shared key cache in separate file
The exisiting implementation is not clearly documented and used by multiple modules.
This commit is contained in:
parent
2246517c3e
commit
8c7d30475f
|
@ -284,6 +284,8 @@ set(toxcore_SOURCES
|
||||||
toxcore/ping_array.h
|
toxcore/ping_array.h
|
||||||
toxcore/ping.c
|
toxcore/ping.c
|
||||||
toxcore/ping.h
|
toxcore/ping.h
|
||||||
|
toxcore/shared_key_cache.c
|
||||||
|
toxcore/shared_key_cache.h
|
||||||
toxcore/state.c
|
toxcore/state.c
|
||||||
toxcore/state.h
|
toxcore/state.h
|
||||||
toxcore/TCP_client.c
|
toxcore/TCP_client.c
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
b2bee729be40b0a0d8a4c6f0e2a527854d9a9d37712b73b915d7470bc91f5e6a /usr/local/bin/tox-bootstrapd
|
769233afaac07be03c094411e6ec8f031bde41beae475c74e154e51e51e9168b /usr/local/bin/tox-bootstrapd
|
||||||
|
|
|
@ -180,6 +180,24 @@ cc_test(
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cc_library(
|
||||||
|
name = "shared_key_cache",
|
||||||
|
srcs = ["shared_key_cache.c"],
|
||||||
|
hdrs = ["shared_key_cache.h"],
|
||||||
|
visibility = [
|
||||||
|
"//c-toxcore/auto_tests:__pkg__",
|
||||||
|
"//c-toxcore/other:__pkg__",
|
||||||
|
"//c-toxcore/other/bootstrap_daemon:__pkg__",
|
||||||
|
"//c-toxcore/testing:__pkg__",
|
||||||
|
"//c-toxcore/toxav:__pkg__",
|
||||||
|
],
|
||||||
|
deps = [
|
||||||
|
":ccompat",
|
||||||
|
":crypto_core",
|
||||||
|
":mono_time",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
cc_library(
|
cc_library(
|
||||||
name = "network",
|
name = "network",
|
||||||
srcs = ["network.c"],
|
srcs = ["network.c"],
|
||||||
|
@ -289,6 +307,7 @@ cc_library(
|
||||||
":mono_time",
|
":mono_time",
|
||||||
":network",
|
":network",
|
||||||
":ping_array",
|
":ping_array",
|
||||||
|
":shared_key_cache",
|
||||||
":state",
|
":state",
|
||||||
":util",
|
":util",
|
||||||
],
|
],
|
||||||
|
@ -326,6 +345,7 @@ cc_library(
|
||||||
":ccompat",
|
":ccompat",
|
||||||
":crypto_core",
|
":crypto_core",
|
||||||
":mono_time",
|
":mono_time",
|
||||||
|
":shared_key_cache",
|
||||||
":util",
|
":util",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -366,6 +386,7 @@ cc_library(
|
||||||
":LAN_discovery",
|
":LAN_discovery",
|
||||||
":ccompat",
|
":ccompat",
|
||||||
":forwarding",
|
":forwarding",
|
||||||
|
":shared_key_cache",
|
||||||
":timed_auth",
|
":timed_auth",
|
||||||
":util",
|
":util",
|
||||||
],
|
],
|
||||||
|
@ -480,6 +501,7 @@ cc_library(
|
||||||
":ccompat",
|
":ccompat",
|
||||||
":mono_time",
|
":mono_time",
|
||||||
":onion",
|
":onion",
|
||||||
|
":shared_key_cache",
|
||||||
":timed_auth",
|
":timed_auth",
|
||||||
":util",
|
":util",
|
||||||
],
|
],
|
||||||
|
|
105
toxcore/DHT.c
105
toxcore/DHT.c
|
@ -18,6 +18,7 @@
|
||||||
#include "mono_time.h"
|
#include "mono_time.h"
|
||||||
#include "network.h"
|
#include "network.h"
|
||||||
#include "ping.h"
|
#include "ping.h"
|
||||||
|
#include "shared_key_cache.h"
|
||||||
#include "state.h"
|
#include "state.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
@ -46,6 +47,10 @@
|
||||||
// TODO(sudden6): find out why we need multiple callbacks and if we really need 32
|
// TODO(sudden6): find out why we need multiple callbacks and if we really need 32
|
||||||
#define DHT_FRIEND_MAX_LOCKS 32
|
#define DHT_FRIEND_MAX_LOCKS 32
|
||||||
|
|
||||||
|
/* Settings for the shared key cache */
|
||||||
|
#define MAX_KEYS_PER_SLOT 4
|
||||||
|
#define KEYS_TIMEOUT 600
|
||||||
|
|
||||||
typedef struct DHT_Friend_Callback {
|
typedef struct DHT_Friend_Callback {
|
||||||
dht_ip_cb *ip_callback;
|
dht_ip_cb *ip_callback;
|
||||||
void *data;
|
void *data;
|
||||||
|
@ -107,8 +112,8 @@ struct DHT {
|
||||||
uint32_t loaded_num_nodes;
|
uint32_t loaded_num_nodes;
|
||||||
unsigned int loaded_nodes_index;
|
unsigned int loaded_nodes_index;
|
||||||
|
|
||||||
Shared_Keys shared_keys_recv;
|
Shared_Key_Cache *shared_keys_recv;
|
||||||
Shared_Keys shared_keys_sent;
|
Shared_Key_Cache *shared_keys_sent;
|
||||||
|
|
||||||
struct Ping *ping;
|
struct Ping *ping;
|
||||||
Ping_Array *dht_ping_array;
|
Ping_Array *dht_ping_array;
|
||||||
|
@ -255,74 +260,22 @@ unsigned int bit_by_bit_cmp(const uint8_t *pk1, const uint8_t *pk2)
|
||||||
return i * 8 + j;
|
return i * 8 + j;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Shared key generations are costly, it is therefore smart to store commonly used
|
|
||||||
* ones so that they can be re-used later without being computed again.
|
|
||||||
*
|
|
||||||
* If a shared key is already in shared_keys, copy it to shared_key.
|
|
||||||
* Otherwise generate it into shared_key and copy it to shared_keys
|
|
||||||
*/
|
|
||||||
void get_shared_key(const Mono_Time *mono_time, Shared_Keys *shared_keys, uint8_t *shared_key,
|
|
||||||
const uint8_t *secret_key, const uint8_t *public_key)
|
|
||||||
{
|
|
||||||
uint32_t num = -1;
|
|
||||||
uint32_t curr = 0;
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < MAX_KEYS_PER_SLOT; ++i) {
|
|
||||||
const int index = public_key[30] * MAX_KEYS_PER_SLOT + i;
|
|
||||||
Shared_Key *const key = &shared_keys->keys[index];
|
|
||||||
|
|
||||||
if (key->stored) {
|
|
||||||
if (pk_equal(public_key, key->public_key)) {
|
|
||||||
memcpy(shared_key, key->shared_key, CRYPTO_SHARED_KEY_SIZE);
|
|
||||||
++key->times_requested;
|
|
||||||
key->time_last_requested = mono_time_get(mono_time);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (num != 0) {
|
|
||||||
if (mono_time_is_timeout(mono_time, key->time_last_requested, KEYS_TIMEOUT)) {
|
|
||||||
num = 0;
|
|
||||||
curr = index;
|
|
||||||
} else if (num > key->times_requested) {
|
|
||||||
num = key->times_requested;
|
|
||||||
curr = index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (num != 0) {
|
|
||||||
num = 0;
|
|
||||||
curr = index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
encrypt_precompute(public_key, secret_key, shared_key);
|
|
||||||
|
|
||||||
if (num != UINT32_MAX) {
|
|
||||||
Shared_Key *const key = &shared_keys->keys[curr];
|
|
||||||
key->stored = true;
|
|
||||||
key->times_requested = 1;
|
|
||||||
memcpy(key->public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE);
|
|
||||||
memcpy(key->shared_key, shared_key, CRYPTO_SHARED_KEY_SIZE);
|
|
||||||
key->time_last_requested = mono_time_get(mono_time);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy shared_key to encrypt/decrypt DHT packet from public_key into shared_key
|
* Copy shared_key to encrypt/decrypt DHT packet from public_key into shared_key
|
||||||
* for packets that we receive.
|
* for packets that we receive.
|
||||||
*/
|
*/
|
||||||
void dht_get_shared_key_recv(DHT *dht, uint8_t *shared_key, const uint8_t *public_key)
|
const uint8_t *dht_get_shared_key_recv(DHT *dht, const uint8_t *public_key)
|
||||||
{
|
{
|
||||||
get_shared_key(dht->mono_time, &dht->shared_keys_recv, shared_key, dht->self_secret_key, public_key);
|
return shared_key_cache_lookup(dht->shared_keys_recv, public_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy shared_key to encrypt/decrypt DHT packet from public_key into shared_key
|
* Copy shared_key to encrypt/decrypt DHT packet from public_key into shared_key
|
||||||
* for packets that we send.
|
* for packets that we send.
|
||||||
*/
|
*/
|
||||||
void dht_get_shared_key_sent(DHT *dht, uint8_t *shared_key, const uint8_t *public_key)
|
const uint8_t *dht_get_shared_key_sent(DHT *dht, const uint8_t *public_key)
|
||||||
{
|
{
|
||||||
get_shared_key(dht->mono_time, &dht->shared_keys_sent, shared_key, dht->self_secret_key, public_key);
|
return shared_key_cache_lookup(dht->shared_keys_sent, public_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CRYPTO_SIZE (1 + CRYPTO_PUBLIC_KEY_SIZE * 2 + CRYPTO_NONCE_SIZE)
|
#define CRYPTO_SIZE (1 + CRYPTO_PUBLIC_KEY_SIZE * 2 + CRYPTO_NONCE_SIZE)
|
||||||
|
@ -1063,8 +1016,7 @@ static bool send_announce_ping(DHT *dht, const uint8_t *public_key, const IP_Por
|
||||||
public_key, CRYPTO_PUBLIC_KEY_SIZE);
|
public_key, CRYPTO_PUBLIC_KEY_SIZE);
|
||||||
memcpy(plain + CRYPTO_PUBLIC_KEY_SIZE, &ping_id, sizeof(ping_id));
|
memcpy(plain + CRYPTO_PUBLIC_KEY_SIZE, &ping_id, sizeof(ping_id));
|
||||||
|
|
||||||
uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE];
|
const uint8_t *shared_key = dht_get_shared_key_sent(dht, public_key);
|
||||||
dht_get_shared_key_sent(dht, shared_key, public_key);
|
|
||||||
|
|
||||||
uint8_t request[1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + sizeof(plain) + CRYPTO_MAC_SIZE];
|
uint8_t request[1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + sizeof(plain) + CRYPTO_MAC_SIZE];
|
||||||
|
|
||||||
|
@ -1092,8 +1044,7 @@ static int handle_data_search_response(void *object, const IP_Port *source,
|
||||||
|
|
||||||
VLA(uint8_t, plain, plain_len);
|
VLA(uint8_t, plain, plain_len);
|
||||||
const uint8_t *public_key = packet + 1;
|
const uint8_t *public_key = packet + 1;
|
||||||
uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE];
|
const uint8_t *shared_key = dht_get_shared_key_recv(dht, public_key);
|
||||||
dht_get_shared_key_recv(dht, shared_key, public_key);
|
|
||||||
|
|
||||||
if (decrypt_data_symmetric(shared_key,
|
if (decrypt_data_symmetric(shared_key,
|
||||||
packet + 1 + CRYPTO_PUBLIC_KEY_SIZE,
|
packet + 1 + CRYPTO_PUBLIC_KEY_SIZE,
|
||||||
|
@ -1522,15 +1473,12 @@ bool dht_getnodes(DHT *dht, const IP_Port *ip_port, const uint8_t *public_key, c
|
||||||
memcpy(plain, client_id, CRYPTO_PUBLIC_KEY_SIZE);
|
memcpy(plain, client_id, CRYPTO_PUBLIC_KEY_SIZE);
|
||||||
memcpy(plain + CRYPTO_PUBLIC_KEY_SIZE, &ping_id, sizeof(ping_id));
|
memcpy(plain + CRYPTO_PUBLIC_KEY_SIZE, &ping_id, sizeof(ping_id));
|
||||||
|
|
||||||
uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE];
|
const uint8_t *shared_key = dht_get_shared_key_sent(dht, public_key);
|
||||||
dht_get_shared_key_sent(dht, shared_key, public_key);
|
|
||||||
|
|
||||||
const int len = dht_create_packet(dht->rng,
|
const int len = dht_create_packet(dht->rng,
|
||||||
dht->self_public_key, shared_key, NET_PACKET_GET_NODES,
|
dht->self_public_key, shared_key, NET_PACKET_GET_NODES,
|
||||||
plain, sizeof(plain), data, sizeof(data));
|
plain, sizeof(plain), data, sizeof(data));
|
||||||
|
|
||||||
crypto_memzero(shared_key, sizeof(shared_key));
|
|
||||||
|
|
||||||
if (len != sizeof(data)) {
|
if (len != sizeof(data)) {
|
||||||
LOGGER_ERROR(dht->log, "getnodes packet encryption failed");
|
LOGGER_ERROR(dht->log, "getnodes packet encryption failed");
|
||||||
return false;
|
return false;
|
||||||
|
@ -1605,9 +1553,7 @@ static int handle_getnodes(void *object, const IP_Port *source, const uint8_t *p
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t plain[CRYPTO_NODE_SIZE];
|
uint8_t plain[CRYPTO_NODE_SIZE];
|
||||||
uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE];
|
const uint8_t *shared_key = dht_get_shared_key_recv(dht, packet + 1);
|
||||||
|
|
||||||
dht_get_shared_key_recv(dht, shared_key, packet + 1);
|
|
||||||
const int len = decrypt_data_symmetric(
|
const int len = decrypt_data_symmetric(
|
||||||
shared_key,
|
shared_key,
|
||||||
packet + 1 + CRYPTO_PUBLIC_KEY_SIZE,
|
packet + 1 + CRYPTO_PUBLIC_KEY_SIZE,
|
||||||
|
@ -1616,7 +1562,6 @@ static int handle_getnodes(void *object, const IP_Port *source, const uint8_t *p
|
||||||
plain);
|
plain);
|
||||||
|
|
||||||
if (len != CRYPTO_NODE_SIZE) {
|
if (len != CRYPTO_NODE_SIZE) {
|
||||||
crypto_memzero(shared_key, sizeof(shared_key));
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1624,8 +1569,6 @@ static int handle_getnodes(void *object, const IP_Port *source, const uint8_t *p
|
||||||
|
|
||||||
ping_add(dht->ping, packet + 1, source);
|
ping_add(dht->ping, packet + 1, source);
|
||||||
|
|
||||||
crypto_memzero(shared_key, sizeof(shared_key));
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1670,8 +1613,7 @@ static bool handle_sendnodes_core(void *object, const IP_Port *source, const uin
|
||||||
}
|
}
|
||||||
|
|
||||||
VLA(uint8_t, plain, 1 + data_size + sizeof(uint64_t));
|
VLA(uint8_t, plain, 1 + data_size + sizeof(uint64_t));
|
||||||
uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE];
|
const uint8_t *shared_key = dht_get_shared_key_sent(dht, packet + 1);
|
||||||
dht_get_shared_key_sent(dht, shared_key, packet + 1);
|
|
||||||
const int len = decrypt_data_symmetric(
|
const int len = decrypt_data_symmetric(
|
||||||
shared_key,
|
shared_key,
|
||||||
packet + 1 + CRYPTO_PUBLIC_KEY_SIZE,
|
packet + 1 + CRYPTO_PUBLIC_KEY_SIZE,
|
||||||
|
@ -1679,8 +1621,6 @@ static bool handle_sendnodes_core(void *object, const IP_Port *source, const uin
|
||||||
1 + data_size + sizeof(uint64_t) + CRYPTO_MAC_SIZE,
|
1 + data_size + sizeof(uint64_t) + CRYPTO_MAC_SIZE,
|
||||||
plain);
|
plain);
|
||||||
|
|
||||||
crypto_memzero(shared_key, sizeof(shared_key));
|
|
||||||
|
|
||||||
if ((unsigned int)len != SIZEOF_VLA(plain)) {
|
if ((unsigned int)len != SIZEOF_VLA(plain)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2796,6 +2736,15 @@ DHT *new_dht(const Logger *log, const Random *rng, const Network *ns, Mono_Time
|
||||||
|
|
||||||
crypto_new_keypair(rng, dht->self_public_key, dht->self_secret_key);
|
crypto_new_keypair(rng, dht->self_public_key, dht->self_secret_key);
|
||||||
|
|
||||||
|
dht->shared_keys_recv = shared_key_cache_new(mono_time, dht->self_secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
|
||||||
|
dht->shared_keys_sent = shared_key_cache_new(mono_time, dht->self_secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
|
||||||
|
|
||||||
|
if (dht->shared_keys_recv == nullptr || dht->shared_keys_sent == nullptr) {
|
||||||
|
kill_dht(dht);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
dht->dht_ping_array = ping_array_new(DHT_PING_ARRAY_SIZE, PING_TIMEOUT);
|
dht->dht_ping_array = ping_array_new(DHT_PING_ARRAY_SIZE, PING_TIMEOUT);
|
||||||
|
|
||||||
if (dht->dht_ping_array == nullptr) {
|
if (dht->dht_ping_array == nullptr) {
|
||||||
|
@ -2858,12 +2807,12 @@ void kill_dht(DHT *dht)
|
||||||
networking_registerhandler(dht->net, NET_PACKET_LAN_DISCOVERY, nullptr, nullptr);
|
networking_registerhandler(dht->net, NET_PACKET_LAN_DISCOVERY, nullptr, nullptr);
|
||||||
cryptopacket_registerhandler(dht, CRYPTO_PACKET_NAT_PING, nullptr, nullptr);
|
cryptopacket_registerhandler(dht, CRYPTO_PACKET_NAT_PING, nullptr, nullptr);
|
||||||
|
|
||||||
|
shared_key_cache_free(dht->shared_keys_recv);
|
||||||
|
shared_key_cache_free(dht->shared_keys_sent);
|
||||||
ping_array_kill(dht->dht_ping_array);
|
ping_array_kill(dht->dht_ping_array);
|
||||||
ping_kill(dht->ping);
|
ping_kill(dht->ping);
|
||||||
free(dht->friends_list);
|
free(dht->friends_list);
|
||||||
free(dht->loaded_nodes_list);
|
free(dht->loaded_nodes_list);
|
||||||
crypto_memzero(&dht->shared_keys_recv, sizeof(dht->shared_keys_recv));
|
|
||||||
crypto_memzero(&dht->shared_keys_sent, sizeof(dht->shared_keys_sent));
|
|
||||||
crypto_memzero(dht->self_secret_key, sizeof(dht->self_secret_key));
|
crypto_memzero(dht->self_secret_key, sizeof(dht->self_secret_key));
|
||||||
free(dht);
|
free(dht);
|
||||||
}
|
}
|
||||||
|
|
|
@ -254,24 +254,6 @@ non_null(1, 4) nullable(3)
|
||||||
int unpack_nodes(Node_format *nodes, uint16_t max_num_nodes, uint16_t *processed_data_len, const uint8_t *data,
|
int unpack_nodes(Node_format *nodes, uint16_t max_num_nodes, uint16_t *processed_data_len, const uint8_t *data,
|
||||||
uint16_t length, bool tcp_enabled);
|
uint16_t length, bool tcp_enabled);
|
||||||
|
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------------*/
|
|
||||||
/* struct to store some shared keys so we don't have to regenerate them for each request. */
|
|
||||||
#define MAX_KEYS_PER_SLOT 4
|
|
||||||
#define KEYS_TIMEOUT 600
|
|
||||||
|
|
||||||
typedef struct Shared_Key {
|
|
||||||
uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE];
|
|
||||||
uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE];
|
|
||||||
uint32_t times_requested;
|
|
||||||
bool stored;
|
|
||||||
uint64_t time_last_requested;
|
|
||||||
} Shared_Key;
|
|
||||||
|
|
||||||
typedef struct Shared_Keys {
|
|
||||||
Shared_Key keys[256 * MAX_KEYS_PER_SLOT];
|
|
||||||
} Shared_Keys;
|
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
typedef int cryptopacket_handler_cb(void *object, const IP_Port *ip_port, const uint8_t *source_pubkey,
|
typedef int cryptopacket_handler_cb(void *object, const IP_Port *ip_port, const uint8_t *source_pubkey,
|
||||||
|
@ -295,31 +277,19 @@ non_null() const uint8_t *dht_get_friend_public_key(const DHT *dht, uint32_t fri
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
|
||||||
* Shared key generations are costly, it is therefore smart to store commonly used
|
|
||||||
* ones so that they can be re-used later without being computed again.
|
|
||||||
*
|
|
||||||
* If a shared key is already in shared_keys, copy it to shared_key.
|
|
||||||
* Otherwise generate it into shared_key and copy it to shared_keys
|
|
||||||
*/
|
|
||||||
non_null()
|
|
||||||
void get_shared_key(
|
|
||||||
const Mono_Time *mono_time, Shared_Keys *shared_keys, uint8_t *shared_key,
|
|
||||||
const uint8_t *secret_key, const uint8_t *public_key);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy shared_key to encrypt/decrypt DHT packet from public_key into shared_key
|
* Copy shared_key to encrypt/decrypt DHT packet from public_key into shared_key
|
||||||
* for packets that we receive.
|
* for packets that we receive.
|
||||||
*/
|
*/
|
||||||
non_null()
|
non_null()
|
||||||
void dht_get_shared_key_recv(DHT *dht, uint8_t *shared_key, const uint8_t *public_key);
|
const uint8_t *dht_get_shared_key_recv(DHT *dht, const uint8_t *public_key);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy shared_key to encrypt/decrypt DHT packet from public_key into shared_key
|
* Copy shared_key to encrypt/decrypt DHT packet from public_key into shared_key
|
||||||
* for packets that we send.
|
* for packets that we send.
|
||||||
*/
|
*/
|
||||||
non_null()
|
non_null()
|
||||||
void dht_get_shared_key_sent(DHT *dht, uint8_t *shared_key, const uint8_t *public_key);
|
const uint8_t *dht_get_shared_key_sent(DHT *dht, const uint8_t *public_key);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a getnodes request to `ip_port` with the public key `public_key` for nodes
|
* Sends a getnodes request to `ip_port` with the public key `public_key` for nodes
|
||||||
|
|
|
@ -61,6 +61,8 @@ libtoxcore_la_SOURCES = ../third_party/cmp/cmp.c \
|
||||||
../toxcore/Messenger.c \
|
../toxcore/Messenger.c \
|
||||||
../toxcore/ping.h \
|
../toxcore/ping.h \
|
||||||
../toxcore/ping.c \
|
../toxcore/ping.c \
|
||||||
|
../toxcore/shared_key_cache.h \
|
||||||
|
../toxcore/shared_key_cache.c \
|
||||||
../toxcore/state.h \
|
../toxcore/state.h \
|
||||||
../toxcore/state.c \
|
../toxcore/state.c \
|
||||||
../toxcore/tox.h \
|
../toxcore/tox.h \
|
||||||
|
|
|
@ -14,9 +14,14 @@
|
||||||
|
|
||||||
#include "LAN_discovery.h"
|
#include "LAN_discovery.h"
|
||||||
#include "ccompat.h"
|
#include "ccompat.h"
|
||||||
|
#include "shared_key_cache.h"
|
||||||
#include "timed_auth.h"
|
#include "timed_auth.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
// Settings for the shared key cache
|
||||||
|
#define MAX_KEYS_PER_SLOT 4
|
||||||
|
#define KEYS_TIMEOUT 600
|
||||||
|
|
||||||
uint8_t announce_response_of_request_type(uint8_t request_type)
|
uint8_t announce_response_of_request_type(uint8_t request_type)
|
||||||
{
|
{
|
||||||
switch (request_type) {
|
switch (request_type) {
|
||||||
|
@ -53,7 +58,7 @@ struct Announcements {
|
||||||
const uint8_t *public_key;
|
const uint8_t *public_key;
|
||||||
const uint8_t *secret_key;
|
const uint8_t *secret_key;
|
||||||
|
|
||||||
Shared_Keys shared_keys;
|
Shared_Key_Cache *shared_keys;
|
||||||
uint8_t hmac_key[CRYPTO_HMAC_KEY_SIZE];
|
uint8_t hmac_key[CRYPTO_HMAC_KEY_SIZE];
|
||||||
|
|
||||||
int32_t synch_offset;
|
int32_t synch_offset;
|
||||||
|
@ -429,10 +434,13 @@ static int create_reply_plain_store_announce_request(Announcements *announce,
|
||||||
}
|
}
|
||||||
|
|
||||||
VLA(uint8_t, plain, plain_len);
|
VLA(uint8_t, plain, plain_len);
|
||||||
uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE];
|
|
||||||
|
|
||||||
get_shared_key(announce->mono_time, &announce->shared_keys, shared_key,
|
const uint8_t* shared_key = shared_key_cache_lookup(announce->shared_keys, data_public_key);
|
||||||
announce->secret_key, data_public_key);
|
|
||||||
|
if (shared_key == nullptr) {
|
||||||
|
/* Error looking up/deriving the shared key */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (decrypt_data_symmetric(shared_key,
|
if (decrypt_data_symmetric(shared_key,
|
||||||
data + CRYPTO_PUBLIC_KEY_SIZE,
|
data + CRYPTO_PUBLIC_KEY_SIZE,
|
||||||
|
@ -549,9 +557,7 @@ static int create_reply(Announcements *announce, const IP_Port *source,
|
||||||
}
|
}
|
||||||
|
|
||||||
VLA(uint8_t, plain, plain_len);
|
VLA(uint8_t, plain, plain_len);
|
||||||
uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE];
|
const uint8_t *shared_key = dht_get_shared_key_recv(announce->dht, data + 1);
|
||||||
|
|
||||||
dht_get_shared_key_recv(announce->dht, shared_key, data + 1);
|
|
||||||
|
|
||||||
if (decrypt_data_symmetric(shared_key,
|
if (decrypt_data_symmetric(shared_key,
|
||||||
data + 1 + CRYPTO_PUBLIC_KEY_SIZE,
|
data + 1 + CRYPTO_PUBLIC_KEY_SIZE,
|
||||||
|
@ -652,6 +658,11 @@ Announcements *new_announcements(const Logger *log, const Random *rng, const Mon
|
||||||
announce->public_key = dht_get_self_public_key(announce->dht);
|
announce->public_key = dht_get_self_public_key(announce->dht);
|
||||||
announce->secret_key = dht_get_self_secret_key(announce->dht);
|
announce->secret_key = dht_get_self_secret_key(announce->dht);
|
||||||
new_hmac_key(announce->rng, announce->hmac_key);
|
new_hmac_key(announce->rng, announce->hmac_key);
|
||||||
|
announce->shared_keys = shared_key_cache_new(mono_time, announce->secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
|
||||||
|
if (announce->shared_keys == nullptr) {
|
||||||
|
free(announce);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
announce->start_time = mono_time_get(announce->mono_time);
|
announce->start_time = mono_time_get(announce->mono_time);
|
||||||
|
|
||||||
|
@ -677,7 +688,7 @@ void kill_announcements(Announcements *announce)
|
||||||
networking_registerhandler(announce->net, NET_PACKET_STORE_ANNOUNCE_REQUEST, nullptr, nullptr);
|
networking_registerhandler(announce->net, NET_PACKET_STORE_ANNOUNCE_REQUEST, nullptr, nullptr);
|
||||||
|
|
||||||
crypto_memzero(announce->hmac_key, CRYPTO_HMAC_KEY_SIZE);
|
crypto_memzero(announce->hmac_key, CRYPTO_HMAC_KEY_SIZE);
|
||||||
crypto_memzero(&announce->shared_keys, sizeof(Shared_Keys));
|
shared_key_cache_free(announce->shared_keys);
|
||||||
|
|
||||||
for (uint32_t i = 0; i < ANNOUNCE_BUCKETS * ANNOUNCE_BUCKET_SIZE; ++i) {
|
for (uint32_t i = 0; i < ANNOUNCE_BUCKETS * ANNOUNCE_BUCKET_SIZE; ++i) {
|
||||||
if (announce->entries[i].data != nullptr) {
|
if (announce->entries[i].data != nullptr) {
|
||||||
|
|
|
@ -223,8 +223,8 @@ static int create_cookie_request(const Net_Crypto *c, uint8_t *packet, const uin
|
||||||
memcpy(plain, c->self_public_key, CRYPTO_PUBLIC_KEY_SIZE);
|
memcpy(plain, c->self_public_key, CRYPTO_PUBLIC_KEY_SIZE);
|
||||||
memcpy(plain + CRYPTO_PUBLIC_KEY_SIZE, padding, CRYPTO_PUBLIC_KEY_SIZE);
|
memcpy(plain + CRYPTO_PUBLIC_KEY_SIZE, padding, CRYPTO_PUBLIC_KEY_SIZE);
|
||||||
memcpy(plain + (CRYPTO_PUBLIC_KEY_SIZE * 2), &number, sizeof(uint64_t));
|
memcpy(plain + (CRYPTO_PUBLIC_KEY_SIZE * 2), &number, sizeof(uint64_t));
|
||||||
|
const uint8_t *tmp_shared_key = dht_get_shared_key_sent(c->dht, dht_public_key);
|
||||||
dht_get_shared_key_sent(c->dht, shared_key, dht_public_key);
|
memcpy(shared_key, tmp_shared_key, CRYPTO_SHARED_KEY_SIZE);
|
||||||
uint8_t nonce[CRYPTO_NONCE_SIZE];
|
uint8_t nonce[CRYPTO_NONCE_SIZE];
|
||||||
random_nonce(c->rng, nonce);
|
random_nonce(c->rng, nonce);
|
||||||
packet[0] = NET_PACKET_COOKIE_REQUEST;
|
packet[0] = NET_PACKET_COOKIE_REQUEST;
|
||||||
|
@ -341,7 +341,8 @@ static int handle_cookie_request(const Net_Crypto *c, uint8_t *request_plain, ui
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(dht_public_key, packet + 1, CRYPTO_PUBLIC_KEY_SIZE);
|
memcpy(dht_public_key, packet + 1, CRYPTO_PUBLIC_KEY_SIZE);
|
||||||
dht_get_shared_key_sent(c->dht, shared_key, dht_public_key);
|
const uint8_t *tmp_shared_key = dht_get_shared_key_sent(c->dht, dht_public_key);
|
||||||
|
memcpy(shared_key, tmp_shared_key, CRYPTO_SHARED_KEY_SIZE);
|
||||||
const int len = decrypt_data_symmetric(shared_key, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE,
|
const int len = decrypt_data_symmetric(shared_key, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE,
|
||||||
packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, COOKIE_REQUEST_PLAIN_LENGTH + CRYPTO_MAC_SIZE,
|
packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, COOKIE_REQUEST_PLAIN_LENGTH + CRYPTO_MAC_SIZE,
|
||||||
request_plain);
|
request_plain);
|
||||||
|
|
|
@ -27,6 +27,11 @@
|
||||||
|
|
||||||
#define KEY_REFRESH_INTERVAL (2 * 60 * 60)
|
#define KEY_REFRESH_INTERVAL (2 * 60 * 60)
|
||||||
|
|
||||||
|
|
||||||
|
// Settings for the shared key cache
|
||||||
|
#define MAX_KEYS_PER_SLOT 4
|
||||||
|
#define KEYS_TIMEOUT 600
|
||||||
|
|
||||||
/** Change symmetric keys every 2 hours to make paths expire eventually. */
|
/** Change symmetric keys every 2 hours to make paths expire eventually. */
|
||||||
non_null()
|
non_null()
|
||||||
static void change_symmetric_key(Onion *onion)
|
static void change_symmetric_key(Onion *onion)
|
||||||
|
@ -314,9 +319,14 @@ static int handle_send_initial(void *object, const IP_Port *source, const uint8_
|
||||||
change_symmetric_key(onion);
|
change_symmetric_key(onion);
|
||||||
|
|
||||||
uint8_t plain[ONION_MAX_PACKET_SIZE];
|
uint8_t plain[ONION_MAX_PACKET_SIZE];
|
||||||
uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE];
|
const uint8_t *public_key = packet + 1 + CRYPTO_NONCE_SIZE;
|
||||||
get_shared_key(onion->mono_time, &onion->shared_keys_1, shared_key, dht_get_self_secret_key(onion->dht),
|
const uint8_t *shared_key = shared_key_cache_lookup(onion->shared_keys_1, public_key);
|
||||||
packet + 1 + CRYPTO_NONCE_SIZE);
|
|
||||||
|
if (shared_key == nullptr) {
|
||||||
|
/* Error looking up/deriving the shared key */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
const int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE,
|
const int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE,
|
||||||
length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE), plain);
|
length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE), plain);
|
||||||
|
|
||||||
|
@ -385,9 +395,14 @@ static int handle_send_1(void *object, const IP_Port *source, const uint8_t *pac
|
||||||
change_symmetric_key(onion);
|
change_symmetric_key(onion);
|
||||||
|
|
||||||
uint8_t plain[ONION_MAX_PACKET_SIZE];
|
uint8_t plain[ONION_MAX_PACKET_SIZE];
|
||||||
uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE];
|
const uint8_t *public_key = packet + 1 + CRYPTO_NONCE_SIZE;
|
||||||
get_shared_key(onion->mono_time, &onion->shared_keys_2, shared_key, dht_get_self_secret_key(onion->dht),
|
const uint8_t *shared_key = shared_key_cache_lookup(onion->shared_keys_2, public_key);
|
||||||
packet + 1 + CRYPTO_NONCE_SIZE);
|
|
||||||
|
if (shared_key == nullptr) {
|
||||||
|
/* Error looking up/deriving the shared key */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE,
|
int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE,
|
||||||
length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + RETURN_1), plain);
|
length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + RETURN_1), plain);
|
||||||
|
|
||||||
|
@ -443,9 +458,14 @@ static int handle_send_2(void *object, const IP_Port *source, const uint8_t *pac
|
||||||
change_symmetric_key(onion);
|
change_symmetric_key(onion);
|
||||||
|
|
||||||
uint8_t plain[ONION_MAX_PACKET_SIZE];
|
uint8_t plain[ONION_MAX_PACKET_SIZE];
|
||||||
uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE];
|
const uint8_t *public_key = packet + 1 + CRYPTO_NONCE_SIZE;
|
||||||
get_shared_key(onion->mono_time, &onion->shared_keys_3, shared_key, dht_get_self_secret_key(onion->dht),
|
const uint8_t *shared_key = shared_key_cache_lookup(onion->shared_keys_3, public_key);
|
||||||
packet + 1 + CRYPTO_NONCE_SIZE);
|
|
||||||
|
if (shared_key == nullptr) {
|
||||||
|
/* Error looking up/deriving the shared key */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE,
|
int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE,
|
||||||
length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + RETURN_2), plain);
|
length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + RETURN_2), plain);
|
||||||
|
|
||||||
|
@ -668,6 +688,19 @@ Onion *new_onion(const Logger *log, const Mono_Time *mono_time, const Random *rn
|
||||||
new_symmetric_key(rng, onion->secret_symmetric_key);
|
new_symmetric_key(rng, onion->secret_symmetric_key);
|
||||||
onion->timestamp = mono_time_get(onion->mono_time);
|
onion->timestamp = mono_time_get(onion->mono_time);
|
||||||
|
|
||||||
|
const uint8_t *secret_key = dht_get_self_secret_key(dht);
|
||||||
|
onion->shared_keys_1 = shared_key_cache_new(mono_time, secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
|
||||||
|
onion->shared_keys_2 = shared_key_cache_new(mono_time, secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
|
||||||
|
onion->shared_keys_3 = shared_key_cache_new(mono_time, secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
|
||||||
|
|
||||||
|
if (onion->shared_keys_1 == nullptr ||
|
||||||
|
onion->shared_keys_2 == nullptr ||
|
||||||
|
onion->shared_keys_3 == nullptr) {
|
||||||
|
kill_onion(onion);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_INITIAL, &handle_send_initial, onion);
|
networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_INITIAL, &handle_send_initial, onion);
|
||||||
networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_1, &handle_send_1, onion);
|
networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_1, &handle_send_1, onion);
|
||||||
networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_2, &handle_send_2, onion);
|
networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_2, &handle_send_2, onion);
|
||||||
|
@ -695,5 +728,9 @@ void kill_onion(Onion *onion)
|
||||||
|
|
||||||
crypto_memzero(onion->secret_symmetric_key, sizeof(onion->secret_symmetric_key));
|
crypto_memzero(onion->secret_symmetric_key, sizeof(onion->secret_symmetric_key));
|
||||||
|
|
||||||
|
shared_key_cache_free(onion->shared_keys_1);
|
||||||
|
shared_key_cache_free(onion->shared_keys_2);
|
||||||
|
shared_key_cache_free(onion->shared_keys_3);
|
||||||
|
|
||||||
free(onion);
|
free(onion);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "DHT.h"
|
#include "DHT.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "mono_time.h"
|
#include "mono_time.h"
|
||||||
|
#include "shared_key_cache.h"
|
||||||
|
|
||||||
typedef int onion_recv_1_cb(void *object, const IP_Port *dest, const uint8_t *data, uint16_t length);
|
typedef int onion_recv_1_cb(void *object, const IP_Port *dest, const uint8_t *data, uint16_t length);
|
||||||
|
|
||||||
|
@ -24,9 +25,9 @@ typedef struct Onion {
|
||||||
uint8_t secret_symmetric_key[CRYPTO_SYMMETRIC_KEY_SIZE];
|
uint8_t secret_symmetric_key[CRYPTO_SYMMETRIC_KEY_SIZE];
|
||||||
uint64_t timestamp;
|
uint64_t timestamp;
|
||||||
|
|
||||||
Shared_Keys shared_keys_1;
|
Shared_Key_Cache *shared_keys_1;
|
||||||
Shared_Keys shared_keys_2;
|
Shared_Key_Cache *shared_keys_2;
|
||||||
Shared_Keys shared_keys_3;
|
Shared_Key_Cache *shared_keys_3;
|
||||||
|
|
||||||
onion_recv_1_cb *recv_1_function;
|
onion_recv_1_cb *recv_1_function;
|
||||||
void *callback_object;
|
void *callback_object;
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "LAN_discovery.h"
|
#include "LAN_discovery.h"
|
||||||
#include "ccompat.h"
|
#include "ccompat.h"
|
||||||
#include "mono_time.h"
|
#include "mono_time.h"
|
||||||
|
#include "shared_key_cache.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#define PING_ID_TIMEOUT ONION_ANNOUNCE_TIMEOUT
|
#define PING_ID_TIMEOUT ONION_ANNOUNCE_TIMEOUT
|
||||||
|
@ -31,6 +32,10 @@
|
||||||
|
|
||||||
#define ONION_MINIMAL_SIZE (ONION_PING_ID_SIZE + CRYPTO_PUBLIC_KEY_SIZE * 2 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH)
|
#define ONION_MINIMAL_SIZE (ONION_PING_ID_SIZE + CRYPTO_PUBLIC_KEY_SIZE * 2 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH)
|
||||||
|
|
||||||
|
/* Settings for the shared key cache */
|
||||||
|
#define MAX_KEYS_PER_SLOT 4
|
||||||
|
#define KEYS_TIMEOUT 600
|
||||||
|
|
||||||
static_assert(ONION_PING_ID_SIZE == CRYPTO_PUBLIC_KEY_SIZE,
|
static_assert(ONION_PING_ID_SIZE == CRYPTO_PUBLIC_KEY_SIZE,
|
||||||
"announce response packets assume that ONION_PING_ID_SIZE is equal to CRYPTO_PUBLIC_KEY_SIZE");
|
"announce response packets assume that ONION_PING_ID_SIZE is equal to CRYPTO_PUBLIC_KEY_SIZE");
|
||||||
|
|
||||||
|
@ -51,7 +56,7 @@ struct Onion_Announce {
|
||||||
Onion_Announce_Entry entries[ONION_ANNOUNCE_MAX_ENTRIES];
|
Onion_Announce_Entry entries[ONION_ANNOUNCE_MAX_ENTRIES];
|
||||||
uint8_t hmac_key[CRYPTO_HMAC_KEY_SIZE];
|
uint8_t hmac_key[CRYPTO_HMAC_KEY_SIZE];
|
||||||
|
|
||||||
Shared_Keys shared_keys_recv;
|
Shared_Key_Cache *shared_keys_recv;
|
||||||
|
|
||||||
uint16_t extra_data_max_size;
|
uint16_t extra_data_max_size;
|
||||||
pack_extra_data_cb *extra_data_callback;
|
pack_extra_data_cb *extra_data_callback;
|
||||||
|
@ -426,9 +431,12 @@ static int handle_announce_request_common(
|
||||||
pack_extra_data_cb *pack_extra_data_callback)
|
pack_extra_data_cb *pack_extra_data_callback)
|
||||||
{
|
{
|
||||||
const uint8_t *packet_public_key = packet + 1 + CRYPTO_NONCE_SIZE;
|
const uint8_t *packet_public_key = packet + 1 + CRYPTO_NONCE_SIZE;
|
||||||
uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE];
|
const uint8_t *shared_key = shared_key_cache_lookup(onion_a->shared_keys_recv, packet_public_key);
|
||||||
get_shared_key(onion_a->mono_time, &onion_a->shared_keys_recv, shared_key, dht_get_self_secret_key(onion_a->dht),
|
|
||||||
packet_public_key);
|
if (shared_key == nullptr) {
|
||||||
|
/* Error looking up/deriving the shared key */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t *plain = (uint8_t *)malloc(plain_size);
|
uint8_t *plain = (uint8_t *)malloc(plain_size);
|
||||||
|
|
||||||
|
@ -653,6 +661,12 @@ Onion_Announce *new_onion_announce(const Logger *log, const Random *rng, const M
|
||||||
onion_a->extra_data_object = nullptr;
|
onion_a->extra_data_object = nullptr;
|
||||||
new_hmac_key(rng, onion_a->hmac_key);
|
new_hmac_key(rng, onion_a->hmac_key);
|
||||||
|
|
||||||
|
onion_a->shared_keys_recv = shared_key_cache_new(mono_time, dht_get_self_secret_key(dht), KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
|
||||||
|
if (onion_a->shared_keys_recv == nullptr) {
|
||||||
|
kill_onion_announce(onion_a);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
networking_registerhandler(onion_a->net, NET_PACKET_ONION_DATA_REQUEST, &handle_data_request, onion_a);
|
networking_registerhandler(onion_a->net, NET_PACKET_ONION_DATA_REQUEST, &handle_data_request, onion_a);
|
||||||
|
@ -671,6 +685,7 @@ void kill_onion_announce(Onion_Announce *onion_a)
|
||||||
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);
|
crypto_memzero(onion_a->hmac_key, CRYPTO_HMAC_KEY_SIZE);
|
||||||
|
shared_key_cache_free(onion_a->shared_keys_recv);
|
||||||
|
|
||||||
free(onion_a);
|
free(onion_a);
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,10 +53,9 @@ void ping_send_request(Ping *ping, const IP_Port *ipp, const uint8_t *public_key
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE];
|
|
||||||
|
|
||||||
// generate key to encrypt ping_id with recipient privkey
|
// generate key to encrypt ping_id with recipient privkey
|
||||||
dht_get_shared_key_sent(ping->dht, shared_key, public_key);
|
const uint8_t *shared_key = dht_get_shared_key_sent(ping->dht, public_key);
|
||||||
// Generate random ping_id.
|
// Generate random ping_id.
|
||||||
uint8_t data[PING_DATA_SIZE];
|
uint8_t data[PING_DATA_SIZE];
|
||||||
pk_copy(data, public_key);
|
pk_copy(data, public_key);
|
||||||
|
@ -64,7 +63,6 @@ void ping_send_request(Ping *ping, const IP_Port *ipp, const uint8_t *public_key
|
||||||
ping_id = ping_array_add(ping->ping_array, ping->mono_time, ping->rng, data, sizeof(data));
|
ping_id = ping_array_add(ping->ping_array, ping->mono_time, ping->rng, data, sizeof(data));
|
||||||
|
|
||||||
if (ping_id == 0) {
|
if (ping_id == 0) {
|
||||||
crypto_memzero(shared_key, sizeof(shared_key));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,8 +80,6 @@ void ping_send_request(Ping *ping, const IP_Port *ipp, const uint8_t *public_key
|
||||||
ping_plain, sizeof(ping_plain),
|
ping_plain, sizeof(ping_plain),
|
||||||
pk + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE);
|
pk + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE);
|
||||||
|
|
||||||
crypto_memzero(shared_key, sizeof(shared_key));
|
|
||||||
|
|
||||||
if (rc != PING_PLAIN_SIZE + CRYPTO_MAC_SIZE) {
|
if (rc != PING_PLAIN_SIZE + CRYPTO_MAC_SIZE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -139,11 +135,11 @@ static int handle_ping_request(void *object, const IP_Port *source, const uint8_
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE];
|
const uint8_t *shared_key = dht_get_shared_key_recv(dht, packet + 1);
|
||||||
|
|
||||||
uint8_t ping_plain[PING_PLAIN_SIZE];
|
uint8_t ping_plain[PING_PLAIN_SIZE];
|
||||||
|
|
||||||
// Decrypt ping_id
|
// Decrypt ping_id
|
||||||
dht_get_shared_key_recv(dht, shared_key, packet + 1);
|
|
||||||
const int rc = decrypt_data_symmetric(shared_key,
|
const int rc = decrypt_data_symmetric(shared_key,
|
||||||
packet + 1 + CRYPTO_PUBLIC_KEY_SIZE,
|
packet + 1 + CRYPTO_PUBLIC_KEY_SIZE,
|
||||||
packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE,
|
packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE,
|
||||||
|
@ -151,12 +147,10 @@ static int handle_ping_request(void *object, const IP_Port *source, const uint8_
|
||||||
ping_plain);
|
ping_plain);
|
||||||
|
|
||||||
if (rc != sizeof(ping_plain)) {
|
if (rc != sizeof(ping_plain)) {
|
||||||
crypto_memzero(shared_key, sizeof(shared_key));
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ping_plain[0] != NET_PACKET_PING_REQUEST) {
|
if (ping_plain[0] != NET_PACKET_PING_REQUEST) {
|
||||||
crypto_memzero(shared_key, sizeof(shared_key));
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,8 +160,6 @@ static int handle_ping_request(void *object, const IP_Port *source, const uint8_
|
||||||
ping_send_response(ping, source, packet + 1, ping_id, shared_key);
|
ping_send_response(ping, source, packet + 1, ping_id, shared_key);
|
||||||
ping_add(ping, packet + 1, source);
|
ping_add(ping, packet + 1, source);
|
||||||
|
|
||||||
crypto_memzero(shared_key, sizeof(shared_key));
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,10 +180,8 @@ static int handle_ping_response(void *object, const IP_Port *source, const uint8
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE];
|
|
||||||
|
|
||||||
// generate key to encrypt ping_id with recipient privkey
|
// generate key to encrypt ping_id with recipient privkey
|
||||||
dht_get_shared_key_sent(ping->dht, shared_key, packet + 1);
|
const uint8_t *shared_key = dht_get_shared_key_sent(ping->dht, packet + 1);
|
||||||
|
|
||||||
uint8_t ping_plain[PING_PLAIN_SIZE];
|
uint8_t ping_plain[PING_PLAIN_SIZE];
|
||||||
// Decrypt ping_id
|
// Decrypt ping_id
|
||||||
|
@ -201,8 +191,6 @@ static int handle_ping_response(void *object, const IP_Port *source, const uint8
|
||||||
PING_PLAIN_SIZE + CRYPTO_MAC_SIZE,
|
PING_PLAIN_SIZE + CRYPTO_MAC_SIZE,
|
||||||
ping_plain);
|
ping_plain);
|
||||||
|
|
||||||
crypto_memzero(shared_key, sizeof(shared_key));
|
|
||||||
|
|
||||||
if (rc != sizeof(ping_plain)) {
|
if (rc != sizeof(ping_plain)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
161
toxcore/shared_key_cache.c
Normal file
161
toxcore/shared_key_cache.c
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
* Copyright © 2022 The TokTok team.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "shared_key_cache.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h> // calloc(...)
|
||||||
|
#include <string.h> // memcpy(...)
|
||||||
|
|
||||||
|
#include "ccompat.h"
|
||||||
|
#include "crypto_core.h"
|
||||||
|
#include "mono_time.h"
|
||||||
|
|
||||||
|
typedef struct Shared_Key {
|
||||||
|
uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE];
|
||||||
|
uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE];
|
||||||
|
uint64_t time_last_requested;
|
||||||
|
} Shared_Key;
|
||||||
|
|
||||||
|
struct Shared_Key_Cache {
|
||||||
|
Shared_Key *keys;
|
||||||
|
const uint8_t* self_secret_key;
|
||||||
|
uint64_t timeout; /** After this time (in seconds), a key is erased on the next housekeeping cycle */
|
||||||
|
const Mono_Time *time;
|
||||||
|
uint8_t keys_per_slot;
|
||||||
|
};
|
||||||
|
|
||||||
|
non_null()
|
||||||
|
static bool shared_key_is_empty(const Shared_Key *k) {
|
||||||
|
assert(k != nullptr);
|
||||||
|
/*
|
||||||
|
* Since time can never be 0, we use that to determine if a key slot is empty.
|
||||||
|
* Additionally this allows us to use crypto_memzero and leave the slot in a valid state.
|
||||||
|
*/
|
||||||
|
return k->time_last_requested == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
non_null()
|
||||||
|
static void shared_key_set_empty(Shared_Key *k) {
|
||||||
|
crypto_memzero(k, sizeof (Shared_Key));
|
||||||
|
assert(shared_key_is_empty(k));
|
||||||
|
}
|
||||||
|
|
||||||
|
Shared_Key_Cache *shared_key_cache_new(const Mono_Time *time, const uint8_t *self_secret_key, uint64_t timeout, uint8_t keys_per_slot)
|
||||||
|
{
|
||||||
|
if (time == nullptr || self_secret_key == nullptr || timeout == 0 || keys_per_slot == 0) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time must not be zero, since we use that as special value for empty slots
|
||||||
|
if (mono_time_get(time) == 0) {
|
||||||
|
// Fail loudly in debug environments
|
||||||
|
assert(false);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Shared_Key_Cache *res = (Shared_Key_Cache *)calloc(1, sizeof (Shared_Key_Cache));
|
||||||
|
if (res == nullptr) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
res->self_secret_key = self_secret_key;
|
||||||
|
res->time = time;
|
||||||
|
res->keys_per_slot = keys_per_slot;
|
||||||
|
// We take one byte from the public key for each bucket and store keys_per_slot elements there
|
||||||
|
const size_t cache_size = 256 * keys_per_slot;
|
||||||
|
res->keys = (Shared_Key *)calloc(cache_size, sizeof (Shared_Key));
|
||||||
|
|
||||||
|
if (res->keys == nullptr) {
|
||||||
|
free(res);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_memlock(res->keys, cache_size * sizeof (Shared_Key));
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void shared_key_cache_free(Shared_Key_Cache *cache)
|
||||||
|
{
|
||||||
|
if (cache == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t cache_size = 256 * cache->keys_per_slot;
|
||||||
|
// Don't leave key material in memory
|
||||||
|
crypto_memzero(cache->keys, cache_size * sizeof (Shared_Key));
|
||||||
|
crypto_memunlock(cache->keys, cache_size * sizeof (Shared_Key));
|
||||||
|
free(cache->keys);
|
||||||
|
free(cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NOTE: On each lookup housekeeping is performed to evict keys that did timeout. */
|
||||||
|
const uint8_t *shared_key_cache_lookup(Shared_Key_Cache *cache, const uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE])
|
||||||
|
{
|
||||||
|
// caching the time is not necessary, but calls to mono_time_get(...) are not free
|
||||||
|
const uint64_t cur_time = mono_time_get(cache->time);
|
||||||
|
// We can't use the first and last bytes because they are masked in curve25519. Selected 8 for good alignment.
|
||||||
|
const uint8_t bucket_idx = public_key[8];
|
||||||
|
Shared_Key* bucket_start = &cache->keys[bucket_idx*cache->keys_per_slot];
|
||||||
|
|
||||||
|
const uint8_t* found = nullptr;
|
||||||
|
|
||||||
|
// Perform lookup
|
||||||
|
for(size_t i = 0; i < cache->keys_per_slot; ++i) {
|
||||||
|
if (shared_key_is_empty(&bucket_start[i])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pk_equal(public_key, bucket_start[i].public_key)) {
|
||||||
|
found = bucket_start[i].shared_key;
|
||||||
|
bucket_start[i].time_last_requested = cur_time;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform housekeeping for this bucket
|
||||||
|
for (size_t i = 0; i < cache->keys_per_slot; ++i) {
|
||||||
|
if (shared_key_is_empty(&bucket_start[i])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool timed_out = (bucket_start[i].time_last_requested + cache->timeout) < cur_time;
|
||||||
|
if (timed_out) {
|
||||||
|
shared_key_set_empty(&bucket_start[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found == nullptr) {
|
||||||
|
// Insert into cache
|
||||||
|
|
||||||
|
uint64_t oldest_timestamp = UINT64_MAX;
|
||||||
|
size_t oldest_index = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find least recently used entry, unused entries are prioritised,
|
||||||
|
* because their time_last_requested field is zeroed.
|
||||||
|
*/
|
||||||
|
for (size_t i = 0; i < cache->keys_per_slot; ++i) {
|
||||||
|
if (bucket_start[i].time_last_requested < oldest_timestamp) {
|
||||||
|
oldest_timestamp = bucket_start[i].time_last_requested;
|
||||||
|
oldest_index = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the shared key for the cache
|
||||||
|
if (encrypt_precompute(public_key, cache->self_secret_key, bucket_start[oldest_index].shared_key) != 0) {
|
||||||
|
// Don't put anything in the cache on error
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update cache entry
|
||||||
|
memcpy(bucket_start[oldest_index].public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE);
|
||||||
|
bucket_start[oldest_index].time_last_requested = cur_time;
|
||||||
|
found = bucket_start[oldest_index].shared_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
51
toxcore/shared_key_cache.h
Normal file
51
toxcore/shared_key_cache.h
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
* Copyright © 2022 The TokTok team.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef C_TOXCORE_TOXCORE_SHARED_KEY_CACHE_H
|
||||||
|
#define C_TOXCORE_TOXCORE_SHARED_KEY_CACHE_H
|
||||||
|
|
||||||
|
#include <stdint.h> // uint*_t
|
||||||
|
|
||||||
|
#include "crypto_core.h"
|
||||||
|
#include "mono_time.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This implements a cache for shared keys, since key generation is expensive.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct Shared_Key_Cache Shared_Key_Cache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes a new shared key cache.
|
||||||
|
* @param time Time object for retrieving current time.
|
||||||
|
* @param self_secret_key Our own secret key of length CRYPTO_SECRET_KEY_SIZE,
|
||||||
|
* it must not change during the lifetime of the cache.
|
||||||
|
* @param timeout Number of milliseconds, after which a key should be evicted.
|
||||||
|
* @param keys_per_slot There are 256 slots, this controls how many keys are stored per slot and the size of the cache.
|
||||||
|
* @return nullptr on error.
|
||||||
|
*/
|
||||||
|
non_null()
|
||||||
|
Shared_Key_Cache *shared_key_cache_new(const Mono_Time *time,
|
||||||
|
const uint8_t *self_secret_key,
|
||||||
|
uint64_t timeout, uint8_t keys_per_slot);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Deletes the cache and frees all resources.
|
||||||
|
* @param cache Cache to delete or nullptr.
|
||||||
|
*/
|
||||||
|
nullable(1)
|
||||||
|
void shared_key_cache_free(Shared_Key_Cache *cache);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Looks up a key from the cache or computes it if it didn't exist yet.
|
||||||
|
* @param cache Cache to perform the lookup on.
|
||||||
|
* @param public_key Public key, used for the lookup and computation.
|
||||||
|
*
|
||||||
|
* @return The shared key of length CRYPTO_SHARED_KEY_SIZE, matching the public key and our secret key.
|
||||||
|
* @return nullptr on error.
|
||||||
|
*/
|
||||||
|
non_null()
|
||||||
|
const uint8_t* shared_key_cache_lookup(Shared_Key_Cache *cache, const uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]);
|
||||||
|
|
||||||
|
#endif // C_TOXCORE_TOXCORE_SHARED_KEY_CACHE_H
|
Loading…
Reference in New Issue
Block a user