Merge #17573: Seed RNG with precision timestamps on receipt of net messages.

02d8c56a18 Seed RNG with precision timestamps on receipt of net messages. (Matt Corallo)

Pull request description:

  See title. Exposes a generic dead-simple "SeedEvent" interface, but currently just used for net messages.

ACKs for top commit:
  sipa:
    utACK 02d8c56a18
  laanwj:
    ACK 02d8c56a18
  meshcollider:
    utACK 02d8c56a18

Tree-SHA512: 28eb39a201ee2b13393c5c64dbf7c1913f3482f095969ef5141bfe549ce77dd63bb5f14738f6eedb296c686ea36014aa157b9c5e8059710a318590f30e9caa14
pull/17666/head
Wladimir J. van der Laan 5 years ago
commit 41919631d5
No known key found for this signature in database
GPG Key ID: 1E4AED62986CD25D

@ -16,6 +16,7 @@
#include <crypto/sha256.h> #include <crypto/sha256.h>
#include <netbase.h> #include <netbase.h>
#include <net_permissions.h> #include <net_permissions.h>
#include <random.h>
#include <scheduler.h> #include <scheduler.h>
#include <ui_interface.h> #include <ui_interface.h>
#include <util/strencodings.h> #include <util/strencodings.h>
@ -445,6 +446,9 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, addr_bind, pszDest ? pszDest : "", false, block_relay_only); CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, addr_bind, pszDest ? pszDest : "", false, block_relay_only);
pnode->AddRef(); pnode->AddRef();
// We're making a new connection, harvest entropy from the time (and our peer count)
RandAddEvent((uint32_t)id);
return pnode; return pnode;
} }
@ -693,6 +697,9 @@ CNetMessage V1TransportDeserializer::GetMessage(const CMessageHeader::MessageSta
msg.m_message_size = hdr.nMessageSize; msg.m_message_size = hdr.nMessageSize;
msg.m_raw_message_size = hdr.nMessageSize + CMessageHeader::HEADER_SIZE; msg.m_raw_message_size = hdr.nMessageSize + CMessageHeader::HEADER_SIZE;
// We just received a message off the wire, harvest entropy from the time (and the message checksum)
RandAddEvent(ReadLE32(hash.begin()));
msg.m_valid_checksum = (memcmp(hash.begin(), hdr.pchChecksum, CMessageHeader::CHECKSUM_SIZE) == 0); msg.m_valid_checksum = (memcmp(hash.begin(), hdr.pchChecksum, CMessageHeader::CHECKSUM_SIZE) == 0);
if (!msg.m_valid_checksum) { if (!msg.m_valid_checksum) {
LogPrint(BCLog::NET, "CHECKSUM ERROR (%s, %u bytes), expected %s was %s\n", LogPrint(BCLog::NET, "CHECKSUM ERROR (%s, %u bytes), expected %s was %s\n",
@ -1017,6 +1024,9 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
LOCK(cs_vNodes); LOCK(cs_vNodes);
vNodes.push_back(pnode); vNodes.push_back(pnode);
} }
// We received a new connection, harvest entropy from the time (and our peer count)
RandAddEvent((uint32_t)id);
} }
void CConnman::DisconnectNodes() void CConnman::DisconnectNodes()

@ -6,6 +6,7 @@
#include <random.h> #include <random.h>
#include <compat/cpuid.h> #include <compat/cpuid.h>
#include <crypto/sha256.h>
#include <crypto/sha512.h> #include <crypto/sha512.h>
#include <support/cleanse.h> #include <support/cleanse.h>
#ifdef WIN32 #ifdef WIN32
@ -449,6 +450,23 @@ static void SeedFast(CSHA512& hasher) noexcept
SeedTimestamp(hasher); SeedTimestamp(hasher);
} }
// We use only SHA256 for the events hashing to get the ASM speedups we have for SHA256,
// since we want it to be fast as network peers may be able to trigger it repeatedly.
static Mutex events_mutex;
static CSHA256 events_hasher;
static void SeedEvents(CSHA512& hasher)
{
LOCK(events_mutex);
unsigned char events_hash[32];
events_hasher.Finalize(events_hash);
hasher.Write(events_hash, 32);
// Re-initialize the hasher with the finalized state to use later.
events_hasher.Reset();
events_hasher.Write(events_hash, 32);
}
static void SeedSlow(CSHA512& hasher) noexcept static void SeedSlow(CSHA512& hasher) noexcept
{ {
unsigned char buffer[32]; unsigned char buffer[32];
@ -460,6 +478,9 @@ static void SeedSlow(CSHA512& hasher) noexcept
GetOSRand(buffer); GetOSRand(buffer);
hasher.Write(buffer, sizeof(buffer)); hasher.Write(buffer, sizeof(buffer));
// Add the events hasher into the mix
SeedEvents(hasher);
// High-precision timestamp. // High-precision timestamp.
// //
// Note that we also commit to a timestamp in the Fast seeder, so we indirectly commit to a // Note that we also commit to a timestamp in the Fast seeder, so we indirectly commit to a
@ -485,6 +506,9 @@ static void SeedPeriodic(CSHA512& hasher, RNGState& rng)
// High-precision timestamp // High-precision timestamp
SeedTimestamp(hasher); SeedTimestamp(hasher);
// Add the events hasher into the mix
SeedEvents(hasher);
// Dynamic environment data (performance monitoring, ...) // Dynamic environment data (performance monitoring, ...)
auto old_size = hasher.Size(); auto old_size = hasher.Size();
RandAddDynamicEnv(hasher); RandAddDynamicEnv(hasher);
@ -553,6 +577,15 @@ void GetRandBytes(unsigned char* buf, int num) noexcept { ProcRand(buf, num, RNG
void GetStrongRandBytes(unsigned char* buf, int num) noexcept { ProcRand(buf, num, RNGLevel::SLOW); } void GetStrongRandBytes(unsigned char* buf, int num) noexcept { ProcRand(buf, num, RNGLevel::SLOW); }
void RandAddPeriodic() { ProcRand(nullptr, 0, RNGLevel::PERIODIC); } void RandAddPeriodic() { ProcRand(nullptr, 0, RNGLevel::PERIODIC); }
void RandAddEvent(const uint32_t event_info) {
LOCK(events_mutex);
events_hasher.Write((const unsigned char *)&event_info, sizeof(event_info));
// Get the low four bytes of the performance counter. This translates to roughly the
// subsecond part.
uint32_t perfcounter = (GetPerformanceCounter() & 0xffffffff);
events_hasher.Write((const unsigned char*)&perfcounter, sizeof(perfcounter));
}
bool g_mock_deterministic_tests{false}; bool g_mock_deterministic_tests{false};
uint64_t GetRand(uint64_t nMax) noexcept uint64_t GetRand(uint64_t nMax) noexcept

@ -89,6 +89,14 @@ void GetStrongRandBytes(unsigned char* buf, int num) noexcept;
*/ */
void RandAddPeriodic(); void RandAddPeriodic();
/**
* Gathers entropy from the low bits of the time at which events occur. Should
* be called with a uint32_t describing the event at the time an event occurs.
*
* Thread-safe.
*/
void RandAddEvent(const uint32_t event_info);
/** /**
* Fast randomness source. This is seeded once with secure random data, but * Fast randomness source. This is seeded once with secure random data, but
* is completely deterministic and does not gather more entropy after that. * is completely deterministic and does not gather more entropy after that.

Loading…
Cancel
Save