Small protocol change for more replay attack prevention.

see the changes to Prevent_Tracking.txt
This commit is contained in:
irungentoo 2014-01-19 13:53:24 -05:00
parent cdcb8b8600
commit 639b37de67
5 changed files with 83 additions and 48 deletions

View File

@ -97,7 +97,8 @@ Data sent to Node D:
announce request packet:
[uint8_t packet id (131)][nonce][our real long term public key or a temporary one (see next)]
encrypted (with our real long term private key if we want to announce ourselves, a temporary one if we are searching for friends) and the pub key of Node D and the nonce:[[(32 bytes) ping_id][client id we are searching for][data to send back in response(fixed size)]]
encrypted (with our real long term private key if we want to announce ourselves, a temporary one if we are searching for friends) and the pub key of Node D and the nonce:
[[(32 bytes) ping_id][client id we are searching for][public key that we want those sending back data packets to use.][data to send back in response(fixed size)]]
(if the ping id is zero, respond with a announce response packet)
(If the ping id matches the one the node sent in the announce response and the public key matches the one being searched for,
@ -105,7 +106,7 @@ add the part used to send data to our list (if the list is full make it replace
data to route request packet:
[uint8_t packet id (133)][public key of destination node][nonce][temporary just generated public key]
encrypted with that temporary private key and the nonce and the real public key of the destination node:[data]
encrypted with that temporary private key and the nonce and the public key from the announce response packet of the destination node:[data]
(if Node D contains the ret data for the node, it sends the stuff in this packet as a data to route response packet to the right node)
The data in the previous packet is in format: [real public key of sender]
@ -114,12 +115,13 @@ encrypted with real private key of the sender, the nonce in the data packet and
Data sent to us:
announce response packet:
[uint8_t packet id (132)][data to send back in response(fixed size)][nonce]
encrypted with the DHT private key of Node D, the public key in the request and the nonce:[[(32 bytes) ping_id][Node_Format * (maximum of 8)]]
(if the ping id is zero, it means the information to reach the client id we are searching for is stored on this node)
encrypted with the DHT private key of Node D, the public key in the request and the nonce:[[uint8_t is_stored]
[(32 bytes) ping_id if is_stored is 0, public key that must be used to send data packets if is_stored is not 0][Node_Format * (maximum of 8)]]
(if the is_stored is not 0, it means the information to reach the client id we are searching for is stored on this node)
data to route response packet:
[uint8_t packet id (134)][nonce][temporary just generated public key]
encrypted with that temporary private key and the nonce and the real public key of the destination node:[data]
encrypted with that temporary private key, the nonce and the public key from the announce response packet of the destination node:[data]
Onion packet (response):

View File

@ -29,7 +29,7 @@
#define PING_ID_TIMEOUT 20
#define ANNOUNCE_REQUEST_SIZE (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + crypto_box_MACBYTES)
#define ANNOUNCE_REQUEST_SIZE (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES + crypto_box_PUBLICKEYBYTES + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + crypto_box_MACBYTES)
#define ANNOUNCE_REQUEST_SIZE_RECV (ANNOUNCE_REQUEST_SIZE + ONION_RETURN_3)
#define DATA_REQUEST_MIN_SIZE (1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES)
@ -43,6 +43,7 @@
* public_key and secret_key is the kepair which will be used to encrypt the request.
* ping_id is the ping id that will be sent in the request.
* client_id is the client id of the node we are searching for.
* data_public_key is the public key we want others to encrypt their data packets with.
* sendback_data is the data of ONION_ANNOUNCE_SENDBACK_DATA_LENGTH length that we expect to
* receive back in the response.
*
@ -50,12 +51,14 @@
* return 0 on success.
*/
int send_announce_request(DHT *dht, Node_format *nodes, uint8_t *public_key, uint8_t *secret_key, uint8_t *ping_id,
uint8_t *client_id, uint8_t *sendback_data)
uint8_t *client_id, uint8_t *data_public_key, uint8_t *sendback_data)
{
uint8_t plain[ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH];
uint8_t plain[ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES + crypto_box_PUBLICKEYBYTES + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH];
memcpy(plain, ping_id, ONION_PING_ID_SIZE);
memcpy(plain + ONION_PING_ID_SIZE, client_id, crypto_box_PUBLICKEYBYTES);
memcpy(plain + ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES, sendback_data, ONION_ANNOUNCE_SENDBACK_DATA_LENGTH);
memcpy(plain + ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES, data_public_key, crypto_box_PUBLICKEYBYTES);
memcpy(plain + ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES + crypto_box_PUBLICKEYBYTES, sendback_data,
ONION_ANNOUNCE_SENDBACK_DATA_LENGTH);
uint8_t packet[ANNOUNCE_REQUEST_SIZE];
packet[0] = NET_PACKET_ANNOUNCE_REQUEST;
new_nonce(packet + 1);
@ -78,12 +81,15 @@ int send_announce_request(DHT *dht, Node_format *nodes, uint8_t *public_key, uin
* send the packet to that person in the form of a response)
*
* public_key is the real public key of the node which we want to send the data of length length to.
* encrypt_public_key is the public key used to encrypt the data packet.
*
* nonce is the nonce to encrypt this packet with
*
* return -1 on failure.
* return 0 on success.
*/
int send_data_request(DHT *dht, Node_format *nodes, uint8_t *public_key, uint8_t *nonce, uint8_t *data, uint16_t length)
int send_data_request(DHT *dht, Node_format *nodes, uint8_t *public_key, uint8_t *encrypt_public_key, uint8_t *nonce,
uint8_t *data, uint16_t length)
{
uint8_t packet[DATA_REQUEST_MIN_SIZE + length];
packet[0] = NET_PACKET_ONION_DATA_REQUEST;
@ -96,7 +102,7 @@ int send_data_request(DHT *dht, Node_format *nodes, uint8_t *public_key, uint8_t
memcpy(packet + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, random_public_key, crypto_box_PUBLICKEYBYTES);
int len = encrypt_data(public_key, random_secret_key, packet + 1 + crypto_box_PUBLICKEYBYTES,
int len = encrypt_data(encrypt_public_key, random_secret_key, packet + 1 + crypto_box_PUBLICKEYBYTES,
data, length, packet + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES);
if (1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + (uint32_t)len != sizeof(packet))
@ -167,10 +173,11 @@ static int cmp_entry(const void *a, const void *b)
/* add entry to entries list
*
* return 0 if failure
* return 1 if added
* return -1 if failure
* return position if added
*/
static int add_to_entries(Onion_Announce *onion_a, IP_Port ret_ip_port, uint8_t *public_key, uint8_t *ret)
static int add_to_entries(Onion_Announce *onion_a, IP_Port ret_ip_port, uint8_t *public_key, uint8_t *data_public_key,
uint8_t *ret)
{
int pos = in_entries(onion_a, public_key);
@ -190,16 +197,17 @@ static int add_to_entries(Onion_Announce *onion_a, IP_Port ret_ip_port, uint8_t
}
if (pos == -1)
return 0;
return -1;
memcpy(onion_a->entries[pos].public_key, public_key, crypto_box_PUBLICKEYBYTES);
onion_a->entries[pos].ret_ip_port = ret_ip_port;
memcpy(onion_a->entries[pos].ret, ret, ONION_RETURN_3);
memcpy(onion_a->entries[pos].data_public_key, data_public_key, crypto_box_PUBLICKEYBYTES);
onion_a->entries[pos].time = unix_time();
memcpy(cmp_public_key, onion_a->dht->self_public_key, crypto_box_PUBLICKEYBYTES);
qsort(onion_a->entries, ONION_ANNOUNCE_MAX_ENTRIES, sizeof(Onion_Announce_Entry), cmp_entry);
return 1;
return pos;
}
static int handle_announce_request(void *object, IP_Port source, uint8_t *packet, uint32_t length)
@ -209,10 +217,11 @@ static int handle_announce_request(void *object, IP_Port source, uint8_t *packet
if (length != ANNOUNCE_REQUEST_SIZE_RECV)
return 1;
uint8_t plain[ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH];
uint8_t plain[ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES + crypto_box_PUBLICKEYBYTES + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH];
int len = decrypt_data(packet + 1 + crypto_box_NONCEBYTES, onion_a->dht->self_secret_key, packet + 1,
packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES,
ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + crypto_box_MACBYTES, plain);
ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES + crypto_box_PUBLICKEYBYTES + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH +
crypto_box_MACBYTES, plain);
if ((uint32_t)len != sizeof(plain))
return 1;
@ -223,13 +232,14 @@ static int handle_announce_request(void *object, IP_Port source, uint8_t *packet
uint8_t ping_id2[ONION_PING_ID_SIZE];
generate_ping_id(onion_a, unix_time() + PING_ID_TIMEOUT, packet + 1 + crypto_box_NONCEBYTES, source, ping_id2);
int stored = 0;
int index = -1;
if (memcmp(ping_id1, plain, ONION_PING_ID_SIZE) == 0 || memcmp(ping_id2, plain, ONION_PING_ID_SIZE) == 0) {
stored = add_to_entries(onion_a, source, packet + 1 + crypto_box_NONCEBYTES,
packet + (ANNOUNCE_REQUEST_SIZE_RECV - ONION_RETURN_3));
index = add_to_entries(onion_a, source, packet + 1 + crypto_box_NONCEBYTES,
plain + ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES,
packet + (ANNOUNCE_REQUEST_SIZE_RECV - ONION_RETURN_3));
} else {
stored = (in_entries(onion_a, plain + ONION_PING_ID_SIZE) != -1);
index = in_entries(onion_a, plain + ONION_PING_ID_SIZE);
}
/*Respond with a announce response packet*/
@ -245,24 +255,29 @@ static int handle_announce_request(void *object, IP_Port source, uint8_t *packet
uint8_t nonce[crypto_box_NONCEBYTES];
new_nonce(nonce);
uint8_t pl[ONION_PING_ID_SIZE + sizeof(nodes_list)] = {0};
uint8_t pl[1 + ONION_PING_ID_SIZE + sizeof(nodes_list)];
if (!stored) {
memcpy(pl, ping_id2, ONION_PING_ID_SIZE);
if (index == -1) {
pl[0] = 0;
memcpy(pl + 1, ping_id2, ONION_PING_ID_SIZE);
} else {
pl[0] = 1;
memcpy(pl + 1, onion_a->entries[index].data_public_key, crypto_box_PUBLICKEYBYTES);
}
memcpy(pl + ONION_PING_ID_SIZE, nodes_list, num_nodes * sizeof(Node_format));
memcpy(pl + 1 + ONION_PING_ID_SIZE, nodes_list, num_nodes * sizeof(Node_format));
uint8_t data[ONION_ANNOUNCE_RESPONSE_MAX_SIZE];
len = encrypt_data(packet + 1 + crypto_box_NONCEBYTES, onion_a->dht->self_secret_key, nonce, pl,
ONION_PING_ID_SIZE + num_nodes * sizeof(Node_format),
1 + ONION_PING_ID_SIZE + num_nodes * sizeof(Node_format),
data + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + crypto_box_NONCEBYTES);
if ((uint32_t)len != ONION_PING_ID_SIZE + num_nodes * sizeof(Node_format) + crypto_box_MACBYTES)
if ((uint32_t)len != 1 + ONION_PING_ID_SIZE + num_nodes * sizeof(Node_format) + crypto_box_MACBYTES)
return 1;
data[0] = NET_PACKET_ANNOUNCE_RESPONSE;
memcpy(data + 1, plain + ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES, ONION_ANNOUNCE_SENDBACK_DATA_LENGTH);
memcpy(data + 1, plain + ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES + crypto_box_PUBLICKEYBYTES,
ONION_ANNOUNCE_SENDBACK_DATA_LENGTH);
memcpy(data + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH, nonce, crypto_box_NONCEBYTES);
if (send_onion_response(onion_a->net, source, data,

View File

@ -31,15 +31,20 @@
#define ONION_ANNOUNCE_SENDBACK_DATA_LENGTH (crypto_secretbox_NONCEBYTES + sizeof(uint32_t) + sizeof(uint64_t) + crypto_box_PUBLICKEYBYTES + sizeof(IP_Port) + crypto_secretbox_MACBYTES)
#define ONION_ANNOUNCE_RESPONSE_MIN_SIZE (1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + crypto_box_NONCEBYTES + ONION_PING_ID_SIZE + crypto_box_MACBYTES)
#define ONION_ANNOUNCE_RESPONSE_MIN_SIZE (1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + crypto_box_NONCEBYTES + 1 + ONION_PING_ID_SIZE + crypto_box_MACBYTES)
#define ONION_ANNOUNCE_RESPONSE_MAX_SIZE (ONION_ANNOUNCE_RESPONSE_MIN_SIZE + sizeof(Node_format)*MAX_SENT_NODES)
#define ONION_DATA_RESPONSE_MIN_SIZE (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES)
#if ONION_PING_ID_SIZE != crypto_box_PUBLICKEYBYTES
#error announce response packets assume that ONION_PING_ID_SIZE is equal to crypto_box_PUBLICKEYBYTES
#endif
typedef struct {
uint8_t public_key[crypto_box_PUBLICKEYBYTES];
IP_Port ret_ip_port;
uint8_t ret[ONION_RETURN_3];
uint8_t data_public_key[crypto_box_PUBLICKEYBYTES];
uint64_t time;
} Onion_Announce_Entry;
@ -59,6 +64,7 @@ typedef struct {
* public_key and secret_key is the kepair which will be used to encrypt the request.
* ping_id is the ping id that will be sent in the request.
* client_id is the client id of the node we are searching for.
* data_public_key is the public key we want others to encrypt their data packets with.
* sendback_data is the data of ONION_ANNOUNCE_SENDBACK_DATA_LENGTH length that we expect to
* receive back in the response.
*
@ -66,7 +72,7 @@ typedef struct {
* return 0 on success.
*/
int send_announce_request(DHT *dht, Node_format *nodes, uint8_t *public_key, uint8_t *secret_key, uint8_t *ping_id,
uint8_t *client_id, uint8_t *sendback_data);
uint8_t *client_id, uint8_t *data_public_key, uint8_t *sendback_data);
/* Create and send an onion data request packet.
*
@ -75,13 +81,15 @@ int send_announce_request(DHT *dht, Node_format *nodes, uint8_t *public_key, uin
* send the packet to that person in the form of a response)
*
* public_key is the real public key of the node which we want to send the data of length length to.
* encrypt_public_key is the public key used to encrypt the data packet.
*
* nonce is the nonce to encrypt this packet with
*
* return -1 on failure.
* return 0 on success.
*/
int send_data_request(DHT *dht, Node_format *nodes, uint8_t *public_key, uint8_t *nonce, uint8_t *data,
uint16_t length);
int send_data_request(DHT *dht, Node_format *nodes, uint8_t *public_key, uint8_t *encrypt_public_key, uint8_t *nonce,
uint8_t *data, uint16_t length);
Onion_Announce *new_onion_announce(DHT *dht);

View File

@ -30,7 +30,6 @@
#define ANNOUNCE_TIMEOUT 10
static uint8_t zero_ping[ONION_PING_ID_SIZE];
/* Creates a sendback for use in an announce request.
*
@ -126,11 +125,11 @@ static int client_send_announce_request(Onion_Client *onion_c, uint32_t num, IP_
if (num == 0) {
return send_announce_request(onion_c->dht, nodes, onion_c->dht->c->self_public_key,
onion_c->dht->c->self_secret_key, ping_id,
onion_c->dht->c->self_public_key, sendback);
onion_c->dht->c->self_public_key, onion_c->temp_public_key, sendback);
} else {
return send_announce_request(onion_c->dht, nodes, onion_c->friends_list[num - 1].temp_public_key,
onion_c->friends_list[num - 1].temp_secret_key, ping_id,
onion_c->friends_list[num - 1].real_client_id, sendback);
onion_c->friends_list[num - 1].real_client_id, zero_ping_id, sendback);
}
}
@ -164,7 +163,7 @@ static int cmp_entry(const void *a, const void *b)
}
static int client_add_to_list(Onion_Client *onion_c, uint32_t num, uint8_t *public_key, IP_Port ip_port,
uint8_t *ping_id)
uint8_t is_stored, uint8_t *pingid_or_key)
{
if (num > onion_c->num_friends)
return -1;
@ -204,7 +203,14 @@ static int client_add_to_list(Onion_Client *onion_c, uint32_t num, uint8_t *publ
memcpy(list_nodes[index].client_id, public_key, CLIENT_ID_SIZE);
list_nodes[index].ip_port = ip_port;
memcpy(list_nodes[index].ping_id, ping_id, ONION_PING_ID_SIZE);
if (is_stored) {
memcpy(list_nodes[index].data_public_key, pingid_or_key, crypto_box_PUBLICKEYBYTES);
} else {
memcpy(list_nodes[index].ping_id, pingid_or_key, ONION_PING_ID_SIZE);
}
list_nodes[index].is_stored = is_stored;
list_nodes[index].timestamp = unix_time();
list_nodes[index].last_pinged = 0;
return 0;
@ -276,7 +282,7 @@ static int handle_announce_response(void *object, IP_Port source, uint8_t *packe
if (num > onion_c->num_friends)
return 1;
uint8_t plain[ONION_PING_ID_SIZE + num_nodes * sizeof(Node_format)];
uint8_t plain[1 + ONION_PING_ID_SIZE + num_nodes * sizeof(Node_format)];
int len = -1;
if (num == 0) {
@ -297,10 +303,10 @@ static int handle_announce_response(void *object, IP_Port source, uint8_t *packe
return 1;
if (client_add_to_list(onion_c, num, public_key, ip_port, plain) == -1)
if (client_add_to_list(onion_c, num, public_key, ip_port, plain[0], plain + 1) == -1)
return 1;
if (client_ping_nodes(onion_c, num, (Node_format *)plain + ONION_PING_ID_SIZE, num_nodes, source) == -1)
if (client_ping_nodes(onion_c, num, (Node_format *)plain + 1 + ONION_PING_ID_SIZE, num_nodes, source) == -1)
return 1;
return 0;
@ -319,7 +325,7 @@ static int handle_data_response(void *object, IP_Port source, uint8_t *packet, u
return 1;
uint8_t temp_plain[length - ONION_DATA_RESPONSE_MIN_SIZE];
int len = decrypt_data(packet + 1 + crypto_box_NONCEBYTES, onion_c->dht->c->self_secret_key, packet + 1,
int len = decrypt_data(packet + 1 + crypto_box_NONCEBYTES, onion_c->temp_secret_key, packet + 1,
packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES,
length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES), temp_plain);
@ -391,7 +397,6 @@ static int handle_fakeid_announce(void *object, uint8_t *source_pubkey, uint8_t
DHT_getnodes(onion_c->dht, &nodes[i].ip_port, nodes[i].client_id, onion_c->friends_list[friend_num].fake_client_id);
}
//TODO replay protection
return 0;
}
/* Send data of length length to friendnum.
@ -431,7 +436,7 @@ int send_onion_data(Onion_Client *onion_c, int friend_num, uint8_t *data, uint32
if (is_timeout(list_nodes[i].timestamp, ONION_NODE_TIMEOUT))
continue;
if (memcmp(list_nodes[i].ping_id, zero_ping, ONION_PING_ID_SIZE) == 0) {
if (list_nodes[i].is_stored) {
Node_format nodes[4];
if (random_path(onion_c, nodes) == -1)
@ -440,8 +445,8 @@ int send_onion_data(Onion_Client *onion_c, int friend_num, uint8_t *data, uint32
memcpy(nodes[3].client_id, list_nodes[i].client_id, crypto_box_PUBLICKEYBYTES);
nodes[3].ip_port = list_nodes[i].ip_port;
if (send_data_request(onion_c->dht, nodes, onion_c->friends_list[friend_num].real_client_id, nonce, packet,
sizeof(packet)) == 0)
if (send_data_request(onion_c->dht, nodes, onion_c->friends_list[friend_num].real_client_id,
list_nodes[i].data_public_key, nonce, packet, sizeof(packet)) == 0)
++good;
}
}
@ -697,7 +702,7 @@ static void do_announce(Onion_Client *onion_c)
++count;
uint32_t interval = ANNOUNCE_INTERVAL_NOT_ANNOUNCED;
if (memcmp(list_nodes[i].ping_id, zero_ping, ONION_PING_ID_SIZE) == 0) {
if (list_nodes[i].is_stored) {
interval = ANNOUNCE_INTERVAL_ANNOUNCED;
}
@ -748,7 +753,7 @@ Onion_Client *new_onion_client(DHT *dht)
onion_c->dht = dht;
onion_c->net = dht->c->lossless_udp->net;
new_symmetric_key(onion_c->secret_symmetric_key);
crypto_box_keypair(onion_c->temp_public_key, onion_c->temp_secret_key);
networking_registerhandler(onion_c->net, NET_PACKET_ANNOUNCE_RESPONSE, &handle_announce_response, onion_c);
networking_registerhandler(onion_c->net, NET_PACKET_ONION_DATA_RESPONSE, &handle_data_response, onion_c);
oniondata_registerhandler(onion_c, FAKEID_DATA_ID, &handle_fakeid_announce, onion_c);

View File

@ -36,6 +36,9 @@ typedef struct {
uint8_t client_id[CLIENT_ID_SIZE];
IP_Port ip_port;
uint8_t ping_id[ONION_PING_ID_SIZE];
uint8_t data_public_key[crypto_box_PUBLICKEYBYTES];
uint8_t is_stored;
uint64_t timestamp;
uint64_t last_pinged;
@ -70,6 +73,8 @@ typedef struct {
uint8_t secret_symmetric_key[crypto_secretbox_KEYBYTES];
uint64_t last_run;
uint8_t temp_public_key[crypto_box_PUBLICKEYBYTES];
uint8_t temp_secret_key[crypto_box_SECRETKEYBYTES];
struct {
oniondata_handler_callback function;
void *object;