Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve wrapper around OpenSSL RAND #4174

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions src/ripple/crypto/csprng.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
65 changes: 28 additions & 37 deletions src/ripple/crypto/impl/csprng.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
*/
//==============================================================================

#include <ripple/basics/ByteUtilities.h>
#include <ripple/basics/contract.h>
#include <ripple/crypto/csprng.h>
#include <array>
Expand All @@ -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
Expand All @@ -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<unsigned char*>(&ret), sizeof(ret));

if (result == 0)
Throw<std::runtime_error>("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<unsigned char*>(ptr), count);

if (result != 1)
Throw<std::runtime_error>("Insufficient entropy");
Throw<std::runtime_error>("CSPRNG: Insufficient entropy");
}

csprng_engine::result_type
csprng_engine::operator()()
{
result_type ret;
(*this)(&ret, sizeof(result_type));
return ret;
}

csprng_engine&
Expand Down