ffi-tox 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. data/ProjectTox-Core/CMakeLists.txt +28 -0
  2. data/ProjectTox-Core/COPYING +674 -0
  3. data/ProjectTox-Core/INSTALL.md +91 -0
  4. data/ProjectTox-Core/README.md +54 -0
  5. data/ProjectTox-Core/core/CMakeLists.txt +17 -0
  6. data/ProjectTox-Core/core/DHT.c +1104 -0
  7. data/ProjectTox-Core/core/DHT.h +111 -0
  8. data/ProjectTox-Core/core/LAN_discovery.c +79 -0
  9. data/ProjectTox-Core/core/LAN_discovery.h +50 -0
  10. data/ProjectTox-Core/core/Lossless_UDP.c +749 -0
  11. data/ProjectTox-Core/core/Lossless_UDP.h +106 -0
  12. data/ProjectTox-Core/core/Messenger.c +581 -0
  13. data/ProjectTox-Core/core/Messenger.h +157 -0
  14. data/ProjectTox-Core/core/friend_requests.c +131 -0
  15. data/ProjectTox-Core/core/friend_requests.h +51 -0
  16. data/ProjectTox-Core/core/net_crypto.c +564 -0
  17. data/ProjectTox-Core/core/net_crypto.h +134 -0
  18. data/ProjectTox-Core/core/network.c +188 -0
  19. data/ProjectTox-Core/core/network.h +134 -0
  20. data/ProjectTox-Core/other/CMakeLists.txt +9 -0
  21. data/ProjectTox-Core/other/DHT_bootstrap.c +139 -0
  22. data/ProjectTox-Core/testing/CMakeLists.txt +18 -0
  23. data/ProjectTox-Core/testing/DHT_cryptosendfiletest.c +228 -0
  24. data/ProjectTox-Core/testing/DHT_sendfiletest.c +176 -0
  25. data/ProjectTox-Core/testing/DHT_test.c +182 -0
  26. data/ProjectTox-Core/testing/Lossless_UDP_testclient.c +214 -0
  27. data/ProjectTox-Core/testing/Lossless_UDP_testserver.c +201 -0
  28. data/ProjectTox-Core/testing/Messenger_test.c +145 -0
  29. data/ProjectTox-Core/testing/misc_tools.c +40 -0
  30. data/ProjectTox-Core/testing/misc_tools.h +29 -0
  31. data/ProjectTox-Core/testing/nTox.c +381 -0
  32. data/ProjectTox-Core/testing/nTox.h +50 -0
  33. data/ProjectTox-Core/testing/nTox_win32.c +323 -0
  34. data/ProjectTox-Core/testing/nTox_win32.h +31 -0
  35. data/ProjectTox-Core/testing/rect.py +45 -0
  36. data/ext/ffi-tox/extconf.rb +16 -0
  37. data/interfaces/libtox.i +18 -0
  38. data/lib/ffi-tox/libtox.rb +37 -0
  39. data/lib/ffi-tox.rb +1 -0
  40. metadata +116 -0
