int send_ping_request(IP_Port ipp, clientid_t* client_id) { pingreq_t pk; int rc; uint64_t ping_id; if (is_pinging(ipp, 0) || id_eq(client_id, self_id)) return 1; // Generate random ping_id ping_id = add_ping(ipp); pk.magic = PACKET_PING_REQ; id_cpy(&pk.client_id, self_id); // Our pubkey random_nonce((uint8_t*) &pk.nonce); // Generate random nonce // Encrypt ping_id using recipient privkey rc = encrypt_data((uint8_t*) client_id, self_secret_key, (uint8_t*) &pk.nonce, (uint8_t*) &ping_id, sizeof(ping_id), (uint8_t*) &pk.ping_id); if (rc != sizeof(ping_id) + ENCRYPTION_PADDING) return 1; return sendpacket(ipp, (uint8_t*) &pk, sizeof(pk)); }
//send a ping response static int pingres(IP_Port ip_port, uint8_t * public_key, uint64_t ping_id) { if(memcmp(public_key, self_public_key, CLIENT_ID_SIZE) == 0)//check if packet is gonna be sent to ourself { return 1; } uint8_t data[1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + sizeof(ping_id) + ENCRYPTION_PADDING]; uint8_t encrypt[sizeof(ping_id) + ENCRYPTION_PADDING]; uint8_t nonce[crypto_box_NONCEBYTES]; random_nonce(nonce); int len = encrypt_data(public_key, self_secret_key, nonce, (uint8_t *)&ping_id, sizeof(ping_id), encrypt); if(len != sizeof(ping_id) + ENCRYPTION_PADDING) { return -1; } data[0] = 1; memcpy(data + 1, self_public_key, CLIENT_ID_SIZE); memcpy(data + 1 + CLIENT_ID_SIZE, nonce, crypto_box_NONCEBYTES); memcpy(data + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, encrypt, len); return sendpacket(ip_port, data, sizeof(data)); }
/* Create an onion announce request packet in packet of max_packet_length (recommended size ONION_ANNOUNCE_REQUEST_SIZE). * * dest_client_id is the public key of the node the packet will be sent to. * public_key and secret_key is the kepair which will be used to encrypt the request. * ping_id is the ping id that will be sent in the request. * client_id is the client id of the node we are searching for. * data_public_key is the public key we want others to encrypt their data packets with. * sendback_data is the data of ONION_ANNOUNCE_SENDBACK_DATA_LENGTH length that we expect to * receive back in the response. * * return -1 on failure. * return packet length on success. */ int create_announce_request(uint8_t *packet, uint16_t max_packet_length, const uint8_t *dest_client_id, const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *ping_id, const uint8_t *client_id, const uint8_t *data_public_key, uint64_t sendback_data) { if (max_packet_length < ONION_ANNOUNCE_REQUEST_SIZE) { return -1; } uint8_t plain[ONION_PING_ID_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_PUBLIC_KEY_SIZE + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH]; memcpy(plain, ping_id, ONION_PING_ID_SIZE); memcpy(plain + ONION_PING_ID_SIZE, client_id, CRYPTO_PUBLIC_KEY_SIZE); memcpy(plain + ONION_PING_ID_SIZE + CRYPTO_PUBLIC_KEY_SIZE, data_public_key, CRYPTO_PUBLIC_KEY_SIZE); memcpy(plain + ONION_PING_ID_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_PUBLIC_KEY_SIZE, &sendback_data, sizeof(sendback_data)); packet[0] = NET_PACKET_ANNOUNCE_REQUEST; random_nonce(packet + 1); int len = encrypt_data(dest_client_id, secret_key, packet + 1, plain, sizeof(plain), packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE); if ((uint32_t)len + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE != ONION_ANNOUNCE_REQUEST_SIZE) { return -1; } memcpy(packet + 1 + CRYPTO_NONCE_SIZE, public_key, CRYPTO_PUBLIC_KEY_SIZE); return ONION_ANNOUNCE_REQUEST_SIZE; }
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 random_nonce(pk + 1 + CRYPTO_PUBLIC_KEY_SIZE); // Generate new nonce // Encrypt ping_id using recipient privkey rc = encrypt_data_symmetric(shared_encryption_key, pk + 1 + CRYPTO_PUBLIC_KEY_SIZE, ping_plain, sizeof(ping_plain), pk + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE); if (rc != PING_PLAIN_SIZE + CRYPTO_MAC_SIZE) { return 1; } return sendpacket(ping->dht->net, ipp, pk, sizeof(pk)); }
/* Send data of length length to friendnum. * This data will be received by the friend using the Onion_Data_Handlers callbacks. * * Even if this function succeeds, the friend might not receive any data. * * return the number of packets sent on success * return -1 on failure. */ int send_onion_data(const Onion_Client *onion_c, int friend_num, const uint8_t *data, uint32_t length) { if ((uint32_t)friend_num >= onion_c->num_friends) return -1; if (length + DATA_IN_RESPONSE_MIN_SIZE > MAX_DATA_REQUEST_SIZE) return -1; if (length == 0) return -1; uint8_t nonce[crypto_box_NONCEBYTES]; random_nonce(nonce); uint8_t packet[DATA_IN_RESPONSE_MIN_SIZE + length]; memcpy(packet, onion_c->c->self_public_key, crypto_box_PUBLICKEYBYTES); int len = encrypt_data(onion_c->friends_list[friend_num].real_client_id, onion_c->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_nodes[MAX_ONION_CLIENTS], num_good = 0, num_nodes = 0; Onion_Path path[MAX_ONION_CLIENTS]; 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; ++num_nodes; if (list_nodes[i].is_stored) { if (random_path(onion_c, &onion_c->friends_list[friend_num].onion_paths, ~0, &path[num_good]) == -1) continue; good_nodes[num_good] = i; ++num_good; } } if (num_good < (num_nodes / 4) + 1) return -1; uint32_t good = 0; for (i = 0; i < num_good; ++i) { uint8_t o_packet[ONION_MAX_PACKET_SIZE]; len = create_data_request(o_packet, sizeof(o_packet), onion_c->friends_list[friend_num].real_client_id, list_nodes[good_nodes[i]].data_public_key, nonce, packet, sizeof(packet)); if (len == -1) continue; if (send_onion_packet_tcp_udp(onion_c, &path[i], list_nodes[good_nodes[i]].ip_port, o_packet, len) == 0) ++good; } return good; }
/* 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 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; }
/* return 0 on success. * return -1 on failure. */ static int generate_handshake(TCP_Client_Connection *TCP_conn) { uint8_t plain[CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE]; crypto_new_keypair(plain, TCP_conn->temp_secret_key); random_nonce(TCP_conn->sent_nonce); memcpy(plain + CRYPTO_PUBLIC_KEY_SIZE, TCP_conn->sent_nonce, CRYPTO_NONCE_SIZE); memcpy(TCP_conn->last_packet, TCP_conn->self_public_key, CRYPTO_PUBLIC_KEY_SIZE); random_nonce(TCP_conn->last_packet + CRYPTO_PUBLIC_KEY_SIZE); int len = encrypt_data_symmetric(TCP_conn->shared_key, TCP_conn->last_packet + CRYPTO_PUBLIC_KEY_SIZE, plain, sizeof(plain), TCP_conn->last_packet + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE); if (len != sizeof(plain) + CRYPTO_MAC_SIZE) { return -1; } TCP_conn->last_packet_length = CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + sizeof(plain) + CRYPTO_MAC_SIZE; TCP_conn->last_packet_sent = 0; return 0; }
/* 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); }
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; random_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; }
/* Create a onion packet to be sent over tcp. * * Use Onion_Path path to create packet for data of length to dest. * Maximum length of data is ONION_MAX_DATA_SIZE. * packet should be at least ONION_MAX_PACKET_SIZE big. * * return -1 on failure. * return length of created packet on success. */ int create_onion_packet_tcp(uint8_t *packet, uint16_t max_packet_length, const Onion_Path *path, IP_Port dest, const uint8_t *data, uint16_t length) { if (crypto_box_NONCEBYTES + SIZE_IPPORT + SEND_BASE * 2 + length > max_packet_length || length == 0) return -1; #ifdef _MSC_VER VLA_s(uint8_t, step1, SIZE_IPPORT + length); #else uint8_t step1[SIZE_IPPORT + length]; #endif ipport_pack(step1, &dest); memcpy(step1 + SIZE_IPPORT, data, length); uint8_t nonce[crypto_box_NONCEBYTES]; random_nonce(nonce); #ifdef _MSC_VER VLA_s(uint8_t, step2, SIZE_IPPORT + SEND_BASE + length); #else uint8_t step2[SIZE_IPPORT + SEND_BASE + length]; #endif ipport_pack(step2, &path->ip_port3); memcpy(step2 + SIZE_IPPORT, path->public_key3, crypto_box_PUBLICKEYBYTES); #ifdef _MSC_VER int len = encrypt_data_symmetric(path->shared_key3, nonce, step1, sizeof_step1, step2 + SIZE_IPPORT + crypto_box_PUBLICKEYBYTES); #else int len = encrypt_data_symmetric(path->shared_key3, nonce, step1, sizeof(step1), step2 + SIZE_IPPORT + crypto_box_PUBLICKEYBYTES); #endif if (len != SIZE_IPPORT + length + crypto_box_MACBYTES) return -1; ipport_pack(packet + crypto_box_NONCEBYTES, &path->ip_port2); memcpy(packet + crypto_box_NONCEBYTES + SIZE_IPPORT, path->public_key2, crypto_box_PUBLICKEYBYTES); #ifdef _MSC_VER len = encrypt_data_symmetric(path->shared_key2, nonce, step2, sizeof_step2, packet + crypto_box_NONCEBYTES + SIZE_IPPORT + crypto_box_PUBLICKEYBYTES); #else len = encrypt_data_symmetric(path->shared_key2, nonce, step2, sizeof(step2), packet + crypto_box_NONCEBYTES + SIZE_IPPORT + crypto_box_PUBLICKEYBYTES); #endif if (len != SIZE_IPPORT + SEND_BASE + length + crypto_box_MACBYTES) return -1; memcpy(packet, nonce, crypto_box_NONCEBYTES); return crypto_box_NONCEBYTES + SIZE_IPPORT + crypto_box_PUBLICKEYBYTES + len; }
/* Create a onion packet. * * Use Onion_Path path to create packet for data of length to dest. * Maximum length of data is ONION_MAX_DATA_SIZE. * packet should be at least ONION_MAX_PACKET_SIZE big. * * return -1 on failure. * return length of created packet on success. */ int create_onion_packet(uint8_t *packet, uint16_t max_packet_length, const Onion_Path *path, IP_Port dest, const uint8_t *data, uint16_t length) { if (1 + length + SEND_1 > max_packet_length || length == 0) { return -1; } uint8_t step1[SIZE_IPPORT + length]; ipport_pack(step1, &dest); memcpy(step1 + SIZE_IPPORT, data, length); uint8_t nonce[crypto_box_NONCEBYTES]; random_nonce(nonce); uint8_t step2[SIZE_IPPORT + SEND_BASE + length]; ipport_pack(step2, &path->ip_port3); memcpy(step2 + SIZE_IPPORT, path->public_key3, crypto_box_PUBLICKEYBYTES); int len = encrypt_data_symmetric(path->shared_key3, nonce, step1, sizeof(step1), step2 + SIZE_IPPORT + crypto_box_PUBLICKEYBYTES); if (len != SIZE_IPPORT + length + crypto_box_MACBYTES) { return -1; } uint8_t step3[SIZE_IPPORT + SEND_BASE * 2 + length]; ipport_pack(step3, &path->ip_port2); memcpy(step3 + SIZE_IPPORT, path->public_key2, crypto_box_PUBLICKEYBYTES); len = encrypt_data_symmetric(path->shared_key2, nonce, step2, sizeof(step2), step3 + SIZE_IPPORT + crypto_box_PUBLICKEYBYTES); if (len != SIZE_IPPORT + SEND_BASE + length + crypto_box_MACBYTES) { return -1; } packet[0] = NET_PACKET_ONION_SEND_INITIAL; memcpy(packet + 1, nonce, crypto_box_NONCEBYTES); memcpy(packet + 1 + crypto_box_NONCEBYTES, path->public_key1, crypto_box_PUBLICKEYBYTES); len = encrypt_data_symmetric(path->shared_key1, nonce, step3, sizeof(step3), packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES); if (len != SIZE_IPPORT + SEND_BASE * 2 + length + crypto_box_MACBYTES) { return -1; } return 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + len; }
/* 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]; random_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 (list_nodes[i].is_stored) { Node_format nodes[4]; Onion_Path path; if (random_path(onion_c->dht, &onion_c->friends_list[friend_num].onion_paths, ~0, &path) == -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->net, &path, list_nodes[i].ip_port, onion_c->friends_list[friend_num].real_client_id, list_nodes[i].data_public_key, nonce, packet, sizeof(packet)) == 0) ++good; } } return good; }
/* 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; }
/* create a request to peer with public_key. 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) returns -1 on failure returns the length of the created packet on success */ int create_request(uint8_t *packet, uint8_t *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 + ENCRYPTION_PADDING) return -1; uint8_t nonce[crypto_box_NONCEBYTES]; random_nonce(nonce); int len = encrypt_data(public_key, self_secret_key, nonce, data, length, 1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + packet); if (len == -1) return -1; packet[0] = request_id; memcpy(packet + 1, public_key, crypto_box_PUBLICKEYBYTES); memcpy(packet + 1 + crypto_box_PUBLICKEYBYTES, self_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; }
/* 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; }
/* 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(); random_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; }
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_SHARED_KEY_SIZE]; // 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_PUBLIC_KEY_SIZE, &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 random_nonce(pk + 1 + CRYPTO_PUBLIC_KEY_SIZE); // Generate new nonce rc = encrypt_data_symmetric(shared_key, pk + 1 + CRYPTO_PUBLIC_KEY_SIZE, ping_plain, sizeof(ping_plain), pk + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE); if (rc != PING_PLAIN_SIZE + CRYPTO_MAC_SIZE) { return 1; } return sendpacket(ping->dht->net, ipp, pk, sizeof(pk)); }
/* 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(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]; random_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, 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, self_public_key, crypto_box_PUBLICKEYBYTES); memcpy(temp_data + 1 + crypto_box_PUBLICKEYBYTES, nonce, crypto_box_NONCEBYTES); return write_packet(connection_id, temp_data, len + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES); }
//send a send nodes response static int sendnodes(IP_Port ip_port, uint8_t * public_key, uint8_t * client_id, uint64_t ping_id) { if(memcmp(public_key, self_public_key, CLIENT_ID_SIZE) == 0)//check if packet is gonna be sent to ourself { return 1; } uint8_t data[1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + sizeof(ping_id) + sizeof(Node_format) * MAX_SENT_NODES + ENCRYPTION_PADDING]; Node_format nodes_list[MAX_SENT_NODES]; int num_nodes = get_close_nodes(client_id, nodes_list); if(num_nodes == 0) { return 0; } uint8_t plain[sizeof(ping_id) + sizeof(Node_format) * MAX_SENT_NODES]; uint8_t encrypt[sizeof(ping_id) + sizeof(Node_format) * MAX_SENT_NODES + ENCRYPTION_PADDING]; uint8_t nonce[crypto_box_NONCEBYTES]; random_nonce(nonce); memcpy(plain, &ping_id, sizeof(ping_id)); memcpy(plain + sizeof(ping_id), nodes_list, num_nodes * sizeof(Node_format)); int len = encrypt_data(public_key, self_secret_key, nonce, plain, sizeof(ping_id) + num_nodes * sizeof(Node_format), encrypt); if(len != sizeof(ping_id) + num_nodes * sizeof(Node_format) + ENCRYPTION_PADDING) { return -1; } data[0] = 3; memcpy(data + 1, self_public_key, CLIENT_ID_SIZE); memcpy(data + 1 + CLIENT_ID_SIZE, nonce, crypto_box_NONCEBYTES); memcpy(data + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, encrypt, len); return sendpacket(ip_port, data, 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + len); }
/* 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 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; random_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 getnodes request static int getnodes(IP_Port ip_port, uint8_t * public_key, uint8_t * client_id) { if(memcmp(public_key, self_public_key, CLIENT_ID_SIZE) == 0)//check if packet is gonna be sent to ourself { return 1; } if(is_gettingnodes(ip_port, 0)) { return 1; } uint64_t ping_id = add_gettingnodes(ip_port); if(ping_id == 0) { return 1; } uint8_t data[1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + sizeof(ping_id) + CLIENT_ID_SIZE + ENCRYPTION_PADDING]; uint8_t plain[sizeof(ping_id) + CLIENT_ID_SIZE]; uint8_t encrypt[sizeof(ping_id) + CLIENT_ID_SIZE + ENCRYPTION_PADDING]; uint8_t nonce[crypto_box_NONCEBYTES]; random_nonce(nonce); memcpy(plain, &ping_id, sizeof(ping_id)); memcpy(plain + sizeof(ping_id), client_id, CLIENT_ID_SIZE); int len = encrypt_data(public_key, self_secret_key, nonce, plain, sizeof(ping_id) + CLIENT_ID_SIZE, encrypt); if(len != sizeof(ping_id) + CLIENT_ID_SIZE + ENCRYPTION_PADDING) { return -1; } data[0] = 2; memcpy(data + 1, self_public_key, CLIENT_ID_SIZE); memcpy(data + 1 + CLIENT_ID_SIZE, nonce, crypto_box_NONCEBYTES); memcpy(data + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, encrypt, len); return sendpacket(ip_port, data, sizeof(data)); }
/* 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; }
/* Encrypt arbitrary with a key produced by tox_derive_key_*. The output * array must be at least data_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long. * key must be TOX_PASS_KEY_LENGTH bytes. * If you already have a symmetric key from somewhere besides this module, simply * call encrypt_data_symmetric in toxcore/crypto_core directly. * * returns true on success */ bool tox_pass_key_encrypt(const Tox_Pass_Key *key, const uint8_t *data, size_t data_len, uint8_t *out, TOX_ERR_ENCRYPTION *error) { if (data_len == 0 || !data || !key || !out) { SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTION_NULL); return 0; } /* the output data consists of, in order: * salt, nonce, mac, enc_data * where the mac is automatically prepended by the encrypt() * the salt+nonce is called the prefix * I'm not sure what else I'm supposed to do with the salt and nonce, since we * need them to decrypt the data */ /* first add the magic number */ memcpy(out, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH); out += TOX_ENC_SAVE_MAGIC_LENGTH; /* then add the rest prefix */ memcpy(out, key->salt, crypto_pwhash_scryptsalsa208sha256_SALTBYTES); out += crypto_pwhash_scryptsalsa208sha256_SALTBYTES; uint8_t nonce[crypto_box_NONCEBYTES]; random_nonce(nonce); memcpy(out, nonce, crypto_box_NONCEBYTES); out += crypto_box_NONCEBYTES; /* now encrypt */ if (encrypt_data_symmetric(key->key, nonce, data, data_len, out) != data_len + crypto_box_MACBYTES) { SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTION_FAILED); return 0; } SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTION_OK); return 1; }
/* Ceate 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; random_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 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; }