static int handle_ping_response(void *_dht, IP_Port source, const uint8_t *packet, uint16_t length) { DHT *dht = _dht; int rc; if (length != DHT_PING_SIZE) return 1; PING *ping = dht->ping; if (id_equal(packet + 1, ping->dht->self_public_key)) return 1; uint8_t shared_key[crypto_box_BEFORENMBYTES]; // generate key to encrypt ping_id with recipient privkey DHT_get_shared_key_sent(ping->dht, shared_key, packet + 1); uint8_t ping_plain[PING_PLAIN_SIZE]; // Decrypt ping_id rc = decrypt_data_symmetric(shared_key, packet + 1 + crypto_box_PUBLICKEYBYTES, packet + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, PING_PLAIN_SIZE + crypto_box_MACBYTES, ping_plain); if (rc != sizeof(ping_plain)) return 1; if (ping_plain[0] != NET_PACKET_PING_RESPONSE) return 1; uint64_t ping_id; memcpy(&ping_id, ping_plain + 1, sizeof(ping_id)); uint8_t data[PING_DATA_SIZE]; if (ping_array_check(data, sizeof(data), &ping->ping_array, ping_id) != sizeof(data)) return 1; if (!id_equal(packet + 1, data)) return 1; IP_Port ipp; memcpy(&ipp, data + crypto_box_PUBLICKEYBYTES, sizeof(IP_Port)); if (!ipport_equal(&ipp, &source)) return 1; addto_lists(dht, source, packet + 1); return 0; }
/* data must be of length TCP_SERVER_HANDSHAKE_SIZE * * return 0 on success. * return -1 on failure. */ static int handle_handshake(TCP_Client_Connection *TCP_conn, const uint8_t *data) { uint8_t plain[crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES]; int len = decrypt_data_symmetric(TCP_conn->shared_key, data, data + crypto_box_NONCEBYTES, TCP_SERVER_HANDSHAKE_SIZE - crypto_box_NONCEBYTES, plain); if (len != sizeof(plain)) return -1; memcpy(TCP_conn->recv_nonce, plain + crypto_box_PUBLICKEYBYTES, crypto_box_NONCEBYTES); encrypt_precompute(plain, TCP_conn->temp_secret_key, TCP_conn->shared_key); memset(TCP_conn->temp_secret_key, 0, crypto_box_SECRETKEYBYTES); return 0; }
static int handle_send_1(void *object, IP_Port source, const uint8_t *packet, uint16_t length) { Onion *onion = object; if (length > ONION_MAX_PACKET_SIZE) return 1; if (length <= 1 + SEND_2) return 1; change_symmetric_key(onion); uint8_t plain[ONION_MAX_PACKET_SIZE]; uint8_t shared_key[crypto_box_BEFORENMBYTES]; get_shared_key(&onion->shared_keys_2, shared_key, onion->dht->self_secret_key, packet + 1 + crypto_box_NONCEBYTES); int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES, length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_1), plain); if (len != length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_1 + crypto_box_MACBYTES)) return 1; IP_Port send_to; if (ipport_unpack(&send_to, plain, len, 0) == -1) return 1; uint8_t data[ONION_MAX_PACKET_SIZE]; data[0] = NET_PACKET_ONION_SEND_2; memcpy(data + 1, packet + 1, crypto_box_NONCEBYTES); memcpy(data + 1 + crypto_box_NONCEBYTES, plain + SIZE_IPPORT, len - SIZE_IPPORT); uint16_t data_len = 1 + crypto_box_NONCEBYTES + (len - SIZE_IPPORT); uint8_t *ret_part = data + data_len; new_nonce(ret_part); uint8_t ret_data[RETURN_1 + SIZE_IPPORT]; ipport_pack(ret_data, &source); memcpy(ret_data + SIZE_IPPORT, packet + (length - RETURN_1), RETURN_1); len = encrypt_data_symmetric(onion->secret_symmetric_key, ret_part, ret_data, sizeof(ret_data), ret_part + crypto_box_NONCEBYTES); if (len != RETURN_2 - crypto_box_NONCEBYTES) return 1; data_len += crypto_box_NONCEBYTES + len; if ((uint32_t)sendpacket(onion->net, send_to, data, data_len) != data_len) return 1; return 0; }
/* data must be of length TCP_SERVER_HANDSHAKE_SIZE * * return 0 on success. * return -1 on failure. */ static int handle_handshake(TCP_Client_Connection *TCP_conn, const uint8_t *data) { uint8_t plain[CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE]; int len = decrypt_data_symmetric(TCP_conn->shared_key, data, data + CRYPTO_NONCE_SIZE, TCP_SERVER_HANDSHAKE_SIZE - CRYPTO_NONCE_SIZE, plain); if (len != sizeof(plain)) { return -1; } memcpy(TCP_conn->recv_nonce, plain + CRYPTO_PUBLIC_KEY_SIZE, CRYPTO_NONCE_SIZE); encrypt_precompute(plain, TCP_conn->temp_secret_key, TCP_conn->shared_key); crypto_memzero(TCP_conn->temp_secret_key, CRYPTO_SECRET_KEY_SIZE); return 0; }
/* return 1 if everything went well. * return -1 if the connection must be killed. */ static int handle_TCP_handshake(TCP_Secure_Connection *con, const uint8_t *data, uint16_t length, const uint8_t *self_secret_key) { if (length != TCP_CLIENT_HANDSHAKE_SIZE) { return -1; } if (con->status != TCP_STATUS_CONNECTED) { return -1; } uint8_t shared_key[crypto_box_BEFORENMBYTES]; encrypt_precompute(data, self_secret_key, shared_key); uint8_t plain[TCP_HANDSHAKE_PLAIN_SIZE]; int len = decrypt_data_symmetric(shared_key, data + crypto_box_PUBLICKEYBYTES, data + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, TCP_HANDSHAKE_PLAIN_SIZE + crypto_box_MACBYTES, plain); if (len != TCP_HANDSHAKE_PLAIN_SIZE) { return -1; } memcpy(con->public_key, data, crypto_box_PUBLICKEYBYTES); uint8_t temp_secret_key[crypto_box_SECRETKEYBYTES]; uint8_t resp_plain[TCP_HANDSHAKE_PLAIN_SIZE]; crypto_box_keypair(resp_plain, temp_secret_key); random_nonce(con->sent_nonce); memcpy(resp_plain + crypto_box_PUBLICKEYBYTES, con->sent_nonce, crypto_box_NONCEBYTES); memcpy(con->recv_nonce, plain + crypto_box_PUBLICKEYBYTES, crypto_box_NONCEBYTES); uint8_t response[TCP_SERVER_HANDSHAKE_SIZE]; random_nonce(response); len = encrypt_data_symmetric(shared_key, response, resp_plain, TCP_HANDSHAKE_PLAIN_SIZE, response + crypto_box_NONCEBYTES); if (len != TCP_HANDSHAKE_PLAIN_SIZE + crypto_box_MACBYTES) { return -1; } if (TCP_SERVER_HANDSHAKE_SIZE != send(con->sock, (const char *)response, TCP_SERVER_HANDSHAKE_SIZE, MSG_NOSIGNAL)) { return -1; } encrypt_precompute(plain, temp_secret_key, con->shared_key); con->status = TCP_STATUS_UNCONFIRMED; return 1; }
static int handle_ping_request(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata) { DHT *dht = (DHT *)object; int rc; if (length != DHT_PING_SIZE) { return 1; } PING *ping = dht->ping; if (id_equal(packet + 1, ping->dht->self_public_key)) { return 1; } uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; uint8_t ping_plain[PING_PLAIN_SIZE]; // Decrypt ping_id DHT_get_shared_key_recv(dht, shared_key, packet + 1); rc = decrypt_data_symmetric(shared_key, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, PING_PLAIN_SIZE + CRYPTO_MAC_SIZE, ping_plain); if (rc != sizeof(ping_plain)) { return 1; } if (ping_plain[0] != NET_PACKET_PING_REQUEST) { return 1; } uint64_t ping_id; memcpy(&ping_id, ping_plain + 1, sizeof(ping_id)); // Send response send_ping_response(ping, source, packet + 1, ping_id, shared_key); add_to_ping(ping, packet + 1, source); return 0; }
static int handle_recv_1(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata) { Onion *onion = (Onion *)object; if (length > ONION_MAX_PACKET_SIZE) { return 1; } if (length <= 1 + RETURN_1) { return 1; } change_symmetric_key(onion); uint8_t plain[SIZE_IPPORT]; int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES, SIZE_IPPORT + crypto_box_MACBYTES, plain); if ((uint32_t)len != SIZE_IPPORT) { return 1; } IP_Port send_to; if (ipport_unpack(&send_to, plain, len, 1) == -1) { return 1; } uint16_t data_len = length - (1 + RETURN_1); if (onion->recv_1_function && send_to.ip.family != AF_INET && send_to.ip.family != AF_INET6) { return onion->recv_1_function(onion->callback_object, send_to, packet + (1 + RETURN_1), data_len); } if ((uint32_t)sendpacket(onion->net, send_to, packet + (1 + RETURN_1), data_len) != data_len) { return 1; } return 0; }
static int handle_recv_2(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata) { Onion *onion = (Onion *)object; if (length > ONION_MAX_PACKET_SIZE) { return 1; } if (length <= 1 + RETURN_2) { return 1; } change_symmetric_key(onion); uint8_t plain[SIZE_IPPORT + RETURN_1]; int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES, SIZE_IPPORT + RETURN_1 + crypto_box_MACBYTES, plain); if ((uint32_t)len != sizeof(plain)) { return 1; } IP_Port send_to; if (ipport_unpack(&send_to, plain, len, 0) == -1) { return 1; } uint8_t data[ONION_MAX_PACKET_SIZE]; data[0] = NET_PACKET_ONION_RECV_1; memcpy(data + 1, plain + SIZE_IPPORT, RETURN_1); memcpy(data + 1 + RETURN_1, packet + 1 + RETURN_2, length - (1 + RETURN_2)); uint16_t data_len = 1 + RETURN_1 + (length - (1 + RETURN_2)); if ((uint32_t)sendpacket(onion->net, send_to, data, data_len) != data_len) { return 1; } return 0; }
/* return length of received packet on success. * return 0 if could not read any packet. * return -1 on failure (connection must be killed). */ int read_packet_TCP_secure_connection(sock_t sock, uint16_t *next_packet_length, const uint8_t *shared_key, uint8_t *recv_nonce, uint8_t *data, uint16_t max_len) { if (*next_packet_length == 0) { uint16_t len = read_TCP_length(sock); if (len == (uint16_t)~0) { return -1; } if (len == 0) { return 0; } *next_packet_length = len; } if (max_len + crypto_box_MACBYTES < *next_packet_length) { return -1; } uint8_t data_encrypted[*next_packet_length]; int len_packet = read_TCP_packet(sock, data_encrypted, *next_packet_length); if (len_packet != *next_packet_length) { return 0; } *next_packet_length = 0; int len = decrypt_data_symmetric(shared_key, recv_nonce, data_encrypted, len_packet, data); if (len + crypto_box_MACBYTES != len_packet) { return -1; } increment_nonce(recv_nonce); return len; }
static int handle_recv_3(void *object, IP_Port source, const uint8_t *packet, uint16_t length) { Onion *onion = object; if (length > ONION_MAX_PACKET_SIZE) return 1; if (length <= 1 + RETURN_3) return 1; if (packet[1 + RETURN_3] != NET_PACKET_ANNOUNCE_RESPONSE && packet[1 + RETURN_3] != NET_PACKET_ONION_DATA_RESPONSE) { return 1; } change_symmetric_key(onion); uint8_t plain[SIZE_IPPORT + RETURN_2]; int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES, SIZE_IPPORT + RETURN_2 + crypto_box_MACBYTES, plain); if ((uint32_t)len != sizeof(plain)) return 1; IP_Port send_to; if (ipport_unpack(&send_to, plain, len, 0) == -1) return 1; uint8_t data[ONION_MAX_PACKET_SIZE]; data[0] = NET_PACKET_ONION_RECV_2; memcpy(data + 1, plain + SIZE_IPPORT, RETURN_2); memcpy(data + 1 + RETURN_2, packet + 1 + RETURN_3, length - (1 + RETURN_3)); uint16_t data_len = 1 + RETURN_2 + (length - (1 + RETURN_3)); if ((uint32_t)sendpacket(onion->net, send_to, data, data_len) != data_len) return 1; return 0; }
/* Checks if the sendback is valid and returns the public key contained in it in ret_pubkey and the * ip contained in it in ret_ip_port * * sendback is the sendback ONION_ANNOUNCE_SENDBACK_DATA_LENGTH big * ret_pubkey must be at least crypto_box_PUBLICKEYBYTES big * ret_ip_port must be at least 1 big * * return ~0 on failure * return num (see new_sendback(...)) on success */ static uint32_t check_sendback(Onion_Client *onion_c, uint8_t *sendback, uint8_t *ret_pubkey, IP_Port *ret_ip_port) { uint8_t plain[sizeof(uint32_t) + sizeof(uint64_t) + crypto_box_PUBLICKEYBYTES + sizeof(IP_Port)]; int len = decrypt_data_symmetric(onion_c->secret_symmetric_key, sendback, sendback + crypto_secretbox_NONCEBYTES, ONION_ANNOUNCE_SENDBACK_DATA_LENGTH - crypto_secretbox_NONCEBYTES, plain); if ((uint32_t)len != sizeof(plain)) return ~0; uint64_t timestamp; memcpy(×tamp, plain + sizeof(uint32_t), sizeof(uint64_t)); uint64_t temp_time = unix_time(); if (timestamp + ANNOUNCE_TIMEOUT < temp_time || temp_time < timestamp) return ~0; memcpy(ret_pubkey, plain + sizeof(uint32_t) + sizeof(uint64_t), crypto_box_PUBLICKEYBYTES); memcpy(ret_ip_port, plain + sizeof(uint32_t) + sizeof(uint64_t) + crypto_box_PUBLICKEYBYTES, sizeof(IP_Port)); uint32_t num; memcpy(&num, plain, sizeof(uint32_t)); return num; }
static int handle_ping_request(void *_dht, IP_Port source, const uint8_t *packet, uint16_t length) { DHT *dht = _dht; int rc; if (length != DHT_PING_SIZE) return 1; PING *ping = dht->ping; if (id_equal(packet + 1, ping->dht->self_public_key)) return 1; uint8_t shared_key[crypto_box_BEFORENMBYTES]; uint8_t ping_plain[PING_PLAIN_SIZE]; // Decrypt ping_id DHT_get_shared_key_recv(dht, shared_key, packet + 1); rc = decrypt_data_symmetric(shared_key, packet + 1 + crypto_box_PUBLICKEYBYTES, packet + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, PING_PLAIN_SIZE + crypto_box_MACBYTES, ping_plain ); if (rc != sizeof(ping_plain)) return 1; if (ping_plain[0] != NET_PACKET_PING_REQUEST) return 1; uint64_t ping_id; memcpy(&ping_id, ping_plain + 1, sizeof(ping_id)); // Send response send_ping_response(ping, source, packet + 1, ping_id, shared_key); add_to_ping(ping, packet + 1, source); return 0; }
static int handle_send_initial(void *object, IP_Port source, const uint8_t *packet, uint16_t length) { Onion *onion = object; if (length > ONION_MAX_PACKET_SIZE) return 1; if (length <= 1 + SEND_1) return 1; change_symmetric_key(onion); uint8_t plain[ONION_MAX_PACKET_SIZE]; uint8_t shared_key[crypto_box_BEFORENMBYTES]; get_shared_key(&onion->shared_keys_1, shared_key, onion->dht->self_secret_key, packet + 1 + crypto_box_NONCEBYTES); int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES, length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES), plain); if (len != length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES)) return 1; return onion_send_1(onion, plain, len, source, packet + 1); }
END_TEST START_TEST(test_large_data) { unsigned char k[CRYPTO_SHARED_KEY_SIZE]; unsigned char n[CRYPTO_NONCE_SIZE]; unsigned char m1[MAX_CRYPTO_PACKET_SIZE - CRYPTO_MAC_SIZE]; unsigned char c1[sizeof(m1) + CRYPTO_MAC_SIZE]; unsigned char m1prime[sizeof(m1)]; unsigned char m2[MAX_CRYPTO_PACKET_SIZE]; unsigned char c2[sizeof(m2) + CRYPTO_MAC_SIZE]; int c1len, c2len; int m1plen; //Generate random messages rand_bytes(m1, sizeof(m1)); rand_bytes(m2, sizeof(m2)); rand_bytes(n, CRYPTO_NONCE_SIZE); //Generate key rand_bytes(k, CRYPTO_SHARED_KEY_SIZE); c1len = encrypt_data_symmetric(k, n, m1, sizeof(m1), c1); c2len = encrypt_data_symmetric(k, n, m2, sizeof(m2), c2); ck_assert_msg(c1len == sizeof(m1) + CRYPTO_MAC_SIZE, "could not encrypt"); ck_assert_msg(c2len == sizeof(m2) + CRYPTO_MAC_SIZE, "could not encrypt"); m1plen = decrypt_data_symmetric(k, n, c1, c1len, m1prime); ck_assert_msg(m1plen == sizeof(m1), "decrypted text lengths differ"); ck_assert_msg(memcmp(m1prime, m1, sizeof(m1)) == 0, "decrypted texts differ"); }
/* This is the inverse of tox_pass_key_encrypt, also using only keys produced by * tox_derive_key. * * the output data has size data_length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH * * returns true on success */ bool tox_pass_key_decrypt(const Tox_Pass_Key *key, const uint8_t *data, size_t length, uint8_t *out, TOX_ERR_DECRYPTION *error) { if (length <= TOX_PASS_ENCRYPTION_EXTRA_LENGTH) { SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_INVALID_LENGTH); return 0; } if (!data || !key || !out) { SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_NULL); return 0; } if (memcmp(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) != 0) { SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_BAD_FORMAT); return 0; } data += TOX_ENC_SAVE_MAGIC_LENGTH; data += crypto_pwhash_scryptsalsa208sha256_SALTBYTES; // salt only affects key derivation size_t decrypt_length = length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH; uint8_t nonce[crypto_box_NONCEBYTES]; memcpy(nonce, data, crypto_box_NONCEBYTES); data += crypto_box_NONCEBYTES; /* decrypt the data */ if (decrypt_data_symmetric(key->key, nonce, data, decrypt_length + crypto_box_MACBYTES, out) != decrypt_length) { SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_FAILED); return 0; } SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_OK); return 1; }
END_TEST START_TEST(test_endtoend) { unsigned char pk1[CRYPTO_PUBLIC_KEY_SIZE]; unsigned char sk1[CRYPTO_SECRET_KEY_SIZE]; unsigned char pk2[CRYPTO_PUBLIC_KEY_SIZE]; unsigned char sk2[CRYPTO_SECRET_KEY_SIZE]; unsigned char k1[CRYPTO_SHARED_KEY_SIZE]; unsigned char k2[CRYPTO_SHARED_KEY_SIZE]; unsigned char n[CRYPTO_NONCE_SIZE]; unsigned char m[500]; unsigned char c1[sizeof(m) + CRYPTO_MAC_SIZE]; unsigned char c2[sizeof(m) + CRYPTO_MAC_SIZE]; unsigned char c3[sizeof(m) + CRYPTO_MAC_SIZE]; unsigned char c4[sizeof(m) + CRYPTO_MAC_SIZE]; unsigned char m1[sizeof(m)]; unsigned char m2[sizeof(m)]; unsigned char m3[sizeof(m)]; unsigned char m4[sizeof(m)]; int mlen; int c1len, c2len, c3len, c4len; int m1len, m2len, m3len, m4len; int testno; // Test 100 random messages and keypairs for (testno = 0; testno < 100; testno++) { //Generate random message (random length from 100 to 500) mlen = (random_u32() % 400) + 100; rand_bytes(m, mlen); rand_bytes(n, CRYPTO_NONCE_SIZE); //Generate keypairs crypto_new_keypair(pk1, sk1); crypto_new_keypair(pk2, sk2); //Precompute shared keys encrypt_precompute(pk2, sk1, k1); encrypt_precompute(pk1, sk2, k2); ck_assert_msg(memcmp(k1, k2, CRYPTO_SHARED_KEY_SIZE) == 0, "encrypt_precompute: bad"); //Encrypt all four ways c1len = encrypt_data(pk2, sk1, n, m, mlen, c1); c2len = encrypt_data(pk1, sk2, n, m, mlen, c2); c3len = encrypt_data_symmetric(k1, n, m, mlen, c3); c4len = encrypt_data_symmetric(k2, n, m, mlen, c4); ck_assert_msg(c1len == c2len && c1len == c3len && c1len == c4len, "cyphertext lengths differ"); ck_assert_msg(c1len == mlen + (int)CRYPTO_MAC_SIZE, "wrong cyphertext length"); ck_assert_msg(memcmp(c1, c2, c1len) == 0 && memcmp(c1, c3, c1len) == 0 && memcmp(c1, c4, c1len) == 0, "crypertexts differ"); //Decrypt all four ways m1len = decrypt_data(pk2, sk1, n, c1, c1len, m1); m2len = decrypt_data(pk1, sk2, n, c1, c1len, m2); m3len = decrypt_data_symmetric(k1, n, c1, c1len, m3); m4len = decrypt_data_symmetric(k2, n, c1, c1len, m4); ck_assert_msg(m1len == m2len && m1len == m3len && m1len == m4len, "decrypted text lengths differ"); ck_assert_msg(m1len == mlen, "wrong decrypted text length"); ck_assert_msg(memcmp(m1, m2, mlen) == 0 && memcmp(m1, m3, mlen) == 0 && memcmp(m1, m4, mlen) == 0, "decrypted texts differ"); ck_assert_msg(memcmp(m1, m, mlen) == 0, "wrong decrypted text"); } }
int main(int argc, char *argv[]) { const int numtrials = 10000; unsigned char pk1[crypto_box_PUBLICKEYBYTES]; unsigned char sk1[crypto_box_SECRETKEYBYTES]; unsigned char pk2[crypto_box_PUBLICKEYBYTES]; unsigned char sk2[crypto_box_SECRETKEYBYTES]; unsigned char k1[crypto_box_BEFORENMBYTES]; unsigned char k2[crypto_box_BEFORENMBYTES]; unsigned char n[crypto_box_NONCEBYTES]; unsigned char m[500]; unsigned char c[sizeof(m) + crypto_box_MACBYTES]; unsigned char k[crypto_box_BEFORENMBYTES]; int trialno; double starttime; double endtime; double slow_time; double fast_time; double keygen_time; double precompute_time; // Pregenerate crypto_box_keypair(pk1, sk1); crypto_box_keypair(pk2, sk2); encrypt_precompute(pk1, sk2, k1); encrypt_precompute(pk2, sk1, k2); rand_bytes(m, sizeof(m)); rand_bytes(n, sizeof(n)); printf("starting slow...\n"); starttime = get_time(); for (trialno = 0; trialno < numtrials; trialno++) { encrypt_data(pk1, sk2, n, m, sizeof(m), c); decrypt_data(pk2, sk1, n, c, sizeof(c), m); } endtime = get_time(); slow_time = endtime - starttime; printf("starting fast...\n"); starttime = get_time(); for (trialno = 0; trialno < numtrials; trialno++) { encrypt_data_symmetric(k1, n, m, sizeof(m), c); decrypt_data_symmetric(k2, n, c, sizeof(c), m); } endtime = get_time(); fast_time = endtime - starttime; printf("starting keygen...\n"); starttime = get_time(); for (trialno = 0; trialno < numtrials; trialno++) { crypto_box_keypair(pk1, sk1); crypto_box_keypair(pk2, sk2); } endtime = get_time(); keygen_time = endtime - starttime; printf("starting precompute...\n"); starttime = get_time(); for (trialno = 0; trialno < numtrials; trialno++) { encrypt_precompute(pk1, sk2, k); encrypt_precompute(pk2, sk1, k); } endtime = get_time(); precompute_time = endtime - starttime; printf("\n"); printf("trials: %i\n", 2 * numtrials); printf("\n"); printf("slow time: %f sec\n", slow_time); printf("fast time: %f sec\n", fast_time); printf("keygen time: %f sec\n", keygen_time); printf("precompute time: %f sec\n", precompute_time); printf("\n"); printf("Speed boost: %.1f%%\n", slow_time * 100 / fast_time); printf("\n"); printf("slow: %.1f per second\n", 2 * numtrials / slow_time); printf("fast: %.1f per second\n", 2 * numtrials / fast_time); return 0; }
static int handle_announce_request(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata) { Onion_Announce *onion_a = (Onion_Announce *)object; if (length != ANNOUNCE_REQUEST_SIZE_RECV) { return 1; } const uint8_t *packet_public_key = packet + 1 + CRYPTO_NONCE_SIZE; uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; get_shared_key(&onion_a->shared_keys_recv, shared_key, onion_a->dht->self_secret_key, packet_public_key); uint8_t plain[ONION_PING_ID_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_PUBLIC_KEY_SIZE + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH]; int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE, ONION_PING_ID_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_PUBLIC_KEY_SIZE + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_MAC_SIZE, plain); if ((uint32_t)len != sizeof(plain)) { return 1; } uint8_t ping_id1[ONION_PING_ID_SIZE]; generate_ping_id(onion_a, unix_time(), packet_public_key, source, ping_id1); uint8_t ping_id2[ONION_PING_ID_SIZE]; generate_ping_id(onion_a, unix_time() + PING_ID_TIMEOUT, packet_public_key, source, ping_id2); int index = -1; uint8_t *data_public_key = plain + ONION_PING_ID_SIZE + CRYPTO_PUBLIC_KEY_SIZE; if (crypto_memcmp(ping_id1, plain, ONION_PING_ID_SIZE) == 0 || crypto_memcmp(ping_id2, plain, ONION_PING_ID_SIZE) == 0) { index = add_to_entries(onion_a, source, packet_public_key, data_public_key, packet + (ANNOUNCE_REQUEST_SIZE_RECV - ONION_RETURN_3)); } else { index = in_entries(onion_a, plain + ONION_PING_ID_SIZE); } /*Respond with a announce response packet*/ Node_format nodes_list[MAX_SENT_NODES]; unsigned int num_nodes = get_close_nodes(onion_a->dht, plain + ONION_PING_ID_SIZE, nodes_list, 0, LAN_ip(source.ip) == 0, 1); uint8_t nonce[CRYPTO_NONCE_SIZE]; random_nonce(nonce); uint8_t pl[1 + ONION_PING_ID_SIZE + sizeof(nodes_list)]; if (index == -1) { pl[0] = 0; memcpy(pl + 1, ping_id2, ONION_PING_ID_SIZE); } else { if (public_key_cmp(onion_a->entries[index].public_key, packet_public_key) == 0) { if (public_key_cmp(onion_a->entries[index].data_public_key, data_public_key) != 0) { pl[0] = 0; memcpy(pl + 1, ping_id2, ONION_PING_ID_SIZE); } else { pl[0] = 2; memcpy(pl + 1, ping_id2, ONION_PING_ID_SIZE); } } else { pl[0] = 1; memcpy(pl + 1, onion_a->entries[index].data_public_key, CRYPTO_PUBLIC_KEY_SIZE); } } int nodes_length = 0; if (num_nodes != 0) { nodes_length = pack_nodes(pl + 1 + ONION_PING_ID_SIZE, sizeof(nodes_list), nodes_list, num_nodes); if (nodes_length <= 0) { return 1; } } uint8_t data[ONION_ANNOUNCE_RESPONSE_MAX_SIZE]; len = encrypt_data_symmetric(shared_key, nonce, pl, 1 + ONION_PING_ID_SIZE + nodes_length, data + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE); if (len != 1 + ONION_PING_ID_SIZE + nodes_length + CRYPTO_MAC_SIZE) { return 1; } data[0] = NET_PACKET_ANNOUNCE_RESPONSE; memcpy(data + 1, plain + ONION_PING_ID_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_PUBLIC_KEY_SIZE, ONION_ANNOUNCE_SENDBACK_DATA_LENGTH); memcpy(data + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH, nonce, CRYPTO_NONCE_SIZE); if (send_onion_response(onion_a->net, source, data, 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE + len, packet + (ANNOUNCE_REQUEST_SIZE_RECV - ONION_RETURN_3)) == -1) { return 1; } return 0; }