aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlloyd <[email protected]>2013-11-08 21:09:36 +0000
committerlloyd <[email protected]>2013-11-08 21:09:36 +0000
commit9fab3b28e9b728dbe71bc5b0afc9a8c408de1d0e (patch)
tree95129c533c2a27840defdc956b4e2bb5f3c2e81d
parent51bdb06ac838b426cacdb4dd8a2efecbf67820ac (diff)
Previously, AutoRNG was just a reference to the global rng, which can
cause a huge amount of lock contention in heavily multithreaded code. Now each AutoRNG is its own uniquely seeded HMAC_RNG. The set of entropy sources is shared rather than being per-RNG (so there is only one open fd to /dev/random, etc). So reseeding is still a global lock, but sharing the resources (open file descriptors, etc) across RNGs seems worth the contention. Remove Randpool, which was only used if HMAC_RNG was disabled at build.
-rw-r--r--doc/relnotes/1_11_5.rst7
-rw-r--r--src/libstate/global_rng.cpp110
-rw-r--r--src/libstate/info.txt26
-rw-r--r--src/libstate/libstate.cpp3
-rw-r--r--src/libstate/libstate.h9
-rw-r--r--src/rng/auto_rng/auto_rng.h26
-rw-r--r--src/rng/auto_rng/info.txt5
-rw-r--r--src/rng/hmac_rng/hmac_rng.cpp194
-rw-r--r--src/rng/hmac_rng/hmac_rng.h38
-rw-r--r--src/rng/randpool/info.txt6
-rw-r--r--src/rng/randpool/randpool.cpp208
-rw-r--r--src/rng/randpool/randpool.h61
-rw-r--r--src/rng/rng.cpp28
-rw-r--r--src/rng/rng.h50
-rw-r--r--src/rng/x931_rng/x931_rng.cpp8
-rw-r--r--src/rng/x931_rng/x931_rng.h1
16 files changed, 216 insertions, 564 deletions
diff --git a/doc/relnotes/1_11_5.rst b/doc/relnotes/1_11_5.rst
index e4528a581..e3ee27a5e 100644
--- a/doc/relnotes/1_11_5.rst
+++ b/doc/relnotes/1_11_5.rst
@@ -18,6 +18,11 @@ Version 1.11.5, Not Yet Released
urandom always occurs, along with however much (if any) output is available
from blocking sources.
+* Previously AutoSeeded_RNG referenced a globally shared PRNG instance.
+ Now each instance has distinct state.
+
+* The Randpool RNG implementation was removed.
+
* All existing cipher mode implementations (such as CBC and XTS) have been
converted from filters to using the interface previously provided by
:ref:`AEAD modes <aead_modes>` which allows for in-place message
@@ -37,7 +42,7 @@ Version 1.11.5, Not Yet Released
* TLS channels now support sending a ``std::vector``
-* Add a generic 64-bit multiply instruction for producing a 128 bit result in mul128.h
+* Add a generic 64x64->128 bit multiply instruction operation in mul128.h
* Avoid potentially undefined operations in the bit rotation operations. Not
known to have caused problems under existing compilers but might break in the
diff --git a/src/libstate/global_rng.cpp b/src/libstate/global_rng.cpp
index e460199c5..38b8ec559 100644
--- a/src/libstate/global_rng.cpp
+++ b/src/libstate/global_rng.cpp
@@ -7,18 +7,6 @@
#include <botan/libstate.h>
-#if defined(BOTAN_HAS_RANDPOOL)
- #include <botan/randpool.h>
-#endif
-
-#if defined(BOTAN_HAS_HMAC_RNG)
- #include <botan/hmac_rng.h>
-#endif
-
-#if defined(BOTAN_HAS_X931_RNG)
- #include <botan/x931_rng.h>
-#endif
-
#if defined(BOTAN_HAS_ENTROPY_SRC_HIGH_RESOLUTION_TIMER)
#include <botan/internal/hres_timer.h>
#endif
@@ -57,58 +45,58 @@
namespace Botan {
-namespace {
-
-/**
-* Add any known entropy sources to this RNG
-*/
-void add_entropy_sources(RandomNumberGenerator* rng)
+std::vector<std::unique_ptr<EntropySource>> Library_State::entropy_sources()
{
+ std::vector<std::unique_ptr<EntropySource>> sources;
+
#if defined(BOTAN_HAS_ENTROPY_SRC_HIGH_RESOLUTION_TIMER)
- rng->add_entropy_source(new High_Resolution_Timestamp);
+ sources.push_back(std::unique_ptr<EntropySource>(new High_Resolution_Timestamp));
#endif
#if defined(BOTAN_HAS_ENTROPY_SRC_RDRAND)
- rng->add_entropy_source(new Intel_Rdrand);
+ sources.push_back(std::unique_ptr<EntropySource>(new Intel_Rdrand));
#endif
#if defined(BOTAN_HAS_ENTROPY_SRC_DEV_RANDOM)
- rng->add_entropy_source(
- new Device_EntropySource(
- split_on("/dev/random:/dev/srandom:/dev/urandom", ':')
- )
- );
+ sources.push_back(std::unique_ptr<EntropySource>(new Device_EntropySource(
+ { "/dev/random", "/dev/srandom", "/dev/urandom" }
+ )));
#endif
#if defined(BOTAN_HAS_ENTROPY_SRC_CAPI)
- rng->add_entropy_source(new Win32_CAPI_EntropySource);
+ sources.push_back(std::unique_ptr<EntropySource>(new Win32_CAPI_EntropySource));
#endif
#if defined(BOTAN_HAS_ENTROPY_SRC_FTW)
- rng->add_entropy_source(new FTW_EntropySource("/proc"));
+ sources.push_back(std::unique_ptr<EntropySource>(new FTW_EntropySource("/proc")));
#endif
#if defined(BOTAN_HAS_ENTROPY_SRC_WIN32)
- rng->add_entropy_source(new Win32_EntropySource);
+ sources.push_back(std::unique_ptr<EntropySource>(new Win32_EntropySource));
#endif
#if defined(BOTAN_HAS_ENTROPY_SRC_BEOS)
- rng->add_entropy_source(new BeOS_EntropySource);
+ sources.push_back(std::unique_ptr<EntropySource>(new BeOS_EntropySource));
#endif
#if defined(BOTAN_HAS_ENTROPY_SRC_UNIX)
- rng->add_entropy_source(
- new Unix_EntropySource(split_on("/bin:/sbin:/usr/bin:/usr/sbin", ':'))
- );
+ sources.push_back(std::unique_ptr<EntropySource>(
+ new Unix_EntropySource(
+ { "/bin", "/sbin", "/usr/bin", "/usr/sbin" }
+ )));
#endif
#if defined(BOTAN_HAS_ENTROPY_SRC_EGD)
- rng->add_entropy_source(
- new EGD_EntropySource(split_on("/var/run/egd-pool:/dev/egd-pool", ':'))
- );
+ sources.push_back(std::unique_ptr<EntropySource>(
+ new EGD_EntropySource({ "/var/run/egd-pool" "/dev/egd-pool" })
+ ));
#endif
+
+ return sources;
}
+namespace {
+
class Serialized_PRNG : public RandomNumberGenerator
{
public:
@@ -142,12 +130,6 @@ class Serialized_PRNG : public RandomNumberGenerator
rng->reseed(poll_bits);
}
- void add_entropy_source(EntropySource* es)
- {
- std::lock_guard<std::mutex> lock(mutex);
- rng->add_entropy_source(es);
- }
-
void add_entropy(const byte in[], size_t len)
{
std::lock_guard<std::mutex> lock(mutex);
@@ -157,47 +139,41 @@ class Serialized_PRNG : public RandomNumberGenerator
// We do not own the mutex; Library_State does
Serialized_PRNG(RandomNumberGenerator* r, std::mutex& m) :
mutex(m), rng(r) {}
-
- ~Serialized_PRNG() { delete rng; }
private:
std::mutex& mutex;
- RandomNumberGenerator* rng;
+ std::unique_ptr<RandomNumberGenerator> rng;
};
}
-RandomNumberGenerator* Library_State::make_global_rng(Algorithm_Factory& af,
- std::mutex& mutex)
+void Library_State::poll_available_sources(class Entropy_Accumulator& accum)
{
- RandomNumberGenerator* rng = nullptr;
+ std::lock_guard<std::mutex> lock(m_entropy_src_mutex);
-#if defined(BOTAN_HAS_HMAC_RNG)
+ const size_t poll_bits = accum.desired_remaining_bits();
- rng = new HMAC_RNG(af.make_mac("HMAC(SHA-512)"),
- af.make_mac("HMAC(SHA-256)"));
+ if(!m_sources.empty())
+ {
+ size_t poll_attempt = 0;
-#elif defined(BOTAN_HAS_RANDPOOL)
-
- rng = new Randpool(af.make_block_cipher("AES-256"),
- af.make_mac("HMAC(SHA-256)"));
+ while(!accum.polling_goal_achieved() && poll_attempt < poll_bits)
+ {
+ const size_t src_idx = poll_attempt % m_sources.size();
+ m_sources[src_idx]->poll(accum);
+ ++poll_attempt;
+ }
+ }
+ }
-#endif
+RandomNumberGenerator* Library_State::make_global_rng(Algorithm_Factory& af,
+ std::mutex& mutex)
+ {
+ auto rng = RandomNumberGenerator::make_rng(af);
if(!rng)
throw Internal_Error("No usable RNG found enabled in build");
- /* If X9.31 is available, use it to wrap the other RNG as a failsafe */
-#if defined(BOTAN_HAS_X931_RNG)
-
- rng = new ANSI_X931_RNG(af.make_block_cipher("AES-256"), rng);
-
-#endif
-
- add_entropy_sources(rng);
-
- rng->reseed(256);
-
- return new Serialized_PRNG(rng, mutex);
+ return new Serialized_PRNG(rng.release(), mutex);
}
}
diff --git a/src/libstate/info.txt b/src/libstate/info.txt
index b0704cd96..49a6d38ee 100644
--- a/src/libstate/info.txt
+++ b/src/libstate/info.txt
@@ -1,29 +1,6 @@
load_on always
-define LIBSTATE_MODULE
-
-<header:public>
-botan.h
-global_state.h
-init.h
-libstate.h
-lookup.h
-scan_name.h
-</header:public>
-
-<source>
-get_enc.cpp
-global_rng.cpp
-global_state.cpp
-init.cpp
-libstate.cpp
-lookup.cpp
-policy.cpp
-scan_name.cpp
-</source>
-
<requires>
-aes
algo_factory
alloc
bigint
@@ -33,7 +10,6 @@ engine
filters
hash
hmac
-hmac_rng
kdf
mac
mode_pad
@@ -41,7 +17,5 @@ pbkdf
pk_pad
pubkey
rng
-sha2_32
-sha2_64
stream
</requires>
diff --git a/src/libstate/libstate.cpp b/src/libstate/libstate.cpp
index 78ff9135c..6a0a28a45 100644
--- a/src/libstate/libstate.cpp
+++ b/src/libstate/libstate.cpp
@@ -157,6 +157,8 @@ void Library_State::initialize()
algorithm_factory().add_engine(new Core_Engine);
+ m_sources = entropy_sources();
+
#if defined(BOTAN_HAS_SELFTESTS)
confirm_startup_self_tests(algorithm_factory());
#endif
@@ -168,7 +170,6 @@ void Library_State::initialize()
Library_State::Library_State()
{
m_algorithm_factory = nullptr;
-
global_rng_ptr = nullptr;
}
diff --git a/src/libstate/libstate.h b/src/libstate/libstate.h
index 4d0a2b3e7..13333367c 100644
--- a/src/libstate/libstate.h
+++ b/src/libstate/libstate.h
@@ -11,11 +11,11 @@
#include <botan/global_state.h>
#include <botan/algo_factory.h>
#include <botan/rng.h>
-
#include <mutex>
#include <string>
#include <vector>
#include <map>
+#include <memory>
namespace Botan {
@@ -43,6 +43,8 @@ class BOTAN_DLL Library_State
*/
RandomNumberGenerator& global_rng();
+ void poll_available_sources(class Entropy_Accumulator& accum);
+
/**
* Set the default allocator
* @param name the name of the allocator to use as the default
@@ -100,11 +102,16 @@ class BOTAN_DLL Library_State
static RandomNumberGenerator* make_global_rng(Algorithm_Factory& af,
std::mutex& mutex);
+ static std::vector<std::unique_ptr<EntropySource>> entropy_sources();
+
void load_default_config();
std::mutex global_rng_lock;
RandomNumberGenerator* global_rng_ptr;
+ std::mutex m_entropy_src_mutex;
+ std::vector<std::unique_ptr<EntropySource>> m_sources;
+
std::mutex config_lock;
std::map<std::string, std::string> config;
diff --git a/src/rng/auto_rng/auto_rng.h b/src/rng/auto_rng/auto_rng.h
index 520323e3e..6971ca211 100644
--- a/src/rng/auto_rng/auto_rng.h
+++ b/src/rng/auto_rng/auto_rng.h
@@ -9,37 +9,37 @@
#define BOTAN_AUTO_SEEDING_RNG_H__
#include <botan/rng.h>
-#include <botan/libstate.h>
#include <string>
+#include <memory>
namespace Botan {
/**
-* An automatically seeded PRNG
+* An older interface kept for compatability with existing code
+*
+* Use RandomNumberGenerator::make_rng instead
*/
class BOTAN_DLL AutoSeeded_RNG : public RandomNumberGenerator
{
public:
void randomize(byte out[], size_t len)
- { rng->randomize(out, len); }
-
- bool is_seeded() const { return rng->is_seeded(); }
+ { m_rng->randomize(out, len); }
- void clear() { rng->clear(); }
+ bool is_seeded() const { return m_rng->is_seeded(); }
- std::string name() const { return rng->name(); }
+ void clear() { m_rng->clear(); }
- void reseed(size_t poll_bits = 256) { rng->reseed(poll_bits); }
+ std::string name() const { return m_rng->name(); }
- void add_entropy_source(EntropySource* es)
- { rng->add_entropy_source(es); }
+ void reseed(size_t poll_bits = 256) { m_rng->reseed(poll_bits); }
void add_entropy(const byte in[], size_t len)
- { rng->add_entropy(in, len); }
+ { m_rng->add_entropy(in, len); }
- AutoSeeded_RNG() { rng = &global_state().global_rng(); }
+ BOTAN_DEPRECATED("Use RandomNumberGenerator::make_rng instead")
+ AutoSeeded_RNG() : m_rng(RandomNumberGenerator::make_rng()) {}
private:
- RandomNumberGenerator* rng;
+ std::unique_ptr<RandomNumberGenerator> m_rng;
};
}
diff --git a/src/rng/auto_rng/info.txt b/src/rng/auto_rng/info.txt
index 6f98a65f4..4e1d04af0 100644
--- a/src/rng/auto_rng/info.txt
+++ b/src/rng/auto_rng/info.txt
@@ -1,5 +1,8 @@
define AUTO_SEEDING_RNG
<requires>
-libstate
+hmac_rng
+hmac
+sha2_32
+sha2_64
</requires>
diff --git a/src/rng/hmac_rng/hmac_rng.cpp b/src/rng/hmac_rng/hmac_rng.cpp
index c20c3b44e..2984e238b 100644
--- a/src/rng/hmac_rng/hmac_rng.cpp
+++ b/src/rng/hmac_rng/hmac_rng.cpp
@@ -1,12 +1,14 @@
/*
* HMAC_RNG
-* (C) 2008-2009 Jack Lloyd
+* (C) 2008-2009,2013 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/
#include <botan/hmac_rng.h>
+#include <botan/libstate.h>
#include <botan/get_byte.h>
+#include <botan/entropy_src.h>
#include <botan/internal/xor_buf.h>
#include <algorithm>
@@ -14,15 +16,15 @@ namespace Botan {
namespace {
-void hmac_prf(MessageAuthenticationCode* prf,
+void hmac_prf(MessageAuthenticationCode& prf,
secure_vector<byte>& K,
u32bit& counter,
const std::string& label)
{
- prf->update(K);
- prf->update(label);
- prf->update_be(counter);
- prf->final(&K[0]);
+ prf.update(K);
+ prf.update(label);
+ prf.update_be(counter);
+ prf.final(&K[0]);
++counter;
}
@@ -30,6 +32,50 @@ void hmac_prf(MessageAuthenticationCode* prf,
}
/*
+* HMAC_RNG Constructor
+*/
+HMAC_RNG::HMAC_RNG(MessageAuthenticationCode* extractor,
+ MessageAuthenticationCode* prf) :
+ m_extractor(extractor), m_prf(prf)
+ {
+ 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());
+
+ // First PRF inputs are all zero, as specified in section 2
+ m_K.resize(m_prf->output_length());
+
+ /*
+ Normally we want to feedback PRF outputs to the extractor function
+ to ensure a single bad poll does not reduce entropy. Thus in reseed
+ we'll want to invoke the PRF before we reset the PRF key, but until
+ the first reseed the PRF is unkeyed. Rather than trying to keep
+ track of this, just set the initial PRF key to constant zero.
+ Since all PRF inputs in the first reseed are constants, this
+ amounts to suffixing the seed in the first poll with a fixed
+ constant string.
+
+ 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);
+
+ /*
+ Use PRF("Botan HMAC_RNG XTS") as the intitial XTS key.
+
+ This will be used during the first extraction sequence; XTS values
+ 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.
+ */
+ m_extractor->set_key(prf->process("Botan HMAC_RNG XTS"));
+ }
+
+/*
* Generate a buffer of random bytes
*/
void HMAC_RNG::randomize(byte out[], size_t length)
@@ -42,16 +88,16 @@ void HMAC_RNG::randomize(byte out[], size_t length)
*/
while(length)
{
- hmac_prf(prf, K, counter, "rng");
+ hmac_prf(*m_prf, m_K, m_counter, "rng");
- const size_t copied = std::min<size_t>(K.size() / 2, length);
+ if(m_counter % AUTOMATIC_RESEED_RATE == 0)
+ reseed(AUTOMATIC_RESEED_BITS);
- copy_mem(out, &K[0], copied);
+ const size_t copied = std::min<size_t>(m_K.size() / 2, length);
+
+ copy_mem(out, &m_K[0], copied);
out += copied;
length -= copied;
-
- if(counter % 1024 == 0)
- reseed(128);
}
}
@@ -68,19 +114,9 @@ void HMAC_RNG::reseed(size_t poll_bits)
a bad poll doesn't wipe us out.
*/
- Entropy_Accumulator_BufferedComputation accum(*extractor, poll_bits);
+ Entropy_Accumulator_BufferedComputation accum(*m_extractor, poll_bits);
- if(!entropy_sources.empty())
- {
- size_t poll_attempt = 0;
-
- while(!accum.polling_goal_achieved() && poll_attempt < poll_bits)
- {
- const size_t src_idx = poll_attempt % entropy_sources.size();
- entropy_sources[src_idx]->poll(accum);
- ++poll_attempt;
- }
- }
+ global_state().poll_available_sources(accum);
/*
* It is necessary to feed forward poll data. Otherwise, a good poll
@@ -93,29 +129,30 @@ void HMAC_RNG::reseed(size_t poll_bits)
* output using the CTXinfo "reseed". Provide these values as input
* to the extractor function.
*/
- hmac_prf(prf, K, counter, "rng");
- extractor->update(K); // K is the CTXinfo=rng PRF output
+ hmac_prf(*m_prf, m_K, m_counter, "rng");
+ m_extractor->update(m_K); // K is the CTXinfo=rng PRF output
- hmac_prf(prf, K, counter, "reseed");
- extractor->update(K); // K is the CTXinfo=reseed PRF output
+ hmac_prf(*m_prf, m_K, m_counter, "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 */
- prf->set_key(extractor->final());
+ m_prf->set_key(m_extractor->final());
// Now generate a new PRF output to use as the XTS extractor salt
- hmac_prf(prf, K, counter, "xts");
- extractor->set_key(K);
+ hmac_prf(*m_prf, m_K, m_counter, "xts");
+ m_extractor->set_key(m_K);
// Reset state
- zeroise(K);
+ zeroise(m_K);
+ m_counter = 0;
/*
* Consider ourselves seeded once we've collected an estimated 128 bits of
* entropy in a single poll.
*/
- if(seeded == false && accum.bits_collected() >= 128)
- seeded = true;
+ if(accum.bits_collected() >= 128)
+ m_seeded = true;
}
/*
@@ -123,20 +160,8 @@ void HMAC_RNG::reseed(size_t poll_bits)
*/
void HMAC_RNG::add_entropy(const byte input[], size_t length)
{
- /*
- * Simply include the data in the extractor input. During the
- * next periodic reseed, the input will be incorporated into
- * the state.
- */
- extractor->update(input, length);
- }
-
-/*
-* Add another entropy source to the list
-*/
-void HMAC_RNG::add_entropy_source(EntropySource* src)
- {
- entropy_sources.push_back(src);
+ m_extractor->update(input, length);
+ reseed(AUTOMATIC_RESEED_BITS);
}
/*
@@ -144,11 +169,11 @@ void HMAC_RNG::add_entropy_source(EntropySource* src)
*/
void HMAC_RNG::clear()
{
- extractor->clear();
- prf->clear();
- zeroise(K);
- counter = 0;
- seeded = false;
+ m_seeded = false;
+ m_extractor->clear();
+ m_prf->clear();
+ zeroise(m_K);
+ m_counter = 0;
}
/*
@@ -156,68 +181,7 @@ void HMAC_RNG::clear()
*/
std::string HMAC_RNG::name() const
{
- return "HMAC_RNG(" + extractor->name() + "," + prf->name() + ")";
- }
-
-/*
-* HMAC_RNG Constructor
-*/
-HMAC_RNG::HMAC_RNG(MessageAuthenticationCode* extractor_mac,
- MessageAuthenticationCode* prf_mac) :
- extractor(extractor_mac), prf(prf_mac)
- {
- if(!prf->valid_keylength(extractor->output_length()) ||
- !extractor->valid_keylength(prf->output_length()))
- throw Invalid_Argument("HMAC_RNG: Bad algo combination " +
- extractor->name() + " and " +
- prf->name());
-
- // First PRF inputs are all zero, as specified in section 2
- K.resize(prf->output_length());
-
- counter = 0;
- seeded = false;
-
- /*
- Normally we want to feedback PRF output into the input to the
- extractor function to ensure a single bad poll does not damage the
- RNG, but obviously that is meaningless to do on the first poll.
-
- We will want to use the PRF before we set the first key (in
- reseed), and it is a pain to keep track if it is set or
- not. Since the first time it doesn't matter anyway, just set the
- PRF key to constant zero: randomize() will not produce output
- unless is_seeded() returns true, and that will only be the case if
- the estimated entropy counter is high enough. That variable is only
- set when a reseeding is performed.
- */
- secure_vector<byte> prf_key(extractor->output_length());
- prf->set_key(prf_key);
-
- /*
- Use PRF("Botan HMAC_RNG XTS") as the intitial XTS key.
-
- This will be used during the first extraction sequence; XTS values
- 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.
- */
- extractor->set_key(prf->process("Botan HMAC_RNG XTS"));
- }
-
-/*
-* HMAC_RNG Destructor
-*/
-HMAC_RNG::~HMAC_RNG()
- {
- delete extractor;
- delete prf;
-
- for(auto src : entropy_sources)
- delete src;
-
- counter = 0;
+ return "HMAC_RNG(" + m_extractor->name() + "," + m_prf->name() + ")";
}
}
diff --git a/src/rng/hmac_rng/hmac_rng.h b/src/rng/hmac_rng/hmac_rng.h
index e4339b264..6d7c3228a 100644
--- a/src/rng/hmac_rng/hmac_rng.h
+++ b/src/rng/hmac_rng/hmac_rng.h
@@ -1,6 +1,6 @@
/*
* HMAC RNG
-* (C) 2008 Jack Lloyd
+* (C) 2008,2013 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/
@@ -15,25 +15,24 @@
namespace Botan {
/**
-HMAC_RNG - based on the design described in "On Extract-then-Expand
-Key Derivation Functions and an HMAC-based KDF" by Hugo Krawczyk
-(henceforce, 'E-t-E')
-
-However it actually can be parameterized with any two MAC functions,
-not restricted to HMAC (this variation is also described in Krawczyk's
-paper), for instance one could use HMAC(SHA-512) as the extractor
-and CMAC(AES-256) as the PRF.
+* HMAC_RNG - based on the design described in "On Extract-then-Expand
+* Key Derivation Functions and an HMAC-based KDF" by Hugo Krawczyk
+* (henceforce, 'E-t-E')
+*
+* However it actually can be parameterized with any two MAC functions,
+* not restricted to HMAC (this variation is also described in
+* Krawczyk's paper), for instance one could use HMAC(SHA-512) as the
+* extractor and CMAC(AES-256) as the PRF.
*/
class BOTAN_DLL HMAC_RNG : public RandomNumberGenerator
{
public:
void randomize(byte buf[], size_t len);
- bool is_seeded() const { return seeded; }
+ bool is_seeded() const { return m_seeded; }
void clear();
std::string name() const;
void reseed(size_t poll_bits);
- void add_entropy_source(EntropySource* es);
void add_entropy(const byte[], size_t);
/**
@@ -42,17 +41,18 @@ class BOTAN_DLL HMAC_RNG : public RandomNumberGenerator
*/
HMAC_RNG(MessageAuthenticationCode* extractor,
MessageAuthenticationCode* prf);
-
- ~HMAC_RNG();
private:
- MessageAuthenticationCode* extractor;
- MessageAuthenticationCode* prf;
+ // make these build.h constants?
+ const size_t AUTOMATIC_RESEED_RATE = 16;
+ const size_t AUTOMATIC_RESEED_BITS = 128;
+
+ std::unique_ptr<MessageAuthenticationCode> m_extractor;
+ std::unique_ptr<MessageAuthenticationCode> m_prf;
- std::vector<EntropySource*> entropy_sources;
- bool seeded;
+ bool m_seeded = false;
- secure_vector<byte> K, io_buffer;
- u32bit counter;
+ secure_vector<byte> m_K;
+ u32bit m_counter = 0;
};
}
diff --git a/src/rng/randpool/info.txt b/src/rng/randpool/info.txt
deleted file mode 100644
index cc54e5d06..000000000
--- a/src/rng/randpool/info.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-define RANDPOOL
-
-<requires>
-block
-mac
-</requires>
diff --git a/src/rng/randpool/randpool.cpp b/src/rng/randpool/randpool.cpp
deleted file mode 100644
index aa029fef3..000000000
--- a/src/rng/randpool/randpool.cpp
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
-* Randpool
-* (C) 1999-2009 Jack Lloyd
-*
-* Distributed under the terms of the Botan license
-*/
-
-#include <botan/randpool.h>
-#include <botan/get_byte.h>
-#include <botan/internal/xor_buf.h>
-#include <algorithm>
-#include <chrono>
-
-namespace Botan {
-
-namespace {
-
-/*
-* PRF based on a MAC
-*/
-enum RANDPOOL_PRF_TAG {
- CIPHER_KEY = 0,
- MAC_KEY = 1,
- GEN_OUTPUT = 2
-};
-
-}
-
-/*
-* Generate a buffer of random bytes
-*/
-void Randpool::randomize(byte out[], size_t length)
- {
- if(!is_seeded())
- throw PRNG_Unseeded(name());
-
- update_buffer();
- while(length)
- {
- const size_t copied = std::min<size_t>(length, buffer.size());
- copy_mem(out, &buffer[0], copied);
- out += copied;
- length -= copied;
- update_buffer();
- }
- }
-
-/*
-* Refill the output buffer
-*/
-void Randpool::update_buffer()
- {
- for(size_t i = 0; i != counter.size(); ++i)
- if(++counter[i])
- break;
-
- mac->update(static_cast<byte>(GEN_OUTPUT));
- mac->update(counter);
- secure_vector<byte> mac_val = mac->final();
-
- for(size_t i = 0; i != mac_val.size(); ++i)
- buffer[i % buffer.size()] ^= mac_val[i];
- cipher->encrypt(buffer);
-
- if(counter[0] % ITERATIONS_BEFORE_RESEED == 0)
- mix_pool();
- }
-
-/*
-* Mix the entropy pool
-*/
-void Randpool::mix_pool()
- {
- const size_t BLOCK_SIZE = cipher->block_size();
-
- mac->update(static_cast<byte>(MAC_KEY));
- mac->update(pool);
- mac->set_key(mac->final());
-
- mac->update(static_cast<byte>(CIPHER_KEY));
- mac->update(pool);
- cipher->set_key(mac->final());
-
- xor_buf(pool, buffer, BLOCK_SIZE);
- cipher->encrypt(pool);
- for(size_t i = 1; i != POOL_BLOCKS; ++i)
- {
- const byte* previous_block = &pool[BLOCK_SIZE*(i-1)];
- byte* this_block = &pool[BLOCK_SIZE*i];
- xor_buf(this_block, previous_block, BLOCK_SIZE);
- cipher->encrypt(this_block);
- }
-
- update_buffer();
- }
-
-/*
-* Reseed the internal state
-*/
-void Randpool::reseed(size_t poll_bits)
- {
- Entropy_Accumulator_BufferedComputation accum(*mac, poll_bits);
-
- if(!entropy_sources.empty())
- {
- size_t poll_attempt = 0;
-
- while(!accum.polling_goal_achieved() && poll_attempt < poll_bits)
- {
- entropy_sources[poll_attempt % entropy_sources.size()]->poll(accum);
- ++poll_attempt;
- }
- }
-
- secure_vector<byte> mac_val = mac->final();
-
- xor_buf(pool, mac_val, mac_val.size());
- mix_pool();
-
- if(accum.bits_collected() >= poll_bits)
- seeded = true;
- }
-
-/*
-* Add user-supplied entropy
-*/
-void Randpool::add_entropy(const byte input[], size_t length)
- {
- secure_vector<byte> mac_val = mac->process(input, length);
- xor_buf(pool, mac_val, mac_val.size());
- mix_pool();
-
- if(length)
- seeded = true;
- }
-
-/*
-* Add another entropy source to the list
-*/
-void Randpool::add_entropy_source(EntropySource* src)
- {
- entropy_sources.push_back(src);
- }
-
-/*
-* Clear memory of sensitive data
-*/
-void Randpool::clear()
- {
- cipher->clear();
- mac->clear();
- zeroise(pool);
- zeroise(buffer);
- zeroise(counter);
- seeded = false;
- }
-
-/*
-* Return the name of this type
-*/
-std::string Randpool::name() const
- {
- return "Randpool(" + cipher->name() + "," + mac->name() + ")";
- }
-
-/*
-* Randpool Constructor
-*/
-Randpool::Randpool(BlockCipher* cipher_in,
- MessageAuthenticationCode* mac_in,
- size_t pool_blocks,
- size_t iter_before_reseed) :
- ITERATIONS_BEFORE_RESEED(iter_before_reseed),
- POOL_BLOCKS(pool_blocks),
- cipher(cipher_in),
- mac(mac_in)
- {
- const size_t BLOCK_SIZE = cipher->block_size();
- const size_t OUTPUT_LENGTH = mac->output_length();
-
- if(OUTPUT_LENGTH < BLOCK_SIZE ||
- !cipher->valid_keylength(OUTPUT_LENGTH) ||
- !mac->valid_keylength(OUTPUT_LENGTH))
- {
- delete cipher;
- delete mac;
- throw Internal_Error("Randpool: Invalid algorithm combination");
- }
-
- buffer.resize(BLOCK_SIZE);
- pool.resize(POOL_BLOCKS * BLOCK_SIZE);
- counter.resize(12);
- seeded = false;
- }
-
-/*
-* Randpool Destructor
-*/
-Randpool::~Randpool()
- {
- delete cipher;
- delete mac;
-
- for(auto i = entropy_sources.begin(); i != entropy_sources.end(); ++i)
- delete *i;
- }
-
-}
diff --git a/src/rng/randpool/randpool.h b/src/rng/randpool/randpool.h
deleted file mode 100644
index 64572bcfb..000000000
--- a/src/rng/randpool/randpool.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
-* Randpool
-* (C) 1999-2008 Jack Lloyd
-*
-* Distributed under the terms of the Botan license
-*/
-
-#ifndef BOTAN_RANDPOOL_H__
-#define BOTAN_RANDPOOL_H__
-
-#include <botan/rng.h>
-#include <botan/block_cipher.h>
-#include <botan/mac.h>
-#include <vector>
-
-namespace Botan {
-
-/**
-* Randpool
-*/
-class BOTAN_DLL Randpool : public RandomNumberGenerator
- {
- public:
- void randomize(byte[], size_t);
- bool is_seeded() const { return seeded; }
- void clear();
- std::string name() const;
-
- void reseed(size_t bits_to_collect);
- void add_entropy_source(EntropySource* es);
- void add_entropy(const byte input[], size_t length);
-
- /**
- * @param cipher a block cipher to use
- * @param mac a message authentication code to use
- * @param pool_blocks how many cipher blocks to use for the pool
- * @param iterations_before_reseed how many times we'll use the
- * internal state to generate output before reseeding
- */
- Randpool(BlockCipher* cipher,
- MessageAuthenticationCode* mac,
- size_t pool_blocks = 32,
- size_t iterations_before_reseed = 128);
-
- ~Randpool();
- private:
- void update_buffer();
- void mix_pool();
-
- size_t ITERATIONS_BEFORE_RESEED, POOL_BLOCKS;
- BlockCipher* cipher;
- MessageAuthenticationCode* mac;
-
- std::vector<EntropySource*> entropy_sources;
- secure_vector<byte> pool, buffer, counter;
- bool seeded;
- };
-
-}
-
-#endif
diff --git a/src/rng/rng.cpp b/src/rng/rng.cpp
index aa9b73ff3..12a6c163e 100644
--- a/src/rng/rng.cpp
+++ b/src/rng/rng.cpp
@@ -6,33 +6,29 @@
*/
#include <botan/rng.h>
-
-#if defined(BOTAN_HAS_AUTO_SEEDING_RNG)
- #include <botan/auto_rng.h>
-#endif
+#include <botan/hmac_rng.h>
+#include <botan/libstate.h>
namespace Botan {
-/*
-* Get a single random byte
-*/
-byte RandomNumberGenerator::next_byte()
+RandomNumberGenerator* RandomNumberGenerator::make_rng()
{
- byte out;
- this->randomize(&out, 1);
- return out;
+ return make_rng(global_state().algorithm_factory()).release();
}
/*
* Create and seed a new RNG object
*/
-RandomNumberGenerator* RandomNumberGenerator::make_rng()
+std::unique_ptr<RandomNumberGenerator> RandomNumberGenerator::make_rng(Algorithm_Factory& af)
{
-#if defined(BOTAN_HAS_AUTO_SEEDING_RNG)
- return new AutoSeeded_RNG;
-#endif
+ std::unique_ptr<RandomNumberGenerator> rng(
+ new HMAC_RNG(af.make_mac("HMAC(SHA-512)"),
+ af.make_mac("HMAC(SHA-256)"))
+ );
+
+ rng->reseed(256);
- throw Algorithm_Not_Found("RandomNumberGenerator::make_rng - no RNG found");
+ return rng;
}
}
diff --git a/src/rng/rng.h b/src/rng/rng.h
index 12b423e7c..a8d8ebf28 100644
--- a/src/rng/rng.h
+++ b/src/rng/rng.h
@@ -11,6 +11,7 @@
#include <botan/entropy_src.h>
#include <botan/exceptn.h>
#include <string>
+#include <memory>
namespace Botan {
@@ -22,10 +23,17 @@ class BOTAN_DLL RandomNumberGenerator
public:
/**
* Create a seeded and active RNG object for general application use
+ * Added in 1.8.0
*/
static RandomNumberGenerator* make_rng();
/**
+ * Create a seeded and active RNG object for general application use
+ * Added in 1.11.5
+ */
+ static std::unique_ptr<RandomNumberGenerator> make_rng(class Algorithm_Factory& af);
+
+ /**
* Randomize a byte array.
* @param output the byte array to hold the random output.
* @param length the length of the byte array output.
@@ -48,13 +56,18 @@ class BOTAN_DLL RandomNumberGenerator
* Return a random byte
* @return random byte
*/
- byte next_byte();
+ byte next_byte()
+ {
+ byte out;
+ this->randomize(&out, 1);
+ return out;
+ }
/**
* Check whether this RNG is seeded.
* @return true if this RNG was already seeded, false otherwise.
*/
- virtual bool is_seeded() const { return true; }
+ virtual bool is_seeded() const = 0;
/**
* Clear all internally held values of this RNG.
@@ -74,24 +87,20 @@ class BOTAN_DLL RandomNumberGenerator
virtual void reseed(size_t bits_to_collect) = 0;
/**
- * Add this entropy source to the RNG object
- * @param source the entropy source which will be retained and used by RNG
- */
- virtual void add_entropy_source(EntropySource* source) = 0;
-
- /**
* Add entropy to this RNG.
* @param in a byte array containg the entropy to be added
* @param length the length of the byte array in
*/
virtual void add_entropy(const byte in[], size_t length) = 0;
+ /*
+ * Never copy a RNG, create a new one
+ */
+ RandomNumberGenerator(const RandomNumberGenerator& rng) = delete;
+ RandomNumberGenerator& operator=(const RandomNumberGenerator& rng) = delete;
+
RandomNumberGenerator() {}
virtual ~RandomNumberGenerator() {}
- private:
- RandomNumberGenerator(const RandomNumberGenerator&) {}
- RandomNumberGenerator& operator=(const RandomNumberGenerator&)
- { return (*this); }
};
/**
@@ -100,14 +109,15 @@ class BOTAN_DLL RandomNumberGenerator
class BOTAN_DLL Null_RNG : public RandomNumberGenerator
{
public:
- void randomize(byte[], size_t) { throw PRNG_Unseeded("Null_RNG"); }
- void clear() {}
- std::string name() const { return "Null_RNG"; }
-
- void reseed(size_t) {}
- bool is_seeded() const { return false; }
- void add_entropy(const byte[], size_t) {}
- void add_entropy_source(EntropySource* es) { delete es; }
+ void randomize(byte[], size_t) override { throw PRNG_Unseeded("Null_RNG"); }
+
+ void clear() override {}
+
+ std::string name() const override { return "Null_RNG"; }
+
+ void reseed(size_t) override {}
+ bool is_seeded() const override { return false; }
+ void add_entropy(const byte[], size_t) override {}
};
}
diff --git a/src/rng/x931_rng/x931_rng.cpp b/src/rng/x931_rng/x931_rng.cpp
index 7562c7ad5..b36f87106 100644
--- a/src/rng/x931_rng/x931_rng.cpp
+++ b/src/rng/x931_rng/x931_rng.cpp
@@ -81,14 +81,6 @@ void ANSI_X931_RNG::reseed(size_t poll_bits)
}
/*
-* Add a entropy source to the underlying PRNG
-*/
-void ANSI_X931_RNG::add_entropy_source(EntropySource* src)
- {
- prng->add_entropy_source(src);
- }
-
-/*
* Add some entropy to the underlying PRNG
*/
void ANSI_X931_RNG::add_entropy(const byte input[], size_t length)
diff --git a/src/rng/x931_rng/x931_rng.h b/src/rng/x931_rng/x931_rng.h
index c8a1b8707..8052cedc3 100644
--- a/src/rng/x931_rng/x931_rng.h
+++ b/src/rng/x931_rng/x931_rng.h
@@ -25,7 +25,6 @@ class BOTAN_DLL ANSI_X931_RNG : public RandomNumberGenerator
std::string name() const;
void reseed(size_t poll_bits);
- void add_entropy_source(EntropySource*);
void add_entropy(const byte[], size_t);
/**