diff --git a/src/network/network.cpp b/src/network/network.cpp index 6c2b00084f..271000f8ab 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -39,11 +39,11 @@ #include "../string_func.h" #include "../string_func_extra.h" #include "../core/serialisation.hpp" -#include "../3rdparty/randombytes/randombytes.h" #include "../3rdparty/monocypher/monocypher.h" #include "../settings_internal.h" #include #include +#include #ifdef DEBUG_DUMP_COMMANDS #include "../fileio_func.h" @@ -1371,7 +1371,7 @@ static void NetworkGenerateServerId() std::string NetworkGenerateRandomKeyString(uint bytes) { uint8_t *key = AllocaM(uint8_t, bytes); - NetworkRandomBytesWithFallback(key, bytes); + RandomBytesWithFallback({ key, bytes }); return FormatArrayAsHex({key, bytes}); } @@ -1416,26 +1416,16 @@ void NetworkShutDown() NetworkCoreShutdown(); } -void NetworkRandomBytesWithFallback(void *buf, size_t bytes) -{ - if (randombytes(buf, bytes) < 0) { - /* Fallback poor-quality random */ - DEBUG(net, 0, "High quality random source unavailable"); - for (uint i = 0; i < bytes; i++) { - reinterpret_cast(buf)[i] = (byte)InteractiveRandom(); - } - } -} - void NetworkGameKeys::Initialise() { assert(!this->inited); this->inited = true; - static_assert(sizeof(this->x25519_priv_key) == 32); - NetworkRandomBytesWithFallback(this->x25519_priv_key, sizeof(this->x25519_priv_key)); - crypto_x25519_public_key(this->x25519_pub_key, this->x25519_priv_key); + static_assert(std::tuple_size::value == 32); + static_assert(std::tuple_size::value == 32); + RandomBytesWithFallback(this->x25519_priv_key); + crypto_x25519_public_key(this->x25519_pub_key.data(), this->x25519_priv_key.data()); } NetworkSharedSecrets::~NetworkSharedSecrets() diff --git a/src/network/network_client.cpp b/src/network/network_client.cpp index 4948d3f9a8..e2ff608efd 100644 --- a/src/network/network_client.cpp +++ b/src/network/network_client.cpp @@ -36,6 +36,8 @@ #include "../debug_settings.h" #include "../3rdparty/monocypher/monocypher.h" +#include + #include "table/strings.h" #include "../safeguards.h" @@ -394,7 +396,7 @@ static uint32_t last_ack_frame; /** One bit of 'entropy' used to generate a salt for the company passwords. */ static uint32_t _company_password_game_seed; /** Network server's x25519 public key, used for key derivation */ -static byte _server_x25519_pub_key[32]; +static std::array _server_x25519_pub_key; /** Key message ID counter */ static uint64_t _next_key_message_id; /** The other bit of 'entropy' used to generate a salt for the server, rcon, and settings passwords. */ @@ -417,24 +419,24 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendKeyPasswordPacket(PacketTy { const NetworkGameKeys &keys = this->GetKeys(); - byte shared_secret[32]; // Shared secret - crypto_x25519(shared_secret, keys.x25519_priv_key, _server_x25519_pub_key); - if (std::all_of(shared_secret, shared_secret + 32, [](auto v) { return v == 0; })) { + std::array shared_secret; // Shared secret + crypto_x25519(shared_secret.data(), keys.x25519_priv_key.data(), _server_x25519_pub_key.data()); + if (std::all_of(shared_secret.begin(), shared_secret.end(), [](auto v) { return v == 0; })) { /* Secret is all 0 because public key is all 0, just give up at this point */ return NETWORK_RECV_STATUS_MALFORMED_PACKET; } crypto_blake2b_ctx ctx; - crypto_blake2b_init (&ctx, 64); - crypto_blake2b_update(&ctx, shared_secret, 32); // Shared secret - crypto_blake2b_update(&ctx, keys.x25519_pub_key, 32); // Client pub key - crypto_blake2b_update(&ctx, _server_x25519_pub_key, 32); // Server pub key - crypto_blake2b_update(&ctx, (const byte *)password.data(), password.size()); // Password - crypto_blake2b_final (&ctx, ss.shared_data); + crypto_blake2b_init (&ctx, ss.shared_data.size()); + crypto_blake2b_update(&ctx, shared_secret.data(), shared_secret.size()); // Shared secret + crypto_blake2b_update(&ctx, keys.x25519_pub_key.data(), keys.x25519_pub_key.size()); // Client pub key + crypto_blake2b_update(&ctx, _server_x25519_pub_key.data(), _server_x25519_pub_key.size()); // Server pub key + crypto_blake2b_update(&ctx, (const byte *)password.data(), password.size()); // Password + crypto_blake2b_final (&ctx, ss.shared_data.data()); /* NetworkSharedSecrets::shared_data now contains 2 keys worth of hash, first key is used for up direction, second key for down direction (if any) */ - crypto_wipe(shared_secret, 32); + crypto_wipe(shared_secret.data(), shared_secret.size()); std::vector message; BufferSerialiser buffer(message); @@ -446,20 +448,22 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendKeyPasswordPacket(PacketTy if (payload != nullptr) buffer.Send_string(*payload); /* Message authentication code */ - uint8_t mac[16]; + std::array mac; /* Use only once per key: random */ - uint8_t nonce[24]; - NetworkRandomBytesWithFallback(nonce, 24); + std::array nonce; + RandomBytesWithFallback(nonce); /* Encrypt in place, use first half of hash as key */ - crypto_aead_lock(message.data(), mac, ss.shared_data, nonce, keys.x25519_pub_key, 32, message.data(), message.size()); + static_assert(std::tuple_size::value == 64); + crypto_aead_lock(message.data(), mac.data(), ss.shared_data.data(), nonce.data(), keys.x25519_pub_key.data(), keys.x25519_pub_key.size(), message.data(), message.size()); Packet *p = new Packet(packet_type, SHRT_MAX); - p->Send_binary(keys.x25519_pub_key, 32); - p->Send_binary(nonce, 24); - p->Send_binary(mac, 16); - p->Send_binary(message.data(), message.size()); + static_assert(std::tuple_size::value == 32); + p->Send_binary(keys.x25519_pub_key); + p->Send_binary(nonce); + p->Send_binary(mac); + p->Send_binary(message); _next_key_message_id++; @@ -910,8 +914,8 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_NEED_GAME_PASSW if (this->status < STATUS_JOIN || this->status >= STATUS_AUTH_GAME) return NETWORK_RECV_STATUS_MALFORMED_PACKET; this->status = STATUS_AUTH_GAME; - static_assert(sizeof(_server_x25519_pub_key) == 32); - p->Recv_binary(_server_x25519_pub_key, sizeof(_server_x25519_pub_key)); + static_assert(_server_x25519_pub_key.size() == 32); + p->Recv_binary(_server_x25519_pub_key); _password_server_id = p->Recv_string(NETWORK_SERVER_ID_LENGTH); if (this->HasClientQuit()) return NETWORK_RECV_STATUS_MALFORMED_PACKET; @@ -951,8 +955,8 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_WELCOME(Packet /* Initialize the password hash salting variables, even if they were previously. */ _company_password_game_seed = p->Recv_uint32(); - static_assert(sizeof(_server_x25519_pub_key) == 32); - p->Recv_binary(_server_x25519_pub_key, sizeof(_server_x25519_pub_key)); + static_assert(_server_x25519_pub_key.size() == 32); + p->Recv_binary(_server_x25519_pub_key); _password_server_id = p->Recv_string(NETWORK_SERVER_ID_LENGTH); _company_password_server_id = p->Recv_string(NETWORK_SERVER_ID_LENGTH); @@ -1319,14 +1323,15 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_RCON(Packet *p) return NETWORK_RECV_STATUS_OKAY; } - byte nonce[24]; - byte mac[16]; - p->Recv_binary(nonce, 24); - p->Recv_binary(mac, 16); + std::array nonce; + std::array mac; + p->Recv_binary(nonce); + p->Recv_binary(mac); std::vector message = p->Recv_binary(p->RemainingBytesToTransfer()); - if (crypto_aead_unlock(message.data(), mac, this->last_rcon_shared_secrets.shared_data + 32, nonce, nullptr, 0, message.data(), message.size()) == 0) { + static_assert(std::tuple_size::value == 64); + if (crypto_aead_unlock(message.data(), mac.data(), this->last_rcon_shared_secrets.shared_data.data() + 32, nonce.data(), nullptr, 0, message.data(), message.size()) == 0) { SubPacketDeserialiser spd(p, message); TextColour colour_code = (TextColour)spd.Recv_uint16(); if (!IsValidConsoleColour(colour_code)) return NETWORK_RECV_STATUS_MALFORMED_PACKET; @@ -1454,7 +1459,7 @@ std::string ClientNetworkGameSocketHandler::GetDebugInfo() const static void ResetClientConnectionKeyStates() { _next_key_message_id = 0; - crypto_wipe(_server_x25519_pub_key, sizeof(_server_x25519_pub_key)); + crypto_wipe(_server_x25519_pub_key.data(), _server_x25519_pub_key.size()); } diff --git a/src/network/network_internal.h b/src/network/network_internal.h index 1b66796fbe..43d5fc9a50 100644 --- a/src/network/network_internal.h +++ b/src/network/network_internal.h @@ -18,6 +18,7 @@ #include "../command_type.h" #include "../date_type.h" +#include #include static const uint32_t FIND_SERVER_EXTENDED_TOKEN = 0x2A49582A; @@ -103,15 +104,15 @@ void NetworkRebuildHostList(); void UpdateNetworkGameWindow(); struct NetworkGameKeys { - byte x25519_priv_key[32]; ///< x25519 key: private part - byte x25519_pub_key[32]; ///< x25519 key: public part + std::array x25519_priv_key; ///< x25519 key: private part + std::array x25519_pub_key; ///< x25519 key: public part bool inited = false; void Initialise(); }; struct NetworkSharedSecrets { - byte shared_data[64]; + std::array shared_data; ~NetworkSharedSecrets(); }; @@ -150,6 +151,4 @@ std::string NormalizeConnectionString(const std::string &connection_string, uint void ClientNetworkEmergencySave(); -void NetworkRandomBytesWithFallback(void *buf, size_t n); - #endif /* NETWORK_INTERNAL_H */ diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp index 90857b388c..9d64747c3c 100644 --- a/src/network/network_server.cpp +++ b/src/network/network_server.cpp @@ -30,10 +30,10 @@ #include "../core/random_func.hpp" #include "../rev.h" #include "../crashlog.h" -#include "../3rdparty/randombytes/randombytes.h" #include "../3rdparty/monocypher/monocypher.h" #include #include +#include #include "../safeguards.h" @@ -227,33 +227,33 @@ ServerNetworkGameSocketHandler::~ServerNetworkGameSocketHandler() bool ServerNetworkGameSocketHandler::ParseKeyPasswordPacket(Packet *p, NetworkSharedSecrets &ss, const std::string &password, std::string *payload, size_t length) { - byte client_pub_key[32]; - byte nonce[24]; - byte mac[16]; - p->Recv_binary(client_pub_key, 32); - p->Recv_binary(nonce, 24); - p->Recv_binary(mac, 16); + std::array client_pub_key; + std::array nonce; + std::array mac; + p->Recv_binary(client_pub_key); + p->Recv_binary(nonce); + p->Recv_binary(mac); const NetworkGameKeys &keys = this->GetKeys(); - byte shared_secret[32]; // Shared secret - crypto_x25519(shared_secret, keys.x25519_priv_key, client_pub_key); - if (std::all_of(shared_secret, shared_secret + 32, [](auto v) { return v == 0; })) { + std::array shared_secret; // Shared secret + crypto_x25519(shared_secret.data(), keys.x25519_priv_key.data(), client_pub_key.data()); + if (std::all_of(shared_secret.begin(), shared_secret.end(), [](auto v) { return v == 0; })) { /* Secret is all 0 because public key is all 0, just reject it */ return false; } crypto_blake2b_ctx ctx; - crypto_blake2b_init (&ctx, 64); - crypto_blake2b_update(&ctx, shared_secret, 32); // Shared secret - crypto_blake2b_update(&ctx, client_pub_key, 32); // Client pub key - crypto_blake2b_update(&ctx, keys.x25519_pub_key, 32); // Server pub key - crypto_blake2b_update(&ctx, (const byte *)password.data(), password.size()); // Password - crypto_blake2b_final (&ctx, ss.shared_data); + crypto_blake2b_init (&ctx, ss.shared_data.size()); + crypto_blake2b_update(&ctx, shared_secret.data(), shared_secret.size()); // Shared secret + crypto_blake2b_update(&ctx, client_pub_key.data(), client_pub_key.size()); // Client pub key + crypto_blake2b_update(&ctx, keys.x25519_pub_key.data(), keys.x25519_pub_key.size()); // Server pub key + crypto_blake2b_update(&ctx, (const byte *)password.data(), password.size()); // Password + crypto_blake2b_final (&ctx, ss.shared_data.data()); /* NetworkSharedSecrets::shared_data now contains 2 keys worth of hash, first key is used for up direction, second key for down direction (if any) */ - crypto_wipe(shared_secret, 32); + crypto_wipe(shared_secret.data(), shared_secret.size()); std::vector message = p->Recv_binary(p->RemainingBytesToTransfer()); if (message.size() < 8) return false; @@ -263,7 +263,8 @@ bool ServerNetworkGameSocketHandler::ParseKeyPasswordPacket(Packet *p, NetworkSh } /* Decrypt in place, use first half of hash as key */ - if (crypto_aead_unlock(message.data(), mac, ss.shared_data, nonce, client_pub_key, 32, message.data(), message.size()) == 0) { + static_assert(std::tuple_size::value == 64); + if (crypto_aead_unlock(message.data(), mac.data(), ss.shared_data.data(), nonce.data(), client_pub_key.data(), client_pub_key.size(), message.data(), message.size()) == 0) { SubPacketDeserialiser spd(p, message); uint64_t message_id = spd.Recv_uint64(); if (message_id < this->min_key_message_id) { @@ -525,8 +526,8 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendNeedGamePassword() const NetworkGameKeys &keys = this->GetKeys(); Packet *p = new Packet(PACKET_SERVER_NEED_GAME_PASSWORD, SHRT_MAX); - static_assert(sizeof(keys.x25519_pub_key) == 32); - p->Send_binary(keys.x25519_pub_key, sizeof(keys.x25519_pub_key)); + static_assert(std::tuple_size::value == 32); + p->Send_binary(keys.x25519_pub_key); p->Send_string(_settings_client.network.network_id); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; @@ -568,8 +569,8 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendWelcome() p = new Packet(PACKET_SERVER_WELCOME, SHRT_MAX); p->Send_uint32(this->client_id); p->Send_uint32(_settings_game.game_creation.generation_seed); - static_assert(sizeof(keys.x25519_pub_key) == 32); - p->Send_binary(keys.x25519_pub_key, sizeof(keys.x25519_pub_key)); + static_assert(std::tuple_size::value == 32); + p->Send_binary(keys.x25519_pub_key); p->Send_string(_settings_client.network.network_id); p->Send_string(_network_company_server_id); this->SendPacket(p); @@ -845,19 +846,21 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendRConResult(uint16_t colour buffer.Send_string(command); /* Message authentication code */ - uint8_t mac[16]; + std::array mac; /* Use only once per key: random */ - uint8_t nonce[24]; - NetworkRandomBytesWithFallback(nonce, 24); + std::array nonce; + RandomBytesWithFallback(nonce); /* Encrypt in place, use first half of hash as key */ - crypto_aead_lock(message.data(), mac, this->rcon_reply_key, nonce, nullptr, 0, message.data(), message.size()); + crypto_aead_lock(message.data(), mac.data(), this->rcon_reply_key, nonce.data(), nullptr, 0, message.data(), message.size()); Packet *p = new Packet(PACKET_SERVER_RCON, SHRT_MAX); - p->Send_binary(nonce, 24); - p->Send_binary(mac, 16); - p->Send_binary(message.data(), message.size()); + static_assert(nonce.size() == 24); + static_assert(mac.size() == 16); + p->Send_binary(nonce); + p->Send_binary(mac); + p->Send_binary(message); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; @@ -1697,7 +1700,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_RCON(Packet *p) DEBUG(net, 3, "[rcon] Client-id %d executed: %s", this->client_id, command.c_str()); _redirect_console_to_client = this->client_id; - this->rcon_reply_key = ss.shared_data + 32; /* second key */ + this->rcon_reply_key = ss.shared_data.data() + 32; /* second key */ IConsoleCmdExec(command); _redirect_console_to_client = INVALID_CLIENT_ID; this->rcon_auth_failures = 0;