diff options
author | Jack Lloyd <[email protected]> | 2016-01-15 19:42:30 -0500 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2016-07-17 10:43:34 -0400 |
commit | 8a1aead31c9ae9caa405c6951de8aa51d6a4b751 (patch) | |
tree | ac0c166c8b98a4c25b69c91aa4d5c2d0bc5bda42 /src/lib/rng/rng.cpp | |
parent | cd1e2d3bff92a2d91343541e2cf83287dce87c6f (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.cpp | 123 |
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; } } |