Below is the file 'botan/rng.cpp' from this revision. You can also download the file.
/************************************************* * Global RNG Source File * * (C) 1999-2005 The Botan Project * *************************************************/ #include <botan/rng.h> #include <botan/mutex.h> #include <botan/lookup.h> #include <botan/init.h> #include <memory> #include <vector> namespace Botan { namespace { /************************************************* * Global RNG/EntropySource state * *************************************************/ class RNG_State { public: void set_rngs(RandomNumberGenerator*, RandomNumberGenerator*); void add_es(EntropySource*, bool); void add_entropy(const byte[], u32bit); u32bit poll_es(EntropySource*, bool); u32bit seed(bool, u32bit); void randomize(byte[], u32bit, RNG_Quality); RNG_State(); ~RNG_State(); private: void seed_nonce_rng(); RandomNumberGenerator* global_rng; RandomNumberGenerator* nonce_rng; Mutex* rng_mutex; Mutex* sources_mutex; std::vector<EntropySource*> sources; }; /************************************************* * Create the RNG state * *************************************************/ RNG_State::RNG_State() { global_rng = nonce_rng = 0; rng_mutex = get_mutex(); sources_mutex = get_mutex(); } /************************************************* * Destroy the RNG state * *************************************************/ RNG_State::~RNG_State() { delete global_rng; delete nonce_rng; for(u32bit j = 0; j != sources.size(); j++) delete sources[j]; delete rng_mutex; delete sources_mutex; } /************************************************* * Set the RNG algorithms * *************************************************/ void RNG_State::set_rngs(RandomNumberGenerator* rng1, RandomNumberGenerator* rng2) { if(rng1) { if(global_rng) delete global_rng; global_rng = rng1; } if(rng2) { if(nonce_rng) delete nonce_rng; nonce_rng = rng2; } } /************************************************* * Get entropy from the global RNG * *************************************************/ void RNG_State::randomize(byte output[], u32bit size, RNG_Quality level) { const std::string LTERM_CIPHER = "WiderWake4+1"; Mutex_Holder lock(rng_mutex); if(!global_rng || !nonce_rng) throw Invalid_State("Global_RNG::randomize: The global RNG is unset"); if(level == Nonce) nonce_rng->randomize(output, size); else if(level == SessionKey) global_rng->randomize(output, size); else if(level == LongTermKey) { global_rng->randomize(output, size); if(have_stream_cipher(LTERM_CIPHER)) { std::auto_ptr<StreamCipher> cipher(get_stream_cipher(LTERM_CIPHER)); SecureVector<byte> key(cipher->MAXIMUM_KEYLENGTH); global_rng->randomize(key.begin(), key.size()); cipher->set_key(key.begin(), key.size()); cipher->encrypt(output, size); } } else throw Invalid_Argument("Global_RNG::randomize: Invalid RNG_Quality"); } /************************************************* * Add entropy to the RNG * *************************************************/ void RNG_State::add_entropy(const byte buf[], u32bit length) { Mutex_Holder lock(rng_mutex); if(!global_rng || !nonce_rng) throw Invalid_State("Global_RNG::add_entropy: The global RNG is unset"); global_rng->add_entropy(buf, length); seed_nonce_rng(); } /************************************************* * Add an EntropySource to the list * *************************************************/ void RNG_State::add_es(EntropySource* src, bool last) { Mutex_Holder lock(sources_mutex); if(last) sources.push_back(src); else sources.insert(sources.begin(), src); } /************************************************* * Seed the nonce RNG * *************************************************/ void RNG_State::seed_nonce_rng() { if(!global_rng->is_seeded()) return; for(u32bit j = 0; j != 3; j++) { if(nonce_rng->is_seeded()) break; SecureVector<byte> entropy(64); global_rng->randomize(entropy.begin(), entropy.size()); nonce_rng->add_entropy(entropy.begin(), entropy.size()); } } /************************************************* * Try to do a poll on an EntropySource * *************************************************/ u32bit RNG_State::poll_es(EntropySource* source, bool slow_poll) { SecureVector<byte> buffer(256); u32bit got = 0; if(slow_poll) got = source->slow_poll(buffer.begin(), buffer.size()); else got = source->fast_poll(buffer.begin(), buffer.size()); add_entropy(buffer.begin(), got); return entropy_estimate(buffer.begin(), got); } /************************************************* * Attempt to seed the RNGs * *************************************************/ u32bit RNG_State::seed(bool slow_poll, u32bit bits_to_get) { Mutex_Holder lock(sources_mutex); u32bit bits = 0; for(u32bit j = 0; j != sources.size(); j++) { bits += poll_es(sources[j], slow_poll); if(bits_to_get && bits >= bits_to_get) return bits; } return bits; } /************************************************* * The global RNG state * *************************************************/ RNG_State* rng_state = 0; } namespace Global_RNG { /************************************************* * Get entropy from the global RNG * *************************************************/ void randomize(byte output[], u32bit size, RNG_Quality level) { if(!rng_state) throw Internal_Error("Global_RNG::randomize: RNG state never created"); rng_state->randomize(output, size, level); } /************************************************* * Get entropy from the global RNG * *************************************************/ byte random(RNG_Quality level) { byte ret = 0; randomize(&ret, 1, level); return ret; } /************************************************* * Add entropy to the global RNG * *************************************************/ void add_entropy(const byte entropy[], u32bit size) { if(!rng_state) throw Internal_Error("Global_RNG::add_entropy: RNG state never created"); rng_state->add_entropy(entropy, size); } /************************************************* * Add entropy to the global RNG * *************************************************/ void add_entropy(EntropySource& src, bool slow_poll) { if(!rng_state) throw Internal_Error("Global_RNG::poll_es: RNG state never created"); rng_state->poll_es(&src, slow_poll); } /************************************************* * Add an EntropySource to the list * *************************************************/ void add_es(EntropySource* src, bool last) { if(!rng_state) throw Internal_Error("Global_RNG::add_es: RNG state never created"); rng_state->add_es(src, last); } /************************************************* * Seed the global RNG * *************************************************/ u32bit seed(bool slow_poll, u32bit bits_to_get) { if(!rng_state) throw Internal_Error("Global_RNG::seed: RNG state never created"); return rng_state->seed(slow_poll, bits_to_get); } } namespace Init { /************************************************* * Initialize the RNG system * *************************************************/ void init_rng_subsystem() { rng_state = new RNG_State; } /************************************************* * Deinitialize the RNG system * *************************************************/ void shutdown_rng_subsystem() { delete rng_state; rng_state = 0; } /************************************************* * Setup the global RNG * *************************************************/ void set_global_rngs(RandomNumberGenerator* rng1, RandomNumberGenerator* rng2) { if(!rng_state) throw Internal_Error("set_global_rngs: RNG state never created"); rng_state->set_rngs(rng1, rng2); } } }