diff --git a/.gitignore b/.gitignore index d7ca164d..4c5c6d3f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ .DS_Store -.travis.yml //nacl build nacl/build/ diff --git a/.travis.yml b/.travis.yml index 8918f02d..78ed6349 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,15 @@ language: c compiler: - gcc +before_script: + - git clone git://github.com/jedisct1/libsodium.git + - cd libsodium + - ./autogen.sh + - ./configure && make check + - sudo make install + - sudo ldconfig + - cd .. + script: - cmake CMakeLists.txt - make -j3 diff --git a/CMakeLists.txt b/CMakeLists.txt index 47fca42b..099232d9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,14 +2,19 @@ cmake_minimum_required(VERSION 2.6.0) project(TOX C) set(core_sources - #core/DHT.c - core/network.c) + core/DHT.c + core/network.c + core/Lossless_UDP.c + core/net_crypto.c + core/Messenger.c) set(test_sources - testing/DHT_test.c) + testing/Messenger_test.c) set(exe_name TOX-app) - + +target_link_libraries(sodium) + add_executable(${exe_name} ${core_sources} ${test_sources}) diff --git a/core/DHT.c b/core/DHT.c index b8cabd52..edcc9a44 100644 --- a/core/DHT.c +++ b/core/DHT.c @@ -54,36 +54,36 @@ typedef struct typedef struct { IP_Port ip_port; - uint32_t ping_id; + uint64_t ping_id; uint32_t timestamp; }Pinged; - -uint8_t self_client_id[CLIENT_ID_SIZE]; - +//Our client id/public key +uint8_t self_public_key[CLIENT_ID_SIZE]; +uint8_t self_secret_key[crypto_box_SECRETKEYBYTES]; //TODO: Move these out of here and put them into the .c file. //A list of the clients mathematically closest to ours. #define LCLIENT_LIST 32 -Client_data close_clientlist[LCLIENT_LIST]; +static Client_data close_clientlist[LCLIENT_LIST]; //Hard maximum number of friends #define MAX_FRIENDS 256 //Let's start with a static array for testing. -Friend friends_list[MAX_FRIENDS]; -uint16_t num_friends; +static Friend friends_list[MAX_FRIENDS]; +static uint16_t num_friends; //The list of ip ports along with the ping_id of what we sent them and a timestamp #define LPING_ARRAY 128 -Pinged pings[LPING_ARRAY]; +static Pinged pings[LPING_ARRAY]; #define LSEND_NODES_ARRAY LPING_ARRAY/2 -Pinged send_nodes[LSEND_NODES_ARRAY]; +static Pinged send_nodes[LSEND_NODES_ARRAY]; //Compares client_id1 and client_id2 with client_id @@ -298,7 +298,7 @@ void addto_lists(IP_Port ip_port, uint8_t * client_id) if(replace_bad(close_clientlist, LCLIENT_LIST, client_id, ip_port)) { //if we can't replace bad nodes we try replacing good ones - replace_good(close_clientlist, LCLIENT_LIST, client_id, ip_port, self_client_id); + replace_good(close_clientlist, LCLIENT_LIST, client_id, ip_port, self_public_key); } } @@ -310,7 +310,7 @@ void addto_lists(IP_Port ip_port, uint8_t * client_id) if(replace_bad(friends_list[i].client_list, MAX_FRIEND_CLIENTS, client_id, ip_port)) { //if we can't replace bad nodes we try replacing good ones - replace_good(friends_list[i].client_list, MAX_FRIEND_CLIENTS, client_id, ip_port, self_client_id); + replace_good(friends_list[i].client_list, MAX_FRIEND_CLIENTS, client_id, ip_port, self_public_key); } } } @@ -324,7 +324,7 @@ void addto_lists(IP_Port ip_port, uint8_t * client_id) //if we are already, return 1 //else return 0 //TODO: Maybe optimize this -int is_pinging(IP_Port ip_port, uint32_t ping_id) +int is_pinging(IP_Port ip_port, uint64_t ping_id) { uint32_t i; uint8_t pinging; @@ -364,7 +364,7 @@ int is_pinging(IP_Port ip_port, uint32_t ping_id) //Same as last function but for get_node requests. -int is_gettingnodes(IP_Port ip_port, uint32_t ping_id) +int is_gettingnodes(IP_Port ip_port, uint64_t ping_id) { uint32_t i; uint8_t pinging; @@ -407,10 +407,10 @@ int is_gettingnodes(IP_Port ip_port, uint32_t ping_id) //returns the ping_id to put in the ping request //returns 0 if problem. //TODO: Maybe optimize this -int add_pinging(IP_Port ip_port) +uint64_t add_pinging(IP_Port ip_port) { uint32_t i, j; - int ping_id = rand(); + uint64_t ping_id = ((uint64_t)random_int() << 32) + random_int(); uint32_t temp_time = unix_time(); for(i = 0; i < PING_TIMEOUT; i++ ) @@ -431,10 +431,10 @@ int add_pinging(IP_Port ip_port) } //Same but for get node requests -int add_gettingnodes(IP_Port ip_port) +uint64_t add_gettingnodes(IP_Port ip_port) { uint32_t i, j; - int ping_id = rand(); + uint64_t ping_id = ((uint64_t)random_int() << 32) + random_int(); uint32_t temp_time = unix_time(); for(i = 0; i < PING_TIMEOUT; i++ ) @@ -458,23 +458,38 @@ int add_gettingnodes(IP_Port ip_port) //send a ping request //Ping request only works if none has been sent to that ip/port in the last 5 seconds. -int pingreq(IP_Port ip_port) +static int pingreq(IP_Port ip_port, uint8_t * public_key) { + if(memcmp(public_key, self_public_key, CLIENT_ID_SIZE) == 0)//check if packet is gonna be sent to ourself + { + return 1; + } + if(is_pinging(ip_port, 0)) { return 1; } - int ping_id = add_pinging(ip_port); + uint64_t ping_id = add_pinging(ip_port); if(ping_id == 0) { return 1; } - uint8_t data[5 + CLIENT_ID_SIZE]; + uint8_t data[1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + sizeof(ping_id) + ENCRYPTION_PADDING]; + uint8_t encrypt[sizeof(ping_id) + ENCRYPTION_PADDING]; + uint8_t nonce[crypto_box_NONCEBYTES]; + random_nonce(nonce); + + int len = encrypt_data(public_key, self_secret_key, nonce, (uint8_t *)&ping_id, sizeof(ping_id), encrypt); + if(len != sizeof(ping_id) + ENCRYPTION_PADDING) + { + return -1; + } data[0] = 0; - memcpy(data + 1, &ping_id, 4); - memcpy(data + 5, self_client_id, CLIENT_ID_SIZE); + memcpy(data + 1, self_public_key, CLIENT_ID_SIZE); + memcpy(data + 1 + CLIENT_ID_SIZE, nonce, crypto_box_NONCEBYTES); + memcpy(data + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, encrypt, len); return sendpacket(ip_port, data, sizeof(data)); @@ -482,65 +497,117 @@ int pingreq(IP_Port ip_port) //send a ping response -int pingres(IP_Port ip_port, uint32_t ping_id) +static int pingres(IP_Port ip_port, uint8_t * public_key, uint64_t ping_id) { - uint8_t data[5 + CLIENT_ID_SIZE]; - data[0] = 1; + if(memcmp(public_key, self_public_key, CLIENT_ID_SIZE) == 0)//check if packet is gonna be sent to ourself + { + return 1; + } - memcpy(data + 1, &ping_id, 4); - memcpy(data + 5, self_client_id, CLIENT_ID_SIZE); + uint8_t data[1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + sizeof(ping_id) + ENCRYPTION_PADDING]; + uint8_t encrypt[sizeof(ping_id) + ENCRYPTION_PADDING]; + uint8_t nonce[crypto_box_NONCEBYTES]; + random_nonce(nonce); + + int len = encrypt_data(public_key, self_secret_key, nonce, (uint8_t *)&ping_id, sizeof(ping_id), encrypt); + if(len != sizeof(ping_id) + ENCRYPTION_PADDING) + { + return -1; + } + data[0] = 1; + memcpy(data + 1, self_public_key, CLIENT_ID_SIZE); + memcpy(data + 1 + CLIENT_ID_SIZE, nonce, crypto_box_NONCEBYTES); + memcpy(data + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, encrypt, len); return sendpacket(ip_port, data, sizeof(data)); } //send a getnodes request -int getnodes(IP_Port ip_port, uint8_t * client_id) +static int getnodes(IP_Port ip_port, uint8_t * public_key, uint8_t * client_id) { + if(memcmp(public_key, self_public_key, CLIENT_ID_SIZE) == 0)//check if packet is gonna be sent to ourself + { + return 1; + } + if(is_gettingnodes(ip_port, 0)) { return 1; } - int ping_id = add_gettingnodes(ip_port); + uint64_t ping_id = add_gettingnodes(ip_port); if(ping_id == 0) { return 1; } - uint8_t data[5 + CLIENT_ID_SIZE*2]; - data[0] = 2; + uint8_t data[1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + sizeof(ping_id) + CLIENT_ID_SIZE + ENCRYPTION_PADDING]; + uint8_t plain[sizeof(ping_id) + CLIENT_ID_SIZE]; + uint8_t encrypt[sizeof(ping_id) + CLIENT_ID_SIZE + ENCRYPTION_PADDING]; + uint8_t nonce[crypto_box_NONCEBYTES]; + random_nonce(nonce); - memcpy(data + 1, &ping_id, 4); - memcpy(data + 5, self_client_id, CLIENT_ID_SIZE); - memcpy(data + 5 + CLIENT_ID_SIZE, client_id, CLIENT_ID_SIZE); - + memcpy(plain, &ping_id, sizeof(ping_id)); + memcpy(plain + sizeof(ping_id), client_id, CLIENT_ID_SIZE); + + int len = encrypt_data(public_key, self_secret_key, nonce, plain, sizeof(ping_id) + CLIENT_ID_SIZE, encrypt); + + if(len != sizeof(ping_id) + CLIENT_ID_SIZE + ENCRYPTION_PADDING) + { + return -1; + } + data[0] = 2; + memcpy(data + 1, self_public_key, CLIENT_ID_SIZE); + memcpy(data + 1 + CLIENT_ID_SIZE, nonce, crypto_box_NONCEBYTES); + memcpy(data + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, encrypt, len); return sendpacket(ip_port, data, sizeof(data)); } //send a send nodes response -int sendnodes(IP_Port ip_port, uint8_t * client_id, uint32_t ping_id) +static int sendnodes(IP_Port ip_port, uint8_t * public_key, uint8_t * client_id, uint64_t ping_id) { - uint8_t data[5 + CLIENT_ID_SIZE + (CLIENT_ID_SIZE + sizeof(IP_Port))*MAX_SENT_NODES]; + if(memcmp(public_key, self_public_key, CLIENT_ID_SIZE) == 0)//check if packet is gonna be sent to ourself + { + return 1; + } + + uint8_t data[1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + sizeof(ping_id) + + sizeof(Node_format) * MAX_SENT_NODES + ENCRYPTION_PADDING]; + Node_format nodes_list[MAX_SENT_NODES]; - int num_nodes = get_close_nodes(client_id, nodes_list); - + if(num_nodes == 0) { return 0; } - + + uint8_t plain[sizeof(ping_id) + sizeof(Node_format) * MAX_SENT_NODES]; + uint8_t encrypt[sizeof(ping_id) + sizeof(Node_format) * MAX_SENT_NODES + ENCRYPTION_PADDING]; + uint8_t nonce[crypto_box_NONCEBYTES]; + random_nonce(nonce); + + memcpy(plain, &ping_id, sizeof(ping_id)); + memcpy(plain + sizeof(ping_id), nodes_list, num_nodes * sizeof(Node_format)); + + int len = encrypt_data(public_key, self_secret_key, nonce, plain, + sizeof(ping_id) + num_nodes * sizeof(Node_format), encrypt); + + if(len != sizeof(ping_id) + num_nodes * sizeof(Node_format) + ENCRYPTION_PADDING) + { + return -1; + } + data[0] = 3; - - memcpy(data + 1, &ping_id, 4); - memcpy(data + 5, self_client_id, CLIENT_ID_SIZE); - memcpy(data + 5 + CLIENT_ID_SIZE, nodes_list, num_nodes * (CLIENT_ID_SIZE + sizeof(IP_Port))); - - return sendpacket(ip_port, data, 5 + CLIENT_ID_SIZE + num_nodes * (CLIENT_ID_SIZE + sizeof(IP_Port))); + memcpy(data + 1, self_public_key, CLIENT_ID_SIZE); + memcpy(data + 1 + CLIENT_ID_SIZE, nonce, crypto_box_NONCEBYTES); + memcpy(data + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, encrypt, len); + + return sendpacket(ip_port, data, 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + len); } @@ -550,26 +617,32 @@ int sendnodes(IP_Port ip_port, uint8_t * client_id, uint32_t ping_id) //Packet handling functions //One to handle each types of packets we receive //return 0 if handled correctly, 1 if packet is bad. -int handle_pingreq(uint8_t * packet, uint32_t length, IP_Port source)//tested +int handle_pingreq(uint8_t * packet, uint32_t length, IP_Port source) { - if(length != 5 + CLIENT_ID_SIZE) + uint64_t ping_id; + if(length != 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + sizeof(ping_id) + ENCRYPTION_PADDING) + { + return 1; + } + if(memcmp(packet + 1, self_public_key, CLIENT_ID_SIZE) == 0)//check if packet is from ourself. { return 1; } - uint32_t ping_id; - memcpy(&ping_id, packet + 1, 4); - IP_Port bad_ip = {{{0}}, 0}; - if(is_pinging(bad_ip, ping_id))//check if packet is from ourself. + int len = decrypt_data(packet + 1, self_secret_key, packet + 1 + CLIENT_ID_SIZE, + packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, + sizeof(ping_id) + ENCRYPTION_PADDING, (uint8_t *)&ping_id); + if(len != sizeof(ping_id)) { return 1; } + - pingres(source, ping_id); + pingres(source, packet + 1, ping_id); - pingreq(source); + pingreq(source, packet + 1);//TODO: make this smarter? return 0; @@ -577,16 +650,29 @@ int handle_pingreq(uint8_t * packet, uint32_t length, IP_Port source)//tested int handle_pingres(uint8_t * packet, uint32_t length, IP_Port source) { - if(length != (5 + CLIENT_ID_SIZE)) + uint64_t ping_id; + if(length != 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + sizeof(ping_id) + ENCRYPTION_PADDING) + { + return 1; + } + if(memcmp(packet + 1, self_public_key, CLIENT_ID_SIZE) == 0)//check if packet is from ourself. + { + return 1; + } + + + + int len = decrypt_data(packet + 1, self_secret_key, packet + 1 + CLIENT_ID_SIZE, + packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, + sizeof(ping_id) + ENCRYPTION_PADDING, (uint8_t *)&ping_id); + if(len != sizeof(ping_id)) { return 1; } - uint32_t ping_id; - memcpy(&ping_id, packet + 1, 4); if(is_pinging(source, ping_id)) { - addto_lists(source, packet + 5); + addto_lists(source, packet + 1); return 0; } return 1; @@ -595,53 +681,80 @@ int handle_pingres(uint8_t * packet, uint32_t length, IP_Port source) int handle_getnodes(uint8_t * packet, uint32_t length, IP_Port source) { - if(length != (5 + CLIENT_ID_SIZE*2)) + uint64_t ping_id; + if(length != 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + sizeof(ping_id) + CLIENT_ID_SIZE + ENCRYPTION_PADDING) { return 1; } - uint32_t ping_id; - memcpy(&ping_id, packet + 1, 4); - sendnodes(source, packet + 5 + CLIENT_ID_SIZE, ping_id); - - IP_Port bad_ip = {{{0}}, 0}; - - if(is_gettingnodes(bad_ip, ping_id))//check if packet is from ourself. + if(memcmp(packet + 1, self_public_key, CLIENT_ID_SIZE) == 0)//check if packet is from ourself. { return 1; } - pingreq(source); + uint8_t plain[sizeof(ping_id) + CLIENT_ID_SIZE]; + + int len = decrypt_data(packet + 1, self_secret_key, packet + 1 + CLIENT_ID_SIZE, + packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, + sizeof(ping_id) + CLIENT_ID_SIZE + ENCRYPTION_PADDING, plain); + + if(len != sizeof(ping_id) + CLIENT_ID_SIZE) + { + return 1; + } + + + memcpy(&ping_id, plain, sizeof(ping_id)); + sendnodes(source, packet + 1, plain + sizeof(ping_id), ping_id); + + pingreq(source, packet + 1);//TODO: make this smarter? return 0; } -int handle_sendnodes(uint8_t * packet, uint32_t length, IP_Port source)//tested +int handle_sendnodes(uint8_t * packet, uint32_t length, IP_Port source) { - if(length > (5 + CLIENT_ID_SIZE + MAX_SENT_NODES * (CLIENT_ID_SIZE + sizeof(IP_Port))) || - (length - 5 - CLIENT_ID_SIZE) % (CLIENT_ID_SIZE + sizeof(IP_Port)) != 0) + uint64_t ping_id; + if(length > (1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + sizeof(ping_id) + + sizeof(Node_format) * MAX_SENT_NODES + ENCRYPTION_PADDING) || + (length - (1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + sizeof(ping_id) + + ENCRYPTION_PADDING)) % (sizeof(Node_format)) != 0 || + length < 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + sizeof(ping_id) + + sizeof(Node_format) + ENCRYPTION_PADDING) { return 1; } - uint32_t num_nodes = (length - 5 - CLIENT_ID_SIZE) / (CLIENT_ID_SIZE + sizeof(IP_Port)); - uint32_t i; - uint32_t ping_id; + uint32_t num_nodes = (length - (1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + + sizeof(ping_id) + ENCRYPTION_PADDING)) / sizeof(Node_format); - memcpy(&ping_id, packet + 1, 4); + uint8_t plain[sizeof(ping_id) + sizeof(Node_format) * MAX_SENT_NODES]; + + int len = decrypt_data(packet + 1, self_secret_key, packet + 1 + CLIENT_ID_SIZE, + packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, + sizeof(ping_id) + num_nodes * sizeof(Node_format) + ENCRYPTION_PADDING, plain); + + + if(len != sizeof(ping_id) + num_nodes * sizeof(Node_format)) + { + return 1; + } + + memcpy(&ping_id, plain, sizeof(ping_id)); if(!is_gettingnodes(source, ping_id)) { return 1; } Node_format nodes_list[MAX_SENT_NODES]; - memcpy(nodes_list, packet + 5 + CLIENT_ID_SIZE, num_nodes * (CLIENT_ID_SIZE + sizeof(IP_Port))); + memcpy(nodes_list, plain + sizeof(ping_id), num_nodes * sizeof(Node_format)); + uint32_t i; for(i = 0; i < num_nodes; i++) { - pingreq(nodes_list[i].ip_port); + pingreq(nodes_list[i].ip_port, nodes_list[i].client_id); } - addto_lists(source, packet + 5); + addto_lists(source, packet + 1); return 0; } @@ -772,7 +885,7 @@ void doDHTFriends() { if((friends_list[i].client_list[j].last_pinged + PING_INTERVAL) <= temp_time) { - pingreq(friends_list[i].client_list[j].ip_port); + pingreq(friends_list[i].client_list[j].ip_port, friends_list[i].client_list[j].client_id); friends_list[i].client_list[j].last_pinged = temp_time; } if(friends_list[i].client_list[j].timestamp + BAD_NODE_TIMEOUT > temp_time)//if node is good. @@ -786,7 +899,8 @@ void doDHTFriends() { rand_node = rand() % num_nodes; getnodes(friends_list[i].client_list[index[rand_node]].ip_port, - friends_list[i].client_list[index[rand_node]].client_id); + friends_list[i].client_list[index[rand_node]].client_id, + friends_list[i].client_id); friend_lastgetnode[i] = temp_time; } } @@ -810,7 +924,7 @@ void doClose()//tested { if((close_clientlist[i].last_pinged + PING_INTERVAL) <= temp_time) { - pingreq(close_clientlist[i].ip_port); + pingreq(close_clientlist[i].ip_port, close_clientlist[i].client_id); close_clientlist[i].last_pinged = temp_time; } if(close_clientlist[i].timestamp + BAD_NODE_TIMEOUT > temp_time)//if node is good. @@ -825,7 +939,8 @@ void doClose()//tested { rand_node = rand() % num_nodes; getnodes(close_clientlist[index[rand_node]].ip_port, - close_clientlist[index[rand_node]].client_id); + close_clientlist[index[rand_node]].client_id, + self_public_key); close_lastgetnodes = temp_time; } @@ -842,10 +957,10 @@ void doDHT() -void DHT_bootstrap(IP_Port ip_port) +void DHT_bootstrap(IP_Port ip_port, uint8_t * public_key) { - getnodes(ip_port, self_client_id); + getnodes(ip_port, public_key, self_public_key); } diff --git a/core/DHT.h b/core/DHT.h index 0290ef92..c80d17fc 100644 --- a/core/DHT.h +++ b/core/DHT.h @@ -26,13 +26,13 @@ #ifndef DHT_H #define DHT_H -#include "network.h" +#include "net_crypto.h" //Current time, unix format #define unix_time() ((uint32_t)time(NULL)) //size of the client_id in bytes -#define CLIENT_ID_SIZE 32 +#define CLIENT_ID_SIZE crypto_box_PUBLICKEYBYTES @@ -68,18 +68,14 @@ void doDHT(); int DHT_handlepacket(uint8_t * packet, uint32_t length, IP_Port source); //Use this function to bootstrap the client -//Sends a get nodes request to the given ip port -void DHT_bootstrap(IP_Port ip_port); +//Sends a get nodes request to the given node with ip port and public_key +void DHT_bootstrap(IP_Port ip_port, uint8_t * public_key); //TODO: //Add functions to save and load the state(client list, friends list) -//Global variables - -//Our client id -extern uint8_t self_client_id[CLIENT_ID_SIZE]; diff --git a/core/Messenger.c b/core/Messenger.c index 57bc50e2..8236c117 100644 --- a/core/Messenger.c +++ b/core/Messenger.c @@ -42,10 +42,10 @@ typedef struct #define MAX_NUM_FRIENDS 256 -Friend friendlist[MAX_NUM_FRIENDS]; +static Friend friendlist[MAX_NUM_FRIENDS]; -uint32_t numfriends; +static uint32_t numfriends; //return the friend id associated to that public key. @@ -189,7 +189,7 @@ int m_sendmessage(int friendnumber, uint8_t * message, uint32_t length) } -void (*friend_request)(uint8_t *, uint8_t *, uint16_t); +static void (*friend_request)(uint8_t *, uint8_t *, uint16_t); //set the function that will be executed when a friend request is received. void m_callback_friendrequest(void (*function)(uint8_t *, uint8_t *, uint16_t)) @@ -198,7 +198,7 @@ void m_callback_friendrequest(void (*function)(uint8_t *, uint8_t *, uint16_t)) } -void (*friend_message)(int, uint8_t *, uint16_t); +static void (*friend_message)(int, uint8_t *, uint16_t); //set the function that will be executed when a message from a friend is received. void m_callback_friendmessage(void (*function)(int, uint8_t *, uint16_t)) @@ -216,11 +216,10 @@ void initMessenger() IP ip; ip.i = 0; init_networking(ip, PORT); - memcpy(self_client_id, self_public_key, crypto_box_PUBLICKEYBYTES); } -void doFriends() +static void doFriends() {//TODO: add incoming connections and some other stuff. uint32_t i; int len; @@ -280,7 +279,7 @@ void doFriends() } } -void doFriendRequest() +static void doFriendRequest() { uint8_t public_key[crypto_box_PUBLICKEYBYTES]; uint8_t temp[MAX_DATA_SIZE]; @@ -296,7 +295,7 @@ void doFriendRequest() -void doInbound() +static void doInbound() { uint8_t secret_nonce[crypto_box_NONCEBYTES]; uint8_t public_key[crypto_box_PUBLICKEYBYTES]; diff --git a/core/net_crypto.c b/core/net_crypto.c index 0bae2d2e..2af5239b 100644 --- a/core/net_crypto.c +++ b/core/net_crypto.c @@ -50,17 +50,17 @@ typedef struct #define MAX_CRYPTO_CONNECTIONS 256 -Crypto_Connection crypto_connections[MAX_CRYPTO_CONNECTIONS]; +static Crypto_Connection crypto_connections[MAX_CRYPTO_CONNECTIONS]; #define MAX_FRIEND_REQUESTS 32 //keeps track of the connection numbers for friends request so we can check later if they were sent -int outbound_friendrequests[MAX_FRIEND_REQUESTS]; +static int outbound_friendrequests[MAX_FRIEND_REQUESTS]; #define MAX_INCOMING 64 //keeps track of the connection numbers for friends request so we can check later if they were sent -int incoming_connections[MAX_INCOMING]; +static int incoming_connections[MAX_INCOMING]; //encrypts plain of length length to encrypted of length + 16 using the //public key(32 bytes) of the receiver and the secret key of the sender and a 24 byte nonce @@ -587,7 +587,7 @@ int new_incoming(int id) //TODO: optimize this //handle all new incoming connections. -void handle_incomings() +static void handle_incomings() { int income; while(1) @@ -601,7 +601,7 @@ void handle_incomings() } //handle received packets for not yet established crypto connections. -void receive_crypto() +static void receive_crypto() { uint32_t i; for(i = 0; i < MAX_CRYPTO_CONNECTIONS; i++) @@ -687,7 +687,7 @@ void initNetCrypto() memset(incoming_connections, -1 ,sizeof(incoming_connections)); } -void killTimedout() +static void killTimedout() { uint32_t i; for(i = 0; i < MAX_CRYPTO_CONNECTIONS; i++) diff --git a/core/net_crypto.h b/core/net_crypto.h index fe655c92..4c3b53de 100644 --- a/core/net_crypto.h +++ b/core/net_crypto.h @@ -32,8 +32,9 @@ #endif //Our public key. extern uint8_t self_public_key[crypto_box_PUBLICKEYBYTES]; +extern uint8_t self_secret_key[crypto_box_SECRETKEYBYTES]; - +#define ENCRYPTION_PADDING (crypto_box_ZEROBYTES - crypto_box_BOXZEROBYTES) //encrypts plain of length length to encrypted of length + 16 using the //public key(32 bytes) of the receiver and the secret key of the sender and a 24 byte nonce @@ -51,6 +52,10 @@ int decrypt_data(uint8_t * public_key, uint8_t * secret_key, uint8_t * nonce, uint8_t * encrypted, uint32_t length, uint8_t * plain); +//fill the given nonce with random bytes. +void random_nonce(uint8_t * nonce); + + //return 0 if there is no received data in the buffer //return -1 if the packet was discarded. //return length of received data if successful diff --git a/core/network.h b/core/network.h index 894bedeb..4fa30905 100644 --- a/core/network.h +++ b/core/network.h @@ -39,8 +39,7 @@ #include #include -//we use libsodium (Portable version of NaCl) because stock NaCl doesn't compile on windows. -#include +#undef VANILLA_NACL//make sure on windows we use libsodium #else //Linux includes @@ -50,13 +49,21 @@ #include #include -//TODO: Including stuff like this is bad. This needs fixing. -//We keep support for the original NaCl for now on UNIX like Operating Systems. -//Commented out for now -//#include "../nacl/build/Linux/include/amd64/crypto_box.h" #endif +#ifndef VANILLA_NACL +//we use libsodium by default +#include +#else + +//TODO: Including stuff like this is bad. This needs fixing. +//We keep support for the original NaCl for now. +#include "../nacl/build/Linux/include/amd64/crypto_box.h" + +#endif + + #define MAX_UDP_PACKET_SIZE 65507 typedef union diff --git a/docs/DHT.txt b/docs/DHT.txt index 486aa38c..088f34ee 100644 --- a/docs/DHT.txt +++ b/docs/DHT.txt @@ -2,7 +2,7 @@ DHT protocol: Follows pretty much the principle of the torrent DHT: http://www.bittorrent.org/beps/bep_0005.html (READ IT) But: - Vastly simplified packet format. + Vastly simplified packet format and encryption. Boostrapping: The first time you install the client we bootstrap it with a node on our servers.(bandwidth should not be a problem as the client only needs to be sent one reply.) @@ -75,13 +75,12 @@ DHT protocol: Valid queries and Responses: - Ping(Request and response): [byte with value: 00 for request, 01 for response][random 4 byte (ping_id)][char array (client node_id), length=32 bytes] + Ping(Request and response): [byte with value: 00 for request, 01 for response][char array (client node_id), length=32 bytes][random 24 byte nonce][Encrypted with the nonce and private key of the sender: [random 8 byte (ping_id)]] ping_id = a random integer, the response must contain the exact same number as the request Get nodes (Request): - Packet contents: [byte with value: 02][random 4 byte (ping_id)][char array (client node_id), length=32 bytes][char array: requested_node_id (node_id of which we want the ip), length=32 bytes] + Packet contents: [byte with value: 02][char array (client node_id), length=32 bytes][random 24 byte nonce][Encrypted with the nonce and private key of the sender:[random 8 byte (ping_id)][char array: requested_node_id (node_id of which we want the ip), length=32 bytes]] Valid replies: a send_nodes packet - Send_nodes (response): [byte with value: 03][random 4 byte (ping_id)][char array (client node_id), length=32 bytes][Nodes in node format, length=40 * (number of nodes (maximum of 8 nodes)) bytes] - ex: 03[Node][Node][Node] \ No newline at end of file + Send_nodes (response): [byte with value: 03][char array (client node_id), length=32 bytes][random 24 byte nonce][Encrypted with the nonce and private key of the sender:[random 8 byte (ping_id)][Nodes in node format, length=40 * (number of nodes (maximum of 8 nodes)) bytes]] diff --git a/testing/DHT_test.c b/testing/DHT_test.c index 38ca4992..083e4d4b 100644 --- a/testing/DHT_test.c +++ b/testing/DHT_test.c @@ -3,10 +3,12 @@ * * Compile with: gcc -O2 -Wall -o test ../core/network.c DHT_test.c * - * Command line arguments are the ip and port of a node and the client_id (32 bytes) of the friend you want to find the ip_port of - * EX: ./test 127.0.0.1 33445 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef + * Command line arguments are the ip, port and public key of a node. + * EX: ./test 127.0.0.1 33445 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + * + * The test will then ask you for the id (in hex format) of the friend you wish to add */ -#include "../core/network.h" +//#include "../core/network.h" #include "../core/DHT.c" #include @@ -94,15 +96,44 @@ void printpacket(uint8_t * data, uint32_t length, IP_Port ip_port) printf("\n--------------------END-----------------------------\n\n\n"); } +//horrible function from one of my first C programs. +//only here because I was too lazy to write a proper one. +unsigned char * hex_string_to_bin(char hex_string[]) +{ + unsigned char * val = malloc(strlen(hex_string)); + char * pos = hex_string; + int i=0; + while(i < strlen(hex_string)) + { + sscanf(pos,"%2hhx",&val[i]); + pos+=2; + i++; + } + return val; +} + int main(int argc, char *argv[]) { //memcpy(self_client_id, "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", 32); if (argc < 4) { - printf("usage %s ip port client_id(of friend to find ip_port of)\n", argv[0]); + printf("usage %s ip port public_key\n", argv[0]); exit(0); } - DHT_addfriend((uint8_t *)argv[3]); + new_keys(); + printf("OUR ID: "); + uint32_t i; + for(i = 0; i < 32; i++) + { + if(self_public_key[i] < 16) + printf("0"); + printf("%hhX",self_public_key[i]); + } + + char temp_id[128]; + printf("\nEnter the client_id of the friend you wish to add (32 bytes HEX format):\n"); + scanf("%s", temp_id); + DHT_addfriend(hex_string_to_bin(temp_id)); //initialize networking //bind to ip 0.0.0.0:PORT @@ -110,8 +141,7 @@ int main(int argc, char *argv[]) ip.i = 0; init_networking(ip, PORT); - int randdomnum = random_int(); - memcpy(self_client_id, &randdomnum, 4); + perror("Initialization"); @@ -122,7 +152,7 @@ int main(int argc, char *argv[]) //bootstrap_ip_port.ip.c[2] = 0; //bootstrap_ip_port.ip.c[3] = 1; bootstrap_ip_port.ip.i = inet_addr(argv[1]); - DHT_bootstrap(bootstrap_ip_port); + DHT_bootstrap(bootstrap_ip_port, hex_string_to_bin(argv[3])); IP_Port ip_port; uint8_t data[MAX_UDP_PACKET_SIZE]; diff --git a/testing/Messenger_test.c b/testing/Messenger_test.c index 6b0e56fc..c049aa18 100644 --- a/testing/Messenger_test.c +++ b/testing/Messenger_test.c @@ -7,7 +7,7 @@ * If it recieves a message from a friend it replies back. * * - * This is how I compile it: gcc -O2 -Wall -o test ../core/Lossless_UDP.c ../core/network.c ../core/net_crypto.c ../core/DHT.c ../core/Messenger.c ../nacl/build/${HOSTNAME%.*}/lib/amd64/* Messenger_test.c + * This is how I compile it: gcc -O2 -Wall -D VANILLA_NACL -o test ../core/Lossless_UDP.c ../core/network.c ../core/net_crypto.c ../core/Messenger.c ../core/DHT.c ../nacl/build/${HOSTNAME%.*}/lib/amd64/{cpucycles.o,libnacl.a,randombytes.o} Messenger_test.c * * * Command line arguments are the ip and port of a node (for bootstrapping). @@ -77,8 +77,8 @@ void print_message(int friendnumber, uint8_t * string, uint16_t length) int main(int argc, char *argv[]) { - if (argc < 3) { - printf("usage %s ip port (of the DHT bootstrap node)\n", argv[0]); + if (argc < 4) { + printf("usage %s ip port public_key (of the DHT bootstrap node)\n", argv[0]); exit(0); } initMessenger(); @@ -96,14 +96,17 @@ int main(int argc, char *argv[]) char temp_id[128]; printf("\nEnter the client_id of the friend you wish to add (32 bytes HEX format):\n"); - scanf("%s", temp_id); + if(scanf("%s", temp_id) != 1) + { + return 1; + } int num = m_addfriend(hex_string_to_bin(temp_id), (uint8_t*)"Install Gentoo", sizeof("Install Gentoo")); perror("Initialization"); IP_Port bootstrap_ip_port; bootstrap_ip_port.port = htons(atoi(argv[2])); bootstrap_ip_port.ip.i = inet_addr(argv[1]); - DHT_bootstrap(bootstrap_ip_port); + DHT_bootstrap(bootstrap_ip_port, hex_string_to_bin(argv[3])); while(1) {