diff options
author | lloyd <[email protected]> | 2013-11-08 21:09:36 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2013-11-08 21:09:36 +0000 |
commit | 9fab3b28e9b728dbe71bc5b0afc9a8c408de1d0e (patch) | |
tree | 95129c533c2a27840defdc956b4e2bb5f3c2e81d | |
parent | 51bdb06ac838b426cacdb4dd8a2efecbf67820ac (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.rst | 7 | ||||
-rw-r--r-- | src/libstate/global_rng.cpp | 110 | ||||
-rw-r--r-- | src/libstate/info.txt | 26 | ||||
-rw-r--r-- | src/libstate/libstate.cpp | 3 | ||||
-rw-r--r-- | src/libstate/libstate.h | 9 | ||||
-rw-r--r-- | src/rng/auto_rng/auto_rng.h | 26 | ||||
-rw-r--r-- | src/rng/auto_rng/info.txt | 5 | ||||
-rw-r--r-- | src/rng/hmac_rng/hmac_rng.cpp | 194 | ||||
-rw-r--r-- | src/rng/hmac_rng/hmac_rng.h | 38 | ||||
-rw-r--r-- | src/rng/randpool/info.txt | 6 | ||||
-rw-r--r-- | src/rng/randpool/randpool.cpp | 208 | ||||
-rw-r--r-- | src/rng/randpool/randpool.h | 61 | ||||
-rw-r--r-- | src/rng/rng.cpp | 28 | ||||
-rw-r--r-- | src/rng/rng.h | 50 | ||||
-rw-r--r-- | src/rng/x931_rng/x931_rng.cpp | 8 | ||||
-rw-r--r-- | src/rng/x931_rng/x931_rng.h | 1 |
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); /** |