aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/rng/rng.cpp
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2016-01-15 19:42:30 -0500
committerJack Lloyd <[email protected]>2016-07-17 10:43:34 -0400
commit8a1aead31c9ae9caa405c6951de8aa51d6a4b751 (patch)
treeac0c166c8b98a4c25b69c91aa4d5c2d0bc5bda42 /src/lib/rng/rng.cpp
parentcd1e2d3bff92a2d91343541e2cf83287dce87c6f (diff)
Switch to HMAC_DRBG for all RNG generation.
Add support and tests for additional_data param to HMAC_DRBG Add Stateful_RNG class which has fork detection and periodic reseeding. AutoSeeded_RNG passes the current pid and time as additional_data
Diffstat (limited to 'src/lib/rng/rng.cpp')
-rw-r--r--src/lib/rng/rng.cpp123
1 files changed, 114 insertions, 9 deletions
diff --git a/src/lib/rng/rng.cpp b/src/lib/rng/rng.cpp
index c17f23dd0..218b9c842 100644
--- a/src/lib/rng/rng.cpp
+++ b/src/lib/rng/rng.cpp
@@ -1,13 +1,17 @@
/*
* Random Number Generator
-* (C) 1999-2008 Jack Lloyd
+* (C) 1999-2008,2016 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#include <botan/rng.h>
-#include <botan/hmac_rng.h>
+#include <botan/hmac_drbg.h>
+#include <botan/auto_rng.h>
#include <botan/entropy_src.h>
+#include <botan/loadstor.h>
+#include <botan/internal/os_utils.h>
+#include <chrono>
namespace Botan {
@@ -25,18 +29,119 @@ size_t RandomNumberGenerator::reseed_with_timeout(size_t bits_to_collect,
timeout);
}
+size_t RandomNumberGenerator::reseed_with_sources(Entropy_Sources& srcs,
+ size_t poll_bits,
+ std::chrono::milliseconds poll_timeout)
+ {
+ typedef std::chrono::system_clock clock;
+
+ auto deadline = clock::now() + poll_timeout;
+
+ double bits_collected = 0;
+
+ Entropy_Accumulator accum([&](const byte in[], size_t in_len, double entropy_estimate) {
+ add_entropy(in, in_len);
+ bits_collected += entropy_estimate;
+ return (bits_collected >= poll_bits || clock::now() > deadline);
+ });
+
+ srcs.poll(accum);
+
+ return bits_collected;
+ }
+
+Stateful_RNG::Stateful_RNG(size_t bytes_before_reseed) :
+ m_max_bytes_before_reseed_required(bytes_before_reseed)
+ {
+ }
+
+size_t Stateful_RNG::reseed_with_sources(Entropy_Sources& srcs,
+ size_t poll_bits,
+ std::chrono::milliseconds poll_timeout)
+ {
+ size_t bits_collected = RandomNumberGenerator::reseed_with_sources(srcs, poll_bits, poll_timeout);
+
+ if(bits_collected >= poll_bits)
+ {
+ m_successful_initialization = true;
+ m_bytes_since_reseed = 0;
+ }
+
+ return bits_collected;
+ }
+
+void Stateful_RNG::reseed_check(size_t bytes_requested)
+ {
+ const bool fork_detected = (m_last_pid > 0) && (OS::get_process_id() != m_last_pid);
+
+ m_bytes_since_reseed += bytes_requested;
+ m_last_pid = OS::get_process_id();
+
+ if(!is_seeded() || fork_detected)
+ {
+ this->reseed(BOTAN_RNG_RESEED_POLL_BITS);
+ }
+ else if(m_max_bytes_before_reseed_required > 0 &&
+ m_bytes_since_reseed >= m_max_bytes_before_reseed_required)
+ {
+ this->reseed_with_timeout(BOTAN_RNG_AUTO_RESEED_POLL_BITS,
+ BOTAN_RNG_AUTO_RESEED_TIMEOUT);
+ }
+
+ if(!is_seeded())
+ {
+ throw PRNG_Unseeded(name());
+ }
+ }
+
+void Stateful_RNG::initialize_with(const byte input[], size_t len)
+ {
+ add_entropy(input, len);
+ m_successful_initialization = true;
+ }
+
+bool Stateful_RNG::is_seeded() const
+ {
+ return m_successful_initialization;
+ }
+
RandomNumberGenerator* RandomNumberGenerator::make_rng()
{
- std::unique_ptr<MessageAuthenticationCode> h1(MessageAuthenticationCode::create("HMAC(SHA-512)"));
- std::unique_ptr<MessageAuthenticationCode> h2(MessageAuthenticationCode::create("HMAC(SHA-512)"));
+ return new AutoSeeded_RNG;
+ }
+
+AutoSeeded_RNG::AutoSeeded_RNG(size_t max_bytes_before_reseed)
+ {
+ m_rng.reset(new HMAC_DRBG("SHA-384", max_bytes_before_reseed));
+ size_t bits = m_rng->reseed(384);
+ if(!m_rng->is_seeded())
+ {
+ throw Exception("AutoSeeded_RNG failed to gather enough entropy only got " +
+ std::to_string(bits) + " bits");
+ }
+ }
+
+void AutoSeeded_RNG::randomize(byte output[], size_t output_len)
+ {
+ /*
+ This data is not secret so skipping a vector/secure_vector allows
+ avoiding an allocation.
+ */
+ typedef std::chrono::high_resolution_clock clock;
+
+ byte nonce_buf[16] = { 0 };
+ const uint32_t cur_ctr = m_counter++;
+ const uint32_t cur_pid = OS::get_process_id();
+ const uint64_t cur_time = clock::now().time_since_epoch().count();
- if(!h1 || !h2)
- throw Algorithm_Not_Found("HMAC_RNG HMACs");
- std::unique_ptr<RandomNumberGenerator> rng(new HMAC_RNG(h1.release(), h2.release()));
+ store_le(cur_ctr, nonce_buf);
+ store_le(cur_pid, nonce_buf + 4);
+ store_le(cur_time, nonce_buf + 8);
- rng->reseed(256);
+ m_rng->randomize_with_input(output, output_len,
+ nonce_buf, sizeof(nonce_buf));
- return rng.release();
+ ++m_counter;
}
}