diff options
Diffstat (limited to 'src/rng')
-rw-r--r-- | src/rng/auto_rng/auto_rng.cpp | 19 | ||||
-rw-r--r-- | src/rng/auto_rng/auto_rng.h | 4 | ||||
-rw-r--r-- | src/rng/hmac_rng/hmac_rng.cpp | 178 | ||||
-rw-r--r-- | src/rng/hmac_rng/hmac_rng.h | 13 | ||||
-rw-r--r-- | src/rng/randpool/randpool.cpp | 140 | ||||
-rw-r--r-- | src/rng/randpool/randpool.h | 22 | ||||
-rw-r--r-- | src/rng/rng.h | 13 | ||||
-rw-r--r-- | src/rng/x931_rng/x931_rng.cpp | 6 | ||||
-rw-r--r-- | src/rng/x931_rng/x931_rng.h | 2 |
9 files changed, 159 insertions, 238 deletions
diff --git a/src/rng/auto_rng/auto_rng.cpp b/src/rng/auto_rng/auto_rng.cpp index 845d958e2..620cc1f61 100644 --- a/src/rng/auto_rng/auto_rng.cpp +++ b/src/rng/auto_rng/auto_rng.cpp @@ -76,19 +76,15 @@ namespace { */ void add_entropy_sources(RandomNumberGenerator* rng) { + + // Add a high resolution timer, if available #if defined(BOTAN_HAS_TIMER_HARDWARE) rng->add_entropy_source(new Hardware_Timer); -#endif - -#if defined(BOTAN_HAS_TIMER_POSIX) +#elif defined(BOTAN_HAS_TIMER_POSIX) rng->add_entropy_source(new POSIX_Timer); -#endif - -#if defined(BOTAN_HAS_TIMER_UNIX) +#elif defined(BOTAN_HAS_TIMER_UNIX) rng->add_entropy_source(new Unix_Timer); -#endif - -#if defined(BOTAN_HAS_TIMER_WIN32) +#elif defined(BOTAN_HAS_TIMER_WIN32) rng->add_entropy_source(new Win32_Timer); #endif @@ -114,7 +110,6 @@ void add_entropy_sources(RandomNumberGenerator* rng) rng->add_entropy_source(new FTW_EntropySource("/proc")); #endif - #if defined(BOTAN_HAS_ENTROPY_SRC_WIN32) rng->add_entropy_source(new Win32_EntropySource); #endif @@ -132,7 +127,7 @@ void add_entropy_sources(RandomNumberGenerator* rng) } -AutoSeeded_RNG::AutoSeeded_RNG() +AutoSeeded_RNG::AutoSeeded_RNG(u32bit poll_bits) { rng = 0; @@ -152,7 +147,7 @@ AutoSeeded_RNG::AutoSeeded_RNG() add_entropy_sources(rng); - rng->reseed(); + rng->reseed(poll_bits); } } diff --git a/src/rng/auto_rng/auto_rng.h b/src/rng/auto_rng/auto_rng.h index dea735470..5536f2b8e 100644 --- a/src/rng/auto_rng/auto_rng.h +++ b/src/rng/auto_rng/auto_rng.h @@ -25,13 +25,13 @@ class BOTAN_DLL AutoSeeded_RNG : public RandomNumberGenerator std::string name() const { return "AutoSeeded(" + rng->name() + ")"; } - void reseed() { rng->reseed(); } + void reseed(u32bit poll_bits) { rng->reseed(poll_bits); } void add_entropy_source(EntropySource* es) { rng->add_entropy_source(es); } void add_entropy(const byte in[], u32bit len) { rng->add_entropy(in, len); } - AutoSeeded_RNG(); + AutoSeeded_RNG(u32bit poll_bits = 256); ~AutoSeeded_RNG() { delete rng; } private: RandomNumberGenerator* rng; diff --git a/src/rng/hmac_rng/hmac_rng.cpp b/src/rng/hmac_rng/hmac_rng.cpp index 188c32689..245a4039e 100644 --- a/src/rng/hmac_rng/hmac_rng.cpp +++ b/src/rng/hmac_rng/hmac_rng.cpp @@ -1,7 +1,7 @@ -/************************************************* -* HMAC_RNG Source File * -* (C) 2008 Jack Lloyd * -*************************************************/ +/* +* HMAC_RNG +* (C) 2008-2009 Jack Lloyd +*/ #include <botan/hmac_rng.h> #include <botan/loadstor.h> @@ -16,9 +16,9 @@ namespace Botan { namespace { void hmac_prf(MessageAuthenticationCode* prf, - MemoryRegion<byte>& K, - u32bit& counter, - const std::string& label) + MemoryRegion<byte>& K, + u32bit& counter, + const std::string& label) { prf->update(K, K.size()); prf->update(label); @@ -31,9 +31,9 @@ void hmac_prf(MessageAuthenticationCode* prf, } -/************************************************* -* Generate a buffer of random bytes * -*************************************************/ +/** +* Generate a buffer of random bytes +*/ void HMAC_RNG::randomize(byte out[], u32bit length) { /* Attempt to seed if we are currently not seeded, or if the @@ -44,7 +44,7 @@ void HMAC_RNG::randomize(byte out[], u32bit length) */ if(!is_seeded() || counter >= 0x100000) { - reseed(); + reseed(8 * prf->OUTPUT_LENGTH); if(!is_seeded()) throw PRNG_Unseeded(name() + " seeding attempt failed"); @@ -63,94 +63,45 @@ void HMAC_RNG::randomize(byte out[], u32bit length) out += copied; length -= copied; } - - /* Every once in a while do a fast poll of a entropy source */ - if(entropy_sources.size() && (counter % 65536 == 0)) - { - u32bit got = entropy_sources.at(source_index)-> - fast_poll(io_buffer, io_buffer.size()); - - source_index = (source_index + 1) % entropy_sources.size(); - extractor->update(io_buffer, got); - io_buffer.clear(); - } } /** * Reseed the internal state, also accepting user input to include */ -void HMAC_RNG::reseed_with_input(const byte input[], u32bit input_length) +void HMAC_RNG::reseed_with_input(u32bit poll_bits, + const byte input[], u32bit input_length) { - if(entropy_sources.size()) + /** + 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 + fast polling each source, and then slow polling as many as we think + we need (in the following loop), and feeding all of the poll + results, along with any optional user input, along with, finally, + feedback of the current PRK value, into the extractor function. + */ + + Entropy_Accumulator accum(poll_bits); + + for(u32bit i = 0; i < entropy_sources.size(); ++i) { - /** - 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 - fast polling each source, and then slow polling as many as we think - we need (in the following loop), and feeding all of the poll - results, along with any optional user input, along with, finally, - feedback of the current PRK value, into the extractor function. - */ - - /* - Previously this function did entropy estimation. However the paper - - "Boaz Barak, Shai Halevi: A model and architecture for - pseudo-random generation with applications to /dev/random. ACM - Conference on Computer and Communications Security 2005." - - provides a pretty strong case to not even try, since what we are - really interested in is the *conditional* entropy from the point - of view of an unknown attacker, which is impossible to - calculate. They recommend, if an entropy estimate of some kind - is needed, to use a low static estimate instead. We use here an - estimate of 1 bit per byte. - - One thing I had been concerned about initially was that people - without any randomness source enabled (much more likely in the - days when you had to enable them manually) would find the RNG - was unseeded and then pull the manuever some OpenSSL users did - and seed the RNG with a constant string. However, upon further - thought, I've decided that people who do that deserve to lose - anyway. - */ - - for(u32bit j = 0; j < entropy_sources.size(); ++j) - { - const u32bit got = - entropy_sources[j]->fast_poll(io_buffer, io_buffer.size()); - - entropy += got; - extractor->update(io_buffer, got); - io_buffer.clear(); - } - - for(u32bit j = 0; j != entropy_sources.size(); ++j) - { - const u32bit got = - entropy_sources[j]->slow_poll(io_buffer, io_buffer.size()); - - entropy += got; - extractor->update(io_buffer, got); - io_buffer.clear(); - } + if(accum.polling_goal_achieved()) + break; + + entropy_sources[i]->poll(accum); } - /* - And now add the user-provided input, if any - */ + // And now add the user-provided input, if any if(input_length) - { - extractor->update(input, input_length); - entropy += input_length; - } + accum.add(input, input_length, 1); + + extractor->update(accum.get_entropy_buffer()); /* - 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. + 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. Cycle the RNG once (CTXinfo="rng"), then generate a new PRF output using the CTXinfo "reseed". Provide these values as input to the @@ -175,45 +126,46 @@ void HMAC_RNG::reseed_with_input(const byte input[], u32bit input_length) counter = 0; // Upper bound entropy estimate at the extractor output size - entropy = std::min<u32bit>(entropy, 8 * extractor->OUTPUT_LENGTH); + entropy = std::min<u32bit>(entropy + accum.bits_collected(), + 8 * extractor->OUTPUT_LENGTH); } /** * Reseed the internal state */ -void HMAC_RNG::reseed() +void HMAC_RNG::reseed(u32bit poll_bits) { - reseed_with_input(0, 0); + reseed_with_input(poll_bits, 0, 0); } /** -Add user-supplied entropy by reseeding and including this -input among the poll data +* Add user-supplied entropy by reseeding and including this +* input among the poll data */ void HMAC_RNG::add_entropy(const byte input[], u32bit length) { - reseed_with_input(input, length); + reseed_with_input(0, input, length); } -/************************************************* -* Add another entropy source to the list * -*************************************************/ +/** +* Add another entropy source to the list +*/ void HMAC_RNG::add_entropy_source(EntropySource* src) { entropy_sources.push_back(src); } -/************************************************* -* Check if the the pool is seeded * -*************************************************/ +/** +* Check if the the pool is seeded +*/ bool HMAC_RNG::is_seeded() const { return (entropy >= 8 * prf->OUTPUT_LENGTH); } - /************************************************* -* Clear memory of sensitive data * -*************************************************/ +/* +* Clear memory of sensitive data +*/ void HMAC_RNG::clear() throw() { extractor->clear(); @@ -221,30 +173,28 @@ void HMAC_RNG::clear() throw() K.clear(); entropy = 0; counter = 0; - source_index = 0; } -/************************************************* -* Return the name of this type * -*************************************************/ +/** +* Return the name of this type +*/ std::string HMAC_RNG::name() const { return "HMAC_RNG(" + extractor->name() + "," + prf->name() + ")"; } -/************************************************* -* HMAC_RNG Constructor * -*************************************************/ +/** +* HMAC_RNG Constructor +*/ HMAC_RNG::HMAC_RNG(MessageAuthenticationCode* extractor_mac, MessageAuthenticationCode* prf_mac) : - extractor(extractor_mac), prf(prf_mac), io_buffer(96) + extractor(extractor_mac), prf(prf_mac) { entropy = 0; // First PRF inputs are all zero, as specified in section 2 K.create(prf->OUTPUT_LENGTH); counter = 0; - source_index = 0; /* Normally we want to feedback PRF output into the input to the @@ -275,9 +225,9 @@ HMAC_RNG::HMAC_RNG(MessageAuthenticationCode* extractor_mac, xts.length()); } -/************************************************* -* HMAC_RNG Destructor * -*************************************************/ +/** +* HMAC_RNG Destructor +*/ HMAC_RNG::~HMAC_RNG() { delete extractor; diff --git a/src/rng/hmac_rng/hmac_rng.h b/src/rng/hmac_rng/hmac_rng.h index b9ea064c3..fbfa8df19 100644 --- a/src/rng/hmac_rng/hmac_rng.h +++ b/src/rng/hmac_rng/hmac_rng.h @@ -1,7 +1,7 @@ -/************************************************* -* HMAC RNG * -* (C) 2008 Jack Lloyd * -*************************************************/ +/* +* HMAC RNG +* (C) 2008 Jack Lloyd +*/ #ifndef BOTAN_HMAC_RNG_H__ #define BOTAN_HMAC_RNG_H__ @@ -30,7 +30,7 @@ class BOTAN_DLL HMAC_RNG : public RandomNumberGenerator void clear() throw(); std::string name() const; - void reseed(); + void reseed(u32bit poll_bits); void add_entropy_source(EntropySource* es); void add_entropy(const byte[], u32bit); @@ -39,7 +39,8 @@ class BOTAN_DLL HMAC_RNG : public RandomNumberGenerator ~HMAC_RNG(); private: - void reseed_with_input(const byte input[], u32bit length); + void reseed_with_input(u32bit poll_bits, + const byte input[], u32bit length); MessageAuthenticationCode* extractor; MessageAuthenticationCode* prf; diff --git a/src/rng/randpool/randpool.cpp b/src/rng/randpool/randpool.cpp index e35ee22ca..594916a84 100644 --- a/src/rng/randpool/randpool.cpp +++ b/src/rng/randpool/randpool.cpp @@ -1,7 +1,7 @@ -/************************************************* -* Randpool Source File * -* (C) 1999-2008 Jack Lloyd * -*************************************************/ +/* +* Randpool Source File +* (C) 1999-2009 Jack Lloyd +*/ #include <botan/randpool.h> #include <botan/loadstor.h> @@ -14,9 +14,9 @@ namespace Botan { namespace { -/************************************************* -* PRF based on a MAC * -*************************************************/ +/** +* PRF based on a MAC +*/ enum RANDPOOL_PRF_TAG { CIPHER_KEY = 0, MAC_KEY = 1, @@ -25,14 +25,14 @@ enum RANDPOOL_PRF_TAG { } -/************************************************* -* Generate a buffer of random bytes * -*************************************************/ +/** +* Generate a buffer of random bytes +*/ void Randpool::randomize(byte out[], u32bit length) { if(!is_seeded()) { - reseed(); + reseed(8 * mac->OUTPUT_LENGTH); if(!is_seeded()) throw PRNG_Unseeded(name()); @@ -49,15 +49,15 @@ void Randpool::randomize(byte out[], u32bit length) } } -/************************************************* -* Refill the output buffer * -*************************************************/ +/** +* Refill the output buffer +*/ void Randpool::update_buffer() { const u64bit timestamp = system_time(); - for(u32bit j = 0; j != counter.size(); ++j) - if(++counter[j]) + for(u32bit i = 0; i != counter.size(); ++i) + if(++counter[i]) break; store_be(timestamp, counter + 4); @@ -65,17 +65,17 @@ void Randpool::update_buffer() mac->update(counter, counter.size()); SecureVector<byte> mac_val = mac->final(); - for(u32bit j = 0; j != mac_val.size(); ++j) - buffer[j % buffer.size()] ^= mac_val[j]; + for(u32bit 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 * -*************************************************/ +/** +* Mix the entropy pool +*/ void Randpool::mix_pool() { const u32bit BLOCK_SIZE = cipher->BLOCK_SIZE; @@ -90,10 +90,10 @@ void Randpool::mix_pool() xor_buf(pool, buffer, BLOCK_SIZE); cipher->encrypt(pool); - for(u32bit j = 1; j != POOL_BLOCKS; ++j) + for(u32bit i = 1; i != POOL_BLOCKS; ++i) { - const byte* previous_block = pool + BLOCK_SIZE*(j-1); - byte* this_block = pool + BLOCK_SIZE*j; + 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); } @@ -101,61 +101,33 @@ void Randpool::mix_pool() update_buffer(); } -/************************************************* -* Reseed the internal state * -*************************************************/ -void Randpool::reseed() +/** +* Reseed the internal state +*/ +void Randpool::reseed(u32bit poll_bits) { - SecureVector<byte> buffer(128); + Entropy_Accumulator accum(poll_bits); - u32bit entropy_est = 0; - - /* - When we reseed, assume we get 1 bit per byte sampled. - - This class used to perform entropy estimation, but what we really - want to measure is the conditional entropy of the data with respect - to an unknown attacker with unknown capabilities. For this reason - making any sort of sane estimate is impossible. See also - "Boaz Barak, Shai Halevi: A model and architecture for - pseudo-random generation with applications to /dev/random. ACM - Conference on Computer and Communications Security 2005." - */ - - // First do a fast poll of all sources (no matter what) - for(u32bit j = 0; j != entropy_sources.size(); ++j) + for(u32bit i = 0; i != entropy_sources.size(); ++i) { - u32bit got = entropy_sources[j]->fast_poll(buffer, buffer.size()); - - mac->update(buffer, got); - entropy_est += got; - buffer.clear(); - } + entropy_sources[i]->poll(accum); - // Then do a slow poll, until we think we have got enough entropy - for(u32bit j = 0; j != entropy_sources.size(); ++j) - { - u32bit got = entropy_sources[j]->slow_poll(buffer, buffer.size()); - - mac->update(buffer, got); - entropy_est += got; - - if(entropy_est > 512) + if(accum.polling_goal_achieved()) break; - buffer.clear(); } - SecureVector<byte> mac_val = mac->final(); + SecureVector<byte> mac_val = mac->process(accum.get_entropy_buffer()); xor_buf(pool, mac_val, mac_val.size()); mix_pool(); - entropy = std::min<u32bit>(entropy + entropy_est, 8 * mac_val.size()); + entropy = std::min<u32bit>(entropy + accum.bits_collected(), + 8 * mac_val.size()); } -/************************************************* -* Add user-supplied entropy * -*************************************************/ +/** +* Add user-supplied entropy +*/ void Randpool::add_entropy(const byte input[], u32bit length) { SecureVector<byte> mac_val = mac->process(input, length); @@ -166,25 +138,25 @@ void Randpool::add_entropy(const byte input[], u32bit length) entropy = std::min<u32bit>(entropy + length, 8 * mac_val.size()); } -/************************************************* -* Add another entropy source to the list * -*************************************************/ +/** +* Add another entropy source to the list +*/ void Randpool::add_entropy_source(EntropySource* src) { entropy_sources.push_back(src); } -/************************************************* -* Check if the the pool is seeded * -*************************************************/ +/** +* Check if the the pool is seeded +*/ bool Randpool::is_seeded() const { return (entropy >= 7 * mac->OUTPUT_LENGTH); } -/************************************************* -* Clear memory of sensitive data * -*************************************************/ +/** +* Clear memory of sensitive data +*/ void Randpool::clear() throw() { cipher->clear(); @@ -195,17 +167,17 @@ void Randpool::clear() throw() entropy = 0; } -/************************************************* -* Return the name of this type * -*************************************************/ +/** +* Return the name of this type +*/ std::string Randpool::name() const { return "Randpool(" + cipher->name() + "," + mac->name() + ")"; } -/************************************************* -* Randpool Constructor * -*************************************************/ +/** +* Randpool Constructor +*/ Randpool::Randpool(BlockCipher* cipher_in, MessageAuthenticationCode* mac_in, u32bit pool_blocks, @@ -234,9 +206,9 @@ Randpool::Randpool(BlockCipher* cipher_in, entropy = 0; } -/************************************************* -* Randpool Destructor * -*************************************************/ +/** +* Randpool Destructor +*/ Randpool::~Randpool() { delete cipher; diff --git a/src/rng/randpool/randpool.h b/src/rng/randpool/randpool.h index f6bae9d52..46683934e 100644 --- a/src/rng/randpool/randpool.h +++ b/src/rng/randpool/randpool.h @@ -1,7 +1,7 @@ -/************************************************* -* Randpool Header File * -* (C) 1999-2008 Jack Lloyd * -*************************************************/ +/* +* Randpool Header File +* (C) 1999-2008 Jack Lloyd +*/ #ifndef BOTAN_RANDPOOL_H__ #define BOTAN_RANDPOOL_H__ @@ -13,9 +13,9 @@ namespace Botan { -/************************************************* -* Randpool * -*************************************************/ +/** +* Randpool +*/ class BOTAN_DLL Randpool : public RandomNumberGenerator { public: @@ -24,11 +24,11 @@ class BOTAN_DLL Randpool : public RandomNumberGenerator void clear() throw(); std::string name() const; - void reseed(); - void add_entropy_source(EntropySource*); - void add_entropy(const byte[], u32bit); + void reseed(u32bit bits_to_collect); + void add_entropy_source(EntropySource* es); + void add_entropy(const byte input[], u32bit length); - Randpool(BlockCipher*, MessageAuthenticationCode*, + Randpool(BlockCipher* cipher, MessageAuthenticationCode* mac, u32bit pool_blocks = 32, u32bit iterations_before_reseed = 128); diff --git a/src/rng/rng.h b/src/rng/rng.h index fb92bb3c5..7fc6ee439 100644 --- a/src/rng/rng.h +++ b/src/rng/rng.h @@ -1,7 +1,7 @@ -/************************************************* -* RandomNumberGenerator Header File * -* (C) 1999-2008 Jack Lloyd * -*************************************************/ +/* +* RandomNumberGenerator Header File +* (C) 1999-2009 Jack Lloyd +*/ #ifndef BOTAN_RANDOM_NUMBER_GENERATOR_H__ #define BOTAN_RANDOM_NUMBER_GENERATOR_H__ @@ -54,8 +54,10 @@ class BOTAN_DLL RandomNumberGenerator /** * Seed this RNG using the entropy sources it contains. + * @param bits_to_collect is the number of bits of entropy to + attempt to gather from the entropy sources */ - virtual void reseed() {} + virtual void reseed(u32bit bits_to_collect) = 0; /** * Add this entropy source to the RNG object @@ -88,6 +90,7 @@ class BOTAN_DLL Null_RNG : public RandomNumberGenerator void clear() throw() {} std::string name() const { return "Null_RNG"; } + void reseed(u32bit) {} bool is_seeded() const { return false; } void add_entropy(const byte[], u32bit) {} void add_entropy_source(EntropySource* es) { delete es; } diff --git a/src/rng/x931_rng/x931_rng.cpp b/src/rng/x931_rng/x931_rng.cpp index 619c37e57..b947f525d 100644 --- a/src/rng/x931_rng/x931_rng.cpp +++ b/src/rng/x931_rng/x931_rng.cpp @@ -15,7 +15,7 @@ namespace Botan { void ANSI_X931_RNG::randomize(byte out[], u32bit length) { if(!is_seeded()) - reseed(); + reseed(8 * cipher->BLOCK_SIZE); while(length) { @@ -53,9 +53,9 @@ void ANSI_X931_RNG::update_buffer() /************************************************* * Reseed the internal state * *************************************************/ -void ANSI_X931_RNG::reseed() +void ANSI_X931_RNG::reseed(u32bit poll_bits) { - prng->reseed(); + prng->reseed(poll_bits); if(prng->is_seeded()) { diff --git a/src/rng/x931_rng/x931_rng.h b/src/rng/x931_rng/x931_rng.h index e1d090c3c..2c68b9cb4 100644 --- a/src/rng/x931_rng/x931_rng.h +++ b/src/rng/x931_rng/x931_rng.h @@ -22,7 +22,7 @@ class BOTAN_DLL ANSI_X931_RNG : public RandomNumberGenerator void clear() throw(); std::string name() const; - void reseed(); + void reseed(u32bit poll_bits); void add_entropy_source(EntropySource*); void add_entropy(const byte[], u32bit); |