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/hmac_drbg | |
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/hmac_drbg')
-rw-r--r-- | src/lib/rng/hmac_drbg/hmac_drbg.cpp | 99 | ||||
-rw-r--r-- | src/lib/rng/hmac_drbg/hmac_drbg.h | 68 | ||||
-rw-r--r-- | src/lib/rng/hmac_drbg/info.txt | 1 |
3 files changed, 133 insertions, 35 deletions
diff --git a/src/lib/rng/hmac_drbg/hmac_drbg.cpp b/src/lib/rng/hmac_drbg/hmac_drbg.cpp index 7325804e3..6ea66aa2e 100644 --- a/src/lib/rng/hmac_drbg/hmac_drbg.cpp +++ b/src/lib/rng/hmac_drbg/hmac_drbg.cpp @@ -10,28 +10,42 @@ namespace Botan { -HMAC_DRBG::HMAC_DRBG(MessageAuthenticationCode* hmac, - size_t max_output_before_reseed) : - Stateful_RNG(max_output_before_reseed), - m_mac(hmac) +HMAC_DRBG::HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf, + RandomNumberGenerator& underlying_rng, + size_t reseed_interval) : + Stateful_RNG(underlying_rng, reseed_interval), + m_mac(std::move(prf)) { - m_V.resize(m_mac->output_length()); + BOTAN_ASSERT_NONNULL(m_mac); clear(); } -HMAC_DRBG::HMAC_DRBG(const std::string& hmac_hash, - size_t max_output_before_reseed) : - Stateful_RNG(max_output_before_reseed) +HMAC_DRBG::HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf, + RandomNumberGenerator& underlying_rng, + Entropy_Sources& entropy_sources, + size_t reseed_interval) : + Stateful_RNG(underlying_rng, entropy_sources, reseed_interval), + m_mac(std::move(prf)) { - const std::string hmac = "HMAC(" + hmac_hash + ")"; + BOTAN_ASSERT_NONNULL(m_mac); + clear(); + } - m_mac = MessageAuthenticationCode::create(hmac); - if(!m_mac) - { - throw Algorithm_Not_Found(hmac); - } +HMAC_DRBG::HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf, + Entropy_Sources& entropy_sources, + size_t reseed_interval) : + Stateful_RNG(entropy_sources, reseed_interval), + m_mac(std::move(prf)) + { + BOTAN_ASSERT_NONNULL(m_mac); + clear(); + } - m_V.resize(m_mac->output_length()); +HMAC_DRBG::HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf) : + Stateful_RNG(), + m_mac(std::move(prf)) + { + BOTAN_ASSERT_NONNULL(m_mac); clear(); } @@ -39,6 +53,7 @@ void HMAC_DRBG::clear() { Stateful_RNG::clear(); + m_V.resize(m_mac->output_length()); for(size_t i = 0; i != m_V.size(); ++i) m_V[i] = 0x01; m_mac->set_key(std::vector<byte>(m_mac->output_length(), 0x00)); @@ -61,25 +76,45 @@ void HMAC_DRBG::randomize(byte output[], size_t output_len) void HMAC_DRBG::randomize_with_input(byte output[], size_t output_len, const byte input[], size_t input_len) { - reseed_check(output_len); - - if(input_len > 0) + /** + * SP 800-90A requires we reject any request for a DRBG output + * longer than max_number_of_bits_per_request. This is an + * implementation-dependent value, but NIST requires for HMAC_DRBG + * that every implementation set a value no more than 2**19 bits + * (or 64 KiB). + * + * To avoid inconveniencing the caller who wants a large output for + * whatever reason, instead treat very long output requests as + * if multiple maximum-length requests had been made. + */ + const size_t max_number_of_bytes_per_request = 64*1024; + + while(output_len > 0) { - update(input, input_len); - } + size_t this_req = std::min(max_number_of_bytes_per_request, output_len); + output_len -= this_req; - while(output_len) - { - const size_t to_copy = std::min(output_len, m_V.size()); - m_mac->update(m_V.data(), m_V.size()); - m_mac->final(m_V.data()); - copy_mem(output, m_V.data(), to_copy); + reseed_check(); + + if(input_len > 0) + { + update(input, input_len); + } + + while(this_req) + { + const size_t to_copy = std::min(this_req, m_V.size()); + m_mac->update(m_V.data(), m_V.size()); + m_mac->final(m_V.data()); + copy_mem(output, m_V.data(), to_copy); - output += to_copy; - output_len -= to_copy; + output += to_copy; + this_req -= to_copy; + } + + update(input, input_len); } - update(input, input_len); } /* @@ -113,4 +148,10 @@ void HMAC_DRBG::add_entropy(const byte input[], size_t input_len) update(input, input_len); } +size_t HMAC_DRBG::security_level() const + { + // sqrt of hash size + return m_mac->output_length() * 8 / 2; + } + } diff --git a/src/lib/rng/hmac_drbg/hmac_drbg.h b/src/lib/rng/hmac_drbg/hmac_drbg.h index 0e294dbdb..4f96af816 100644 --- a/src/lib/rng/hmac_drbg/hmac_drbg.h +++ b/src/lib/rng/hmac_drbg/hmac_drbg.h @@ -8,11 +8,13 @@ #ifndef BOTAN_HMAC_DRBG_H__ #define BOTAN_HMAC_DRBG_H__ -#include <botan/rng.h> +#include <botan/stateful_rng.h> #include <botan/mac.h> namespace Botan { +class Entropy_Sources; + /** * HMAC_DRBG from NIST SP800-90A */ @@ -20,13 +22,64 @@ class BOTAN_DLL HMAC_DRBG final : public Stateful_RNG { public: /** - * Initialize an HMAC_DRBG instance with the given hash function + * Initialize an HMAC_DRBG instance with the given MAC as PRF (normally HMAC) + * + * Automatic reseeding is disabled completely, as it as no access to + * any source for seed material. + * + * If a fork is detected, the RNG will be unable to reseed itself + * in response. In this case, an exception will be thrown rather + * than generating duplicated output. + */ + HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf); + + /** + * Initialize an HMAC_DRBG instance with the given MAC as PRF (normally HMAC) + * + * @param underlying_rng is a reference to some RNG which will be used + * to perform the periodic reseeding + * @param reseed_interval specifies a limit of how many times + * the RNG will be called before automatic reseeding is performed. + */ + HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf, + RandomNumberGenerator& underlying_rng, + size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL); + + /** + * Initialize an HMAC_DRBG instance with the given MAC as PRF (normally HMAC) + * + * @param entropy_sources will be polled to perform reseeding periodically + * @param reseed_interval specifies a limit of how many times + * the RNG will be called before automatic reseeding is performed. */ - HMAC_DRBG(const std::string& hmac_hash, - size_t max_output_before_reseed = BOTAN_RNG_DEFAULT_MAX_OUTPUT_BEFORE_RESEED); + HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf, + Entropy_Sources& entropy_sources, + size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL); - HMAC_DRBG(MessageAuthenticationCode* hmac, - size_t max_output_before_reseed = BOTAN_RNG_DEFAULT_MAX_OUTPUT_BEFORE_RESEED); + /** + * Initialize an HMAC_DRBG instance with the given MAC as PRF (normally HMAC) + * + * @param underlying_rng is a reference to some RNG which will be used + * to perform the periodic reseeding + * @param entropy_sources will be polled to perform reseeding periodically + * @param reseed_interval specifies a limit of how many times + * the RNG will be called before automatic reseeding is performed. + */ + HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf, + RandomNumberGenerator& underlying_rng, + Entropy_Sources& entropy_sources, + size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL); + + /** + * Constructor taking a string for the hash + */ + HMAC_DRBG(const std::string& hmac_hash) : Stateful_RNG() + { + m_mac = MessageAuthenticationCode::create("HMAC(" + hmac_hash + ")"); + if(!m_mac) + throw Algorithm_Not_Found(hmac_hash); + clear(); + } std::string name() const override; @@ -38,6 +91,9 @@ class BOTAN_DLL HMAC_DRBG final : public Stateful_RNG const byte input[], size_t input_len) override; void add_entropy(const byte input[], size_t input_len) override; + + size_t security_level() const override; + private: void update(const byte input[], size_t input_len); diff --git a/src/lib/rng/hmac_drbg/info.txt b/src/lib/rng/hmac_drbg/info.txt index f386db199..7f2c12fd0 100644 --- a/src/lib/rng/hmac_drbg/info.txt +++ b/src/lib/rng/hmac_drbg/info.txt @@ -2,4 +2,5 @@ define HMAC_DRBG 20140319 <requires> hmac +stateful_rng </requires> |