diff --git a/src/ripple/crypto/csprng.h b/src/ripple/crypto/csprng.h index 39506324963..3ad5d700046 100644 --- a/src/ripple/crypto/csprng.h +++ b/src/ripple/crypto/csprng.h @@ -39,9 +39,6 @@ class csprng_engine private: std::mutex mutex_; - void - mix(void* buffer, std::size_t count, double bitsPerByte); - public: using result_type = std::uint64_t; diff --git a/src/ripple/crypto/impl/csprng.cpp b/src/ripple/crypto/impl/csprng.cpp index a166fe28807..04b3b3fc385 100644 --- a/src/ripple/crypto/impl/csprng.cpp +++ b/src/ripple/crypto/impl/csprng.cpp @@ -17,7 +17,6 @@ */ //============================================================================== -#include #include #include #include @@ -28,25 +27,19 @@ namespace ripple { -void -csprng_engine::mix(void* data, std::size_t size, double bitsPerByte) -{ - assert(data != nullptr); - assert(size != 0); - assert(bitsPerByte != 0); - - std::lock_guard lock(mutex_); - RAND_add(data, size, (size * bitsPerByte) / 8.0); -} - csprng_engine::csprng_engine() { - mix_entropy(); + // This is not strictly necessary + if (RAND_poll() != 1) + Throw("CSPRNG: Initial polling failed"); } csprng_engine::~csprng_engine() { + // This cleanup function is not needed in newer versions of OpenSSL +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) RAND_cleanup(); +#endif } void @@ -64,44 +57,42 @@ csprng_engine::mix_entropy(void* buffer, std::size_t count) e = rd(); } - // Assume 2 bits per byte for the system entropy: - mix(entropy.data(), - entropy.size() * sizeof(std::random_device::result_type), - 2.0); - - // We want to be extremely conservative about estimating - // how much entropy the buffer the user gives us contains - // and assume only 0.5 bits of entropy per byte: - if (buffer != nullptr && count != 0) - mix(buffer, count, 0.5); -} - -csprng_engine::result_type -csprng_engine::operator()() -{ - result_type ret; - std::lock_guard lock(mutex_); - auto const result = - RAND_bytes(reinterpret_cast(&ret), sizeof(ret)); - - if (result == 0) - Throw("Insufficient entropy"); + // We add data to the pool, but we conservatively assume that + // it contributes no actual entropy. + RAND_add( + entropy.data(), + entropy.size() * sizeof(std::random_device::result_type), + 0); - return ret; + if (buffer != nullptr && count != 0) + RAND_add(buffer, count, 0); } void csprng_engine::operator()(void* ptr, std::size_t count) { + // RAND_bytes is thread-safe on OpenSSL 1.1.0 and later when compiled + // with thread support, so we don't need to grab a mutex. + // https://mta.openssl.org/pipermail/openssl-users/2020-November/013146.html +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || !defined(OPENSSL_THREADS) std::lock_guard lock(mutex_); +#endif auto const result = RAND_bytes(reinterpret_cast(ptr), count); if (result != 1) - Throw("Insufficient entropy"); + Throw("CSPRNG: Insufficient entropy"); +} + +csprng_engine::result_type +csprng_engine::operator()() +{ + result_type ret; + (*this)(&ret, sizeof(result_type)); + return ret; } csprng_engine&