diff options
author | Jack Lloyd <[email protected]> | 2016-08-19 07:51:47 -0400 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2016-08-24 11:31:54 -0400 |
commit | 80c160f08f2a69eb4e41a68380796bf31fd2f924 (patch) | |
tree | 83259da316524ed3b96b0913e5b023bc40f26a28 /src/lib/rng/rng.cpp | |
parent | 91474f60d72937ad3c21d8aa53c14f7a0cceb9ca (diff) |
RNG changes (GH #593)
Change reseed interval logic to count calls to `randomize` rather than
bytes, to match SP 800-90A
Changes RNG reseeding API: there is no implicit reference to the
global entropy sources within the RNGs anymore. The entropy sources
must be supplied with the API call. Adds support for reseding directly
from another RNG (such as a system or hardware RNG).
Stateful_RNG keeps optional references to both an RNG and a set of
entropy sources. During a reseed, both sources are used if set.
These can be provided to HMAC_DRBG constructor.
For HMAC_DRBG, SP800-90A requires we output no more than 2**16 bytes
per DRBG request. We treat requests longer than that as if the caller
had instead made several sequential maximum-length requests. This
means it is possible for one or more reseeds to trigger even in the
course of generating a single (long) output (generate a 256-bit key
and use ChaCha or HKDF if this is a problem).
Adds RNG::randomize_with_ts_input which takes timestamps and uses them
as the additional_data DRBG field. Stateful_RNG overrides this to also
include the process ID and the reseed counter. AutoSeeded_RNG's
`randomize` uses this.
Officially deprecates RNG::make_rng and the Serialized_RNG construtor
which creates an AutoSeeded_RNG. With these removed, it would be
possible to perform a build with no AutoSeeded_RNG/HMAC_DRBG at all
(eg, for applications which only use the system RNG).
Tests courtesy @cordney in GH PRs #598 and #600
Diffstat (limited to 'src/lib/rng/rng.cpp')
-rw-r--r-- | src/lib/rng/rng.cpp | 140 |
1 files changed, 29 insertions, 111 deletions
diff --git a/src/lib/rng/rng.cpp b/src/lib/rng/rng.cpp index 5501c143e..8c2982312 100644 --- a/src/lib/rng/rng.cpp +++ b/src/lib/rng/rng.cpp @@ -1,144 +1,62 @@ /* -* Random Number Generator -* (C) 1999-2008,2016 Jack Lloyd +* (C) 2016 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #include <botan/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> +#if defined(BOTAN_HAS_AUTO_SEEDING_RNG) + #include <botan/auto_rng.h> #endif namespace Botan { -size_t RandomNumberGenerator::reseed(size_t bits_to_collect) +void RandomNumberGenerator::randomize_with_ts_input(byte output[], size_t output_len) { - return this->reseed_with_timeout(bits_to_collect, - BOTAN_RNG_RESEED_DEFAULT_TIMEOUT); - } - -size_t RandomNumberGenerator::reseed_with_timeout(size_t bits_to_collect, - std::chrono::milliseconds timeout) - { - return this->reseed_with_sources(Entropy_Sources::global_sources(), - 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; - } + /* + Form additional input which is provided to the PRNG implementation + to paramaterize the KDF output. + */ + byte additional_input[16] = { 0 }; + store_le(OS::get_system_timestamp_ns(), additional_input); + store_le(OS::get_processor_timestamp(), additional_input + 8); - return bits_collected; + randomize_with_input(output, output_len, additional_input, sizeof(additional_input)); } -void Stateful_RNG::reseed_check(size_t bytes_requested) +void RandomNumberGenerator::randomize_with_input(byte output[], size_t output_len, + const byte input[], size_t input_len) { - 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()); - } + this->add_entropy(input, input_len); + this->randomize(output, output_len); } -void Stateful_RNG::initialize_with(const byte input[], size_t len) +size_t RandomNumberGenerator::reseed(Entropy_Sources& srcs, + size_t poll_bits, + std::chrono::milliseconds poll_timeout) { - add_entropy(input, len); - m_successful_initialization = true; + return srcs.poll(*this, poll_bits, poll_timeout); } -bool Stateful_RNG::is_seeded() const +void RandomNumberGenerator::reseed_from_rng(RandomNumberGenerator& rng, size_t poll_bits) { - return m_successful_initialization; + secure_vector<byte> buf(poll_bits / 8); + rng.randomize(buf.data(), buf.size()); + this->add_entropy(buf.data(), buf.size()); } RandomNumberGenerator* RandomNumberGenerator::make_rng() { +#if defined(BOTAN_HAS_AUTO_SEEDING_RNG) return new AutoSeeded_RNG; +#else + throw Exception("make_rng failed, no AutoSeeded_RNG in this build"); +#endif } -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)); - - size_t bits = m_rng->reseed(BOTAN_AUTO_RNG_ENTROPY_TARGET); - - 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); - } +Serialized_RNG::Serialized_RNG() : m_rng(RandomNumberGenerator::make_rng()) {} } |