diff options
Diffstat (limited to 'botan/src/rng')
-rw-r--r-- | botan/src/rng/auto_rng/auto_rng.cpp | 158 | ||||
-rw-r--r-- | botan/src/rng/auto_rng/auto_rng.h | 44 | ||||
-rw-r--r-- | botan/src/rng/auto_rng/info.txt | 16 | ||||
-rw-r--r-- | botan/src/rng/hmac_rng/hmac_rng.cpp | 223 | ||||
-rw-r--r-- | botan/src/rng/hmac_rng/hmac_rng.h | 59 | ||||
-rw-r--r-- | botan/src/rng/hmac_rng/info.txt | 14 | ||||
-rw-r--r-- | botan/src/rng/info.txt | 12 | ||||
-rw-r--r-- | botan/src/rng/randpool/info.txt | 15 | ||||
-rw-r--r-- | botan/src/rng/randpool/randpool.cpp | 214 | ||||
-rw-r--r-- | botan/src/rng/randpool/randpool.h | 53 | ||||
-rw-r--r-- | botan/src/rng/rng.cpp | 38 | ||||
-rw-r--r-- | botan/src/rng/rng.h | 103 | ||||
-rw-r--r-- | botan/src/rng/x931_rng/info.txt | 14 | ||||
-rw-r--r-- | botan/src/rng/x931_rng/x931_rng.cpp | 154 | ||||
-rw-r--r-- | botan/src/rng/x931_rng/x931_rng.h | 45 |
15 files changed, 1162 insertions, 0 deletions
diff --git a/botan/src/rng/auto_rng/auto_rng.cpp b/botan/src/rng/auto_rng/auto_rng.cpp new file mode 100644 index 0000000..8405170 --- /dev/null +++ b/botan/src/rng/auto_rng/auto_rng.cpp @@ -0,0 +1,158 @@ +/* +* Auto Seeded RNG +* (C) 2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/auto_rng.h> +#include <botan/parsing.h> +#include <botan/timer.h> +#include <botan/hmac.h> +#include <botan/sha2_32.h> +#include <botan/sha2_64.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_AES) + #include <botan/aes.h> +#endif + +#if defined(BOTAN_HAS_TIMER_HARDWARE) + #include <botan/tm_hard.h> +#endif + +#if defined(BOTAN_HAS_TIMER_POSIX) + #include <botan/tm_posix.h> +#endif + +#if defined(BOTAN_HAS_TIMER_UNIX) + #include <botan/tm_unix.h> +#endif + +#if defined(BOTAN_HAS_TIMER_WIN32) + #include <botan/tm_win32.h> +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_DEVICE) + #include <botan/es_dev.h> +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_EGD) + #include <botan/es_egd.h> +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_UNIX) + #include <botan/es_unix.h> +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_BEOS) + #include <botan/es_beos.h> +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_CAPI) + #include <botan/es_capi.h> +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_WIN32) + #include <botan/es_win32.h> +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_FTW) + #include <botan/es_ftw.h> +#endif + +namespace Botan { + +namespace { + +/** +* Add any known entropy sources to this RNG +*/ +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); +#elif defined(BOTAN_HAS_TIMER_POSIX) + rng->add_entropy_source(new POSIX_Timer); +#elif defined(BOTAN_HAS_TIMER_UNIX) + rng->add_entropy_source(new Unix_Timer); +#elif defined(BOTAN_HAS_TIMER_WIN32) + rng->add_entropy_source(new Win32_Timer); +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_DEVICE) + rng->add_entropy_source( + new Device_EntropySource( + split_on("/dev/urandom:/dev/random:/dev/srandom", ':') + ) + ); +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_EGD) + rng->add_entropy_source( + new EGD_EntropySource(split_on("/var/run/egd-pool:/dev/egd-pool", ':')) + ); +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_CAPI) + rng->add_entropy_source(new Win32_CAPI_EntropySource); +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_FTW) + rng->add_entropy_source(new FTW_EntropySource("/proc")); +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_WIN32) + rng->add_entropy_source(new Win32_EntropySource); +#endif + +#if defined(BOTAN_HAS_ENTROPY_SRC_BEOS) + rng->add_entropy_source(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", ':')) + ); +#endif + } + +} + +AutoSeeded_RNG::AutoSeeded_RNG(u32bit poll_bits) + { + rng = 0; + +#if defined(BOTAN_HAS_HMAC_RNG) + rng = new HMAC_RNG(new HMAC(new SHA_512), new HMAC(new SHA_256)); +#elif defined(BOTAN_HAS_RANDPOOL) && defined(BOTAN_HAS_AES) + rng = new Randpool(new AES_256, new HMAC(new SHA_256)); +#endif + + if(!rng) + throw Algorithm_Not_Found("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) && defined(BOTAN_HAS_AES) + rng = new ANSI_X931_RNG(new AES_256, rng); +#endif + + add_entropy_sources(rng); + + rng->reseed(poll_bits); + } + +} diff --git a/botan/src/rng/auto_rng/auto_rng.h b/botan/src/rng/auto_rng/auto_rng.h new file mode 100644 index 0000000..f18f8e5 --- /dev/null +++ b/botan/src/rng/auto_rng/auto_rng.h @@ -0,0 +1,44 @@ +/* +* Auto Seeded RNG +* (C) 2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_AUTO_SEEDING_RNG_H__ +#define BOTAN_AUTO_SEEDING_RNG_H__ + +#include <botan/rng.h> +#include <string> + +namespace Botan { + +/** +* RNG that attempts to seed itself +*/ +class BOTAN_DLL AutoSeeded_RNG : public RandomNumberGenerator + { + public: + void randomize(byte out[], u32bit len) + { rng->randomize(out, len); } + bool is_seeded() const + { return rng->is_seeded(); } + void clear() throw() { rng->clear(); } + std::string name() const + { return "AutoSeeded(" + rng->name() + ")"; } + + void reseed(u32bit poll_bits = 256) { 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(u32bit poll_bits = 256); + ~AutoSeeded_RNG() { delete rng; } + private: + RandomNumberGenerator* rng; + }; + +} + +#endif diff --git a/botan/src/rng/auto_rng/info.txt b/botan/src/rng/auto_rng/info.txt new file mode 100644 index 0000000..7d5d5dd --- /dev/null +++ b/botan/src/rng/auto_rng/info.txt @@ -0,0 +1,16 @@ +realname "Auto-seeded Random Number Generator" + +define AUTO_SEEDING_RNG + +load_on auto + +<add> +auto_rng.h +auto_rng.cpp +</add> + +<requires> +hmac +sha2 +timer +</requires> diff --git a/botan/src/rng/hmac_rng/hmac_rng.cpp b/botan/src/rng/hmac_rng/hmac_rng.cpp new file mode 100644 index 0000000..113489d --- /dev/null +++ b/botan/src/rng/hmac_rng/hmac_rng.cpp @@ -0,0 +1,223 @@ +/* +* HMAC_RNG +* (C) 2008-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/hmac_rng.h> +#include <botan/loadstor.h> +#include <botan/xor_buf.h> +#include <botan/util.h> +#include <botan/stl_util.h> +#include <algorithm> + +namespace Botan { + +namespace { + +void hmac_prf(MessageAuthenticationCode* prf, + MemoryRegion<byte>& K, + u32bit& counter, + const std::string& label) + { + prf->update(K, K.size()); + prf->update(label); + for(u32bit i = 0; i != 4; ++i) + prf->update(get_byte(i, counter)); + prf->final(K); + + ++counter; + } + +} + +/** +* Generate a buffer of random bytes +*/ +void HMAC_RNG::randomize(byte out[], u32bit length) + { + if(!is_seeded()) + throw PRNG_Unseeded(name()); + + /* + HMAC KDF as described in E-t-E, using a CTXinfo of "rng" + */ + while(length) + { + hmac_prf(prf, K, counter, "rng"); + + const u32bit copied = std::min(K.size(), length); + + copy_mem(out, K.begin(), copied); + out += copied; + length -= copied; + } + } + +/** +* Reseed the internal state, also accepting user input to include +*/ +void HMAC_RNG::reseed_with_input(u32bit poll_bits, + const byte input[], u32bit input_length) + { + /** + 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_BufferedComputation accum(*extractor, poll_bits); + + if(!entropy_sources.empty()) + { + u32bit poll_attempt = 0; + + while(!accum.polling_goal_achieved() && poll_attempt < poll_bits) + { + entropy_sources[poll_attempt % entropy_sources.size()]->poll(accum); + ++poll_attempt; + } + } + + // And now add the user-provided input, if any + if(input_length) + accum.add(input, input_length, 1); + + /* + 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 + extractor function. + */ + hmac_prf(prf, K, counter, "rng"); + extractor->update(K); // K is the CTXinfo=rng PRF output + + hmac_prf(prf, K, counter, "reseed"); + extractor->update(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()); + + // Now generate a new PRF output to use as the XTS extractor salt + hmac_prf(prf, K, counter, "xts"); + extractor->set_key(K, K.size()); + + // Reset state + K.clear(); + counter = 0; + + if(input_length || accum.bits_collected() >= poll_bits) + seeded = true; + } + +/** +* Reseed the internal state +*/ +void HMAC_RNG::reseed(u32bit poll_bits) + { + reseed_with_input(poll_bits, 0, 0); + } + +/** +* 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(0, input, length); + } + +/** +* Add another entropy source to the list +*/ +void HMAC_RNG::add_entropy_source(EntropySource* src) + { + entropy_sources.push_back(src); + } + +/* +* Clear memory of sensitive data +*/ +void HMAC_RNG::clear() throw() + { + extractor->clear(); + prf->clear(); + K.clear(); + counter = 0; + seeded = false; + } + +/** +* Return the name of this type +*/ +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) + { + // First PRF inputs are all zero, as specified in section 2 + K.create(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_with_input), 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 it to + a constant: 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. + */ + std::string prf_key = "Botan HMAC_RNG PRF"; + prf->set_key(reinterpret_cast<const byte*>(prf_key.c_str()), + prf_key.length()); + + /* + This will be used as the first XTS value when extracting input. + 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. + */ + std::string xts = "Botan HMAC_RNG XTS"; + extractor->set_key(reinterpret_cast<const byte*>(xts.c_str()), + xts.length()); + } + +/** +* HMAC_RNG Destructor +*/ +HMAC_RNG::~HMAC_RNG() + { + delete extractor; + delete prf; + + std::for_each(entropy_sources.begin(), entropy_sources.end(), + del_fun<EntropySource>()); + + counter = 0; + } + +} diff --git a/botan/src/rng/hmac_rng/hmac_rng.h b/botan/src/rng/hmac_rng/hmac_rng.h new file mode 100644 index 0000000..318e2a9 --- /dev/null +++ b/botan/src/rng/hmac_rng/hmac_rng.h @@ -0,0 +1,59 @@ +/* +* HMAC RNG +* (C) 2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_HMAC_RNG_H__ +#define BOTAN_HMAC_RNG_H__ + +#include <botan/mac.h> +#include <botan/rng.h> +#include <vector> + +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. +*/ +class BOTAN_DLL HMAC_RNG : public RandomNumberGenerator + { + public: + void randomize(byte buf[], u32bit len); + bool is_seeded() const { return seeded; } + void clear() throw(); + std::string name() const; + + void reseed(u32bit poll_bits); + void add_entropy_source(EntropySource* es); + void add_entropy(const byte[], u32bit); + + HMAC_RNG(MessageAuthenticationCode* extractor, + MessageAuthenticationCode* prf); + + ~HMAC_RNG(); + private: + void reseed_with_input(u32bit poll_bits, + const byte input[], u32bit length); + + MessageAuthenticationCode* extractor; + MessageAuthenticationCode* prf; + + std::vector<EntropySource*> entropy_sources; + bool seeded; + + SecureVector<byte> K, io_buffer; + u32bit counter, source_index; + }; + +} + +#endif diff --git a/botan/src/rng/hmac_rng/info.txt b/botan/src/rng/hmac_rng/info.txt new file mode 100644 index 0000000..2c7f13e --- /dev/null +++ b/botan/src/rng/hmac_rng/info.txt @@ -0,0 +1,14 @@ +realname "HMAC RNG" + +define HMAC_RNG + +load_on auto + +<add> +hmac_rng.cpp +hmac_rng.h +</add> + +<requires> +mac +</requires> diff --git a/botan/src/rng/info.txt b/botan/src/rng/info.txt new file mode 100644 index 0000000..44a4166 --- /dev/null +++ b/botan/src/rng/info.txt @@ -0,0 +1,12 @@ +realname "Random Number Generators" + +load_on auto + +<add> +rng.cpp +rng.h +</add> + +<requires> +entropy +</requires> diff --git a/botan/src/rng/randpool/info.txt b/botan/src/rng/randpool/info.txt new file mode 100644 index 0000000..cc7f615 --- /dev/null +++ b/botan/src/rng/randpool/info.txt @@ -0,0 +1,15 @@ +realname "Randpool RNG" + +define RANDPOOL + +load_on auto + +<add> +randpool.cpp +randpool.h +</add> + +<requires> +block +mac +</requires> diff --git a/botan/src/rng/randpool/randpool.cpp b/botan/src/rng/randpool/randpool.cpp new file mode 100644 index 0000000..4d7b92d --- /dev/null +++ b/botan/src/rng/randpool/randpool.cpp @@ -0,0 +1,214 @@ +/* +* Randpool +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/randpool.h> +#include <botan/loadstor.h> +#include <botan/xor_buf.h> +#include <botan/util.h> +#include <botan/stl_util.h> +#include <algorithm> + +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[], u32bit length) + { + if(!is_seeded()) + throw PRNG_Unseeded(name()); + + update_buffer(); + while(length) + { + const u32bit copied = std::min(length, buffer.size()); + copy_mem(out, buffer.begin(), copied); + out += copied; + length -= copied; + update_buffer(); + } + } + +/** +* Refill the output buffer +*/ +void Randpool::update_buffer() + { + const u64bit timestamp = system_time(); + + for(u32bit i = 0; i != counter.size(); ++i) + if(++counter[i]) + break; + store_be(timestamp, counter + 4); + + mac->update(static_cast<byte>(GEN_OUTPUT)); + mac->update(counter, counter.size()); + SecureVector<byte> mac_val = mac->final(); + + 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 +*/ +void Randpool::mix_pool() + { + const u32bit BLOCK_SIZE = cipher->BLOCK_SIZE; + + mac->update(static_cast<byte>(MAC_KEY)); + mac->update(pool, pool.size()); + mac->set_key(mac->final()); + + mac->update(static_cast<byte>(CIPHER_KEY)); + mac->update(pool, pool.size()); + cipher->set_key(mac->final()); + + xor_buf(pool, buffer, BLOCK_SIZE); + cipher->encrypt(pool); + for(u32bit 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(u32bit poll_bits) + { + Entropy_Accumulator_BufferedComputation accum(*mac, poll_bits); + + if(!entropy_sources.empty()) + { + u32bit poll_attempt = 0; + + while(!accum.polling_goal_achieved() && poll_attempt < poll_bits) + { + entropy_sources[poll_attempt % entropy_sources.size()]->poll(accum); + ++poll_attempt; + } + } + + SecureVector<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[], u32bit length) + { + SecureVector<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() throw() + { + cipher->clear(); + mac->clear(); + pool.clear(); + buffer.clear(); + counter.clear(); + 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, + u32bit pool_blocks, + u32bit iter_before_reseed) : + ITERATIONS_BEFORE_RESEED(iter_before_reseed), + POOL_BLOCKS(pool_blocks), + cipher(cipher_in), + mac(mac_in) + { + const u32bit BLOCK_SIZE = cipher->BLOCK_SIZE; + const u32bit OUTPUT_LENGTH = mac->OUTPUT_LENGTH; + + if(OUTPUT_LENGTH < BLOCK_SIZE || + !cipher->valid_keylength(OUTPUT_LENGTH) || + !mac->valid_keylength(OUTPUT_LENGTH)) + { + std::string ciphername = cipher->name(), macname = mac->name(); + delete cipher; + delete mac; + throw Internal_Error("Randpool: Invalid algorithm combination " + + ciphername + "/" + macname); + } + + buffer.create(BLOCK_SIZE); + pool.create(POOL_BLOCKS * BLOCK_SIZE); + counter.create(12); + seeded = false; + } + +/** +* Randpool Destructor +*/ +Randpool::~Randpool() + { + delete cipher; + delete mac; + + std::for_each(entropy_sources.begin(), entropy_sources.end(), + del_fun<EntropySource>()); + } + +} diff --git a/botan/src/rng/randpool/randpool.h b/botan/src/rng/randpool/randpool.h new file mode 100644 index 0000000..b6a3add --- /dev/null +++ b/botan/src/rng/randpool/randpool.h @@ -0,0 +1,53 @@ +/* +* 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[], u32bit); + bool is_seeded() const { return seeded; } + void clear() throw(); + std::string name() const; + + void reseed(u32bit bits_to_collect); + void add_entropy_source(EntropySource* es); + void add_entropy(const byte input[], u32bit length); + + Randpool(BlockCipher* cipher, MessageAuthenticationCode* mac, + u32bit pool_blocks = 32, + u32bit iterations_before_reseed = 128); + + ~Randpool(); + private: + void update_buffer(); + void mix_pool(); + + u32bit ITERATIONS_BEFORE_RESEED, POOL_BLOCKS; + BlockCipher* cipher; + MessageAuthenticationCode* mac; + + std::vector<EntropySource*> entropy_sources; + SecureVector<byte> pool, buffer, counter; + bool seeded; + }; + +} + +#endif diff --git a/botan/src/rng/rng.cpp b/botan/src/rng/rng.cpp new file mode 100644 index 0000000..aa9b73f --- /dev/null +++ b/botan/src/rng/rng.cpp @@ -0,0 +1,38 @@ +/* +* Random Number Generator Base +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/rng.h> + +#if defined(BOTAN_HAS_AUTO_SEEDING_RNG) + #include <botan/auto_rng.h> +#endif + +namespace Botan { + +/* +* Get a single random byte +*/ +byte RandomNumberGenerator::next_byte() + { + byte out; + this->randomize(&out, 1); + return out; + } + +/* +* Create and seed a new RNG object +*/ +RandomNumberGenerator* RandomNumberGenerator::make_rng() + { +#if defined(BOTAN_HAS_AUTO_SEEDING_RNG) + return new AutoSeeded_RNG; +#endif + + throw Algorithm_Not_Found("RandomNumberGenerator::make_rng - no RNG found"); + } + +} diff --git a/botan/src/rng/rng.h b/botan/src/rng/rng.h new file mode 100644 index 0000000..41904db --- /dev/null +++ b/botan/src/rng/rng.h @@ -0,0 +1,103 @@ +/* +* RandomNumberGenerator +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_RANDOM_NUMBER_GENERATOR_H__ +#define BOTAN_RANDOM_NUMBER_GENERATOR_H__ + +#include <botan/entropy_src.h> +#include <botan/exceptn.h> +#include <string> + +namespace Botan { + +/** +* This class represents a random number (RNG) generator object. +*/ +class BOTAN_DLL RandomNumberGenerator + { + public: + /** + * Create a seeded and active RNG object for general application use + */ + static RandomNumberGenerator* make_rng(); + + /** + * Randomize a byte array. + * @param output the byte array to hold the random output. + * @param length the length of the byte array output. + */ + virtual void randomize(byte output[], u32bit length) = 0; + + /** + * Return a random byte + * @return random byte + */ + byte next_byte(); + + /** + * Check whether this RNG is seeded. + * @return true if this RNG was already seeded, false otherwise. + */ + virtual bool is_seeded() const { return true; } + + /** + * Clear all internally held values of this RNG. + */ + virtual void clear() throw() = 0; + + /** + * Return the name of this object + */ + virtual std::string name() const = 0; + + /** + * 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(u32bit 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[], u32bit length) = 0; + + RandomNumberGenerator() {} + virtual ~RandomNumberGenerator() {} + private: + RandomNumberGenerator(const RandomNumberGenerator&) {} + RandomNumberGenerator& operator=(const RandomNumberGenerator&) + { return (*this); } + }; + +/* +* Null Random Number Generator +*/ +class BOTAN_DLL Null_RNG : public RandomNumberGenerator + { + public: + void randomize(byte[], u32bit) { throw PRNG_Unseeded("Null_RNG"); } + 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; } + }; + +} + +#endif diff --git a/botan/src/rng/x931_rng/info.txt b/botan/src/rng/x931_rng/info.txt new file mode 100644 index 0000000..633eb02 --- /dev/null +++ b/botan/src/rng/x931_rng/info.txt @@ -0,0 +1,14 @@ +realname "ANSI X9.31 PRNG" + +define X931_RNG + +load_on auto + +<add> +x931_rng.cpp +x931_rng.h +</add> + +<requires> +block +</requires> diff --git a/botan/src/rng/x931_rng/x931_rng.cpp b/botan/src/rng/x931_rng/x931_rng.cpp new file mode 100644 index 0000000..e239bce --- /dev/null +++ b/botan/src/rng/x931_rng/x931_rng.cpp @@ -0,0 +1,154 @@ +/* +* ANSI X9.31 RNG +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/x931_rng.h> +#include <botan/xor_buf.h> +#include <algorithm> + +namespace Botan { + +/** +* Generate a buffer of random bytes +*/ +void ANSI_X931_RNG::randomize(byte out[], u32bit length) + { + if(!is_seeded()) + throw PRNG_Unseeded(name()); + + while(length) + { + if(position == R.size()) + update_buffer(); + + const u32bit copied = std::min(length, R.size() - position); + + copy_mem(out, R + position, copied); + out += copied; + length -= copied; + position += copied; + } + } + +/** +* Refill the internal state +*/ +void ANSI_X931_RNG::update_buffer() + { + SecureVector<byte> DT(cipher->BLOCK_SIZE); + + prng->randomize(DT, DT.size()); + cipher->encrypt(DT); + + xor_buf(R, V, DT, cipher->BLOCK_SIZE); + cipher->encrypt(R); + + xor_buf(V, R, DT, cipher->BLOCK_SIZE); + cipher->encrypt(V); + + position = 0; + } + +/** +* Reset V and the cipher key with new values +*/ +void ANSI_X931_RNG::rekey() + { + if(prng->is_seeded()) + { + SecureVector<byte> key(cipher->MAXIMUM_KEYLENGTH); + prng->randomize(key, key.size()); + cipher->set_key(key, key.size()); + + if(V.size() != cipher->BLOCK_SIZE) + V.create(cipher->BLOCK_SIZE); + prng->randomize(V, V.size()); + + update_buffer(); + } + } + +/** +* Reseed the internal state +*/ +void ANSI_X931_RNG::reseed(u32bit poll_bits) + { + prng->reseed(poll_bits); + rekey(); + } + +/** +* 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[], u32bit length) + { + prng->add_entropy(input, length); + rekey(); + } + +/** +* Check if the the PRNG is seeded +*/ +bool ANSI_X931_RNG::is_seeded() const + { + return V.has_items(); + } + +/** +* Clear memory of sensitive data +*/ +void ANSI_X931_RNG::clear() throw() + { + cipher->clear(); + prng->clear(); + R.clear(); + V.destroy(); + + position = 0; + } + +/** +* Return the name of this type +*/ +std::string ANSI_X931_RNG::name() const + { + return "X9.31(" + cipher->name() + ")"; + } + +/** +* ANSI X931 RNG Constructor +*/ +ANSI_X931_RNG::ANSI_X931_RNG(BlockCipher* cipher_in, + RandomNumberGenerator* prng_in) + { + if(!prng_in || !cipher_in) + throw Invalid_Argument("ANSI_X931_RNG constructor: NULL arguments"); + + cipher = cipher_in; + prng = prng_in; + + R.create(cipher->BLOCK_SIZE); + position = 0; + } + +/** +* ANSI X931 RNG Destructor +*/ +ANSI_X931_RNG::~ANSI_X931_RNG() + { + delete cipher; + delete prng; + } + +} diff --git a/botan/src/rng/x931_rng/x931_rng.h b/botan/src/rng/x931_rng/x931_rng.h new file mode 100644 index 0000000..44e9b44 --- /dev/null +++ b/botan/src/rng/x931_rng/x931_rng.h @@ -0,0 +1,45 @@ +/* +* ANSI X9.31 RNG +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ANSI_X931_RNG_H__ +#define BOTAN_ANSI_X931_RNG_H__ + +#include <botan/rng.h> +#include <botan/block_cipher.h> + +namespace Botan { + +/** +* ANSI X9.31 RNG +*/ +class BOTAN_DLL ANSI_X931_RNG : public RandomNumberGenerator + { + public: + void randomize(byte[], u32bit); + bool is_seeded() const; + void clear() throw(); + std::string name() const; + + void reseed(u32bit poll_bits); + void add_entropy_source(EntropySource*); + void add_entropy(const byte[], u32bit); + + ANSI_X931_RNG(BlockCipher*, RandomNumberGenerator*); + ~ANSI_X931_RNG(); + private: + void rekey(); + void update_buffer(); + + BlockCipher* cipher; + RandomNumberGenerator* prng; + SecureVector<byte> V, R; + u32bit position; + }; + +} + +#endif |