/* Create a new onion path. * * Create a new onion path out of nodes (nodes is a list of ONION_PATH_LENGTH nodes) * * new_path must be an empty memory location of atleast Onion_Path size. * * return -1 on failure. * return 0 on success. */ int create_onion_path(const DHT *dht, Onion_Path *new_path, const Node_format *nodes) { if (!new_path || !nodes) return -1; encrypt_precompute(nodes[0].public_key, dht->self_secret_key, new_path->shared_key1); memcpy(new_path->public_key1, dht->self_public_key, crypto_box_PUBLICKEYBYTES); uint8_t random_public_key[crypto_box_PUBLICKEYBYTES]; uint8_t random_secret_key[crypto_box_SECRETKEYBYTES]; crypto_box_keypair(random_public_key, random_secret_key); encrypt_precompute(nodes[1].public_key, random_secret_key, new_path->shared_key2); memcpy(new_path->public_key2, random_public_key, crypto_box_PUBLICKEYBYTES); crypto_box_keypair(random_public_key, random_secret_key); encrypt_precompute(nodes[2].public_key, random_secret_key, new_path->shared_key3); memcpy(new_path->public_key3, random_public_key, crypto_box_PUBLICKEYBYTES); new_path->ip_port1 = nodes[0].ip_port; new_path->ip_port2 = nodes[1].ip_port; new_path->ip_port3 = nodes[2].ip_port; memcpy(new_path->node_public_key1, nodes[0].public_key, crypto_box_PUBLICKEYBYTES); memcpy(new_path->node_public_key2, nodes[1].public_key, crypto_box_PUBLICKEYBYTES); memcpy(new_path->node_public_key3, nodes[2].public_key, crypto_box_PUBLICKEYBYTES); return 0; }
/* handle received packets for not yet established crypto connections. */ static void receive_crypto(void) { uint32_t i; for (i = 0; i < MAX_CRYPTO_CONNECTIONS; ++i) { if (crypto_connections[i].status == CONN_HANDSHAKE_SENT) { uint8_t temp_data[MAX_DATA_SIZE]; uint8_t secret_nonce[crypto_box_NONCEBYTES]; uint8_t public_key[crypto_box_PUBLICKEYBYTES]; uint8_t session_key[crypto_box_PUBLICKEYBYTES]; uint16_t len; if (id_packet(crypto_connections[i].number) == 1) /* if the packet is a friend request drop it (because we are already friends) */ len = read_packet(crypto_connections[i].number, temp_data); if (id_packet(crypto_connections[i].number) == 2) { /* handle handshake packet. */ len = read_packet(crypto_connections[i].number, temp_data); if (handle_cryptohandshake(public_key, secret_nonce, session_key, temp_data, len)) { if (memcmp(public_key, crypto_connections[i].public_key, crypto_box_PUBLICKEYBYTES) == 0) { memcpy(crypto_connections[i].sent_nonce, secret_nonce, crypto_box_NONCEBYTES); memcpy(crypto_connections[i].peersessionpublic_key, session_key, crypto_box_PUBLICKEYBYTES); increment_nonce(crypto_connections[i].sent_nonce); uint32_t zero = 0; encrypt_precompute(crypto_connections[i].peersessionpublic_key, crypto_connections[i].sessionsecret_key, crypto_connections[i].shared_key); crypto_connections[i].status = CONN_ESTABLISHED; /* connection status needs to be 3 for write_cryptpacket() to work */ write_cryptpacket(i, ((uint8_t *)&zero), sizeof(zero)); crypto_connections[i].status = CONN_NOT_CONFIRMED; /* set it to its proper value right after. */ } } } else if (id_packet(crypto_connections[i].number) != -1) // This should not happen kill the connection if it does crypto_kill(crypto_connections[i].number); } if (crypto_connections[i].status == CONN_NOT_CONFIRMED) { if (id_packet(crypto_connections[i].number) == 3) { uint8_t temp_data[MAX_DATA_SIZE]; uint8_t data[MAX_DATA_SIZE]; int length = read_packet(crypto_connections[i].number, temp_data); int len = decrypt_data(crypto_connections[i].peersessionpublic_key, crypto_connections[i].sessionsecret_key, crypto_connections[i].recv_nonce, temp_data + 1, length - 1, data); uint32_t zero = 0; if (len == sizeof(uint32_t) && memcmp(((uint8_t *)&zero), data, sizeof(uint32_t)) == 0) { increment_nonce(crypto_connections[i].recv_nonce); encrypt_precompute(crypto_connections[i].peersessionpublic_key, crypto_connections[i].sessionsecret_key, crypto_connections[i].shared_key); crypto_connections[i].status = CONN_ESTABLISHED; /* connection is accepted so we disable the auto kill by setting it to about 1 month from now. */ kill_connection_in(crypto_connections[i].number, 3000000); } else crypto_kill(crypto_connections[i].number); // This should not happen kill the connection if it does } else if(id_packet(crypto_connections[i].number) != -1) /* This should not happen kill the connection if it does */ crypto_kill(crypto_connections[i].number); } } }
END_TEST START_TEST(test_fast_known) { unsigned char k[CRYPTO_SHARED_KEY_SIZE]; unsigned char c[147]; unsigned char m[131]; int clen, mlen; encrypt_precompute(bobpk, alicesk, k); ck_assert_msg(sizeof(c) == sizeof(m) + CRYPTO_MAC_SIZE * sizeof(unsigned char), "cyphertext should be CRYPTO_MAC_SIZE bytes longer than plaintext"); ck_assert_msg(sizeof(test_c) == sizeof(c), "sanity check failed"); ck_assert_msg(sizeof(test_m) == sizeof(m), "sanity check failed"); clen = encrypt_data_symmetric(k, test_nonce, test_m, sizeof(test_m) / sizeof(unsigned char), c); ck_assert_msg(memcmp(test_c, c, sizeof(c)) == 0, "cyphertext doesn't match test vector"); ck_assert_msg(clen == sizeof(c) / sizeof(unsigned char), "wrong ciphertext length"); mlen = decrypt_data_symmetric(k, test_nonce, test_c, sizeof(test_c) / sizeof(unsigned char), m); ck_assert_msg(memcmp(test_m, m, sizeof(m)) == 0, "decrypted text doesn't match test vector"); ck_assert_msg(mlen == sizeof(m) / sizeof(unsigned char), "wrong plaintext length"); }
int decrypt_data(uint8_t *public_key, uint8_t *secret_key, uint8_t *nonce, uint8_t *encrypted, uint32_t length, uint8_t *plain) { uint8_t k[crypto_box_BEFORENMBYTES]; encrypt_precompute(public_key, secret_key, k); return decrypt_data_fast(k, nonce, encrypted, length, plain); }
/* 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; }
/* Accept an incoming connection using the parameters provided by crypto_inbound. * * return -1 if not successful. * return the crypt_connection_id if successful. */ int accept_crypto_inbound(Net_Crypto *c, int connection_id, uint8_t *public_key, uint8_t *secret_nonce, uint8_t *session_key) { uint32_t i; if (discard_packet(c->lossless_udp, connection_id) == -1) return -1; /* * if(getcryptconnection_id(public_key) != -1) * { * return -1; * } */ if (realloc_cryptoconnection(c, c->crypto_connections_length + 1) == -1 || c->crypto_connections == NULL) return -1; memset(&(c->crypto_connections[c->crypto_connections_length]), 0, sizeof(Crypto_Connection)); c->crypto_connections[c->crypto_connections_length].number = ~0; for (i = 0; i <= c->crypto_connections_length; ++i) { if (c->crypto_connections[i].status == CRYPTO_CONN_NO_CONNECTION) { c->crypto_connections[i].number = connection_id; c->crypto_connections[i].status = CRYPTO_CONN_NOT_CONFIRMED; c->crypto_connections[i].timeout = unix_time() + CRYPTO_HANDSHAKE_TIMEOUT; random_nonce(c->crypto_connections[i].recv_nonce); memcpy(c->crypto_connections[i].sent_nonce, secret_nonce, crypto_box_NONCEBYTES); memcpy(c->crypto_connections[i].peersessionpublic_key, session_key, crypto_box_PUBLICKEYBYTES); increment_nonce(c->crypto_connections[i].sent_nonce); memcpy(c->crypto_connections[i].public_key, public_key, crypto_box_PUBLICKEYBYTES); crypto_box_keypair(c->crypto_connections[i].sessionpublic_key, c->crypto_connections[i].sessionsecret_key); if (c->crypto_connections_length == i) ++c->crypto_connections_length; if (send_cryptohandshake(c, connection_id, public_key, c->crypto_connections[i].recv_nonce, c->crypto_connections[i].sessionpublic_key) == 1) { increment_nonce(c->crypto_connections[i].recv_nonce); uint32_t zero = 0; encrypt_precompute(c->crypto_connections[i].peersessionpublic_key, c->crypto_connections[i].sessionsecret_key, c->crypto_connections[i].shared_key); c->crypto_connections[i].status = CRYPTO_CONN_ESTABLISHED; /* Connection status needs to be 3 for write_cryptpacket() to work. */ write_cryptpacket(c, i, ((uint8_t *)&zero), sizeof(zero)); c->crypto_connections[i].status = CRYPTO_CONN_NOT_CONFIRMED; /* Set it to its proper value right after. */ return i; } return -1; /* This should never happen. */ } } return -1; }
int32_t decrypt_data(const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *nonce, const uint8_t *encrypted, size_t length, uint8_t *plain) { if (!public_key || !secret_key) { return -1; } uint8_t k[crypto_box_BEFORENMBYTES]; encrypt_precompute(public_key, secret_key, k); int ret = decrypt_data_symmetric(k, nonce, encrypted, length, plain); crypto_memzero(k, sizeof k); return ret; }
/* 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; }
/* 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 0 on success. * return -1 on failure. */ static int generate_handshake(TCP_Client_Connection *TCP_conn, const uint8_t *self_public_key, const uint8_t *self_secret_key) { uint8_t plain[crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES]; crypto_box_keypair(plain, TCP_conn->temp_secret_key); encrypt_precompute(TCP_conn->public_key, self_secret_key, TCP_conn->shared_key); random_nonce(TCP_conn->sent_nonce); memcpy(plain + crypto_box_PUBLICKEYBYTES, TCP_conn->sent_nonce, crypto_box_NONCEBYTES); memcpy(TCP_conn->last_packet, self_public_key, crypto_box_PUBLICKEYBYTES); new_nonce(TCP_conn->last_packet + crypto_box_PUBLICKEYBYTES); int len = encrypt_data_symmetric(TCP_conn->shared_key, TCP_conn->last_packet + crypto_box_PUBLICKEYBYTES, plain, sizeof(plain), TCP_conn->last_packet + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES); if (len != sizeof(plain) + crypto_box_MACBYTES) return -1; TCP_conn->last_packet_length = crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + sizeof(plain) + crypto_box_MACBYTES; TCP_conn->last_packet_sent = 0; return 0; }
/* accept an incoming connection using the parameters provided by crypto_inbound return -1 if not successful returns the crypt_connection_id if successful */ int accept_crypto_inbound(int connection_id, uint8_t *public_key, uint8_t *secret_nonce, uint8_t *session_key) { uint32_t i; if (connection_id == -1) return -1; /* if(getcryptconnection_id(public_key) != -1) { return -1; }*/ for (i = 0; i < MAX_CRYPTO_CONNECTIONS; ++i) { if(crypto_connections[i].status == CONN_NO_CONNECTION) { crypto_connections[i].number = connection_id; crypto_connections[i].status = CONN_NOT_CONFIRMED; random_nonce(crypto_connections[i].recv_nonce); memcpy(crypto_connections[i].sent_nonce, secret_nonce, crypto_box_NONCEBYTES); memcpy(crypto_connections[i].peersessionpublic_key, session_key, crypto_box_PUBLICKEYBYTES); increment_nonce(crypto_connections[i].sent_nonce); memcpy(crypto_connections[i].public_key, public_key, crypto_box_PUBLICKEYBYTES); crypto_box_keypair(crypto_connections[i].sessionpublic_key, crypto_connections[i].sessionsecret_key); if (send_cryptohandshake(connection_id, public_key, crypto_connections[i].recv_nonce, crypto_connections[i].sessionpublic_key) == 1) { increment_nonce(crypto_connections[i].recv_nonce); uint32_t zero = 0; encrypt_precompute(crypto_connections[i].peersessionpublic_key, crypto_connections[i].sessionsecret_key, crypto_connections[i].shared_key); crypto_connections[i].status = CONN_ESTABLISHED; /* connection status needs to be 3 for write_cryptpacket() to work */ write_cryptpacket(i, ((uint8_t *)&zero), sizeof(zero)); crypto_connections[i].status = CONN_NOT_CONFIRMED; /* set it to its proper value right after. */ return i; } return -1; /* this should never happen. */ } } 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"); } }
/* Handle received packets for not yet established crypto connections. */ static void receive_crypto(Net_Crypto *c) { uint32_t i; uint64_t temp_time = unix_time(); for (i = 0; i < c->crypto_connections_length; ++i) { if (c->crypto_connections[i].status == CRYPTO_CONN_NO_CONNECTION) continue; if (c->crypto_connections[i].status == CRYPTO_CONN_HANDSHAKE_SENT) { uint8_t temp_data[MAX_DATA_SIZE]; uint8_t secret_nonce[crypto_box_NONCEBYTES]; uint8_t public_key[crypto_box_PUBLICKEYBYTES]; uint8_t session_key[crypto_box_PUBLICKEYBYTES]; uint16_t len; if (id_packet(c->lossless_udp, c->crypto_connections[i].number) == 2) { /* Handle handshake packet. */ len = read_packet(c->lossless_udp, c->crypto_connections[i].number, temp_data); if (handle_cryptohandshake(c, public_key, secret_nonce, session_key, temp_data, len)) { if (memcmp(public_key, c->crypto_connections[i].public_key, crypto_box_PUBLICKEYBYTES) == 0) { memcpy(c->crypto_connections[i].sent_nonce, secret_nonce, crypto_box_NONCEBYTES); memcpy(c->crypto_connections[i].peersessionpublic_key, session_key, crypto_box_PUBLICKEYBYTES); increment_nonce(c->crypto_connections[i].sent_nonce); uint32_t zero = 0; encrypt_precompute(c->crypto_connections[i].peersessionpublic_key, c->crypto_connections[i].sessionsecret_key, c->crypto_connections[i].shared_key); c->crypto_connections[i].status = CRYPTO_CONN_ESTABLISHED; /* Connection status needs to be 3 for write_cryptpacket() to work. */ write_cryptpacket(c, i, ((uint8_t *)&zero), sizeof(zero)); c->crypto_connections[i].status = CRYPTO_CONN_NOT_CONFIRMED; /* Set it to its proper value right after. */ } else { /* This should not happen, timeout the connection if it does. */ c->crypto_connections[i].status = CRYPTO_CONN_TIMED_OUT; } } else { /* This should not happen, timeout the connection if it does. */ c->crypto_connections[i].status = CRYPTO_CONN_TIMED_OUT; } } else if (id_packet(c->lossless_udp, c->crypto_connections[i].number) != -1) { /* This should not happen, timeout the connection if it does. */ c->crypto_connections[i].status = CRYPTO_CONN_TIMED_OUT; } } if (c->crypto_connections[i].status == CRYPTO_CONN_NOT_CONFIRMED) { if (id_packet(c->lossless_udp, c->crypto_connections[i].number) == 3) { uint8_t temp_data[MAX_DATA_SIZE]; uint8_t data[MAX_DATA_SIZE]; int length = read_packet(c->lossless_udp, c->crypto_connections[i].number, temp_data); int len = decrypt_data(c->crypto_connections[i].peersessionpublic_key, c->crypto_connections[i].sessionsecret_key, c->crypto_connections[i].recv_nonce, temp_data + 1, length - 1, data); uint32_t zero = 0; if (len == sizeof(uint32_t) && memcmp(((uint8_t *)&zero), data, sizeof(uint32_t)) == 0) { increment_nonce(c->crypto_connections[i].recv_nonce); encrypt_precompute(c->crypto_connections[i].peersessionpublic_key, c->crypto_connections[i].sessionsecret_key, c->crypto_connections[i].shared_key); c->crypto_connections[i].status = CRYPTO_CONN_ESTABLISHED; c->crypto_connections[i].timeout = ~0; /* Connection is accepted. */ confirm_connection(c->lossless_udp, c->crypto_connections[i].number); } else { /* This should not happen, timeout the connection if it does. */ c->crypto_connections[i].status = CRYPTO_CONN_TIMED_OUT; } } else if (id_packet(c->lossless_udp, c->crypto_connections[i].number) != -1) { /* This should not happen, timeout the connection if it does. */ c->crypto_connections[i].status = CRYPTO_CONN_TIMED_OUT; } } if (temp_time > c->crypto_connections[i].timeout) { c->crypto_connections[i].status = CRYPTO_CONN_TIMED_OUT; } } }
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; }
/* Handle received packets for not yet established crypto connections. */ static void receive_crypto(Net_Crypto *c) { uint32_t i; for (i = 0; i < c->crypto_connections_length; ++i) { if (c->crypto_connections[i].status == CONN_HANDSHAKE_SENT) { uint8_t temp_data[MAX_DATA_SIZE]; uint8_t secret_nonce[crypto_box_NONCEBYTES]; uint8_t public_key[crypto_box_PUBLICKEYBYTES]; uint8_t session_key[crypto_box_PUBLICKEYBYTES]; uint16_t len; if (id_packet(c->lossless_udp, c->crypto_connections[i].number) == 2) { /* Handle handshake packet. */ len = read_packet(c->lossless_udp, c->crypto_connections[i].number, temp_data); if (handle_cryptohandshake(c, public_key, secret_nonce, session_key, temp_data, len)) { if (memcmp(public_key, c->crypto_connections[i].public_key, crypto_box_PUBLICKEYBYTES) == 0) { memcpy(c->crypto_connections[i].sent_nonce, secret_nonce, crypto_box_NONCEBYTES); memcpy(c->crypto_connections[i].peersessionpublic_key, session_key, crypto_box_PUBLICKEYBYTES); increment_nonce(c->crypto_connections[i].sent_nonce); uint32_t zero = 0; encrypt_precompute(c->crypto_connections[i].peersessionpublic_key, c->crypto_connections[i].sessionsecret_key, c->crypto_connections[i].shared_key); c->crypto_connections[i].status = CONN_ESTABLISHED; /* Connection status needs to be 3 for write_cryptpacket() to work. */ write_cryptpacket(c, i, ((uint8_t *)&zero), sizeof(zero)); c->crypto_connections[i].status = CONN_NOT_CONFIRMED; /* Set it to its proper value right after. */ } } } else if (id_packet(c->lossless_udp, c->crypto_connections[i].number) != -1) { // This should not happen, kill the connection if it does. crypto_kill(c, i); return; } } if (c->crypto_connections[i].status == CONN_NOT_CONFIRMED) { if (id_packet(c->lossless_udp, c->crypto_connections[i].number) == 3) { uint8_t temp_data[MAX_DATA_SIZE]; uint8_t data[MAX_DATA_SIZE]; int length = read_packet(c->lossless_udp, c->crypto_connections[i].number, temp_data); int len = decrypt_data(c->crypto_connections[i].peersessionpublic_key, c->crypto_connections[i].sessionsecret_key, c->crypto_connections[i].recv_nonce, temp_data + 1, length - 1, data); uint32_t zero = 0; if (len == sizeof(uint32_t) && memcmp(((uint8_t *)&zero), data, sizeof(uint32_t)) == 0) { increment_nonce(c->crypto_connections[i].recv_nonce); encrypt_precompute(c->crypto_connections[i].peersessionpublic_key, c->crypto_connections[i].sessionsecret_key, c->crypto_connections[i].shared_key); c->crypto_connections[i].status = CONN_ESTABLISHED; /* Connection is accepted so we disable the auto kill by setting it to about 1 month from now. */ kill_connection_in(c->lossless_udp, c->crypto_connections[i].number, 3000000); } else { /* This should not happen, kill the connection if it does. */ crypto_kill(c, i); return; } } else if (id_packet(c->lossless_udp, c->crypto_connections[i].number) != -1) /* This should not happen, kill the connection if it does. */ crypto_kill(c, i); return; } } }
/* Create new TCP connection to ip_port/public_key */ TCP_Client_Connection *new_TCP_connection(IP_Port ip_port, const uint8_t *public_key, const uint8_t *self_public_key, const uint8_t *self_secret_key, TCP_Proxy_Info *proxy_info) { if (networking_at_startup() != 0) { return NULL; } if (ip_port.ip.family != AF_INET && ip_port.ip.family != AF_INET6) { return NULL; } uint8_t family = ip_port.ip.family; TCP_Proxy_Info default_proxyinfo; if (proxy_info == NULL) { default_proxyinfo.proxy_type = TCP_PROXY_NONE; proxy_info = &default_proxyinfo; } if (proxy_info->proxy_type != TCP_PROXY_NONE) { family = proxy_info->ip_port.ip.family; } Socket sock = net_socket(family, TOX_SOCK_STREAM, TOX_PROTO_TCP); if (!sock_valid(sock)) { return NULL; } if (!set_socket_nosigpipe(sock)) { kill_sock(sock); return 0; } if (!(set_socket_nonblock(sock) && connect_sock_to(sock, ip_port, proxy_info))) { kill_sock(sock); return NULL; } TCP_Client_Connection *temp = (TCP_Client_Connection *)calloc(sizeof(TCP_Client_Connection), 1); if (temp == NULL) { kill_sock(sock); return NULL; } temp->sock = sock; memcpy(temp->public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); memcpy(temp->self_public_key, self_public_key, CRYPTO_PUBLIC_KEY_SIZE); encrypt_precompute(temp->public_key, self_secret_key, temp->shared_key); temp->ip_port = ip_port; temp->proxy_info = *proxy_info; switch (proxy_info->proxy_type) { case TCP_PROXY_HTTP: temp->status = TCP_CLIENT_PROXY_HTTP_CONNECTING; proxy_http_generate_connection_request(temp); break; case TCP_PROXY_SOCKS5: temp->status = TCP_CLIENT_PROXY_SOCKS5_CONNECTING; proxy_socks5_generate_handshake(temp); break; case TCP_PROXY_NONE: temp->status = TCP_CLIENT_CONNECTING; if (generate_handshake(temp) == -1) { kill_sock(sock); free(temp); return NULL; } break; } temp->kill_at = unix_time() + TCP_CONNECTION_TIMEOUT; return temp; }