diff options
Diffstat (limited to 'core/net_crypto.c')
-rw-r--r-- | core/net_crypto.c | 622 |
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. | ||
15 | uint8_t self_public_key[crypto_box_PUBLICKEYBYTES]; | ||
16 | uint8_t self_secret_key[crypto_box_SECRETKEYBYTES]; | ||
17 | |||
18 | |||
19 | typedef 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 | |||
33 | Crypto_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 | ||
38 | int 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 | ||
43 | int 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. | ||
49 | int 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. | ||
78 | int 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 | ||
106 | void 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 | ||
121 | void 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 | ||
133 | int 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 | ||
162 | int 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. | ||
192 | int 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 | ||
238 | int 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 | ||
271 | int 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 | ||
291 | int 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. | ||
316 | int 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. | ||
354 | int 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 | ||
391 | int 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. | ||
417 | int 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 | ||
436 | int 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 | ||
471 | int 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. | ||
483 | void 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 | ||
492 | int 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. | ||
508 | void 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. | ||
526 | void 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. | ||
594 | void 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 | |||
601 | void 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 | ||
614 | void 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 | } | ||