diff options
Diffstat (limited to 'src/lib/rng/rng.cpp')
-rw-r--r-- | src/lib/rng/rng.cpp | 120 |
1 files changed, 111 insertions, 9 deletions
diff --git a/src/lib/rng/rng.cpp b/src/lib/rng/rng.cpp index c17f23dd0..5501c143e 100644 --- a/src/lib/rng/rng.cpp +++ b/src/lib/rng/rng.cpp @@ -1,13 +1,23 @@ /* * 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/auto_rng.h> #include <botan/entropy_src.h> +#include <botan/loadstor.h> +#include <botan/internal/os_utils.h> + +#if defined(BOTAN_HAS_HMAC_DRBG) + #include <botan/hmac_drbg.h> +#endif + +#if defined(BOTAN_HAS_HMAC_RNG) + #include <botan/hmac_rng.h> +#endif namespace Botan { @@ -25,18 +35,110 @@ 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) + { + return srcs.poll(*this, poll_bits, poll_timeout); + } + +Stateful_RNG::Stateful_RNG(size_t max_output_before_reseed) : m_max_output_before_reseed(max_output_before_reseed) + { + } + +void Stateful_RNG::clear() + { + m_successful_initialization = false; + m_bytes_since_reseed = 0; + m_last_pid = 0; + } + +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_output_before_reseed > 0 && m_bytes_since_reseed >= m_max_output_before_reseed) + { + this->reseed_with_timeout(BOTAN_RNG_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; + } - if(!h1 || !h2) - throw Algorithm_Not_Found("HMAC_RNG HMACs"); - std::unique_ptr<RandomNumberGenerator> rng(new HMAC_RNG(h1.release(), h2.release())); +AutoSeeded_RNG::AutoSeeded_RNG(size_t max_output_before_reseed) + { + m_rng.reset(new BOTAN_AUTO_RNG_DRBG(BOTAN_AUTO_RNG_HASH, max_output_before_reseed)); - rng->reseed(256); + size_t bits = m_rng->reseed(BOTAN_AUTO_RNG_ENTROPY_TARGET); - return rng.release(); + 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) + { + /* + Form additional input which is provided to the PRNG implementation + to paramaterize the KDF output. + */ + byte additional_input[24] = { 0 }; + store_le(OS::get_system_timestamp_ns(), additional_input); + store_le(OS::get_processor_timestamp(), additional_input + 8); + store_le(OS::get_process_id(), additional_input + 16); + store_le(m_counter++, additional_input + 20); + + randomize_with_input(output, output_len, additional_input, sizeof(additional_input)); + } + +void AutoSeeded_RNG::randomize_with_input(byte output[], size_t output_len, + const byte ad[], size_t ad_len) + { + m_rng->randomize_with_input(output, output_len, ad, ad_len); } } |