Replace NetworkRandomBytesWithFallback with RandomBytesWithFallback

Replace related key/data arrays with std::array
This commit is contained in:
Jonathan G Rennison
2024-02-06 18:51:33 +00:00
parent bb627e944c
commit f44ec32011
4 changed files with 77 additions and 80 deletions

View File

@@ -39,11 +39,11 @@
#include "../string_func.h" #include "../string_func.h"
#include "../string_func_extra.h" #include "../string_func_extra.h"
#include "../core/serialisation.hpp" #include "../core/serialisation.hpp"
#include "../3rdparty/randombytes/randombytes.h"
#include "../3rdparty/monocypher/monocypher.h" #include "../3rdparty/monocypher/monocypher.h"
#include "../settings_internal.h" #include "../settings_internal.h"
#include <sstream> #include <sstream>
#include <iomanip> #include <iomanip>
#include <tuple>
#ifdef DEBUG_DUMP_COMMANDS #ifdef DEBUG_DUMP_COMMANDS
#include "../fileio_func.h" #include "../fileio_func.h"
@@ -1371,7 +1371,7 @@ static void NetworkGenerateServerId()
std::string NetworkGenerateRandomKeyString(uint bytes) std::string NetworkGenerateRandomKeyString(uint bytes)
{ {
uint8_t *key = AllocaM(uint8_t, bytes); uint8_t *key = AllocaM(uint8_t, bytes);
NetworkRandomBytesWithFallback(key, bytes); RandomBytesWithFallback({ key, bytes });
return FormatArrayAsHex({key, bytes}); return FormatArrayAsHex({key, bytes});
} }
@@ -1416,26 +1416,16 @@ void NetworkShutDown()
NetworkCoreShutdown(); 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<byte *>(buf)[i] = (byte)InteractiveRandom();
}
}
}
void NetworkGameKeys::Initialise() void NetworkGameKeys::Initialise()
{ {
assert(!this->inited); assert(!this->inited);
this->inited = true; this->inited = true;
static_assert(sizeof(this->x25519_priv_key) == 32); static_assert(std::tuple_size<decltype(NetworkGameKeys::x25519_priv_key)>::value == 32);
NetworkRandomBytesWithFallback(this->x25519_priv_key, sizeof(this->x25519_priv_key)); static_assert(std::tuple_size<decltype(NetworkGameKeys::x25519_pub_key)>::value == 32);
crypto_x25519_public_key(this->x25519_pub_key, this->x25519_priv_key); RandomBytesWithFallback(this->x25519_priv_key);
crypto_x25519_public_key(this->x25519_pub_key.data(), this->x25519_priv_key.data());
} }
NetworkSharedSecrets::~NetworkSharedSecrets() NetworkSharedSecrets::~NetworkSharedSecrets()

View File

