Improve wrapper around OpenSSL RAND

This commit is contained in:
Nik Bougalis
2022-05-21 20:42:30 -07:00
parent 0ecfc7cb1a
commit 7b3507bb87
2 changed files with 33 additions and 45 deletions

View File

@@ -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;

View File

@@ -17,7 +17,6 @@
*/
//==============================================================================
#include <ripple/basics/ByteUtilities.h>
#include <ripple/basics/contract.h>
#include <ripple/crypto/csprng.h>
#include <array>
@@ -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<std::runtime_error>("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,46 +57,44 @@ 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);
std::lock_guard lock(mutex_);
// 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);
// 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);
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<unsigned char*>(ptr), count);
if (result != 1)
Throw<std::runtime_error>("CSPRNG: Insufficient entropy");
}
csprng_engine::result_type
csprng_engine::operator()()
{
result_type ret;
std::lock_guard lock(mutex_);
auto const result =
RAND_bytes(reinterpret_cast<unsigned char*>(&ret), sizeof(ret));
if (result == 0)
Throw<std::runtime_error>("Insufficient entropy");
(*this)(&ret, sizeof(result_type));
return ret;
}
void
csprng_engine::operator()(void* ptr, std::size_t count)
{
std::lock_guard lock(mutex_);
auto const result =
RAND_bytes(reinterpret_cast<unsigned char*>(ptr), count);
if (result != 1)
Throw<std::runtime_error>("Insufficient entropy");
}
csprng_engine&
crypto_prng()
{