From b9370d519ff87020cf32f3d04b6a2c4eebcc9563 Mon Sep 17 00:00:00 2001 From: irungentoo Date: Mon, 28 Apr 2014 20:14:07 -0400 Subject: [PATCH] Added some functions to create/handle middle level protocol packets. --- docs/Tox_middle_level_network_protocol.txt | 27 ++++- toxcore/crypto_core.c | 13 +++ toxcore/crypto_core.h | 4 + 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: [uint8_t 24][Senders DHT Public key (32 bytes)][Random nonce (24 bytes)][Encrypted message containing: [Senders real public key (32 bytes)][Recievers real public key (32 bytes)]] -Encrypted message is encrypted with sender DHT private key, recievers DHT public -key and the nonce. +Encrypted message is encrypted with sender DHT private key, recievers DHT +public key and the nonce. cookie response packet: [uint8_t 25][Random nonce (24 bytes)][Encrypted message containing: [Cookie]] -Encrypted message is encrypted with sender DHT private key, recievers DHT public -key and the nonce. +Encrypted message is encrypted with sender DHT private key, recievers DHT +public key and the nonce. The Cookie should be basically: [nonce][encrypted data:[uint64_t time][Senders real public key (32 @@ -61,3 +61,22 @@ nonce][session public key of the peer (32 bytes)]] The handshake packet is encrypted using the real private key of the sender, the real private key of the reciever and the nonce. + +Alice wants to connect to bob. + +Alice sends a cookie request packet to bob and gets a cookie response back. + +Alice then generates a nonce and a temporary public/private keypair. + +Alice then takes that nonce and just generated private key and the obtained +cookie and puts them in a handshake packet which she sends to bob. + +Bob gets the handshake packet, accepts the connection request, then generates a +nonce and a temporary public/private keypair and sends a handshake packet back +with this just generated information and with the cookie field being random +data/zeros. + +Both then use these temporary keys to generate the session key with which every +data packet sent and recieved will be encrypted and decrypted. The nonce sent +in the handshake will be used to encrypt the first data packet sent, the nonce ++ 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) return check; // We return zero if mem is made out of zeroes. } +/* Use this instead of memcmp; not vulnerable to timing attacks. + returns 0 if both mem locations of length are equal. */ +unsigned int crypto_cmp(uint8_t *mem1, uint8_t *mem2, uint32_t length) +{ + unsigned int i, check = 0;; + + for (i = 0; i < length; ++i) { + check |= mem1[i] ^ mem2[i]; + } + + return check; +} + /* Precomputes the shared key from their public_key and our secret_key. * This way we can avoid an expensive elliptic curve scalar multiply for each * 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 @@ /* return zero if the buffer contains only zeros. */ uint8_t crypto_iszero(uint8_t *buffer, uint32_t blen); +/* Use this instead of memcmp; not vulnerable to timing attacks. + returns 0 if both mem locations of length are equal. */ +unsigned int crypto_cmp(uint8_t *mem1, uint8_t *mem2, uint32_t length); + /* 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. * 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 #define COOKIE_RESPONSE_LENGTH (1 + crypto_box_NONCEBYTES + COOKIE_LENGTH + crypto_box_MACBYTES) -/* Open cookie of length COOKIE_LENGTH from bytes of length COOKIE_REQUEST_PLAIN_LENGTH using encryption_key +/* Open cookie of length COOKIE_LENGTH to bytes of length COOKIE_REQUEST_PLAIN_LENGTH using encryption_key * * return -1 on failure. * return 0 on success. @@ -172,7 +172,7 @@ static int handle_cookie_request(Net_Crypto *c, uint8_t *request_plain, uint8_t */ static int udp_handle_cookie_request(void *object, IP_Port source, uint8_t *packet, uint32_t length) { - Net_Crypto *c = c; + Net_Crypto *c = object; uint8_t request_plain[COOKIE_REQUEST_PLAIN_LENGTH]; uint8_t shared_key[crypto_box_BEFORENMBYTES]; @@ -190,6 +190,125 @@ static int udp_handle_cookie_request(void *object, IP_Port source, uint8_t *pack return 0; } +/* Handle a cookie response packet of length encrypted with shared_key. + * put the cookie in the response in cookie + * + * cookie must be of length COOKIE_LENGTH. + * + * return -1 on failure. + * return COOKIE_LENGTH on success. + */ +static int handle_cookie_response(Net_Crypto *c, uint8_t *cookie, uint8_t *packet, uint32_t length, uint8_t *shared_key) +{ + if (length != COOKIE_RESPONSE_LENGTH) + return -1; + + int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES, + length - (1 + crypto_box_NONCEBYTES), cookie); + + if (len != COOKIE_LENGTH) + return -1; + + return COOKIE_LENGTH; +} + +#define HANDSHAKE_PACKET_LENGTH (1 + COOKIE_LENGTH + crypto_box_NONCEBYTES + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES) + +/* Create a handshake packet and put it in packet. + * cookie must be COOKIE_LENGTH bytes. + * packet must be of size HANDSHAKE_PACKET_LENGTH or bigger. + * + * return -1 on failure. + * return HANDSHAKE_PACKET_LENGTH on success. + */ +static int create_crypto_handshake(Net_Crypto *c, uint8_t *packet, uint8_t *cookie, uint8_t *nonce, uint8_t *session_pk, + uint8_t *peer_real_pk) +{ + uint8_t plain[crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES]; + memcpy(plain, nonce, crypto_box_NONCEBYTES); + memcpy(plain + crypto_box_NONCEBYTES, session_pk, crypto_box_PUBLICKEYBYTES); + new_nonce(packet + 1 + COOKIE_LENGTH); + int len = encrypt_data(peer_real_pk, c->self_secret_key, packet + 1 + COOKIE_LENGTH, plain, sizeof(plain), + packet + 1 + COOKIE_LENGTH + crypto_box_NONCEBYTES); + + if (len != HANDSHAKE_PACKET_LENGTH - (1 + COOKIE_LENGTH + crypto_box_NONCEBYTES)) + return -1; + + packet[0] = NET_PACKET_CRYPTO_HS; + memcpy(packet + 1, cookie, COOKIE_LENGTH); + + return HANDSHAKE_PACKET_LENGTH; +} + +/* Handle a crypto handshake packet of length. + * put the nonce contained in the packet in nonce, + * the session public key in session_pk and + * the real public key of the peer in peer_real_pk. + * + * nonce must be at least crypto_box_NONCEBYTES + * session_pk must be at least crypto_box_PUBLICKEYBYTES + * peer_real_pk must be at least crypto_box_PUBLICKEYBYTES + * + * return -1 on failure. + * return 0 on success. + */ +static int handle_crypto_handshake(Net_Crypto *c, uint8_t *nonce, uint8_t *session_pk, uint8_t *peer_real_pk, + uint8_t *packet, uint32_t length) +{ + if (length != HANDSHAKE_PACKET_LENGTH) + return -1; + + uint8_t cookie_plain[COOKIE_REQUEST_PLAIN_LENGTH]; + + if (open_cookie(cookie_plain, packet + 1, c->secret_symmetric_key) != 0) + return -1; + + if (crypto_cmp(cookie_plain + crypto_box_PUBLICKEYBYTES, c->self_public_key, crypto_box_PUBLICKEYBYTES) != 0) + return -1; + + uint8_t plain[crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES]; + int len = decrypt_data(cookie_plain, c->self_secret_key, packet + 1 + COOKIE_LENGTH, + packet + 1 + COOKIE_LENGTH + crypto_box_NONCEBYTES, + HANDSHAKE_PACKET_LENGTH - (1 + COOKIE_LENGTH + crypto_box_NONCEBYTES), plain); + + if (len != sizeof(plain)) + return -1; + + memcpy(nonce, plain, crypto_box_NONCEBYTES); + memcpy(session_pk, plain + crypto_box_NONCEBYTES, crypto_box_PUBLICKEYBYTES); + memcpy(peer_real_pk, cookie_plain, crypto_box_PUBLICKEYBYTES); + return 0; +} + +/* Handle a crypto handshake packet of length without opening the cookie from peer + * with the real public key peer_real_pk. + * put the nonce contained in the packet in nonce and the session public key in + * session_pk. + * + * nonce must be at least crypto_box_NONCEBYTES + * session_pk must be at least crypto_box_PUBLICKEYBYTES + * + * return -1 on failure. + * return 0 on success. + */ +static int handle_crypto_handshake_nocookie(Net_Crypto *c, uint8_t *nonce, uint8_t *session_pk, uint8_t *packet, + uint32_t length, uint8_t *peer_real_pk) +{ + if (length != HANDSHAKE_PACKET_LENGTH) + return -1; + + uint8_t plain[crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES]; + int len = decrypt_data(peer_real_pk, c->self_secret_key, packet + 1 + COOKIE_LENGTH, + packet + 1 + COOKIE_LENGTH + crypto_box_NONCEBYTES, + HANDSHAKE_PACKET_LENGTH - (1 + COOKIE_LENGTH + crypto_box_NONCEBYTES), plain); + + if (len != sizeof(plain)) + return -1; + + memcpy(nonce, plain, crypto_box_NONCEBYTES); + memcpy(session_pk, plain + crypto_box_NONCEBYTES, crypto_box_PUBLICKEYBYTES); + return 0; +} /* 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.