@@ -36,6 +36,8 @@
#include "../debug_settings.h" #include "../debug_settings.h"
#include "../3rdparty/monocypher/monocypher.h" #include "../3rdparty/monocypher/monocypher.h"
#include <tuple>
#include "table/strings.h" #include "table/strings.h"
#include "../safeguards.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. */ /** One bit of 'entropy' used to generate a salt for the company passwords. */
static uint32_t _company_password_game_seed; static uint32_t _company_password_game_seed;
/** Network server's x25519 public key, used for key derivation */ /** Network server's x25519 public key, used for key derivation */
static byte _server_x25519_pub_key[32]; static std::array<byte, 32> _server_x25519_pub_key;
/** Key message ID counter */ /** Key message ID counter */
static uint64_t _next_key_message_id; static uint64_t _next_key_message_id;
/** The other bit of 'entropy' used to generate a salt for the server, rcon, and settings passwords. */ /** 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(); const NetworkGameKeys &keys = this->GetKeys();
byte shared_secret[32]; // Shared secret std::array<uint8_t, 32> shared_secret; // Shared secret
crypto_x25519(shared_secret, keys.x25519_priv_key, _server_x25519_pub_key); crypto_x25519(shared_secret.data(), keys.x25519_priv_key.data(), _server_x25519_pub_key.data());
if (std::all_of(shared_secret, shared_secret + 32, [](auto v) { return v == 0; })) { 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 */ /* Secret is all 0 because public key is all 0, just give up at this point */
return NETWORK_RECV_STATUS_MALFORMED_PACKET; return NETWORK_RECV_STATUS_MALFORMED_PACKET;
} }
crypto_blake2b_ctx ctx; crypto_blake2b_ctx ctx;
crypto_blake2b_init (&ctx, 64); crypto_blake2b_init (&ctx, ss.shared_data.size());
crypto_blake2b_update(&ctx, shared_secret, 32); // Shared secret crypto_blake2b_update(&ctx, shared_secret.data(), shared_secret.size()); // Shared secret
crypto_blake2b_update(&ctx, keys.x25519_pub_key, 32); // Client pub key 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, 32); // Server 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_update(&ctx, (const byte *)password.data(), password.size()); // Password
crypto_blake2b_final (&ctx, ss.shared_data); 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) */ /* 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<byte> message; std::vector<byte> message;
BufferSerialiser buffer(message); BufferSerialiser buffer(message);
@@ -446,20 +448,22 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendKeyPasswordPacket(PacketTy
if (payload != nullptr) buffer.Send_string(*payload); if (payload != nullptr) buffer.Send_string(*payload);
/* Message authentication code */ /* Message authentication code */
uint8_t mac[16]; std::array<uint8_t, 16> mac;
/* Use only once per key: random */ /* Use only once per key: random */
uint8_t nonce[24]; std::array<uint8_t, 24> nonce;
NetworkRandomBytesWithFallback(nonce, 24); RandomBytesWithFallback(nonce);
/* Encrypt in place, use first half of hash as key */ /* 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<decltype(ss.shared_data)>::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); Packet *p = new Packet(packet_type, SHRT_MAX);
p->Send_binary(keys.x25519_pub_key, 32); static_assert(std::tuple_size<decltype(keys.x25519_pub_key)>::value == 32);
p->Send_binary(nonce, 24); p->Send_binary(keys.x25519_pub_key);
p->Send_binary(mac, 16); p->Send_binary(nonce);
p->Send_binary(message.data(), message.size()); p->Send_binary(mac);
p->Send_binary(message);
_next_key_message_id++; _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; if (this->status < STATUS_JOIN || this->status >= STATUS_AUTH_GAME) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
this->status = STATUS_AUTH_GAME; this->status = STATUS_AUTH_GAME;
static_assert(sizeof(_server_x25519_pub_key) == 32); static_assert(_server_x25519_pub_key.size() == 32);
p->Recv_binary(_server_x25519_pub_key, sizeof(_server_x25519_pub_key)); p->Recv_binary(_server_x25519_pub_key);
_password_server_id = p->Recv_string(NETWORK_SERVER_ID_LENGTH); _password_server_id = p->Recv_string(NETWORK_SERVER_ID_LENGTH);
if (this->HasClientQuit()) return NETWORK_RECV_STATUS_MALFORMED_PACKET; 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. */ /* Initialize the password hash salting variables, even if they were previously. */
_company_password_game_seed = p->Recv_uint32(); _company_password_game_seed = p->Recv_uint32();
static_assert(sizeof(_server_x25519_pub_key) == 32); static_assert(_server_x25519_pub_key.size() == 32);
p->Recv_binary(_server_x25519_pub_key, sizeof(_server_x25519_pub_key)); p->Recv_binary(_server_x25519_pub_key);
_password_server_id = p->Recv_string(NETWORK_SERVER_ID_LENGTH); _password_server_id = p->Recv_string(NETWORK_SERVER_ID_LENGTH);
_company_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; return NETWORK_RECV_STATUS_OKAY;
} }
byte nonce[24]; std::array<uint8_t, 24> nonce;
byte mac[16]; std::array<uint8_t, 16> mac;
p->Recv_binary(nonce, 24); p->Recv_binary(nonce);
p->Recv_binary(mac, 16); p->Recv_binary(mac);
std::vector<byte> message = p->Recv_binary(p->RemainingBytesToTransfer()); std::vector<byte> 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<decltype(NetworkSharedSecrets::shared_data)>::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); SubPacketDeserialiser spd(p, message);
TextColour colour_code = (TextColour)spd.Recv_uint16(); TextColour colour_code = (TextColour)spd.Recv_uint16();
if (!IsValidConsoleColour(colour_code)) return NETWORK_RECV_STATUS_MALFORMED_PACKET; if (!IsValidConsoleColour(colour_code)) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
@@ -1454,7 +1459,7 @@ std::string ClientNetworkGameSocketHandler::GetDebugInfo() const
static void ResetClientConnectionKeyStates() static void ResetClientConnectionKeyStates()
{ {
_next_key_message_id = 0; _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());
} }

