aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/rng/hmac_rng/hmac_rng.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/rng/hmac_rng/hmac_rng.cpp')
-rw-r--r--src/lib/rng/hmac_rng/hmac_rng.cpp166
1 files changed, 81 insertions, 85 deletions
diff --git a/src/lib/rng/hmac_rng/hmac_rng.cpp b/src/lib/rng/hmac_rng/hmac_rng.cpp
index 7a9e4dbc5..081d8b38a 100644
--- a/src/lib/rng/hmac_rng/hmac_rng.cpp
+++ b/src/lib/rng/hmac_rng/hmac_rng.cpp
@@ -9,31 +9,80 @@
#include <botan/entropy_src.h>
#include <botan/internal/os_utils.h>
#include <algorithm>
-#include <chrono>
namespace Botan {
-/*
-* HMAC_RNG Constructor
-*/
-HMAC_RNG::HMAC_RNG(MessageAuthenticationCode* extractor,
- MessageAuthenticationCode* prf) :
- m_extractor(extractor), m_prf(prf)
+HMAC_RNG::HMAC_RNG(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_prf(std::move(prf))
+ {
+ BOTAN_ASSERT_NONNULL(m_prf);
+
+ if(!m_prf->valid_keylength(m_prf->output_length()))
+ {
+ throw Invalid_Argument("HMAC_RNG cannot use " + m_prf->name());
+ }
+
+ m_extractor.reset(m_prf->clone());
+ this->clear();
+ }
+
+HMAC_RNG::HMAC_RNG(std::unique_ptr<MessageAuthenticationCode> prf,
+ RandomNumberGenerator& underlying_rng,
+ size_t reseed_interval) :
+ Stateful_RNG(underlying_rng, reseed_interval),
+ m_prf(std::move(prf))
+ {
+ BOTAN_ASSERT_NONNULL(m_prf);
+
+ if(!m_prf->valid_keylength(m_prf->output_length()))
+ {
+ throw Invalid_Argument("HMAC_RNG cannot use " + m_prf->name());
+ }
+
+ m_extractor.reset(m_prf->clone());
+ this->clear();
+ }
+
+HMAC_RNG::HMAC_RNG(std::unique_ptr<MessageAuthenticationCode> prf,
+ Entropy_Sources& entropy_sources,
+ size_t reseed_interval) :
+ Stateful_RNG(entropy_sources, reseed_interval),
+ m_prf(std::move(prf)),
+ m_extractor(m_prf->clone())
{
- if(!m_prf->valid_keylength(m_extractor->output_length()) ||
- !m_extractor->valid_keylength(m_prf->output_length()))
+ BOTAN_ASSERT_NONNULL(m_prf);
+
+ if(!m_prf->valid_keylength(m_prf->output_length()))
{
- throw Invalid_Argument("HMAC_RNG: Bad algo combination " +
- m_extractor->name() + " and " +
- m_prf->name());
+ throw Invalid_Argument("HMAC_RNG cannot use " + m_prf->name());
}
+ m_extractor.reset(m_prf->clone());
+ this->clear();
+ }
+
+HMAC_RNG::HMAC_RNG(std::unique_ptr<MessageAuthenticationCode> prf) :
+ Stateful_RNG(),
+ m_prf(std::move(prf))
+ {
+ BOTAN_ASSERT_NONNULL(m_prf);
+
+ if(!m_prf->valid_keylength(m_prf->output_length()))
+ {
+ throw Invalid_Argument("HMAC_RNG cannot use " + m_prf->name());
+ }
+
+ m_extractor.reset(m_prf->clone());
this->clear();
}
void HMAC_RNG::clear()
{
- m_collected_entropy_estimate = 0;
+ Stateful_RNG::clear();
m_counter = 0;
// First PRF inputs are all zero, as specified in section 2
@@ -71,7 +120,7 @@ void HMAC_RNG::clear()
void HMAC_RNG::new_K_value(byte label)
{
m_prf->update(m_K);
- m_prf->update_be(m_pid);
+ m_prf->update_be(last_pid());
m_prf->update_be(OS::get_processor_timestamp());
m_prf->update_be(OS::get_system_timestamp_ns());
m_prf->update_be(m_counter++);
@@ -84,76 +133,38 @@ void HMAC_RNG::new_K_value(byte label)
*/
void HMAC_RNG::randomize(byte out[], size_t length)
{
- if(!is_seeded() || m_pid != OS::get_process_id())
- {
- reseed(256);
- if(!is_seeded())
- throw PRNG_Unseeded(name());
- }
-
- const size_t max_per_prf_iter = m_prf->output_length() / 2;
+ reseed_check();
- m_output_since_reseed += length;
-
- if(m_output_since_reseed >= BOTAN_RNG_MAX_OUTPUT_BEFORE_RESEED)
- {
- reseed_with_sources(Entropy_Sources::global_sources(),
- 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)
{
new_K_value(Running);
- const size_t copied = std::min<size_t>(length, max_per_prf_iter);
+ const size_t copied = std::min<size_t>(length, m_prf->output_length());
copy_mem(out, m_K.data(), copied);
out += copied;
length -= copied;
}
+
+ new_K_value(BlockFinished);
}
-size_t HMAC_RNG::reseed_with_sources(Entropy_Sources& srcs,
- size_t poll_bits,
- std::chrono::milliseconds timeout)
+size_t HMAC_RNG::reseed(Entropy_Sources& srcs,
+ size_t poll_bits,
+ std::chrono::milliseconds timeout)
{
+ new_K_value(Reseed);
+ m_extractor->update(m_K); // m_K is the PRF output
+
/*
- 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
- polling as many sources as we think needed to reach our polling
- goal. We then also include feedback of the current PRK so that
- a bad poll doesn't wipe us out.
+ * This ends up calling add_entropy which provides input to the extractor
*/
-
- typedef std::chrono::system_clock clock;
- auto deadline = clock::now() + timeout;
-
- double bits_collected = 0;
-
- 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 || clock::now() > deadline);
- });
-
- srcs.poll(accum);
+ size_t bits_collected = Stateful_RNG::reseed(srcs, poll_bits, timeout);
/*
- * It is necessary to feed forward poll data. Otherwise, a good poll
- * (collecting a large amount of conditional entropy) followed by a
- * 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.
+ Now derive the new PRK using everything that has been fed into
+ the extractor, and set the PRF key to that
*/
- 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
- the extractor, and set the PRF key to that */
m_prf->set_key(m_extractor->final());
// Now generate a new PRF output to use as the XTS extractor salt
@@ -164,32 +175,17 @@ size_t HMAC_RNG::reseed_with_sources(Entropy_Sources& srcs,
zeroise(m_K);
m_counter = 0;
- m_collected_entropy_estimate =
- std::min<size_t>(m_collected_entropy_estimate + static_cast<size_t>(bits_collected),
- m_extractor->output_length() * 8);
-
- m_output_since_reseed = 0;
- m_pid = OS::get_process_id();
-
- return static_cast<size_t>(bits_collected);
- }
-
-bool HMAC_RNG::is_seeded() const
- {
- return (m_collected_entropy_estimate >= 256);
+ return bits_collected;
}
/*
-* Add user-supplied entropy to the extractor input then reseed
-* to incorporate it into the state
+* Add user-supplied entropy to the extractor input then set remaining
+* output length to for a reseed on next use.
*/
void HMAC_RNG::add_entropy(const byte input[], size_t length)
{
m_extractor->update(input, length);
-
- reseed_with_sources(Entropy_Sources::global_sources(),
- BOTAN_RNG_RESEED_POLL_BITS,
- BOTAN_RNG_RESEED_DEFAULT_TIMEOUT);
+ force_reseed();
}
/*