/* Try to send the fakeid via the DHT instead of onion * * Even if this function succeeds, the friend might not recieve any data. * * return the number of packets sent on success * return -1 on failure. */ static int send_dht_fakeid(Onion_Client *onion_c, int friend_num, uint8_t *data, uint32_t length) { if ((uint32_t)friend_num >= onion_c->num_friends) return -1; if (!onion_c->friends_list[friend_num].is_fake_clientid) return -1; uint8_t nonce[crypto_box_NONCEBYTES]; new_nonce(nonce); uint8_t temp[DATA_IN_RESPONSE_MIN_SIZE + crypto_box_NONCEBYTES + length]; memcpy(temp, onion_c->dht->c->self_public_key, crypto_box_PUBLICKEYBYTES); memcpy(temp + crypto_box_PUBLICKEYBYTES, nonce, crypto_box_NONCEBYTES); int len = encrypt_data(onion_c->friends_list[friend_num].real_client_id, onion_c->dht->c->self_secret_key, nonce, data, length, temp + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES); if ((uint32_t)len + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES != sizeof(temp)) return -1; uint8_t packet[MAX_DATA_SIZE]; len = create_request(onion_c->dht->self_public_key, onion_c->dht->self_secret_key, packet, onion_c->friends_list[friend_num].fake_client_id, temp, sizeof(temp), FAKEID_DATA_ID); if (len == -1) return -1; return route_tofriend(onion_c->dht, onion_c->friends_list[friend_num].fake_client_id, packet, len); }
int onion_send_1(const Onion *onion, const uint8_t *plain, uint32_t len, IP_Port source, const uint8_t *nonce) { IP_Port send_to; ipport_unpack(&send_to, plain); to_host_family(&send_to.ip); uint8_t ip_port[SIZE_IPPORT]; ipport_pack(ip_port, &source); uint8_t data[ONION_MAX_PACKET_SIZE]; data[0] = NET_PACKET_ONION_SEND_1; memcpy(data + 1, nonce, crypto_box_NONCEBYTES); memcpy(data + 1 + crypto_box_NONCEBYTES, plain + SIZE_IPPORT, len - SIZE_IPPORT); uint32_t data_len = 1 + crypto_box_NONCEBYTES + (len - SIZE_IPPORT); uint8_t *ret_part = data + data_len; new_nonce(ret_part); len = encrypt_data_symmetric(onion->secret_symmetric_key, ret_part, ip_port, SIZE_IPPORT, ret_part + crypto_box_NONCEBYTES); if (len != SIZE_IPPORT + crypto_box_MACBYTES) 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; }
int send_ping_request(PING *ping, IP_Port ipp, size_t *client_id) { size_t pk[DHT_PING_SIZE]; int rc; size_t ping_id; if (is_pinging(ping, ipp, 0) || id_equal(client_id, ping->dht->self_public_key)) return 1; // Generate random ping_id. ping_id = add_ping(ping, ipp); pk[0] = NET_PACKET_PING_REQUEST; id_copy(pk + 1, ping->dht->self_public_key); // Our pubkey new_nonce(pk + 1 + CLIENT_ID_SIZE); // Generate new nonce // Encrypt ping_id using recipient privkey rc = encrypt_data(client_id, ping->dht->self_secret_key, pk + 1 + CLIENT_ID_SIZE, (size_t *) &ping_id, sizeof(ping_id), pk + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES); if (rc != sizeof(ping_id) + crypto_box_MACBYTES) return 1; return sendpacket(ping->dht->net, ipp, pk, sizeof(pk)); }
static int send_ping_response(PING *ping, IP_Port ipp, const uint8_t *public_key, uint64_t ping_id, uint8_t *shared_encryption_key) { uint8_t pk[DHT_PING_SIZE]; int rc; if (id_equal(public_key, ping->dht->self_public_key)) return 1; uint8_t ping_plain[PING_PLAIN_SIZE]; ping_plain[0] = NET_PACKET_PING_RESPONSE; memcpy(ping_plain + 1, &ping_id, sizeof(ping_id)); pk[0] = NET_PACKET_PING_RESPONSE; id_copy(pk + 1, ping->dht->self_public_key); // Our pubkey new_nonce(pk + 1 + crypto_box_PUBLICKEYBYTES); // Generate new nonce // Encrypt ping_id using recipient privkey rc = encrypt_data_symmetric(shared_encryption_key, pk + 1 + crypto_box_PUBLICKEYBYTES, ping_plain, sizeof(ping_plain), pk + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES ); if (rc != PING_PLAIN_SIZE + crypto_box_MACBYTES) return 1; return sendpacket(ping->dht->net, ipp, pk, sizeof(pk)); }
static int handle_send_2(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_3) 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_3, 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_2), plain); if (len != length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_2 + crypto_box_MACBYTES)) return 1; if (len <= SIZE_IPPORT) { return 1; } if (plain[SIZE_IPPORT] != NET_PACKET_ANNOUNCE_REQUEST && plain[SIZE_IPPORT] != NET_PACKET_ONION_DATA_REQUEST) { return 1; } IP_Port send_to; if (ipport_unpack(&send_to, plain, len, 0) == -1) return 1; uint8_t data[ONION_MAX_PACKET_SIZE]; memcpy(data, plain + SIZE_IPPORT, len - SIZE_IPPORT); uint16_t data_len = (len - SIZE_IPPORT); uint8_t *ret_part = data + (len - SIZE_IPPORT); new_nonce(ret_part); uint8_t ret_data[RETURN_2 + SIZE_IPPORT]; ipport_pack(ret_data, &source); memcpy(ret_data + SIZE_IPPORT, packet + (length - RETURN_2), RETURN_2); len = encrypt_data_symmetric(onion->secret_symmetric_key, ret_part, ret_data, sizeof(ret_data), ret_part + crypto_box_NONCEBYTES); if (len != RETURN_3 - crypto_box_NONCEBYTES) return 1; data_len += RETURN_3; if ((uint32_t)sendpacket(onion->net, send_to, data, data_len) != data_len) return 1; return 0; }
static int handle_send_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 + 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; }
/* Send data of length length to friendnum. * This data will be recieved by the friend using the Onion_Data_Handlers callbacks. * * Even if this function succeeds, the friend might not recieve any data. * * return the number of packets sent on success * return -1 on failure. */ int send_onion_data(Onion_Client *onion_c, int friend_num, uint8_t *data, uint32_t length) { if ((uint32_t)friend_num >= onion_c->num_friends) return -1; if (length + DATA_IN_RESPONSE_MIN_SIZE + ONION_DATA_RESPONSE_MIN_SIZE + ONION_SEND_1 > MAX_DATA_SIZE) return -1; if (length == 0) return -1; uint8_t nonce[crypto_box_NONCEBYTES]; new_nonce(nonce); uint8_t packet[DATA_IN_RESPONSE_MIN_SIZE + length]; memcpy(packet, onion_c->dht->c->self_public_key, crypto_box_PUBLICKEYBYTES); int len = encrypt_data(onion_c->friends_list[friend_num].real_client_id, onion_c->dht->c->self_secret_key, nonce, data, length, packet + crypto_box_PUBLICKEYBYTES); if ((uint32_t)len + crypto_box_PUBLICKEYBYTES != sizeof(packet)) return -1; uint32_t i, good = 0; Onion_Node *list_nodes = onion_c->friends_list[friend_num].clients_list; for (i = 0; i < MAX_ONION_CLIENTS; ++i) { if (is_timeout(list_nodes[i].timestamp, ONION_NODE_TIMEOUT)) continue; if (memcmp(list_nodes[i].ping_id, zero_ping, ONION_PING_ID_SIZE) == 0) { Node_format nodes[4]; if (random_path(onion_c, nodes) == -1) continue; memcpy(nodes[3].client_id, list_nodes[i].client_id, crypto_box_PUBLICKEYBYTES); nodes[3].ip_port = list_nodes[i].ip_port; if (send_data_request(onion_c->dht, nodes, onion_c->friends_list[friend_num].real_client_id, nonce, packet, sizeof(packet)) == 0) ++good; } } return good; }
/* Creates a sendback for use in an announce request. * * num is 0 if we used our secret public key for the announce * num is 1 + friendnum if we use a temporary one. * * Public key is the key we will be sending it to. * ip_port is the ip_port of the node we will be sending * it to. * * sendback must be at least ONION_ANNOUNCE_SENDBACK_DATA_LENGTH big * * return -1 on failure * return 0 on success * */ static int new_sendback(Onion_Client *onion_c, uint32_t num, uint8_t *public_key, IP_Port ip_port, uint8_t *sendback) { uint8_t plain[sizeof(uint32_t) + sizeof(uint64_t) + crypto_box_PUBLICKEYBYTES + sizeof(IP_Port)]; uint64_t time = unix_time(); new_nonce(sendback); memcpy(plain, &num, sizeof(uint32_t)); memcpy(plain + sizeof(uint32_t), &time, sizeof(uint64_t)); memcpy(plain + sizeof(uint32_t) + sizeof(uint64_t), public_key, crypto_box_PUBLICKEYBYTES); memcpy(plain + sizeof(uint32_t) + sizeof(uint64_t) + crypto_box_PUBLICKEYBYTES, &ip_port, sizeof(IP_Port)); int len = encrypt_data_symmetric(onion_c->secret_symmetric_key, sendback, plain, sizeof(plain), sendback + crypto_secretbox_NONCEBYTES); if ((uint32_t)len + crypto_secretbox_NONCEBYTES != ONION_ANNOUNCE_SENDBACK_DATA_LENGTH) return -1; 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]; new_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, 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; }
/* 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; }
int send_ping_request(PING *ping, IP_Port ipp, const uint8_t *public_key) { uint8_t pk[DHT_PING_SIZE]; int rc; uint64_t ping_id; if (id_equal(public_key, 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, public_key); // Generate random ping_id. uint8_t data[PING_DATA_SIZE]; id_copy(data, public_key); memcpy(data + crypto_box_PUBLICKEYBYTES, &ipp, sizeof(IP_Port)); ping_id = ping_array_add(&ping->ping_array, data, sizeof(data)); if (ping_id == 0) return 1; uint8_t ping_plain[PING_PLAIN_SIZE]; ping_plain[0] = NET_PACKET_PING_REQUEST; memcpy(ping_plain + 1, &ping_id, sizeof(ping_id)); pk[0] = NET_PACKET_PING_REQUEST; id_copy(pk + 1, ping->dht->self_public_key); // Our pubkey new_nonce(pk + 1 + crypto_box_PUBLICKEYBYTES); // Generate new nonce rc = encrypt_data_symmetric(shared_key, pk + 1 + crypto_box_PUBLICKEYBYTES, ping_plain, sizeof(ping_plain), pk + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES); if (rc != PING_PLAIN_SIZE + crypto_box_MACBYTES) return 1; return sendpacket(ping->dht->net, ipp, pk, sizeof(pk)); }
int onion_send_1(const Onion *onion, const uint8_t *plain, uint16_t len, IP_Port source, const uint8_t *nonce) { if (len > ONION_MAX_PACKET_SIZE + SIZE_IPPORT - (1 + crypto_box_NONCEBYTES + ONION_RETURN_1)) { return 1; } if (len <= SIZE_IPPORT + SEND_BASE * 2) { return 1; } IP_Port send_to; if (ipport_unpack(&send_to, plain, len, 0) == -1) { return 1; } uint8_t ip_port[SIZE_IPPORT]; ipport_pack(ip_port, &source); uint8_t data[ONION_MAX_PACKET_SIZE]; data[0] = NET_PACKET_ONION_SEND_1; memcpy(data + 1, nonce, 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); len = encrypt_data_symmetric(onion->secret_symmetric_key, ret_part, ip_port, SIZE_IPPORT, ret_part + crypto_box_NONCEBYTES); if (len != SIZE_IPPORT + crypto_box_MACBYTES) { 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; }
/* Send a crypto handshake packet containing an encrypted secret nonce and session public key * to peer with connection_id and public_key. * The packet is encrypted with a random nonce which is sent in plain text with the packet. */ static int send_cryptohandshake(Net_Crypto *c, int connection_id, uint8_t *public_key, uint8_t *secret_nonce, uint8_t *session_key) { uint8_t temp_data[MAX_DATA_SIZE]; uint8_t temp[crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES]; uint8_t nonce[crypto_box_NONCEBYTES]; new_nonce(nonce); memcpy(temp, secret_nonce, crypto_box_NONCEBYTES); memcpy(temp + crypto_box_NONCEBYTES, session_key, crypto_box_PUBLICKEYBYTES); int len = encrypt_data(public_key, c->self_secret_key, nonce, temp, crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES, 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + temp_data); if (len == -1) return 0; temp_data[0] = 2; memcpy(temp_data + 1, c->self_public_key, crypto_box_PUBLICKEYBYTES); memcpy(temp_data + 1 + crypto_box_PUBLICKEYBYTES, nonce, crypto_box_NONCEBYTES); return write_packet(c->lossless_udp, connection_id, temp_data, len + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES); }
/* Create a request to peer. * send_public_key and send_secret_key are the pub/secret keys of the sender. * recv_public_key is public key of reciever. * packet must be an array of MAX_DATA_SIZE big. * Data represents the data we send with the request with length being the length of the data. * request_id is the id of the request (32 = friend request, 254 = ping request). * * return -1 on failure. * return the length of the created packet on success. */ int create_request(uint8_t *send_public_key, uint8_t *send_secret_key, uint8_t *packet, uint8_t *recv_public_key, uint8_t *data, uint32_t length, uint8_t request_id) { if (MAX_DATA_SIZE < length + 1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1 + ENCRYPTION_PADDING) return -1; uint8_t nonce[crypto_box_NONCEBYTES]; uint8_t temp[MAX_DATA_SIZE]; memcpy(temp + 1, data, length); temp[0] = request_id; new_nonce(nonce); int len = encrypt_data(recv_public_key, send_secret_key, nonce, temp, length + 1, 1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + packet); if (len == -1) return -1; packet[0] = NET_PACKET_CRYPTO; memcpy(packet + 1, recv_public_key, crypto_box_PUBLICKEYBYTES); memcpy(packet + 1 + crypto_box_PUBLICKEYBYTES, send_public_key, crypto_box_PUBLICKEYBYTES); memcpy(packet + 1 + crypto_box_PUBLICKEYBYTES * 2, nonce, crypto_box_NONCEBYTES); return len + 1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES; }
static int send_ping_response(PING *ping, IP_Port ipp, uint8_t *client_id, uint64_t ping_id) { uint8_t pk[DHT_PING_SIZE]; int rc; if (id_eq(client_id, ping->c->self_public_key)) return 1; pk[0] = NET_PACKET_PING_RESPONSE; id_cpy(pk + 1, ping->c->self_public_key); // Our pubkey new_nonce(pk + 1 + CLIENT_ID_SIZE); // Generate new nonce // Encrypt ping_id using recipient privkey rc = encrypt_data(client_id, ping->c->self_secret_key, pk + 1 + CLIENT_ID_SIZE, (uint8_t *) &ping_id, sizeof(ping_id), pk + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES); if (rc != sizeof(ping_id) + ENCRYPTION_PADDING) return 1; return sendpacket(ping->c->lossless_udp->net, ipp, pk, sizeof(pk)); }