summaryrefslogtreecommitdiff
path: root/core/net_crypto.c
diff options
context:
space:
mode:
authorirungentoo <irungentoo@gmail.com>2013-07-05 17:00:39 -0400
committerirungentoo <irungentoo@gmail.com>2013-07-05 17:00:39 -0400
commita480c0195a78f56116b3bf58fe17d930bf4e64f4 (patch)
treec549b6347e28b8570ed27b5c53b768b8f7b11a61 /core/net_crypto.c
parent358f46f6483f0c24186272914952e44221c76871 (diff)
Crypto done(still need to test it a bit more thought)
Replaced chars with uint8_t Added a new test program. Added some functions to Lossless UDP. And some other stuff.
Diffstat (limited to 'core/net_crypto.c')
-rw-r--r--core/net_crypto.c622
1 files changed, 622 insertions, 0 deletions
diff --git a/core/net_crypto.c b/core/net_crypto.c
new file mode 100644
index 00000000..38a72205
--- /dev/null
+++ b/core/net_crypto.c
@@ -0,0 +1,622 @@
1/* net_crypto.c
2*
3* Functions for the core network crypto.
4* See also: docs/Crypto.txt
5*
6* NOTE: This code has to be perfect. We don't mess around with encryption.
7*
8*/
9
10
11#include "net_crypto.h"
12
13
14//Our public and secret keys.
15uint8_t self_public_key[crypto_box_PUBLICKEYBYTES];
16uint8_t self_secret_key[crypto_box_SECRETKEYBYTES];
17
18
19typedef struct
20{
21 uint8_t public_key[crypto_box_PUBLICKEYBYTES];
22 uint8_t recv_nonce[crypto_box_NONCEBYTES];//nonce of recieved packets
23 uint8_t sent_nonce[crypto_box_NONCEBYTES];//nonce of sent packets.
24 uint8_t status;//0 if no connection, 1 we have sent a handshake, 2 if connexion is not confirmed yet
25 //(we have recieved a hanshake but no empty data packet), 3 if the connection is established.
26 //4 if the connection is timed out.
27 uint16_t number; //Lossless_UDP connection number corresponding to this connection.
28
29}Crypto_Connection;
30
31#define MAX_CRYPTO_CONNECTIONS 256
32
33Crypto_Connection crypto_connections[MAX_CRYPTO_CONNECTIONS];
34
35#define MAX_FRIEND_REQUESTS 32
36
37//keeps track of the connection numbers for friends request so we can check later if they were sent
38int outbound_friendrequests[MAX_FRIEND_REQUESTS];
39
40#define MAX_INCOMING 64
41
42//keeps track of the connection numbers for friends request so we can check later if they were sent
43int incoming_connections[MAX_INCOMING];
44
45//encrypts plain of length length to encrypted of length + 16 using the
46//public key(32 bytes) of the reciever and a 24 byte nonce
47//return -1 if there was a problem.
48//return length of encrypted data if everything was fine.
49int encrypt_data(uint8_t * public_key, uint8_t * nonce, uint8_t * plain, uint32_t length, uint8_t * encrypted)
50{
51 if(length - crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES > MAX_DATA_SIZE || length == 0)
52 {
53 return -1;
54 }
55
56 uint8_t temp_plain[MAX_DATA_SIZE + crypto_box_ZEROBYTES - crypto_box_BOXZEROBYTES] = {0};
57 uint8_t temp_encrypted[MAX_DATA_SIZE + crypto_box_ZEROBYTES];
58 uint8_t zeroes[crypto_box_BOXZEROBYTES] = {0};
59
60 memcpy(temp_plain + crypto_box_ZEROBYTES, plain, length);//pad the message with 32 0 bytes.
61
62 crypto_box(temp_encrypted, temp_plain, length + crypto_box_ZEROBYTES, nonce, public_key, self_secret_key);
63
64 //if encryption is successful the first crypto_box_BOXZEROBYTES of the message will be zero
65 if(memcmp(temp_encrypted, zeroes, crypto_box_BOXZEROBYTES) != 0)
66 {
67 return -1;
68 }
69 //unpad the encrypted message
70 memcpy(encrypted, temp_encrypted + crypto_box_BOXZEROBYTES, length - crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES);
71 return length - crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES;
72}
73
74//decrypts encrypted of length length to plain of length length - 16 using the
75//public key(32 bytes) of the sender and a 24 byte nonce
76//return -1 if there was a problem(decryption failed)
77//return length of plain data if everything was fine.
78int decrypt_data(uint8_t * public_key, uint8_t * nonce, uint8_t * encrypted, uint32_t length, uint8_t * plain)
79{
80 if(length > MAX_DATA_SIZE || length <= crypto_box_BOXZEROBYTES)
81 {
82 return -1;
83 }
84 uint8_t temp_plain[MAX_DATA_SIZE - crypto_box_ZEROBYTES + crypto_box_BOXZEROBYTES];
85 uint8_t temp_encrypted[MAX_DATA_SIZE + crypto_box_ZEROBYTES] = {0};
86 uint8_t zeroes[crypto_box_ZEROBYTES] = {0};
87
88 memcpy(temp_encrypted + crypto_box_BOXZEROBYTES, encrypted, length);//pad the message with 16 0 bytes.
89
90 if(crypto_box_open(temp_plain, temp_encrypted, length + crypto_box_BOXZEROBYTES,
91 nonce, public_key, self_secret_key) == -1)
92 {
93 return -1;
94 }
95 //if decryption is successful the first crypto_box_ZEROBYTES of the message will be zero
96 if(memcmp(temp_plain, zeroes, crypto_box_ZEROBYTES) != 0)
97 {
98 return -1;
99 }
100 //unpad the plain message
101 memcpy(plain, temp_plain + crypto_box_ZEROBYTES, length - crypto_box_ZEROBYTES + crypto_box_BOXZEROBYTES);
102 return length - crypto_box_ZEROBYTES + crypto_box_BOXZEROBYTES;
103}
104
105//increment the given nonce by 1
106void increment_nonce(uint8_t * nonce)
107{
108 uint32_t i;
109 for(i = 0; i < crypto_box_NONCEBYTES; i++)
110 {
111 nonce[i]++;
112 if(nonce[i] != 0)
113 {
114 break;
115 }
116 }
117}
118
119//fill the given nonce with random bytes.
120//TODO: make this more optimized
121void random_nonce(uint8_t * nonce)
122{
123 uint32_t i;
124 for(i = 0; i < crypto_box_NONCEBYTES; i++)
125 {
126 nonce[i] = random_int() % 256;
127 }
128}
129
130//return 0 if there is no received data in the buffer
131//return -1 if the packet was discarded.
132//return length of recieved data if successful
133int read_cryptpacket(int crypt_connection_id, uint8_t * data)
134{
135 if(crypto_connections[crypt_connection_id].status != 3)
136 {
137 return 0;
138 }
139 uint8_t temp_data[MAX_DATA_SIZE];
140 int length = read_packet(crypto_connections[crypt_connection_id].number, temp_data);
141 if(length == 0)
142 {
143 return 0;
144 }
145 if(temp_data[0] != 3)
146 {
147 return -1;
148 }
149 int len = decrypt_data(crypto_connections[crypt_connection_id].public_key,
150 crypto_connections[crypt_connection_id].recv_nonce, temp_data + 1, length - 1, data);
151 if(len != -1)
152 {
153 increment_nonce(crypto_connections[crypt_connection_id].recv_nonce);
154 return len;
155 }
156 return -1;
157}
158
159
160//return 0 if data could not be put in packet queue
161//return 1 if data was put into the queue
162int write_cryptpacket(int crypt_connection_id, uint8_t * data, uint32_t length)
163{
164 if(length - crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES > MAX_DATA_SIZE - 1)
165 {
166 return 0;
167 }
168 if(crypto_connections[crypt_connection_id].status != 3)
169 {
170 return 0;
171 }
172 uint8_t temp_data[MAX_DATA_SIZE];
173 int len = encrypt_data(crypto_connections[crypt_connection_id].public_key,
174 crypto_connections[crypt_connection_id].sent_nonce, data, length, temp_data + 1);
175 if(len == -1)
176 {
177 return 0;
178 }
179 temp_data[0] = 3;
180 if(write_packet(crypto_connections[crypt_connection_id].number, temp_data, len + 1) == 0)
181 {
182 return 0;
183 }
184 increment_nonce(crypto_connections[crypt_connection_id].sent_nonce);
185 return 1;
186}
187
188//send a friend request to peer with public_key and ip_port.
189//Data represents the data we send with the friends request.
190//returns -1 on failure
191//returns a positive friend request id that can be used later to see if it was sent correctly on success.
192int send_friendrequest(uint8_t * public_key, IP_Port ip_port, uint8_t * data, uint32_t length)
193{
194 if(length > MAX_DATA_SIZE - 1 - crypto_box_PUBLICKEYBYTES - crypto_box_NONCEBYTES)
195 {
196 return -1;
197 }
198 uint32_t i;
199 for(i = 0; i < MAX_FRIEND_REQUESTS; i++)
200 {
201 if(outbound_friendrequests[i] == -1)
202 {
203 break;
204 }
205 }
206 if(i == MAX_FRIEND_REQUESTS)
207 {
208 return -1;
209 }
210 uint8_t temp_data[MAX_DATA_SIZE];
211 uint8_t nonce[crypto_box_NONCEBYTES];
212 random_nonce(nonce);
213 int len = encrypt_data(public_key, nonce, data, length, 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + temp_data);
214 if(len == -1)
215 {
216 return -1;
217 }
218 temp_data[0] = 1;
219 memcpy(temp_data + 1, self_public_key, crypto_box_PUBLICKEYBYTES);
220 memcpy(temp_data + 1 + crypto_box_PUBLICKEYBYTES, nonce, crypto_box_NONCEBYTES);
221 int id = new_connection(ip_port);
222 if(id == -1)
223 {
224 return -1;
225 }
226 if(write_packet(id, temp_data, len + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES) == 1)
227 {
228 outbound_friendrequests[i] = id;
229 return i;
230 }
231 return -1;
232}
233
234//return -1 if failure
235//return 0 if connection is still trying to send the request.
236//return 1 if sent correctly
237//return 2 if connection timed out
238int check_friendrequest(int friend_request)
239{
240 if(friend_request < 0 || friend_request > MAX_FRIEND_REQUESTS)
241 {
242 return -1;
243 }
244 if(outbound_friendrequests[friend_request] == -1)
245 {
246 return -1;
247 }
248 if(sendqueue(outbound_friendrequests[friend_request]) == 0)
249 {
250 kill_connection(outbound_friendrequests[friend_request]);
251 outbound_friendrequests[friend_request] = -1;
252 return 1;
253 }
254 int status = is_connected(outbound_friendrequests[friend_request]);
255 if(status == 4)
256 {
257 kill_connection(outbound_friendrequests[friend_request]);
258 outbound_friendrequests[friend_request] = -1;
259 return 2;
260 }
261 if(status == 0)
262 {
263 outbound_friendrequests[friend_request] = -1;
264 return 2;
265 }
266 return 0;
267}
268
269//Send a crypto handshake packet containing an encrypted secret nonce to peer with connection_id and public_key
270//the packet is encrypted with a random nonce which is sent in plain text with the packet
271int send_cryptohandshake(int connection_id, uint8_t * public_key, uint8_t * secret_nonce)
272{
273 uint8_t temp_data[MAX_DATA_SIZE];
274 uint8_t nonce[crypto_box_NONCEBYTES];
275 random_nonce(nonce);
276 int len = encrypt_data(public_key, nonce, secret_nonce, crypto_box_NONCEBYTES,
277 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + temp_data);
278 if(len == -1)
279 {
280 return 0;
281 }
282 temp_data[0] = 2;
283 memcpy(temp_data + 1, self_public_key, crypto_box_PUBLICKEYBYTES);
284 memcpy(temp_data + 1 + crypto_box_PUBLICKEYBYTES, nonce, crypto_box_NONCEBYTES);
285 return write_packet(connection_id, temp_data, len + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES);
286}
287
288//Extract secret nonce and public_key from a packet(data) with length length
289//return 1 if successful
290//return 0 if failure
291int handle_cryptohandshake(uint8_t * public_key, uint8_t * secret_nonce, uint8_t * data, uint16_t length)
292{
293 int pad = (- crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES);
294 if(length != 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + crypto_box_NONCEBYTES + pad)
295 {
296 return 0;
297 }
298 if(data[0] != 2)
299 {
300 return 0;
301 }
302 memcpy(public_key, data + 1, crypto_box_PUBLICKEYBYTES);
303 int len = decrypt_data(public_key, data + 1 + crypto_box_PUBLICKEYBYTES,
304 data + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, crypto_box_NONCEBYTES + pad, secret_nonce);
305 if(len != crypto_box_NONCEBYTES)
306 {
307 return 0;
308 }
309 return 1;
310}
311
312
313//puts the public key of the friend if public_key, the data from the request
314//in data if a friend request was sent to us and returns the length of the data.
315//return -1 if no valid friend requests.
316int handle_friendrequest(uint8_t * public_key, uint8_t * data)
317{
318 uint32_t i;
319 for(i = 0; i < MAX_INCOMING; i++)
320 {
321 if(incoming_connections[i] != -1)
322 {
323 if(id_packet(incoming_connections[i]) == 1)
324 {
325 uint8_t temp_data[MAX_DATA_SIZE];
326 uint16_t len = read_packet(incoming_connections[i], temp_data);
327 if(len > crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + 1
328 - crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES)
329 {
330 memcpy(public_key, temp_data + 1, crypto_box_PUBLICKEYBYTES);
331 uint8_t nonce[crypto_box_NONCEBYTES];
332 memcpy(nonce, temp_data + 1 + crypto_box_PUBLICKEYBYTES, crypto_box_NONCEBYTES);
333 int len1 = decrypt_data(public_key, nonce, temp_data + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES,
334 len - (crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + 1), data);
335 if(len1 != -1)
336 {
337 kill_connection_in(incoming_connections[i], 1); //conection is useless now, kill it in 1 seconds
338 incoming_connections[i] = -1;
339 return len1;
340 }
341 }
342 kill_connection(incoming_connections[i]); //conection is useless now, kill it.
343 incoming_connections[i] = -1;
344 }
345 }
346 }
347 return -1;
348}
349
350
351//Start a secure connection with other peer who has public_key and ip_port
352//returns -1 if failure
353//returns crypt_connection_id of the initialized connection if everything went well.
354int crypto_connect(uint8_t * public_key, IP_Port ip_port)
355{
356 uint32_t i;
357 if(getconnection_id(ip_port) != -1)
358 {
359 return -1;
360 }
361 for(i = 0; i < MAX_CRYPTO_CONNECTIONS; i++)
362 {
363 if(crypto_connections[i].status == 0)
364 {
365 int id = new_connection(ip_port);
366 if(id == -1)
367 {
368 return -1;
369 }
370 crypto_connections[i].number = id;
371 crypto_connections[i].status = 1;
372 random_nonce(crypto_connections[i].recv_nonce);
373 memcpy(crypto_connections[i].public_key, public_key, crypto_box_PUBLICKEYBYTES);
374 if(send_cryptohandshake(id, public_key, crypto_connections[i].recv_nonce) == 1)
375 {
376 increment_nonce(crypto_connections[i].recv_nonce);
377 return i;
378 }
379 return -1;//this should never happen.
380 }
381 }
382 return -1;
383}
384
385//handle an incoming connection
386//return -1 if no crypto inbound connection
387//return incomming connection id (Lossless_UDP one) if there is an incomming crypto connection
388//Put the public key of the peer in public_key and the secret_nonce from the handshake into secret_nonce
389//to accept it see: accept_crypto_inbound(...)
390//to refuse it just call kill_connection(...) on the connection id
391int crypto_inbound(uint8_t * public_key, uint8_t * secret_nonce)
392{
393 uint32_t i;
394 for(i = 0; i < MAX_INCOMING; i++)
395 {
396 if(incoming_connections[i] != -1)
397 {
398 if(id_packet(incoming_connections[i]) == 2)
399 {
400 uint8_t temp_data[MAX_DATA_SIZE];
401 uint16_t len = read_packet(incoming_connections[i], temp_data);
402 if(handle_cryptohandshake(public_key, secret_nonce, temp_data, len))
403 {
404 int connection_id = incoming_connections[i];
405 incoming_connections[i] = -1;//remove this connection from the incoming connection list.
406 return connection_id;
407 }
408 }
409 }
410 }
411 return -1;
412}
413
414//kill a crypto connection
415//return 0 if killed successfully
416//return 1 if there was a problem.
417int crypto_kill(int crypt_connection_id)
418{
419 if(crypt_connection_id < 0 || crypt_connection_id >= MAX_CRYPTO_CONNECTIONS)
420 {
421 return 1;
422 }
423 if(crypto_connections[crypt_connection_id].status != 0)
424 {
425 crypto_connections[crypt_connection_id].status = 0;
426 kill_connection(crypto_connections[crypt_connection_id].number);
427 return 0;
428 }
429 return 1;
430}
431
432
433//accept an incoming connection using the parameters provided by crypto_inbound
434//return -1 if not successful
435//returns the crypt_connection_id if successful
436int accept_crypto_inbound(int connection_id, uint8_t * public_key, uint8_t * secret_nonce)
437{
438 uint32_t i;
439 if(connection_id == -1)
440 {
441 return -1;
442 }
443 for(i = 0; i < MAX_CRYPTO_CONNECTIONS; i++)
444 {
445 if(crypto_connections[i].status == 0)
446 {
447 crypto_connections[i].number = connection_id;
448 crypto_connections[i].status = 2;
449 random_nonce(crypto_connections[i].recv_nonce);
450 memcpy(crypto_connections[i].sent_nonce, secret_nonce, crypto_box_NONCEBYTES);
451 increment_nonce(crypto_connections[i].sent_nonce);
452 memcpy(crypto_connections[i].public_key, public_key, crypto_box_PUBLICKEYBYTES);
453 if(send_cryptohandshake(connection_id, public_key, crypto_connections[i].recv_nonce) == 1)
454 {
455 increment_nonce(crypto_connections[i].recv_nonce);
456 uint32_t zero = 0;
457 crypto_connections[i].status = 3;//connection status needs to be 3 for write_cryptpacket() to work
458 write_cryptpacket(i, ((uint8_t *)&zero), sizeof(zero));
459 crypto_connections[i].status = 2;//set it to its proper value right after.
460 return i;
461 }
462 return -1;//this should never happen.
463 }
464 }
465 return -1;
466}
467
468//return 0 if no connection, 1 we have sent a handshake, 2 if connexion is not confirmed yet
469//(we have recieved a hanshake but no empty data packet), 3 if the connection is established.
470//4 if the connection is timed out and wating to be killed
471int is_cryptoconnected(int crypt_connection_id)
472{
473 if(crypt_connection_id >= 0 && crypt_connection_id < MAX_CRYPTO_CONNECTIONS)
474 {
475 return crypto_connections[crypt_connection_id].status;
476 }
477 return 0;
478}
479
480
481//Generate our public and private keys
482//Only call this function the first time the program starts.
483void new_keys()
484{
485 crypto_box_keypair(self_public_key,self_secret_key);
486}
487
488//TODO: optimize this
489//adds an incoming connection to the incoming_connection list.
490//returns 0 if successful
491//returns 1 if failure
492int new_incoming(int id)
493{
494 uint32_t i;
495 for(i = 0; i < MAX_INCOMING; i++)
496 {
497 if(incoming_connections[i] == -1)
498 {
499 incoming_connections[i] = id;
500 return 0;
501 }
502 }
503 return 1;
504}
505
506//TODO: optimize this
507//handle all new incoming connections.
508void handle_incomings()
509{
510 int income;
511 while(1)
512 {
513 income = incoming_connection();
514 if(income == -1)
515 {
516 break;
517 }
518 if(new_incoming(income))
519 {
520 break;
521 }
522 }
523}
524
525//handle recieved packets for not yet established crypto connections.
526void recieve_crypto()
527{
528 uint32_t i;
529 for(i = 0; i < MAX_CRYPTO_CONNECTIONS; i++)
530 {
531 if(crypto_connections[i].status == 1)
532 {
533 if(id_packet(crypto_connections[i].number) == 2)//handle handshake packet.
534 {
535 uint8_t temp_data[MAX_DATA_SIZE];
536 uint8_t secret_nonce[crypto_box_NONCEBYTES];
537 uint8_t public_key[crypto_box_PUBLICKEYBYTES];
538 uint16_t len = read_packet(crypto_connections[i].number, temp_data);
539 if(handle_cryptohandshake(public_key, secret_nonce, temp_data, len))
540 {
541 if(memcmp(public_key, crypto_connections[i].public_key, crypto_box_PUBLICKEYBYTES) == 0)
542 {
543 memcpy(crypto_connections[i].sent_nonce, secret_nonce, crypto_box_NONCEBYTES);
544 increment_nonce(crypto_connections[i].sent_nonce);
545 uint32_t zero = 0;
546 crypto_connections[i].status = 3;//connection status needs to be 3 for write_cryptpacket() to work
547 write_cryptpacket(i, ((uint8_t *)&zero), sizeof(zero));
548 crypto_connections[i].status = 2;//set it to its proper value right after.
549 }
550 }
551 }
552 else if(id_packet(crypto_connections[i].number) != -1)
553 {
554 //This should not happen
555 //kill the connection if it does
556 crypto_kill(crypto_connections[i].number);
557 }
558
559 }
560 if(crypto_connections[i].status == 2)
561 {
562 if(id_packet(crypto_connections[i].number) == 3)
563 {
564 uint8_t temp_data[MAX_DATA_SIZE];
565 uint8_t data[MAX_DATA_SIZE];
566 int length = read_packet(crypto_connections[i].number, temp_data);
567 int len = decrypt_data(crypto_connections[i].public_key,
568 crypto_connections[i].recv_nonce, temp_data + 1, length - 1, data);
569 uint32_t zero = 0;
570 if(len == sizeof(uint32_t) && memcmp(((uint8_t *)&zero), data, sizeof(uint32_t)) == 0)
571 {
572 increment_nonce(crypto_connections[i].recv_nonce);
573 crypto_connections[i].status = 3;
574 }
575 else
576 {
577 //This should not happen
578 //kill the connection if it does
579 crypto_kill(crypto_connections[i].number);
580 }
581 }
582 else if(id_packet(crypto_connections[i].number) != -1)
583 {
584 //This should not happen
585 //kill the connection if it does
586 crypto_kill(crypto_connections[i].number);
587 }
588 }
589 }
590}
591
592//run this to (re)initialize net_crypto
593//sets all the global connection variables to their default values.
594void initNetCrypto()
595{
596 memset(crypto_connections, 0 ,sizeof(crypto_connections));
597 memset(outbound_friendrequests, -1 ,sizeof(outbound_friendrequests));
598 memset(incoming_connections, -1 ,sizeof(incoming_connections));
599}
600
601void killTimedout()
602{
603 uint32_t i;
604 for(i = 0; i < MAX_CRYPTO_CONNECTIONS; i++)
605 {
606 if(is_connected(crypto_connections[i].number) == 4)
607 {
608 crypto_connections[i].status = 4;
609 }
610 }
611}
612
613//main loop
614void doNetCrypto()
615{
616 //TODO:check if friend requests were sent correctly
617 //handle new incoming connections
618 //handle friend requests
619 handle_incomings();
620 recieve_crypto();
621 killTimedout();
622}