diff --git a/auto_tests/onion_test.c b/auto_tests/onion_test.c index 1f175134..5d7eba5e 100644 --- a/auto_tests/onion_test.c +++ b/auto_tests/onion_test.c @@ -96,6 +96,7 @@ static int handle_test_3(void *object, IP_Port source, uint8_t *packet, uint32_t return 0; } +uint8_t nonce[crypto_box_NONCEBYTES]; static int handled_test_4; static int handle_test_4(void *object, IP_Port source, uint8_t *packet, uint32_t length) { @@ -105,6 +106,10 @@ static int handle_test_4(void *object, IP_Port source, uint8_t *packet, uint32_t return 1; uint8_t plain[sizeof("Install gentoo")] = {0}; + + if (memcmp(nonce, packet + 1, crypto_box_NONCEBYTES) != 0) + return 1; + int len = decrypt_data(packet + 1 + crypto_box_NONCEBYTES, onion->dht->c->self_secret_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES, sizeof("Install gentoo") + crypto_box_MACBYTES, plain); @@ -195,7 +200,9 @@ START_TEST(test_basic) c_sleep(1000); Onion *onion3 = new_onion(new_DHT(new_net_crypto(new_networking(ip, 34569)))); ck_assert_msg((onion3 != NULL), "Onion failed initializing."); - ret = send_data_request(onion3->dht, nodes, onion1->dht->c->self_public_key, (uint8_t *)"Install gentoo", + + new_nonce(nonce); + ret = send_data_request(onion3->dht, nodes, onion1->dht->c->self_public_key, nonce, (uint8_t *)"Install gentoo", sizeof("Install gentoo")); ck_assert_msg(ret == 0, "Failed to create/send onion data_request packet."); handled_test_4 = 0; diff --git a/docs/Prevent_Tracking.txt b/docs/Prevent_Tracking.txt index b44c4cf7..5f7aaf1e 100644 --- a/docs/Prevent_Tracking.txt +++ b/docs/Prevent_Tracking.txt @@ -108,6 +108,9 @@ data to route request packet: encrypted with that temporary private key and the nonce and the real public key 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] +encrypted with real private key of the sender, the nonce in the data packet and the real public key of the reciever:[[uint8_t id][data (optional)]] + Data sent to us: announce response packet: [uint8_t packet id (132)][data to send back in response(fixed size)][nonce] @@ -117,6 +120,8 @@ encrypted with the DHT private key of Node D, the public key in the request and 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] + + Onion packet (response): initial (sent from node D to node C): diff --git a/toxcore/onion_announce.c b/toxcore/onion_announce.c index 480475be..92c9e940 100644 --- a/toxcore/onion_announce.c +++ b/toxcore/onion_announce.c @@ -78,16 +78,17 @@ 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. + * 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 *data, uint16_t length) +int send_data_request(DHT *dht, Node_format *nodes, uint8_t *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; memcpy(packet + 1, public_key, crypto_box_PUBLICKEYBYTES); - new_nonce(packet + 1 + crypto_box_PUBLICKEYBYTES); + memcpy(packet + 1 + crypto_box_PUBLICKEYBYTES, nonce, crypto_box_NONCEBYTES); uint8_t random_public_key[crypto_box_PUBLICKEYBYTES]; uint8_t random_secret_key[crypto_box_SECRETKEYBYTES]; diff --git a/toxcore/onion_announce.h b/toxcore/onion_announce.h index f7d565e5..01cd7243 100644 --- a/toxcore/onion_announce.h +++ b/toxcore/onion_announce.h @@ -75,11 +75,13 @@ 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. + * 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 *data, uint16_t length); +int send_data_request(DHT *dht, Node_format *nodes, uint8_t *public_key, uint8_t *nonce, uint8_t *data, + uint16_t length); Onion_Announce *new_onion_announce(DHT *dht); diff --git a/toxcore/onion_client.c b/toxcore/onion_client.c index 2d049f7a..f865dcd9 100644 --- a/toxcore/onion_client.c +++ b/toxcore/onion_client.c @@ -30,6 +30,7 @@ #define ANNOUNCE_TIMEOUT 10 +uint8_t zero_ping[ONION_PING_ID_SIZE]; /* Creates a sendback for use in an announce request. * @@ -297,26 +298,93 @@ static int handle_announce_response(void *object, IP_Port source, uint8_t *packe return 0; } +#define DATA_IN_RESPONSE_MIN_SIZE (crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES) + static int handle_data_response(void *object, IP_Port source, uint8_t *packet, uint32_t length) { Onion_Client *onion_c = object; - if (length <= ONION_DATA_RESPONSE_MIN_SIZE) + if (length <= (ONION_DATA_RESPONSE_MIN_SIZE + DATA_IN_RESPONSE_MIN_SIZE)) return 1; if (length > MAX_DATA_SIZE) return 1; - uint8_t plain[length - ONION_DATA_RESPONSE_MIN_SIZE]; + 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, packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES, - length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES), plain); + length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES), temp_plain); + + if ((uint32_t)len != sizeof(temp_plain)) + return 1; + + uint8_t plain[sizeof(temp_plain) - DATA_IN_RESPONSE_MIN_SIZE]; + len = decrypt_data(temp_plain, onion_c->dht->c->self_secret_key, packet + 1, temp_plain + crypto_box_PUBLICKEYBYTES, + sizeof(temp_plain) - crypto_box_PUBLICKEYBYTES, plain); if ((uint32_t)len != sizeof(plain)) return 1; - //TODO do something with the plain - return 0; + if (!onion_c->Onion_Data_Handlers[plain[0]].function) + return 1; + + return onion_c->Onion_Data_Handlers[plain[0]].function(onion_c->Onion_Data_Handlers[plain[0]].object, temp_plain, plain, + sizeof(plain)); +} + +/* Send data of length length to friendnum. + * This data will be recieved by the friend using the Onion_Data_Handlers callbacks. + * + * Even if this function succeeds, the friend might not recieve any data. + * + * return the number of packets sent on success + * return -1 on failure. + */ +int send_onion_data(Onion_Client *onion_c, int friend_num, uint8_t *data, uint32_t length) +{ + if ((uint32_t)friend_num >= onion_c->num_friends) + return -1; + + if (length + DATA_IN_RESPONSE_MIN_SIZE + ONION_DATA_RESPONSE_MIN_SIZE + ONION_SEND_1 > MAX_DATA_SIZE) + return -1; + + if (length == 0) + return -1; + + uint8_t nonce[crypto_box_NONCEBYTES]; + new_nonce(nonce); + + uint8_t packet[DATA_IN_RESPONSE_MIN_SIZE + length]; + memcpy(packet, onion_c->dht->c->self_public_key, crypto_box_PUBLICKEYBYTES); + int len = encrypt_data(onion_c->friends_list[friend_num].real_client_id, onion_c->dht->c->self_secret_key, nonce, data, + length, packet + crypto_box_PUBLICKEYBYTES); + + if ((uint32_t)len + crypto_box_PUBLICKEYBYTES != sizeof(packet)) + return -1; + + uint32_t i, good = 0; + Onion_Node *list_nodes = onion_c->friends_list[friend_num].clients_list; + + for (i = 0; i < MAX_ONION_CLIENTS; ++i) { + 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) { + Node_format nodes[4]; + + if (random_path(onion_c, nodes) == -1) + continue; + + 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) + ++good; + } + } + + return good; } /* Get the friend_num of a friend. @@ -382,7 +450,7 @@ int onion_addfriend(Onion_Client *onion_c, uint8_t *client_id) } } - if (index == ~0) { + if (index == (uint32_t)~0) { if (realloc_onion_friends(onion_c, onion_c->num_friends + 1) == -1) return -1; @@ -453,7 +521,7 @@ int random_path(Onion_Client *onion_c, Node_format *nodes) } #define ANNOUNCE_FRIEND 30 -uint8_t zero_ping[ONION_PING_ID_SIZE]; + static void do_friend(Onion_Client *onion_c, uint16_t friendnum) { if (friendnum >= onion_c->num_friends) @@ -489,6 +557,12 @@ static void do_friend(Onion_Client *onion_c, uint16_t friendnum) //TODO send packets to friend telling them our fake DHT id. } +/* Function to call when onion data packet with contents beginning with byte is received. */ +void oniondata_registerhandler(Onion_Client *onion_c, uint8_t byte, oniondata_handler_callback cb, void *object) +{ + onion_c->Onion_Data_Handlers[byte].function = cb; + onion_c->Onion_Data_Handlers[byte].object = object; +} #define ANNOUNCE_INTERVAL_NOT_ANNOUNCED 10 #define ANNOUNCE_INTERVAL_ANNOUNCED 60 diff --git a/toxcore/onion_client.h b/toxcore/onion_client.h index 0ec381e6..f5940d7c 100644 --- a/toxcore/onion_client.h +++ b/toxcore/onion_client.h @@ -48,6 +48,8 @@ typedef struct { uint8_t temp_secret_key[crypto_box_SECRETKEYBYTES]; } Onion_Friend; +typedef int (*oniondata_handler_callback)(void *object, uint8_t *source_pubkey, uint8_t *data, uint32_t len); + typedef struct { DHT *dht; Networking_Core *net; @@ -58,6 +60,11 @@ typedef struct { uint8_t secret_symmetric_key[crypto_secretbox_KEYBYTES]; uint64_t last_run; + + struct { + oniondata_handler_callback function; + void *object; + } Onion_Data_Handlers[256]; } Onion_Client; /* Add a friend who we want to connect to. @@ -99,6 +106,19 @@ int onion_getfriendip(Onion_Client *onion_c, int friend_num, IP_Port *ip_port); */ int random_path(Onion_Client *onion_c, Node_format *nodes); +/* Send data of length length to friendnum. + * This data will be recieved by the friend using the Onion_Data_Handlers callbacks. + * + * Even if this function succeeds, the friend might not recieve any data. + * + * return the number of packets sent on success + * return -1 on failure. + */ +int send_onion_data(Onion_Client *onion_c, int friend_num, uint8_t *data, uint32_t length); + +/* Function to call when onion data packet with contents beginning with byte is received. */ +void oniondata_registerhandler(Onion_Client *onion_c, uint8_t byte, oniondata_handler_callback cb, void *object); + void do_onion_client(Onion_Client *onion_c); Onion_Client *new_onion_client(DHT *dht);