aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/rng/hmac_drbg
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2016-08-19 07:51:47 -0400
committerJack Lloyd <[email protected]>2016-08-24 11:31:54 -0400
commit80c160f08f2a69eb4e41a68380796bf31fd2f924 (patch)
tree83259da316524ed3b96b0913e5b023bc40f26a28 /src/lib/rng/hmac_drbg
parent91474f60d72937ad3c21d8aa53c14f7a0cceb9ca (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.cpp99
-rw-r--r--src/lib/rng/hmac_drbg/hmac_drbg.h68
-rw-r--r--src/lib/rng/hmac_drbg/info.txt1
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>