Skip to content

Commit

Permalink
Abstract out seeding/extracting entropy into RNGState::MixExtract
Browse files Browse the repository at this point in the history
  • Loading branch information
sipa authored and Fuzzbawls committed Apr 14, 2021
1 parent 298f97c commit 5f20e62
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 25 deletions.
2 changes: 1 addition & 1 deletion src/crypto/sha512.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class CSHA512
size_t bytes;

public:
static const size_t OUTPUT_SIZE = 64;
static constexpr size_t OUTPUT_SIZE = 64;

CSHA512();
CSHA512& Write(const unsigned char* data, size_t len);
Expand Down
60 changes: 36 additions & 24 deletions src/random.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,34 @@ struct RNGState {
{
InitHardwareRand();
}

/** Extract up to 32 bytes of entropy from the RNG state, mixing in new entropy from hasher. */
void MixExtract(unsigned char* out, size_t num, CSHA512&& hasher)
{
assert(num <= 32);
unsigned char buf[64];
static_assert(sizeof(buf) == CSHA512::OUTPUT_SIZE, "Buffer needs to have hasher's output size");
{
LOCK(m_mutex);
// Write the current state of the RNG into the hasher
hasher.Write(m_state, 32);
// Write a new counter number into the state
hasher.Write((const unsigned char*)&m_counter, sizeof(m_counter));
++m_counter;
// Finalize the hasher
hasher.Finalize(buf);
// Store the last 32 bytes of the hash output as new RNG state.
memcpy(m_state, buf + 32, 32);
}
// If desired, copy (up to) the first 32 bytes of the hash output as output.
if (num) {
assert(out != nullptr);
memcpy(out, buf, num);
}
// Best effort cleanup of internal state
hasher.Reset();
memory_cleanse(buf, 64);
}
};

RNGState& GetRNGState()
Expand All @@ -315,38 +343,29 @@ RNGState& GetRNGState()
}
}

static void AddDataToRng(void* data, size_t len);
static void AddDataToRng(void* data, size_t len, RNGState& rng);

void RandAddSeedSleep()
{
RNGState& rng = GetRNGState();

int64_t nPerfCounter1 = GetPerformanceCounter();
std::this_thread::sleep_for(std::chrono::milliseconds(1));
int64_t nPerfCounter2 = GetPerformanceCounter();

// Combine with and update state
AddDataToRng(&nPerfCounter1, sizeof(nPerfCounter1));
AddDataToRng(&nPerfCounter2, sizeof(nPerfCounter2));
AddDataToRng(&nPerfCounter1, sizeof(nPerfCounter1), rng);
AddDataToRng(&nPerfCounter2, sizeof(nPerfCounter2), rng);

memory_cleanse(&nPerfCounter1, sizeof(nPerfCounter1));
memory_cleanse(&nPerfCounter2, sizeof(nPerfCounter2));
}

static void AddDataToRng(void* data, size_t len) {
RNGState& rng = GetRNGState();

static void AddDataToRng(void* data, size_t len, RNGState& rng) {
CSHA512 hasher;
hasher.Write((const unsigned char*)&len, sizeof(len));
hasher.Write((const unsigned char*)data, len);
unsigned char buf[64];
{
WAIT_LOCK(rng.m_mutex, lock);
hasher.Write(rng.m_state, sizeof(rng.m_state));
hasher.Write((const unsigned char*)&rng.m_counter, sizeof(rng.m_counter));
++rng.m_counter;
hasher.Finalize(buf);
memcpy(rng.m_state, buf + 32, 32);
}
memory_cleanse(buf, 64);
rng.MixExtract(nullptr, 0, std::move(hasher));
}

void GetStrongRandBytes(unsigned char* out, int num)
Expand All @@ -372,14 +391,7 @@ void GetStrongRandBytes(unsigned char* out, int num)
}

// Combine with and update state
{
WAIT_LOCK(rng.m_mutex, lock);
hasher.Write(rng.m_state, sizeof(rng.m_state));
hasher.Write((const unsigned char*)&rng.m_counter, sizeof(rng.m_counter));
++rng.m_counter;
hasher.Finalize(buf);
memcpy(rng.m_state, buf + 32, 32);
}
rng.MixExtract(out, num, std::move(hasher));

// Produce output
memcpy(out, buf, num);
Expand Down

0 comments on commit 5f20e62

Please sign in to comment.