View File

@@ -18,6 +18,7 @@
#include "../command_type.h" #include "../command_type.h"
#include "../date_type.h" #include "../date_type.h"
#include <array>
#include <vector> #include <vector>
static const uint32_t FIND_SERVER_EXTENDED_TOKEN = 0x2A49582A; static const uint32_t FIND_SERVER_EXTENDED_TOKEN = 0x2A49582A;
@@ -103,15 +104,15 @@ void NetworkRebuildHostList();
void UpdateNetworkGameWindow(); void UpdateNetworkGameWindow();
struct NetworkGameKeys { struct NetworkGameKeys {
byte x25519_priv_key[32]; ///< x25519 key: private part std::array<uint8_t, 32> x25519_priv_key; ///< x25519 key: private part
byte x25519_pub_key[32]; ///< x25519 key: public part std::array<uint8_t, 32> x25519_pub_key; ///< x25519 key: public part
bool inited = false; bool inited = false;
void Initialise(); void Initialise();
}; };
struct NetworkSharedSecrets { struct NetworkSharedSecrets {
byte shared_data[64]; std::array<uint8_t, 64> shared_data;
~NetworkSharedSecrets(); ~NetworkSharedSecrets();
}; };
@@ -150,6 +151,4 @@ std::string NormalizeConnectionString(const std::string &connection_string, uint
void ClientNetworkEmergencySave(); void ClientNetworkEmergencySave();
void NetworkRandomBytesWithFallback(void *buf, size_t n);
#endif /* NETWORK_INTERNAL_H */ #endif /* NETWORK_INTERNAL_H */

View File

@@ -30,10 +30,10 @@
#include "../core/random_func.hpp" #include "../core/random_func.hpp"
#include "../rev.h" #include "../rev.h"
#include "../crashlog.h" #include "../crashlog.h"
#include "../3rdparty/randombytes/randombytes.h"
#include "../3rdparty/monocypher/monocypher.h" #include "../3rdparty/monocypher/monocypher.h"
#include <mutex> #include <mutex>
#include <condition_variable> #include <condition_variable>
#include <tuple>
#include "../safeguards.h" #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) bool ServerNetworkGameSocketHandler::ParseKeyPasswordPacket(Packet *p, NetworkSharedSecrets &ss, const std::string &password, std::string *payload, size_t length)
{ {
byte client_pub_key[32]; std::array<uint8_t, 32> client_pub_key;
byte nonce[24]; std::array<uint8_t, 24> nonce;
byte mac[16]; std::array<uint8_t, 16> mac;
p->Recv_binary(client_pub_key, 32); p->Recv_binary(client_pub_key);
p->Recv_binary(nonce, 24); p->Recv_binary(nonce);
p->Recv_binary(mac, 16); p->Recv_binary(mac);
const NetworkGameKeys &keys = this->GetKeys(); const NetworkGameKeys &keys = this->GetKeys();
byte shared_secret[32]; // Shared secret std::array<uint8_t, 32> shared_secret; // Shared secret
crypto_x25519(shared_secret, keys.x25519_priv_key, client_pub_key); crypto_x25519(shared_secret.data(), keys.x25519_priv_key.data(), client_pub_key.data());
if (std::all_of(shared_secret, shared_secret + 32, [](auto v) { return v == 0; })) { 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 */ /* Secret is all 0 because public key is all 0, just reject it */
return false; return false;
} }
crypto_blake2b_ctx ctx; crypto_blake2b_ctx ctx;
crypto_blake2b_init (&ctx, 64); crypto_blake2b_init (&ctx, ss.shared_data.size());
crypto_blake2b_update(&ctx, shared_secret, 32); // Shared secret crypto_blake2b_update(&ctx, shared_secret.data(), shared_secret.size()); // Shared secret
crypto_blake2b_update(&ctx, client_pub_key, 32); // Client pub key crypto_blake2b_update(&ctx, client_pub_key.data(), client_pub_key.size()); // Client pub key
crypto_blake2b_update(&ctx, keys.x25519_pub_key, 32); // Server 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_update(&ctx, (const byte *)password.data(), password.size()); // Password
crypto_blake2b_final (&ctx, ss.shared_data); 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) */ /* 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<byte> message = p->Recv_binary(p->RemainingBytesToTransfer()); std::vector<byte> message = p->Recv_binary(p->RemainingBytesToTransfer());
if (message.size() < 8) return false; 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 */ /* 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<decltype(ss.shared_data)>::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); SubPacketDeserialiser spd(p, message);
uint64_t message_id = spd.Recv_uint64(); uint64_t message_id = spd.Recv_uint64();
if (message_id < this->min_key_message_id) { if (message_id < this->min_key_message_id) {
@@ -525,8 +526,8 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendNeedGamePassword()
const NetworkGameKeys &keys = this->GetKeys(); const NetworkGameKeys &keys = this->GetKeys();
Packet *p = new Packet(PACKET_SERVER_NEED_GAME_PASSWORD, SHRT_MAX); Packet *p = new Packet(PACKET_SERVER_NEED_GAME_PASSWORD, SHRT_MAX);
static_assert(sizeof(keys.x25519_pub_key) == 32); static_assert(std::tuple_size<decltype(keys.x25519_pub_key)>::value == 32);
p->Send_binary(keys.x25519_pub_key, sizeof(keys.x25519_pub_key)); p->Send_binary(keys.x25519_pub_key);
p->Send_string(_settings_client.network.network_id); p->Send_string(_settings_client.network.network_id);
this->SendPacket(p); this->SendPacket(p);
return NETWORK_RECV_STATUS_OKAY; return NETWORK_RECV_STATUS_OKAY;
@@ -568,8 +569,8 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendWelcome()
p = new Packet(PACKET_SERVER_WELCOME, SHRT_MAX); p = new Packet(PACKET_SERVER_WELCOME, SHRT_MAX);
p->Send_uint32(this->client_id); p->Send_uint32(this->client_id);
p->Send_uint32(_settings_game.game_creation.generation_seed); p->Send_uint32(_settings_game.game_creation.generation_seed);
static_assert(sizeof(keys.x25519_pub_key) == 32); static_assert(std::tuple_size<decltype(keys.x25519_pub_key)>::value == 32);
p->Send_binary(keys.x25519_pub_key, sizeof(keys.x25519_pub_key)); p->Send_binary(keys.x25519_pub_key);
p->Send_string(_settings_client.network.network_id); p->Send_string(_settings_client.network.network_id);
p->Send_string(_network_company_server_id); p->Send_string(_network_company_server_id);
this->SendPacket(p); this->SendPacket(p);
@@ -845,19 +846,21 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendRConResult(uint16_t colour
buffer.Send_string(command); buffer.Send_string(command);
/* Message authentication code */ /* Message authentication code */
uint8_t mac[16]; std::array<uint8_t, 16> mac;
/* Use only once per key: random */ /* Use only once per key: random */
uint8_t nonce[24]; std::array<uint8_t, 24> nonce;
NetworkRandomBytesWithFallback(nonce, 24); RandomBytesWithFallback(nonce);
/* Encrypt in place, use first half of hash as key */ /* 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); Packet *p = new Packet(PACKET_SERVER_RCON, SHRT_MAX);
p->Send_binary(nonce, 24); static_assert(nonce.size() == 24);
p->Send_binary(mac, 16); static_assert(mac.size() == 16);
p->Send_binary(message.data(), message.size()); p->Send_binary(nonce);
p->Send_binary(mac);
p->Send_binary(message);
this->SendPacket(p); this->SendPacket(p);
return NETWORK_RECV_STATUS_OKAY; 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()); DEBUG(net, 3, "[rcon] Client-id %d executed: %s", this->client_id, command.c_str());
_redirect_console_to_client = this->client_id; _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); IConsoleCmdExec(command);
_redirect_console_to_client = INVALID_CLIENT_ID; _redirect_console_to_client = INVALID_CLIENT_ID;
this->rcon_auth_failures = 0; this->rcon_auth_failures = 0;