aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/build-data/buildh.in10
-rw-r--r--src/lib/rng/hmac_rng/hmac_rng.cpp93
-rw-r--r--src/lib/rng/hmac_rng/hmac_rng.h22
3 files changed, 63 insertions, 62 deletions
diff --git a/src/build-data/buildh.in b/src/build-data/buildh.in
index e9115132f..f8009cf0b 100644
--- a/src/build-data/buildh.in
+++ b/src/build-data/buildh.in
@@ -45,8 +45,8 @@
#define BOTAN_MP_WORD_BITS %{mp_bits}
/*
-If enabled uses memset via volatile function pointer to zero memory,
-otherwise does a byte at a time write via a volatile pointer.
+* If enabled uses memset via volatile function pointer to zero memory,
+* otherwise does a byte at a time write via a volatile pointer.
*/
#define BOTAN_USE_VOLATILE_MEMSET_FOR_ZERO 1
@@ -62,11 +62,13 @@ otherwise does a byte at a time write via a volatile pointer.
#define BOTAN_PRIVATE_KEY_STRONG_CHECKS_ON_GENERATE 1
/*
-* RNGs will automatically poll the system for additional
-* seed material after producing this many bytes of output.
+* RNGs will automatically poll the system for additional seed material
+* after producing this many bytes of output.
*/
#define BOTAN_RNG_MAX_OUTPUT_BEFORE_RESEED 512
#define BOTAN_RNG_RESEED_POLL_BITS 128
+#define BOTAN_RNG_AUTO_RESEED_TIMEOUT std::chrono::milliseconds(20)
+#define BOTAN_RNG_RESEED_DEFAULT_TIMEOUT std::chrono::milliseconds(100)
/* Should we use GCC-style inline assembler? */
#if !defined(BOTAN_USE_GCC_INLINE_ASM) && defined(__GNUG__)
diff --git a/src/lib/rng/hmac_rng/hmac_rng.cpp b/src/lib/rng/hmac_rng/hmac_rng.cpp
index 3e8d63f8d..873a83ae9 100644
--- a/src/lib/rng/hmac_rng/hmac_rng.cpp
+++ b/src/lib/rng/hmac_rng/hmac_rng.cpp
@@ -1,6 +1,6 @@
/*
* HMAC_RNG
-* (C) 2008-2009,2013,2015 Jack Lloyd
+* (C) 2008,2009,2013,2015 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -14,28 +14,6 @@
namespace Botan {
-namespace {
-
-void hmac_prf(MessageAuthenticationCode& prf,
- secure_vector<byte>& K,
- u32bit& counter,
- const std::string& label)
- {
- typedef std::chrono::high_resolution_clock clock;
-
- auto timestamp = clock::now().time_since_epoch().count();
-
- prf.update(K);
- prf.update(label);
- prf.update_be(timestamp);
- prf.update_be(counter);
- prf.final(&K[0]);
-
- ++counter;
- }
-
-}
-
/*
* HMAC_RNG Constructor
*/
@@ -45,12 +23,23 @@ HMAC_RNG::HMAC_RNG(MessageAuthenticationCode* extractor,
{
if(!m_prf->valid_keylength(m_extractor->output_length()) ||
!m_extractor->valid_keylength(m_prf->output_length()))
+ {
throw Invalid_Argument("HMAC_RNG: Bad algo combination " +
m_extractor->name() + " and " +
m_prf->name());
+ }
+
+ this->clear();
+ }
+
+void HMAC_RNG::clear()
+ {
+ m_collected_entropy_estimate = 0;
+ m_counter = 0;
// First PRF inputs are all zero, as specified in section 2
m_K.resize(m_prf->output_length());
+ zeroise(m_K);
/*
Normally we want to feedback PRF outputs to the extractor function
@@ -65,8 +54,8 @@ HMAC_RNG::HMAC_RNG(MessageAuthenticationCode* extractor,
The PRF key will not be used to generate outputs until after reseed
sets m_seeded to true.
*/
- secure_vector<byte> prf_key(m_extractor->output_length());
- m_prf->set_key(prf_key);
+ std::vector<byte> prf_zero_key(m_extractor->output_length());
+ m_prf->set_key(&prf_zero_key[0], prf_zero_key.size());
/*
Use PRF("Botan HMAC_RNG XTS") as the intitial XTS key.
@@ -75,9 +64,20 @@ HMAC_RNG::HMAC_RNG(MessageAuthenticationCode* extractor,
after this one are generated using the PRF.
If I understand the E-t-E paper correctly (specifically Section 4),
- using this fixed extractor key is safe to do.
+ using this fixed initial extractor key is safe to do.
*/
- m_extractor->set_key(prf->process("Botan HMAC_RNG XTS"));
+ m_extractor->set_key(m_prf->process("Botan HMAC_RNG XTS"));
+ }
+
+void HMAC_RNG::new_K_value(byte label)
+ {
+ typedef std::chrono::high_resolution_clock clock;
+
+ m_prf->update(m_K);
+ m_prf->update_be(clock::now().time_since_epoch().count());
+ m_prf->update_be(m_counter++);
+ m_prf->update(label);
+ m_prf->final(&m_K[0]);
}
/*
@@ -97,14 +97,14 @@ void HMAC_RNG::randomize(byte out[], size_t length)
m_output_since_reseed += length;
if(m_output_since_reseed >= BOTAN_RNG_MAX_OUTPUT_BEFORE_RESEED)
- reseed(BOTAN_RNG_RESEED_POLL_BITS);
+ reseed_with_timeout(BOTAN_RNG_RESEED_POLL_BITS, BOTAN_RNG_AUTO_RESEED_TIMEOUT);
/*
HMAC KDF as described in E-t-E, using a CTXinfo of "rng"
*/
while(length)
{
- hmac_prf(*m_prf, m_K, m_counter, "rng");
+ new_K_value(Running);
const size_t copied = std::min<size_t>(length, max_per_prf_iter);
@@ -119,6 +119,11 @@ void HMAC_RNG::randomize(byte out[], size_t length)
*/
void HMAC_RNG::reseed(size_t poll_bits)
{
+ reseed_with_timeout(poll_bits, BOTAN_RNG_RESEED_DEFAULT_TIMEOUT);
+ }
+
+void HMAC_RNG::reseed_with_timeout(size_t poll_bits, std::chrono::milliseconds timeout)
+ {
/*
Using the terminology of E-t-E, XTR is the MAC function (normally
HMAC) seeded with XTS (below) and we form SKM, the key material, by
@@ -129,12 +134,15 @@ void HMAC_RNG::reseed(size_t poll_bits)
double bits_collected = 0;
+ typedef std::chrono::high_resolution_clock clock;
+ auto deadline = clock::now() + timeout;
+
Entropy_Accumulator accum(
[&](const byte in[], size_t in_len, double entropy_estimate)
{
m_extractor->update(in, in_len);
bits_collected += entropy_estimate;
- return (bits_collected >= poll_bits);
+ return (bits_collected >= poll_bits || clock::now() > deadline);
});
EntropySource::poll_available_sources(accum);
@@ -145,15 +153,8 @@ void HMAC_RNG::reseed(size_t poll_bits)
* bad one (collecting little) would be unsafe. Do this by
* generating new PRF outputs using the previous key and feeding
* them into the extractor function.
- *
- * Cycle the RNG once (CTXinfo="rng"), then generate a new PRF
- * output using the CTXinfo "reseed". Provide these values as input
- * to the extractor function.
*/
- hmac_prf(*m_prf, m_K, m_counter, "rng");
- m_extractor->update(m_K); // K is the CTXinfo=rng PRF output
-
- hmac_prf(*m_prf, m_K, m_counter, "reseed");
+ new_K_value(Reseed);
m_extractor->update(m_K); // K is the CTXinfo=reseed PRF output
/* Now derive the new PRK using everything that has been fed into
@@ -161,7 +162,7 @@ void HMAC_RNG::reseed(size_t poll_bits)
m_prf->set_key(m_extractor->final());
// Now generate a new PRF output to use as the XTS extractor salt
- hmac_prf(*m_prf, m_K, m_counter, "xts");
+ new_K_value(ExtractorSeed);
m_extractor->set_key(m_K);
// Reset state
@@ -186,19 +187,7 @@ bool HMAC_RNG::is_seeded() const
void HMAC_RNG::add_entropy(const byte input[], size_t length)
{
m_extractor->update(input, length);
- reseed(BOTAN_RNG_RESEED_POLL_BITS);
- }
-
-/*
-* Clear memory of sensitive data
-*/
-void HMAC_RNG::clear()
- {
- m_collected_entropy_estimate = 0;
- m_extractor->clear();
- m_prf->clear();
- zeroise(m_K);
- m_counter = 0;
+ reseed_with_timeout(BOTAN_RNG_RESEED_POLL_BITS, BOTAN_RNG_AUTO_RESEED_TIMEOUT);
}
/*
diff --git a/src/lib/rng/hmac_rng/hmac_rng.h b/src/lib/rng/hmac_rng/hmac_rng.h
index 85a411b16..ba12e665d 100644
--- a/src/lib/rng/hmac_rng/hmac_rng.h
+++ b/src/lib/rng/hmac_rng/hmac_rng.h
@@ -27,13 +27,16 @@ namespace Botan {
class BOTAN_DLL HMAC_RNG : public RandomNumberGenerator
{
public:
- void randomize(byte buf[], size_t len);
- bool is_seeded() const;
- void clear();
- std::string name() const;
+ void randomize(byte buf[], size_t len) override;
+ bool is_seeded() const override;
+ void clear() override;
+ std::string name() const override;
- void reseed(size_t poll_bits);
- void add_entropy(const byte[], size_t);
+ void reseed(size_t poll_bits) override;
+
+ void reseed_with_timeout(size_t poll_bits, std::chrono::milliseconds ms);
+
+ void add_entropy(const byte[], size_t) override;
/**
* @param extractor a MAC used for extracting the entropy
@@ -45,6 +48,13 @@ class BOTAN_DLL HMAC_RNG : public RandomNumberGenerator
std::unique_ptr<MessageAuthenticationCode> m_extractor;
std::unique_ptr<MessageAuthenticationCode> m_prf;
+ enum HMAC_PRF_Label {
+ Running,
+ Reseed,
+ ExtractorSeed,
+ };
+ void new_K_value(byte label);
+
size_t m_collected_entropy_estimate = 0;
size_t m_output_since_reseed = 0;