diff options
-rw-r--r-- | docs/Tox_middle_level_network_protocol.txt | 27 | ||||
-rw-r--r-- | toxcore/crypto_core.c | 13 | ||||
-rw-r--r-- | toxcore/crypto_core.h | 4 | ||||
-rw-r--r-- | toxcore/net_crypto.c | 123 |
4 files changed, 161 insertions, 6 deletions
diff --git a/docs/Tox_middle_level_network_protocol.txt b/docs/Tox_middle_level_network_protocol.txt index be8253cd..49ad330c 100644 --- a/docs/Tox_middle_level_network_protocol.txt +++ b/docs/Tox_middle_level_network_protocol.txt | |||
@@ -42,13 +42,13 @@ cookie request packet: | |||
42 | [uint8_t 24][Senders DHT Public key (32 bytes)][Random nonce (24 | 42 | [uint8_t 24][Senders DHT Public key (32 bytes)][Random nonce (24 |
43 | bytes)][Encrypted message containing: [Senders real public key (32 | 43 | bytes)][Encrypted message containing: [Senders real public key (32 |
44 | bytes)][Recievers real public key (32 bytes)]] | 44 | bytes)][Recievers real public key (32 bytes)]] |
45 | Encrypted message is encrypted with sender DHT private key, recievers DHT public | 45 | Encrypted message is encrypted with sender DHT private key, recievers DHT |
46 | key and the nonce. | 46 | public key and the nonce. |
47 | 47 | ||
48 | cookie response packet: | 48 | cookie response packet: |
49 | [uint8_t 25][Random nonce (24 bytes)][Encrypted message containing: [Cookie]] | 49 | [uint8_t 25][Random nonce (24 bytes)][Encrypted message containing: [Cookie]] |
50 | Encrypted message is encrypted with sender DHT private key, recievers DHT public | 50 | Encrypted message is encrypted with sender DHT private key, recievers DHT |
51 | key and the nonce. | 51 | public key and the nonce. |
52 | 52 | ||
53 | The Cookie should be basically: | 53 | The Cookie should be basically: |
54 | [nonce][encrypted data:[uint64_t time][Senders real public key (32 | 54 | [nonce][encrypted data:[uint64_t time][Senders real public key (32 |
@@ -61,3 +61,22 @@ nonce][session public key of the peer (32 bytes)]] | |||
61 | The handshake packet is encrypted using the real private key of the sender, the | 61 | The handshake packet is encrypted using the real private key of the sender, the |
62 | real private key of the reciever and the nonce. | 62 | real private key of the reciever and the nonce. |
63 | 63 | ||
64 | |||
65 | Alice wants to connect to bob. | ||
66 | |||
67 | Alice sends a cookie request packet to bob and gets a cookie response back. | ||
68 | |||
69 | Alice then generates a nonce and a temporary public/private keypair. | ||
70 | |||
71 | Alice then takes that nonce and just generated private key and the obtained | ||
72 | cookie and puts them in a handshake packet which she sends to bob. | ||
73 | |||
74 | Bob gets the handshake packet, accepts the connection request, then generates a | ||
75 | nonce and a temporary public/private keypair and sends a handshake packet back | ||
76 | with this just generated information and with the cookie field being random | ||
77 | data/zeros. | ||
78 | |||
79 | Both then use these temporary keys to generate the session key with which every | ||
80 | data packet sent and recieved will be encrypted and decrypted. The nonce sent | ||
81 | in the handshake will be used to encrypt the first data packet sent, the nonce | ||
82 | + 1 the second, the nonce + 2 the third and so on. | ||
diff --git a/toxcore/crypto_core.c b/toxcore/crypto_core.c index 59053bc4..6e8b747a 100644 --- a/toxcore/crypto_core.c +++ b/toxcore/crypto_core.c | |||
@@ -42,6 +42,19 @@ uint8_t crypto_iszero(uint8_t *mem, uint32_t length) | |||
42 | return check; // We return zero if mem is made out of zeroes. | 42 | return check; // We return zero if mem is made out of zeroes. |
43 | } | 43 | } |
44 | 44 | ||
45 | /* Use this instead of memcmp; not vulnerable to timing attacks. | ||
46 | returns 0 if both mem locations of length are equal. */ | ||
47 | unsigned int crypto_cmp(uint8_t *mem1, uint8_t *mem2, uint32_t length) | ||
48 | { | ||
49 | unsigned int i, check = 0;; | ||
50 | |||
51 | for (i = 0; i < length; ++i) { | ||
52 | check |= mem1[i] ^ mem2[i]; | ||
53 | } | ||
54 | |||
55 | return check; | ||
56 | } | ||
57 | |||
45 | /* Precomputes the shared key from their public_key and our secret_key. | 58 | /* Precomputes the shared key from their public_key and our secret_key. |
46 | * This way we can avoid an expensive elliptic curve scalar multiply for each | 59 | * This way we can avoid an expensive elliptic curve scalar multiply for each |
47 | * encrypt/decrypt operation. | 60 | * encrypt/decrypt operation. |
diff --git a/toxcore/crypto_core.h b/toxcore/crypto_core.h index a862635e..de8656c7 100644 --- a/toxcore/crypto_core.h +++ b/toxcore/crypto_core.h | |||
@@ -29,6 +29,10 @@ | |||
29 | /* return zero if the buffer contains only zeros. */ | 29 | /* return zero if the buffer contains only zeros. */ |
30 | uint8_t crypto_iszero(uint8_t *buffer, uint32_t blen); | 30 | uint8_t crypto_iszero(uint8_t *buffer, uint32_t blen); |
31 | 31 | ||
32 | /* Use this instead of memcmp; not vulnerable to timing attacks. | ||
33 | returns 0 if both mem locations of length are equal. */ | ||
34 | unsigned int crypto_cmp(uint8_t *mem1, uint8_t *mem2, uint32_t length); | ||
35 | |||
32 | /* Encrypts plain of length length to encrypted of length + 16 using the | 36 | /* Encrypts plain of length length to encrypted of length + 16 using the |
33 | * public key(32 bytes) of the receiver and the secret key of the sender and a 24 byte nonce. | 37 | * public key(32 bytes) of the receiver and the secret key of the sender and a 24 byte nonce. |
34 | * | 38 | * |
diff --git a/toxcore/net_crypto.c b/toxcore/net_crypto.c index 3d36e8e0..97533512 100644 --- a/toxcore/net_crypto.c +++ b/toxcore/net_crypto.c | |||
@@ -94,7 +94,7 @@ static int create_cookie(uint8_t *cookie, uint8_t *bytes, uint8_t *encryption_ke | |||
94 | 94 | ||
95 | #define COOKIE_RESPONSE_LENGTH (1 + crypto_box_NONCEBYTES + COOKIE_LENGTH + crypto_box_MACBYTES) | 95 | #define COOKIE_RESPONSE_LENGTH (1 + crypto_box_NONCEBYTES + COOKIE_LENGTH + crypto_box_MACBYTES) |
96 | 96 | ||
97 | /* Open cookie of length COOKIE_LENGTH from bytes of length COOKIE_REQUEST_PLAIN_LENGTH using encryption_key | 97 | /* Open cookie of length COOKIE_LENGTH to bytes of length COOKIE_REQUEST_PLAIN_LENGTH using encryption_key |
98 | * | 98 | * |
99 | * return -1 on failure. | 99 | * return -1 on failure. |
100 | * return 0 on success. | 100 | * return 0 on success. |
@@ -172,7 +172,7 @@ static int handle_cookie_request(Net_Crypto *c, uint8_t *request_plain, uint8_t | |||
172 | */ | 172 | */ |
173 | static int udp_handle_cookie_request(void *object, IP_Port source, uint8_t *packet, uint32_t length) | 173 | static int udp_handle_cookie_request(void *object, IP_Port source, uint8_t *packet, uint32_t length) |
174 | { | 174 | { |
175 | Net_Crypto *c = c; | 175 | Net_Crypto *c = object; |
176 | uint8_t request_plain[COOKIE_REQUEST_PLAIN_LENGTH]; | 176 | uint8_t request_plain[COOKIE_REQUEST_PLAIN_LENGTH]; |
177 | uint8_t shared_key[crypto_box_BEFORENMBYTES]; | 177 | uint8_t shared_key[crypto_box_BEFORENMBYTES]; |
178 | 178 | ||
@@ -190,6 +190,125 @@ static int udp_handle_cookie_request(void *object, IP_Port source, uint8_t *pack | |||
190 | return 0; | 190 | return 0; |
191 | } | 191 | } |
192 | 192 | ||
193 | /* Handle a cookie response packet of length encrypted with shared_key. | ||
194 | * put the cookie in the response in cookie | ||
195 | * | ||
196 | * cookie must be of length COOKIE_LENGTH. | ||
197 | * | ||
198 | * return -1 on failure. | ||
199 | * return COOKIE_LENGTH on success. | ||
200 | */ | ||
201 | static int handle_cookie_response(Net_Crypto *c, uint8_t *cookie, uint8_t *packet, uint32_t length, uint8_t *shared_key) | ||
202 | { | ||
203 | if (length != COOKIE_RESPONSE_LENGTH) | ||
204 | return -1; | ||
205 | |||
206 | int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES, | ||
207 | length - (1 + crypto_box_NONCEBYTES), cookie); | ||
208 | |||
209 | if (len != COOKIE_LENGTH) | ||
210 | return -1; | ||
211 | |||
212 | return COOKIE_LENGTH; | ||
213 | } | ||
214 | |||
215 | #define HANDSHAKE_PACKET_LENGTH (1 + COOKIE_LENGTH + crypto_box_NONCEBYTES + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES) | ||
216 | |||
217 | /* Create a handshake packet and put it in packet. | ||
218 | * cookie must be COOKIE_LENGTH bytes. | ||
219 | * packet must be of size HANDSHAKE_PACKET_LENGTH or bigger. | ||
220 | * | ||
221 | * return -1 on failure. | ||
222 | * return HANDSHAKE_PACKET_LENGTH on success. | ||
223 | */ | ||
224 | static int create_crypto_handshake(Net_Crypto *c, uint8_t *packet, uint8_t *cookie, uint8_t *nonce, uint8_t *session_pk, | ||
225 | uint8_t *peer_real_pk) | ||
226 | { | ||
227 | uint8_t plain[crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES]; | ||
228 | memcpy(plain, nonce, crypto_box_NONCEBYTES); | ||
229 | memcpy(plain + crypto_box_NONCEBYTES, session_pk, crypto_box_PUBLICKEYBYTES); | ||
230 | new_nonce(packet + 1 + COOKIE_LENGTH); | ||
231 | int len = encrypt_data(peer_real_pk, c->self_secret_key, packet + 1 + COOKIE_LENGTH, plain, sizeof(plain), | ||
232 | packet + 1 + COOKIE_LENGTH + crypto_box_NONCEBYTES); | ||
233 | |||
234 | if (len != HANDSHAKE_PACKET_LENGTH - (1 + COOKIE_LENGTH + crypto_box_NONCEBYTES)) | ||
235 | return -1; | ||
236 | |||
237 | packet[0] = NET_PACKET_CRYPTO_HS; | ||
238 | memcpy(packet + 1, cookie, COOKIE_LENGTH); | ||
239 | |||
240 | return HANDSHAKE_PACKET_LENGTH; | ||
241 | } | ||
242 | |||
243 | /* Handle a crypto handshake packet of length. | ||
244 | * put the nonce contained in the packet in nonce, | ||
245 | * the session public key in session_pk and | ||
246 | * the real public key of the peer in peer_real_pk. | ||
247 | * | ||
248 | * nonce must be at least crypto_box_NONCEBYTES | ||
249 | * session_pk must be at least crypto_box_PUBLICKEYBYTES | ||
250 | * peer_real_pk must be at least crypto_box_PUBLICKEYBYTES | ||
251 | * | ||
252 | * return -1 on failure. | ||
253 | * return 0 on success. | ||
254 | */ | ||
255 | static int handle_crypto_handshake(Net_Crypto *c, uint8_t *nonce, uint8_t *session_pk, uint8_t *peer_real_pk, | ||
256 | uint8_t *packet, uint32_t length) | ||
257 | { | ||
258 | if (length != HANDSHAKE_PACKET_LENGTH) | ||
259 | return -1; | ||
260 | |||
261 | uint8_t cookie_plain[COOKIE_REQUEST_PLAIN_LENGTH]; | ||
262 | |||
263 | if (open_cookie(cookie_plain, packet + 1, c->secret_symmetric_key) != 0) | ||
264 | return -1; | ||
265 | |||
266 | if (crypto_cmp(cookie_plain + crypto_box_PUBLICKEYBYTES, c->self_public_key, crypto_box_PUBLICKEYBYTES) != 0) | ||
267 | return -1; | ||
268 | |||
269 | uint8_t plain[crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES]; | ||
270 | int len = decrypt_data(cookie_plain, c->self_secret_key, packet + 1 + COOKIE_LENGTH, | ||
271 | packet + 1 + COOKIE_LENGTH + crypto_box_NONCEBYTES, | ||
272 | HANDSHAKE_PACKET_LENGTH - (1 + COOKIE_LENGTH + crypto_box_NONCEBYTES), plain); | ||
273 | |||
274 | if (len != sizeof(plain)) | ||
275 | return -1; | ||
276 | |||
277 | memcpy(nonce, plain, crypto_box_NONCEBYTES); | ||
278 | memcpy(session_pk, plain + crypto_box_NONCEBYTES, crypto_box_PUBLICKEYBYTES); | ||
279 | memcpy(peer_real_pk, cookie_plain, crypto_box_PUBLICKEYBYTES); | ||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | /* Handle a crypto handshake packet of length without opening the cookie from peer | ||
284 | * with the real public key peer_real_pk. | ||
285 | * put the nonce contained in the packet in nonce and the session public key in | ||
286 | * session_pk. | ||
287 | * | ||
288 | * nonce must be at least crypto_box_NONCEBYTES | ||
289 | * session_pk must be at least crypto_box_PUBLICKEYBYTES | ||
290 | * | ||
291 | * return -1 on failure. | ||
292 | * return 0 on success. | ||
293 | */ | ||
294 | static int handle_crypto_handshake_nocookie(Net_Crypto *c, uint8_t *nonce, uint8_t *session_pk, uint8_t *packet, | ||
295 | uint32_t length, uint8_t *peer_real_pk) | ||
296 | { | ||
297 | if (length != HANDSHAKE_PACKET_LENGTH) | ||
298 | return -1; | ||
299 | |||
300 | uint8_t plain[crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES]; | ||
301 | int len = decrypt_data(peer_real_pk, c->self_secret_key, packet + 1 + COOKIE_LENGTH, | ||
302 | packet + 1 + COOKIE_LENGTH + crypto_box_NONCEBYTES, | ||
303 | HANDSHAKE_PACKET_LENGTH - (1 + COOKIE_LENGTH + crypto_box_NONCEBYTES), plain); | ||
304 | |||
305 | if (len != sizeof(plain)) | ||
306 | return -1; | ||
307 | |||
308 | memcpy(nonce, plain, crypto_box_NONCEBYTES); | ||
309 | memcpy(session_pk, plain + crypto_box_NONCEBYTES, crypto_box_PUBLICKEYBYTES); | ||
310 | return 0; | ||
311 | } | ||
193 | /* return 0 if there is no received data in the buffer. | 312 | /* return 0 if there is no received data in the buffer. |
194 | * return -1 if the packet was discarded. | 313 | * return -1 if the packet was discarded. |
195 | * return length of received data if successful. | 314 | * return length of received data if successful. |