/* 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); } } }
/* return 1 on success. * return 0 if could not send packet. * return -1 on failure (connection must be killed). */ static int write_packet_TCP_secure_connection(TCP_Secure_Connection *con, const uint8_t *data, uint16_t length, bool priority) { if (length + crypto_box_MACBYTES > MAX_PACKET_SIZE) { return -1; } bool sendpriority = 1; if (send_pending_data(con) == -1) { if (priority) { sendpriority = 0; } else { return 0; } } uint8_t packet[sizeof(uint16_t) + length + crypto_box_MACBYTES]; uint16_t c_length = htons(length + crypto_box_MACBYTES); memcpy(packet, &c_length, sizeof(uint16_t)); int len = encrypt_data_symmetric(con->shared_key, con->sent_nonce, data, length, packet + sizeof(uint16_t)); if ((unsigned int)len != (sizeof(packet) - sizeof(uint16_t))) { return -1; } if (priority) { len = sendpriority ? send(con->sock, (const char *)packet, sizeof(packet), MSG_NOSIGNAL) : 0; if (len <= 0) { len = 0; } increment_nonce(con->sent_nonce); if ((unsigned int)len == sizeof(packet)) { return 1; } return add_priority(con, packet, sizeof(packet), len); } len = send(con->sock, (const char *)packet, sizeof(packet), MSG_NOSIGNAL); if (len <= 0) { return 0; } increment_nonce(con->sent_nonce); if ((unsigned int)len == sizeof(packet)) { return 1; } memcpy(con->last_packet, packet, sizeof(packet)); con->last_packet_length = sizeof(packet); con->last_packet_sent = len; 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; }
/* return 0 if data could not be put in packet queue. * return 1 if data was put into the queue. */ int write_cryptpacket(Net_Crypto *c, int crypt_connection_id, uint8_t *data, uint32_t length) { if (crypt_connection_id_not_valid(c, crypt_connection_id)) return 0; if (length - crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES > MAX_DATA_SIZE - 1) return 0; if (c->crypto_connections[crypt_connection_id].status != CRYPTO_CONN_ESTABLISHED) return 0; uint8_t temp_data[MAX_DATA_SIZE]; int len = encrypt_data_fast(c->crypto_connections[crypt_connection_id].shared_key, c->crypto_connections[crypt_connection_id].sent_nonce, data, length, temp_data + 1); if (len == -1) return 0; temp_data[0] = 3; if (write_packet(c->lossless_udp, c->crypto_connections[crypt_connection_id].number, temp_data, len + 1) == 0) return 0; increment_nonce(c->crypto_connections[crypt_connection_id].sent_nonce); return 1; }
/* return 0 if data could not be put in packet queue return 1 if data was put into the queue */ int write_cryptpacket(int crypt_connection_id, uint8_t * data, uint32_t length) { if(crypt_connection_id < 0 || crypt_connection_id >= MAX_CRYPTO_CONNECTIONS) { return 0; } if(length - crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES > MAX_DATA_SIZE - 1) { return 0; } if(crypto_connections[crypt_connection_id].status != 3) { return 0; } uint8_t temp_data[MAX_DATA_SIZE]; int len = encrypt_data(crypto_connections[crypt_connection_id].peersessionpublic_key, crypto_connections[crypt_connection_id].sessionsecret_key, crypto_connections[crypt_connection_id].sent_nonce, data, length, temp_data + 1); if(len == -1) { return 0; } temp_data[0] = 3; if(write_packet(crypto_connections[crypt_connection_id].number, temp_data, len + 1) == 0) { return 0; } increment_nonce(crypto_connections[crypt_connection_id].sent_nonce); return 1; }
/* 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 */ int read_cryptpacket(int crypt_connection_id, uint8_t * data) { if(crypt_connection_id < 0 || crypt_connection_id >= MAX_CRYPTO_CONNECTIONS) { return 0; } if(crypto_connections[crypt_connection_id].status != 3) { return 0; } uint8_t temp_data[MAX_DATA_SIZE]; int length = read_packet(crypto_connections[crypt_connection_id].number, temp_data); if(length == 0) { return 0; } if(temp_data[0] != 3) { return -1; } int len = decrypt_data(crypto_connections[crypt_connection_id].peersessionpublic_key, crypto_connections[crypt_connection_id].sessionsecret_key, crypto_connections[crypt_connection_id].recv_nonce, temp_data + 1, length - 1, data); if(len != -1) { increment_nonce(crypto_connections[crypt_connection_id].recv_nonce); return len; } return -1; }
/* return 1 on success. * return 0 if could not send packet. * return -1 on failure (connection must be killed). */ static int write_packet_TCP_secure_connection(TCP_Secure_Connection *con, uint8_t *data, uint16_t length) { if (length + crypto_box_MACBYTES > MAX_PACKET_SIZE) return -1; uint8_t packet[sizeof(uint16_t) + length + crypto_box_MACBYTES]; length = htons(length); memcpy(packet, &length, sizeof(uint16_t)); uint32_t len = encrypt_data_fast(con->shared_key, con->sent_nonce, data, length, packet + sizeof(uint16_t)); if (len != (sizeof(packet) - sizeof(uint16_t))) return -1; increment_nonce(con->sent_nonce); len = send(con->sock, packet, sizeof(packet), 0); if (len == sizeof(packet)) return 1; if (len <= 0) return 0; return -1; }
/* return length of recieved packet on success. * return 0 if could not read any packet. * return -1 on failure (connection must be killed). */ static int read_packet_TCP_secure_connection(TCP_Secure_Connection *con, uint8_t *data, uint16_t max_len) { if (con->next_packet_length == 0) { uint16_t len = read_length(con->sock); if (len == (uint16_t)~0) return -1; if (len == 0) return 0; con->next_packet_length = len; } if (max_len + crypto_box_MACBYTES < con->next_packet_length) return -1; uint8_t data_encrypted[con->next_packet_length]; int len_packet = read_TCP_packet(con->sock, data_encrypted, con->next_packet_length); if (len_packet != con->next_packet_length) return 0; con->next_packet_length = 0; int len = decrypt_data_fast(con->shared_key, con->recv_nonce, data_encrypted, len_packet, data); if (len + crypto_box_MACBYTES != len_packet) return -1; increment_nonce(con->recv_nonce); return len; }
void increment_and_send_nonce(struct network_status *net_stat) /*@ requires [?f0]world(?pub, ?key_clsfy) &*& proof_obligations(pub) &*& network_status(net_stat) &*& principal(?principal, ?count1) &*& true == bad(principal); @*/ /*@ ensures [f0]world(pub, key_clsfy) &*& proof_obligations(pub) &*& network_status(net_stat) &*& principal(principal, ?count2); @*/ { struct item *nonce = network_receive(net_stat); //@ assert item(nonce, ?n, pub); if (is_nonce(nonce)) { increment_nonce(nonce); //@ assert item(nonce, ?n_inc, pub); //@ open proof_obligations(pub); /*@ if (col) { assert is_public_collision(?proof, pub); proof(n_inc); } else { assert is_public_incremented_nonce(?proof, pub); proof(n, n_inc); } @*/ //@ close proof_obligations(pub); network_send(net_stat, nonce); } item_free(nonce); }
/* Start a secure connection with other peer who has public_key and ip_port returns -1 if failure returns crypt_connection_id of the initialized connection if everything went well. */ int crypto_connect(uint8_t *public_key, IP_Port ip_port) { uint32_t i; int id = getcryptconnection_id(public_key); if (id != -1) { IP_Port c_ip = connection_ip(crypto_connections[id].number); if(c_ip.ip.i == ip_port.ip.i && c_ip.port == ip_port.port) return -1; } for (i = 0; i < MAX_CRYPTO_CONNECTIONS; ++i) { if (crypto_connections[i].status == CONN_NO_CONNECTION) { int id = new_connection(ip_port); if (id == -1) return -1; crypto_connections[i].number = id; crypto_connections[i].status = CONN_HANDSHAKE_SENT; random_nonce(crypto_connections[i].recv_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(id, public_key, crypto_connections[i].recv_nonce, crypto_connections[i].sessionpublic_key) == 1) { increment_nonce(crypto_connections[i].recv_nonce); return i; } return -1; /* this should never happen. */ } } return -1; }
/* 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; }
/* 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. */ int read_cryptpacket(Net_Crypto *c, int crypt_connection_id, uint8_t *data) { if (crypt_connection_id_not_valid(c, crypt_connection_id)) return 0; if (c->crypto_connections[crypt_connection_id].status != CRYPTO_CONN_ESTABLISHED) return 0; uint8_t temp_data[MAX_DATA_SIZE]; int length = read_packet(c->lossless_udp, c->crypto_connections[crypt_connection_id].number, temp_data); if (length == 0) return 0; if (temp_data[0] != 3) return -1; int len = decrypt_data_fast(c->crypto_connections[crypt_connection_id].shared_key, c->crypto_connections[crypt_connection_id].recv_nonce, temp_data + 1, length - 1, data); if (len != -1) { increment_nonce(c->crypto_connections[crypt_connection_id].recv_nonce); return len; } return -1; }
/* return 1 on success. * return 0 if could not send packet. * return -1 on failure (connection must be killed). */ static int write_packet_TCP_secure_connection(TCP_Secure_Connection *con, const uint8_t *data, uint16_t length) { if (length + crypto_box_MACBYTES > MAX_PACKET_SIZE) return -1; if (send_pending_data(con) == -1) return 0; uint8_t packet[sizeof(uint16_t) + length + crypto_box_MACBYTES]; uint16_t c_length = htons(length + crypto_box_MACBYTES); memcpy(packet, &c_length, sizeof(uint16_t)); int len = encrypt_data_symmetric(con->shared_key, con->sent_nonce, data, length, packet + sizeof(uint16_t)); if ((unsigned int)len != (sizeof(packet) - sizeof(uint16_t))) return -1; increment_nonce(con->sent_nonce); len = send(con->sock, packet, sizeof(packet), MSG_NOSIGNAL); if ((unsigned int)len == sizeof(packet)) return 1; if (len <= 0) return 0; memcpy(con->last_packet, packet, length); con->last_packet_length = sizeof(packet); con->last_packet_sent = len; return 1; }
/* Gives a nonce guaranteed to be different from previous ones.*/ void new_nonce(uint8_t *nonce) { if (nonce_set == 0) { random_nonce(base_nonce); nonce_set = 1; } increment_nonce(base_nonce); memcpy(nonce, base_nonce, crypto_box_NONCEBYTES); }
/* 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 == 0) { crypto_connections[i].number = connection_id; crypto_connections[i].status = 2; 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; crypto_connections[i].status = 3; /* connection status needs to be 3 for write_cryptpacket() to work */ write_cryptpacket(i, ((uint8_t *)&zero), sizeof(zero)); crypto_connections[i].status = 2; /* set it to its proper value right after. */ return i; } return -1; /* this should never happen. */ } } return -1; }
/* Start a secure connection with other peer who has public_key and ip_port. * * return -1 if failure. * return crypt_connection_id of the initialized connection if everything went well. */ int crypto_connect(Net_Crypto *c, uint8_t *public_key, IP_Port ip_port) { uint32_t i; int id_existing = getcryptconnection_id(c, public_key); if (id_existing != -1) { IP_Port c_ip = connection_ip(c->lossless_udp, c->crypto_connections[id_existing].number); if (ipport_equal(&c_ip, &ip_port)) 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) { int id_new = new_connection(c->lossless_udp, ip_port); if (id_new == -1) return -1; c->crypto_connections[i].number = id_new; c->crypto_connections[i].status = CRYPTO_CONN_HANDSHAKE_SENT; random_nonce(c->crypto_connections[i].recv_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); c->crypto_connections[i].timeout = unix_time() + CRYPTO_HANDSHAKE_TIMEOUT; if (c->crypto_connections_length == i) ++c->crypto_connections_length; if (send_cryptohandshake(c, id_new, public_key, c->crypto_connections[i].recv_nonce, c->crypto_connections[i].sessionpublic_key) == 1) { increment_nonce(c->crypto_connections[i].recv_nonce); return i; } return -1; /* This should never happen. */ } } return -1; }
/* Start a secure connection with other peer who has public_key and ip_port. * * return -1 if failure. * return crypt_connection_id of the initialized connection if everything went well. */ int crypto_connect(Net_Crypto *c, uint8_t *public_key, IP_Port ip_port) { uint32_t i; int id = getcryptconnection_id(c, public_key); if (id != -1) { IP_Port c_ip = connection_ip(c->lossless_udp, c->crypto_connections[id].number); if (c_ip.ip.uint32 == ip_port.ip.uint32 && c_ip.port == ip_port.port) return -1; } if (realloc_cryptoconnection(c, c->crypto_connections_length + 1) == -1) 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 == CONN_NO_CONNECTION) { int id = new_connection(c->lossless_udp, ip_port); if (id == -1) return -1; c->crypto_connections[i].number = id; c->crypto_connections[i].status = CONN_HANDSHAKE_SENT; random_nonce(c->crypto_connections[i].recv_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, id, public_key, c->crypto_connections[i].recv_nonce, c->crypto_connections[i].sessionpublic_key) == 1) { increment_nonce(c->crypto_connections[i].recv_nonce); return i; } return -1; /* This should never happen. */ } } return -1; }
/* return 0 if data could not be put in packet queue return 1 if data was put into the queue */ int write_cryptpacket(int crypt_connection_id, uint8_t *data, uint32_t length) { if (crypt_connection_id < 0 || crypt_connection_id >= MAX_CRYPTO_CONNECTIONS) return 0; if (length - crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES > MAX_DATA_SIZE - 1) return 0; if (crypto_connections[crypt_connection_id].status != CONN_ESTABLISHED) return 0; uint8_t temp_data[MAX_DATA_SIZE]; int len = encrypt_data_fast(crypto_connections[crypt_connection_id].shared_key, crypto_connections[crypt_connection_id].sent_nonce, data, length, temp_data + 1); if (len == -1) return 0; temp_data[0] = 3; if (write_packet(crypto_connections[crypt_connection_id].number, temp_data, len + 1) == 0) return 0; increment_nonce(crypto_connections[crypt_connection_id].sent_nonce); return 1; }
/* 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 */ int read_cryptpacket(int crypt_connection_id, uint8_t *data) { if (crypt_connection_id < 0 || crypt_connection_id >= MAX_CRYPTO_CONNECTIONS) return 0; if (crypto_connections[crypt_connection_id].status != CONN_ESTABLISHED) return 0; uint8_t temp_data[MAX_DATA_SIZE]; int length = read_packet(crypto_connections[crypt_connection_id].number, temp_data); if (length == 0) return 0; if (temp_data[0] != 3) return -1; int len = decrypt_data_fast(crypto_connections[crypt_connection_id].shared_key, crypto_connections[crypt_connection_id].recv_nonce, temp_data + 1, length - 1, data); if (len != -1) { increment_nonce(crypto_connections[crypt_connection_id].recv_nonce); return len; } return -1; }
/* 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(Socket 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_MAC_SIZE < *next_packet_length) { return -1; } VLA(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_MAC_SIZE != len_packet) { return -1; } increment_nonce(recv_nonce); return len; }
/* 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; } } }
/* 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; } } }