@@ -0,0 +1,564 @@
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
+ * Copyright (C) 2013 Tox project All Rights Reserved.
9
+ *
10
+ * This file is part of Tox.
11
+ *
12
+ * Tox is free software: you can redistribute it and/or modify
13
+ * it under the terms of the GNU General Public License as published by
14
+ * the Free Software Foundation, either version 3 of the License, or
15
+ * (at your option) any later version.
16
+ *
17
+ * Tox is distributed in the hope that it will be useful,
18
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
+ * GNU General Public License for more details.
21
+ *
22
+ * You should have received a copy of the GNU General Public License
23
+ * along with Tox. If not, see <http://www.gnu.org/licenses/>.
24
+ *
25
+ */
26
+
27
+ #include "net_crypto.h"
28
+
29
+ /* Our public and secret keys. */
30
+ uint8_t self_public_key[crypto_box_PUBLICKEYBYTES];
31
+ uint8_t self_secret_key[crypto_box_SECRETKEYBYTES];
32
+
33
+ typedef struct {
34
+ uint8_t public_key[crypto_box_PUBLICKEYBYTES]; /* the real public key of the peer. */
35
+ uint8_t recv_nonce[crypto_box_NONCEBYTES]; /* nonce of received packets */
36
+ uint8_t sent_nonce[crypto_box_NONCEBYTES]; /* nonce of sent packets. */
37
+ uint8_t sessionpublic_key[crypto_box_PUBLICKEYBYTES]; /* our public key for this session. */
38
+ uint8_t sessionsecret_key[crypto_box_SECRETKEYBYTES]; /* our private key for this session. */
39
+ uint8_t peersessionpublic_key[crypto_box_PUBLICKEYBYTES]; /* The public key of the peer. */
40
+ uint8_t status; /* 0 if no connection, 1 we have sent a handshake, 2 if connexion is not confirmed yet
41
+ (we have received a handshake but no empty data packet), 3 if the connection is established.
42
+ 4 if the connection is timed out. */
43
+ uint16_t number; /* Lossless_UDP connection number corresponding to this connection. */
44
+
45
+ } Crypto_Connection;
46
+
47
+ #define MAX_CRYPTO_CONNECTIONS 256
48
+
49
+ static Crypto_Connection crypto_connections[MAX_CRYPTO_CONNECTIONS];
50
+
51
+ #define MAX_INCOMING 64
52
+
53
+ /* keeps track of the connection numbers for friends request so we can check later if they were sent */
54
+ static int incoming_connections[MAX_INCOMING];
55
+
56
+ /* encrypts plain of length length to encrypted of length + 16 using the
57
+ public key(32 bytes) of the receiver and the secret key of the sender and a 24 byte nonce
58
+ return -1 if there was a problem.
59
+ return length of encrypted data if everything was fine. */
60
+ int encrypt_data(uint8_t *public_key, uint8_t *secret_key, uint8_t *nonce,
61
+ uint8_t *plain, uint32_t length, uint8_t *encrypted)
62
+ {
63
+ if (length - crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES > MAX_DATA_SIZE || length == 0)
64
+ return -1;
65
+
66
+ uint8_t temp_plain[MAX_DATA_SIZE + crypto_box_ZEROBYTES - crypto_box_BOXZEROBYTES] = {0};
67
+ uint8_t temp_encrypted[MAX_DATA_SIZE + crypto_box_ZEROBYTES];
68
+ uint8_t zeroes[crypto_box_BOXZEROBYTES] = {0};
69
+
70
+ memcpy(temp_plain + crypto_box_ZEROBYTES, plain, length); /* pad the message with 32 0 bytes. */
71
+
72
+ crypto_box(temp_encrypted, temp_plain, length + crypto_box_ZEROBYTES, nonce, public_key, secret_key);
73
+
74
+ /* if encryption is successful the first crypto_box_BOXZEROBYTES of the message will be zero */
75
+ if (memcmp(temp_encrypted, zeroes, crypto_box_BOXZEROBYTES) != 0)
76
+ return -1;
77
+
78
+ /* unpad the encrypted message */
79
+ memcpy(encrypted, temp_encrypted + crypto_box_BOXZEROBYTES, length - crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES);
80
+ return length - crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES;
81
+ }
82
+
83
+ /* decrypts encrypted of length length to plain of length length - 16 using the
84
+ public key(32 bytes) of the sender, the secret key of the receiver and a 24 byte nonce
85
+ return -1 if there was a problem(decryption failed)
86
+ return length of plain data if everything was fine. */
87
+ int decrypt_data(uint8_t *public_key, uint8_t *secret_key, uint8_t *nonce,
88
+ uint8_t *encrypted, uint32_t length, uint8_t *plain)
89
+ {
90
+ if (length > MAX_DATA_SIZE || length <= crypto_box_BOXZEROBYTES)
91
+ return -1;
92
+
93
+ uint8_t temp_plain[MAX_DATA_SIZE - crypto_box_ZEROBYTES + crypto_box_BOXZEROBYTES];
94
+ uint8_t temp_encrypted[MAX_DATA_SIZE + crypto_box_ZEROBYTES] = {0};
95
+ uint8_t zeroes[crypto_box_ZEROBYTES] = {0};
96
+
97
+ memcpy(temp_encrypted + crypto_box_BOXZEROBYTES, encrypted, length); /* pad the message with 16 0 bytes. */
98
+
99
+ if (crypto_box_open(temp_plain, temp_encrypted, length + crypto_box_BOXZEROBYTES,
100
+ nonce, public_key, secret_key) == -1)
101
+ return -1;
102
+
103
+ /* if decryption is successful the first crypto_box_ZEROBYTES of the message will be zero */
104
+ if (memcmp(temp_plain, zeroes, crypto_box_ZEROBYTES) != 0)
105
+ return -1;
106
+
107
+ /* unpad the plain message */
108
+ memcpy(plain, temp_plain + crypto_box_ZEROBYTES, length - crypto_box_ZEROBYTES + crypto_box_BOXZEROBYTES);
109
+ return length - crypto_box_ZEROBYTES + crypto_box_BOXZEROBYTES;
110
+ }
111
+
112
+ /* increment the given nonce by 1 */
113
+ void increment_nonce(uint8_t *nonce)
114
+ {
115
+ uint32_t i;
116
+ for (i = 0; i < crypto_box_NONCEBYTES; ++i) {
117
+ ++nonce[i];
118
+ if(nonce[i] != 0)
119
+ break;
120
+ }
121
+ }
122
+
123
+ /* fill the given nonce with random bytes. */
124
+ void random_nonce(uint8_t *nonce)
125
+ {
126
+ uint32_t i, temp;
127
+ for (i = 0; i < crypto_box_NONCEBYTES / 4; ++i) {
128
+ temp = random_int();
129
+ memcpy(nonce + 4 * i, &temp, 4);
130
+ }
131
+ }
132
+
133
+ /* return 0 if there is no received data in the buffer
134
+ return -1 if the packet was discarded.
135
+ return length of received data if successful */
136
+ int read_cryptpacket(int crypt_connection_id, uint8_t *data)
137
+ {
138
+ if (crypt_connection_id < 0 || crypt_connection_id >= MAX_CRYPTO_CONNECTIONS)
139
+ return 0;
140
+ if (crypto_connections[crypt_connection_id].status != 3)
141
+ return 0;
142
+ uint8_t temp_data[MAX_DATA_SIZE];
143
+ int length = read_packet(crypto_connections[crypt_connection_id].number, temp_data);
144
+ if (length == 0)
145
+ return 0;
146
+ if (temp_data[0] != 3)
147
+ return -1;
148
+ int len = decrypt_data(crypto_connections[crypt_connection_id].peersessionpublic_key,
149
+ crypto_connections[crypt_connection_id].sessionsecret_key,
150
+ crypto_connections[crypt_connection_id].recv_nonce, temp_data + 1, length - 1, data);
151
+ if (len != -1) {
152
+ increment_nonce(crypto_connections[crypt_connection_id].recv_nonce);
153
+ return len;
154
+ }
155
+ return -1;
156
+ }
157
+
158
+ /* return 0 if data could not be put in packet queue
159
+ return 1 if data was put into the queue */
160
+ int write_cryptpacket(int crypt_connection_id, uint8_t *data, uint32_t length)
161
+ {
162
+ if (crypt_connection_id < 0 || crypt_connection_id >= MAX_CRYPTO_CONNECTIONS)
163
+ return 0;
164
+ if (length - crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES > MAX_DATA_SIZE - 1)
165
+ return 0;
166
+ if (crypto_connections[crypt_connection_id].status != 3)
167
+ return 0;
168
+ uint8_t temp_data[MAX_DATA_SIZE];
169
+ int len = encrypt_data(crypto_connections[crypt_connection_id].peersessionpublic_key,
170
+ crypto_connections[crypt_connection_id].sessionsecret_key,
171
+ crypto_connections[crypt_connection_id].sent_nonce, data, length, temp_data + 1);
172
+ if (len == -1)
173
+ return 0;
174
+ temp_data[0] = 3;
175
+ if (write_packet(crypto_connections[crypt_connection_id].number, temp_data, len + 1) == 0)
176
+ return 0;
177
+ increment_nonce(crypto_connections[crypt_connection_id].sent_nonce);
178
+ return 1;
179
+ }
180
+
181
+ /* create a request to peer with public_key.
182
+ packet must be an array of MAX_DATA_SIZE big.
183
+ Data represents the data we send with the request with length being the length of the data.
184
+ request_id is the id of the request (32 = friend request, 254 = ping request)
185
+ returns -1 on failure
186
+ returns the length of the created packet on success */
187
+ int create_request(uint8_t *packet, uint8_t *public_key, uint8_t *data, uint32_t length, uint8_t request_id)
188
+ {
189
+ if (MAX_DATA_SIZE < length + 1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + ENCRYPTION_PADDING)
190
+ return -1;
191
+ uint8_t nonce[crypto_box_NONCEBYTES];
192
+ random_nonce(nonce);
193
+ int len = encrypt_data(public_key, self_secret_key, nonce, data, length,
194
+ 1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + packet);
195
+ if (len == -1)
196
+ return -1;
197
+ packet[0] = request_id;
198
+ memcpy(packet + 1, public_key, crypto_box_PUBLICKEYBYTES);
199
+ memcpy(packet + 1 + crypto_box_PUBLICKEYBYTES, self_public_key, crypto_box_PUBLICKEYBYTES);
200
+ memcpy(packet + 1 + crypto_box_PUBLICKEYBYTES * 2, nonce, crypto_box_NONCEBYTES);
201
+
202
+ return len + 1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES;
203
+ }
204
+
205
+ /* puts the senders public key in the request in public_key, the data from the request
206
+ in data if a friend or ping request was sent to us and returns the length of the data.
207
+ packet is the request packet and length is its length
208
+ return -1 if not valid request. */
209
+ int handle_request(uint8_t *public_key, uint8_t *data, uint8_t *packet, uint16_t length)
210
+ {
211
+
212
+ if (length > crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1 + ENCRYPTION_PADDING &&
213
+ length <= MAX_DATA_SIZE + ENCRYPTION_PADDING &&
214
+ memcmp(packet + 1, self_public_key, crypto_box_PUBLICKEYBYTES) == 0) {
215
+ memcpy(public_key, packet + 1 + crypto_box_PUBLICKEYBYTES, crypto_box_PUBLICKEYBYTES);
216
+ uint8_t nonce[crypto_box_NONCEBYTES];
217
+ memcpy(nonce, packet + 1 + crypto_box_PUBLICKEYBYTES * 2, crypto_box_NONCEBYTES);
218
+ int len1 = decrypt_data(public_key, self_secret_key, nonce, packet + 1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES,
219
+ length - (crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1), data);
220
+ if(len1 == -1)
221
+ return -1;
222
+ return len1;
223
+ } else
224
+ return -1;
225
+ }
226
+
227
+ /* Send a crypto handshake packet containing an encrypted secret nonce and session public key
228
+ to peer with connection_id and public_key
229
+ the packet is encrypted with a random nonce which is sent in plain text with the packet */
230
+ int send_cryptohandshake(int connection_id, uint8_t *public_key, uint8_t *secret_nonce, uint8_t *session_key)
231
+ {
232
+ uint8_t temp_data[MAX_DATA_SIZE];
233
+ uint8_t temp[crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES];
234
+ uint8_t nonce[crypto_box_NONCEBYTES];
235
+
236
+ random_nonce(nonce);
237
+ memcpy(temp, secret_nonce, crypto_box_NONCEBYTES);
238
+ memcpy(temp + crypto_box_NONCEBYTES, session_key, crypto_box_PUBLICKEYBYTES);
239
+
240
+ int len = encrypt_data(public_key, self_secret_key, nonce, temp, crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES,
241
+ 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + temp_data);
242
+ if (len == -1)
243
+ return 0;
244
+ temp_data[0] = 2;
245
+ memcpy(temp_data + 1, self_public_key, crypto_box_PUBLICKEYBYTES);
246
+ memcpy(temp_data + 1 + crypto_box_PUBLICKEYBYTES, nonce, crypto_box_NONCEBYTES);
247
+ return write_packet(connection_id, temp_data, len + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES);
248
+ }
249
+
250
+ /* Extract secret nonce, session public key and public_key from a packet(data) with length length
251
+ return 1 if successful
252
+ return 0 if failure */
253
+ int handle_cryptohandshake(uint8_t *public_key, uint8_t *secret_nonce,
254
+ uint8_t *session_key, uint8_t *data, uint16_t length)
255
+ {
256
+ int pad = (- crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES);
257
+ if (length != 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES
258
+ + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + pad) {
259
+ return 0;
260
+ }
261
+ if (data[0] != 2)
262
+ return 0;
263
+ uint8_t temp[crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES];
264
+
265
+ memcpy(public_key, data + 1, crypto_box_PUBLICKEYBYTES);
266
+
267
+ int len = decrypt_data(public_key, self_secret_key, data + 1 + crypto_box_PUBLICKEYBYTES,
268
+ data + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES,
269
+ crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + pad, temp);
270
+
271
+ if (len != crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES)
272
+ return 0;
273
+
274
+ memcpy(secret_nonce, temp, crypto_box_NONCEBYTES);
275
+ memcpy(session_key, temp + crypto_box_NONCEBYTES, crypto_box_PUBLICKEYBYTES);
276
+ return 1;
277
+ }
278
+
279
+ /* get crypto connection id from public key of peer
280
+ return -1 if there are no connections like we are looking for
281
+ return id if it found it */
282
+ int getcryptconnection_id(uint8_t *public_key)
283
+ {
284
+ uint32_t i;
285
+ for (i = 0; i < MAX_CRYPTO_CONNECTIONS; ++i) {
286
+ if (crypto_connections[i].status > 0)
287
+ if (memcmp(public_key, crypto_connections[i].public_key, crypto_box_PUBLICKEYBYTES) == 0)
288
+ return i;
289
+ }
290
+ return -1;
291
+ }
292
+
293
+ /* Start a secure connection with other peer who has public_key and ip_port
294
+ returns -1 if failure
295
+ returns crypt_connection_id of the initialized connection if everything went well. */
296
+ int crypto_connect(uint8_t *public_key, IP_Port ip_port)
297
+ {
298
+ uint32_t i;
299
+ int id = getcryptconnection_id(public_key);
300
+ if (id != -1) {
301
+ IP_Port c_ip = connection_ip(crypto_connections[id].number);
302
+ if(c_ip.ip.i == ip_port.ip.i && c_ip.port == ip_port.port)
303
+ return -1;
304
+ }
305
+ for (i = 0; i < MAX_CRYPTO_CONNECTIONS; ++i) {
306
+ if (crypto_connections[i].status == 0) {
307
+ int id = new_connection(ip_port);
308
+ if (id == -1)
309
+ return -1;
310
+ crypto_connections[i].number = id;
311
+ crypto_connections[i].status = 1;
312
+ random_nonce(crypto_connections[i].recv_nonce);
313
+ memcpy(crypto_connections[i].public_key, public_key, crypto_box_PUBLICKEYBYTES);
314
+ crypto_box_keypair(crypto_connections[i].sessionpublic_key, crypto_connections[i].sessionsecret_key);
315
+
316
+ if (send_cryptohandshake(id, public_key, crypto_connections[i].recv_nonce,
317
+ crypto_connections[i].sessionpublic_key) == 1) {
318
+ increment_nonce(crypto_connections[i].recv_nonce);
319
+ return i;
320
+ }
321
+ return -1; /* this should never happen. */
322
+ }
323
+ }
324
+ return -1;
325
+ }
326
+
327
+ /* handle an incoming connection
328
+ return -1 if no crypto inbound connection
329
+ return incoming connection id (Lossless_UDP one) if there is an incoming crypto connection
330
+ Put the public key of the peer in public_key, the secret_nonce from the handshake into secret_nonce
331
+ and the session public key for the connection in session_key
332
+ to accept it see: accept_crypto_inbound(...)
333
+ to refuse it just call kill_connection(...) on the connection id */
334
+ int crypto_inbound(uint8_t *public_key, uint8_t *secret_nonce, uint8_t *session_key)
335
+ {
336
+ uint32_t i;
337
+ for (i = 0; i < MAX_INCOMING; ++i) {
338
+ if (incoming_connections[i] != -1) {
339
+ if (is_connected(incoming_connections[i]) == 4 || is_connected(incoming_connections[i]) == 0) {
340
+ kill_connection(incoming_connections[i]);
341
+ incoming_connections[i] = -1;
342
+ continue;
343
+ }
344
+ if (id_packet(incoming_connections[i]) == 2) {
345
+ uint8_t temp_data[MAX_DATA_SIZE];
346
+ uint16_t len = read_packet(incoming_connections[i], temp_data);
347
+ if (handle_cryptohandshake(public_key, secret_nonce, session_key, temp_data, len)) {
348
+ int connection_id = incoming_connections[i];
349
+ incoming_connections[i] = -1; /* remove this connection from the incoming connection list. */
350
+ return connection_id;
351
+ }
352
+ }
353
+ }
354
+ }
355
+ return -1;
356
+ }
357
+
358
+ /* kill a crypto connection
359
+ return 0 if killed successfully
360
+ return 1 if there was a problem. */
361
+ int crypto_kill(int crypt_connection_id)
362
+ {
363
+ if (crypt_connection_id < 0 || crypt_connection_id >= MAX_CRYPTO_CONNECTIONS)
364
+ return 1;
365
+ if (crypto_connections[crypt_connection_id].status != 0) {
366
+ crypto_connections[crypt_connection_id].status = 0;
367
+ kill_connection(crypto_connections[crypt_connection_id].number);
368
+ crypto_connections[crypt_connection_id].number = ~0;
369
+ return 0;
370
+ }
371
+ return 1;
372
+ }
373
+
374
+ /* accept an incoming connection using the parameters provided by crypto_inbound
375
+ return -1 if not successful
376
+ returns the crypt_connection_id if successful */
377
+ int accept_crypto_inbound(int connection_id, uint8_t *public_key, uint8_t *secret_nonce, uint8_t *session_key)
378
+ {
379
+ uint32_t i;
380
+ if (connection_id == -1)
381
+ return -1;
382
+ /*
383
+ if(getcryptconnection_id(public_key) != -1)
384
+ {
385
+ return -1;
386
+ }*/
387
+ for (i = 0; i < MAX_CRYPTO_CONNECTIONS; ++i) {
388
+ if(crypto_connections[i].status == 0) {
389
+ crypto_connections[i].number = connection_id;
390
+ crypto_connections[i].status = 2;
391
+ random_nonce(crypto_connections[i].recv_nonce);
392
+ memcpy(crypto_connections[i].sent_nonce, secret_nonce, crypto_box_NONCEBYTES);
393
+ memcpy(crypto_connections[i].peersessionpublic_key, session_key, crypto_box_PUBLICKEYBYTES);
394
+ increment_nonce(crypto_connections[i].sent_nonce);
395
+ memcpy(crypto_connections[i].public_key, public_key, crypto_box_PUBLICKEYBYTES);
396
+
397
+ crypto_box_keypair(crypto_connections[i].sessionpublic_key, crypto_connections[i].sessionsecret_key);
398
+
399
+ if (send_cryptohandshake(connection_id, public_key, crypto_connections[i].recv_nonce,
400
+ crypto_connections[i].sessionpublic_key) == 1) {
401
+ increment_nonce(crypto_connections[i].recv_nonce);
402
+ uint32_t zero = 0;
403
+ crypto_connections[i].status = 3; /* connection status needs to be 3 for write_cryptpacket() to work */
404
+ write_cryptpacket(i, ((uint8_t *)&zero), sizeof(zero));
405
+ crypto_connections[i].status = 2; /* set it to its proper value right after. */
406
+ return i;
407
+ }
408
+ return -1; /* this should never happen. */
409
+ }
410
+ }
411
+ return -1;
412
+ }
413
+
414
+ /* return 0 if no connection, 1 we have sent a handshake, 2 if connection is not confirmed yet
415
+ (we have received a handshake but no empty data packet), 3 if the connection is established.
416
+ 4 if the connection is timed out and waiting to be killed */
417
+ int is_cryptoconnected(int crypt_connection_id)
418
+ {
419
+ if (crypt_connection_id >= 0 && crypt_connection_id < MAX_CRYPTO_CONNECTIONS)
420
+ return crypto_connections[crypt_connection_id].status;
421
+ return 0;
422
+ }
423
+
424
+ /* Generate our public and private keys
425
+ Only call this function the first time the program starts. */
426
+ void new_keys()
427
+ {
428
+ crypto_box_keypair(self_public_key,self_secret_key);
429
+ }
430
+
431
+ /* save the public and private keys to the keys array
432
+ Length must be crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES */
433
+ void save_keys(uint8_t *keys)
434
+ {
435
+ memcpy(keys, self_public_key, crypto_box_PUBLICKEYBYTES);
436
+ memcpy(keys + crypto_box_PUBLICKEYBYTES, self_secret_key, crypto_box_SECRETKEYBYTES);
437
+ }
438
+
439
+ /* load the public and private keys from the keys array
440
+ Length must be crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES */
441
+ void load_keys(uint8_t *keys)
442
+ {
443
+ memcpy(self_public_key, keys, crypto_box_PUBLICKEYBYTES);
444
+ memcpy(self_secret_key, keys + crypto_box_PUBLICKEYBYTES, crypto_box_SECRETKEYBYTES);
445
+ }
446
+
447
+ /* TODO: optimize this
448
+ adds an incoming connection to the incoming_connection list.
449
+ returns 0 if successful
450
+ returns 1 if failure */
451
+ int new_incoming(int id)
452
+ {
453
+ uint32_t i;
454
+ for (i = 0; i < MAX_INCOMING; ++i) {
455
+ if (incoming_connections[i] == -1) {
456
+ incoming_connections[i] = id;
457
+ return 0;
458
+ }
459
+ }
460
+ return 1;
461
+ }
462
+
463
+ /* TODO: optimize this
464
+ handle all new incoming connections. */
465
+ static void handle_incomings()
466
+ {
467
+ int income;
468
+ while (1) {
469
+ income = incoming_connection();
470
+ if(income == -1 || new_incoming(income) )
471
+ break;
472
+ }
473
+ }
474
+
475
+ /* handle received packets for not yet established crypto connections. */
476
+ static void receive_crypto()
477
+ {
478
+ uint32_t i;
479
+ for (i = 0; i < MAX_CRYPTO_CONNECTIONS; ++i) {
480
+ if (crypto_connections[i].status == 1) {
481
+ uint8_t temp_data[MAX_DATA_SIZE];
482
+ uint8_t secret_nonce[crypto_box_NONCEBYTES];
483
+ uint8_t public_key[crypto_box_PUBLICKEYBYTES];
484
+ uint8_t session_key[crypto_box_PUBLICKEYBYTES];
485
+ uint16_t len;
486
+ if (id_packet(crypto_connections[i].number) == 1)
487
+ /* if the packet is a friend request drop it (because we are already friends) */
488
+ len = read_packet(crypto_connections[i].number, temp_data);
489
+ if (id_packet(crypto_connections[i].number) == 2) { /* handle handshake packet. */
490
+ len = read_packet(crypto_connections[i].number, temp_data);
491
+ if (handle_cryptohandshake(public_key, secret_nonce, session_key, temp_data, len)) {
492
+ if (memcmp(public_key, crypto_connections[i].public_key, crypto_box_PUBLICKEYBYTES) == 0) {
493
+ memcpy(crypto_connections[i].sent_nonce, secret_nonce, crypto_box_NONCEBYTES);
494
+ memcpy(crypto_connections[i].peersessionpublic_key, session_key, crypto_box_PUBLICKEYBYTES);
495
+ increment_nonce(crypto_connections[i].sent_nonce);
496
+ uint32_t zero = 0;
497
+ crypto_connections[i].status = 3; /* connection status needs to be 3 for write_cryptpacket() to work */
498
+ write_cryptpacket(i, ((uint8_t *)&zero), sizeof(zero));
499
+ crypto_connections[i].status = 2; /* set it to its proper value right after. */
500
+ }
501
+ }
502
+ } else if (id_packet(crypto_connections[i].number) != -1) // This should not happen kill the connection if it does
503
+ crypto_kill(crypto_connections[i].number);
504
+
505
+ }
506
+ if (crypto_connections[i].status == 2) {
507
+ if (id_packet(crypto_connections[i].number) == 3) {
508
+ uint8_t temp_data[MAX_DATA_SIZE];
509
+ uint8_t data[MAX_DATA_SIZE];
510
+ int length = read_packet(crypto_connections[i].number, temp_data);
511
+ int len = decrypt_data(crypto_connections[i].peersessionpublic_key,
512
+ crypto_connections[i].sessionsecret_key,
513
+ crypto_connections[i].recv_nonce, temp_data + 1, length - 1, data);
514
+ uint32_t zero = 0;
515
+ if (len == sizeof(uint32_t) && memcmp(((uint8_t *)&zero), data, sizeof(uint32_t)) == 0) {
516
+ increment_nonce(crypto_connections[i].recv_nonce);
517
+ crypto_connections[i].status = 3;
518
+
519
+ /* connection is accepted so we disable the auto kill by setting it to about 1 month from now. */
520
+ kill_connection_in(crypto_connections[i].number, 3000000);
521
+ } else
522
+ crypto_kill(crypto_connections[i].number); // This should not happen kill the connection if it does
523
+ } else if(id_packet(crypto_connections[i].number) != -1)
524
+ /* This should not happen
525
+ kill the connection if it does */
526
+ crypto_kill(crypto_connections[i].number);
527
+ }
528
+ }
529
+ }
530
+
531
+ /* run this to (re)initialize net_crypto
532
+ sets all the global connection variables to their default values. */
533
+ void initNetCrypto()
534
+ {
535
+ memset(crypto_connections, 0 ,sizeof(crypto_connections));
536
+ memset(incoming_connections, -1 ,sizeof(incoming_connections));
537
+ uint32_t i;
538
+ for (i = 0; i < MAX_CRYPTO_CONNECTIONS; ++i)
539
+ crypto_connections[i].number = ~0;
540
+ }
541
+
542
+ static void killTimedout()
543
+ {
544
+ uint32_t i;
545
+ for (i = 0; i < MAX_CRYPTO_CONNECTIONS; ++i) {
546
+ if (crypto_connections[i].status != 0 && is_connected(crypto_connections[i].number) == 4)
547
+ crypto_connections[i].status = 4;
548
+ else if (is_connected(crypto_connections[i].number) == 4) {
549
+ kill_connection(crypto_connections[i].number);
550
+ crypto_connections[i].number = ~0;
551
+ }
552
+ }
553
+ }
554
+
555
+ /* main loop */
556
+ void doNetCrypto()
557
+ {
558
+ /* TODO:check if friend requests were sent correctly
559
+ handle new incoming connections
560
+ handle friend requests */
561
+ handle_incomings();
562
+ receive_crypto();
563
+ killTimedout();
564
+ }
@@ -0,0 +1,134 @@
1
+ /* net_crypto.h
2
+ *
3
+ * Functions for the core network crypto.
4
+ *
5
+ * Copyright (C) 2013 Tox project All Rights Reserved.
6
+ *
7
+ * This file is part of Tox.
8
+ *
9
+ * Tox is free software: you can redistribute it and/or modify
10
+ * it under the terms of the GNU General Public License as published by
11
+ * the Free Software Foundation, either version 3 of the License, or
12
+ * (at your option) any later version.
13
+ *
14
+ * Tox is distributed in the hope that it will be useful,
15
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ * GNU General Public License for more details.
18
+ *
19
+ * You should have received a copy of the GNU General Public License
20
+ * along with Tox. If not, see <http://www.gnu.org/licenses/>.
21
+ *
22
+ */
23
+
24
+ #ifndef NET_CRYPTO_H
25
+ #define NET_CRYPTO_H
26
+
27
+ #include "Lossless_UDP.h"
28
+
29
+ #ifdef __cplusplus
30
+ extern "C" {
31
+ #endif
32
+
33
+ /* Our public key. */
34
+ extern uint8_t self_public_key[crypto_box_PUBLICKEYBYTES];
35
+ extern uint8_t self_secret_key[crypto_box_SECRETKEYBYTES];
36
+
37
+ #define ENCRYPTION_PADDING (crypto_box_ZEROBYTES - crypto_box_BOXZEROBYTES)
38
+
39
+ /* encrypts plain of length length to encrypted of length + 16 using the
40
+ public key(32 bytes) of the receiver and the secret key of the sender and a 24 byte nonce
41
+ return -1 if there was a problem.
42
+ return length of encrypted data if everything was fine. */
43
+ int encrypt_data(uint8_t *public_key, uint8_t *secret_key, uint8_t *nonce,
44
+ uint8_t *plain, uint32_t length, uint8_t *encrypted);
45
+
46
+
47
+ /* decrypts encrypted of length length to plain of length length - 16 using the
48
+ public key(32 bytes) of the sender, the secret key of the receiver and a 24 byte nonce
49
+ return -1 if there was a problem(decryption failed)
50
+ return length of plain data if everything was fine. */
51
+ int decrypt_data(uint8_t *public_key, uint8_t *secret_key, uint8_t *nonce,
52
+ uint8_t *encrypted, uint32_t length, uint8_t *plain);
53
+
54
+
55
+ /* fill the given nonce with random bytes. */
56
+ void random_nonce(uint8_t *nonce);
57
+
58
+ /* return 0 if there is no received data in the buffer
59
+ return -1 if the packet was discarded.
60
+ return length of received data if successful */
61
+ int read_cryptpacket(int crypt_connection_id, uint8_t *data);
62
+
63
+ /* return 0 if data could not be put in packet queue
64
+ return 1 if data was put into the queue */
65
+ int write_cryptpacket(int crypt_connection_id, uint8_t *data, uint32_t length);
66
+
67
+ /* create a request to peer with public_key.
68
+ packet must be an array of MAX_DATA_SIZE big.
69
+ Data represents the data we send with the request with length being the length of the data.
70
+ request_id is the id of the request (32 = friend request, 254 = ping request)
71
+ returns -1 on failure
72
+ returns the length of the created packet on success */
73
+ int create_request(uint8_t *packet, uint8_t * public_key, uint8_t *data, uint32_t length, uint8_t request_id);
74
+
75
+ /* puts the senders public key in the request in public_key, the data from the request
76
+ in data if a friend or ping request was sent to us and returns the length of the data.
77
+ packet is the request packet and length is its length
78
+ return -1 if not valid request. */
79
+ int handle_request(uint8_t *public_key, uint8_t *data, uint8_t *packet, uint16_t length);
80
+
81
+ /* Start a secure connection with other peer who has public_key and ip_port
82
+ returns -1 if failure
83
+ returns crypt_connection_id of the initialized connection if everything went well. */
84
+ int crypto_connect(uint8_t *public_key, IP_Port ip_port);
85
+
86
+ /* kill a crypto connection
87
+ return 0 if killed successfully
88
+ return 1 if there was a problem. */
89
+ int crypto_kill(int crypt_connection_id);
90
+
91
+ /* handle an incoming connection
92
+ return -1 if no crypto inbound connection
93
+ return incoming connection id (Lossless_UDP one) if there is an incoming crypto connection
94
+ Put the public key of the peer in public_key, the secret_nonce from the handshake into secret_nonce
95
+ and the session public key for the connection in session_key
96
+ to accept it see: accept_crypto_inbound(...)
97
+ to refuse it just call kill_connection(...) on the connection id */
98
+ int crypto_inbound(uint8_t *public_key, uint8_t * secret_nonce, uint8_t *session_key);
99
+
100
+ /* accept an incoming connection using the parameters provided by crypto_inbound
101
+ return -1 if not successful
102
+ returns the crypt_connection_id if successful */
103
+ int accept_crypto_inbound(int connection_id, uint8_t *public_key, uint8_t * secret_nonce, uint8_t *session_key);
104
+
105
+ /* return 0 if no connection, 1 we have sent a handshake, 2 if connexion is not confirmed yet
106
+ (we have received a handshake but no empty data packet), 3 if the connection is established.
107
+ 4 if the connection is timed out and waiting to be killed */
108
+ int is_cryptoconnected(int crypt_connection_id);
109
+
110
+
111
+ /* Generate our public and private keys
112
+ Only call this function the first time the program starts. */
113
+ void new_keys();
114
+
115
+ /* save the public and private keys to the keys array
116
+ Length must be crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES */
117
+ void save_keys(uint8_t * keys);
118
+
119
+ /* load the public and private keys from the keys array
120
+ Length must be crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES */
121
+ void load_keys(uint8_t * keys);
122
+
123
+ /* run this to (re)initialize net_crypto
124
+ sets all the global connection variables to their default values. */
125
+ void initNetCrypto();
126
+
127
+ /* main loop */
128
+ void doNetCrypto();
129
+
130
+ #ifdef __cplusplus
131
+ }
132
+ #endif
133
+
134
+ #endif