From 02d8c56a18b9a2960888d6ec1209955105bae847 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Sat, 23 Nov 2019 11:42:23 -0500 Subject: [PATCH] Seed RNG with precision timestamps on receipt of net messages. --- src/net.cpp | 10 ++++++++++ src/random.cpp | 33 +++++++++++++++++++++++++++++++++ src/random.h | 8 ++++++++ 3 files changed, 51 insertions(+) diff --git a/src/net.cpp b/src/net.cpp index 84692d2a79a..99dae88bab7 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -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); pnode->AddRef(); + // We're making a new connection, harvest entropy from the time (and our peer count) + RandAddEvent((uint32_t)id); + return pnode; } @@ -693,6 +697,9 @@ CNetMessage V1TransportDeserializer::GetMessage(const CMessageHeader::MessageSta msg.m_message_size = hdr.nMessageSize; 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); if (!msg.m_valid_checksum) { 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); 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() diff --git a/src/random.cpp b/src/random.cpp index 47d76d87007..09777237c20 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #ifdef WIN32 @@ -449,6 +450,23 @@ static void SeedFast(CSHA512& hasher) noexcept 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 { unsigned char buffer[32]; @@ -460,6 +478,9 @@ static void SeedSlow(CSHA512& hasher) noexcept GetOSRand(buffer); hasher.Write(buffer, sizeof(buffer)); + // Add the events hasher into the mix + SeedEvents(hasher); + // High-precision timestamp. // // 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 SeedTimestamp(hasher); + // Add the events hasher into the mix + SeedEvents(hasher); + // Dynamic environment data (performance monitoring, ...) auto old_size = hasher.Size(); 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 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}; uint64_t GetRand(uint64_t nMax) noexcept diff --git a/src/random.h b/src/random.h index 2d8ab085e3a..b6e70fcb1fc 100644 --- a/src/random.h +++ b/src/random.h @@ -89,6 +89,14 @@ void GetStrongRandBytes(unsigned char* buf, int num) noexcept; */ 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 * is completely deterministic and does not gather more entropy after that.