diff options
author | Jack Lloyd <[email protected]> | 2016-06-30 13:15:30 -0400 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2016-07-17 10:43:40 -0400 |
commit | 93922f20f04058ec624f7db3c74d8aa5a3d06440 (patch) | |
tree | 81144cfacced43c68c4385683ee0c123a1987042 /src/lib | |
parent | 4c5847412d41756aab738a3746666cfaffe5d4af (diff) |
Add Stateful_RNG
Handles fork checking for HMAC_RNG and HMAC_DRBG
AutoSeeded_RNG change - switch to HMAC_DRBG as default.
Start removing the io buffer from entropy poller.
Update default RNG poll bits to 256.
Fix McEliece test, was using wrong RNG API.
Update docs.
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/entropy/darwin_secrandom/darwin_secrandom.cpp | 6 | ||||
-rw-r--r-- | src/lib/entropy/darwin_secrandom/darwin_secrandom.h | 2 | ||||
-rw-r--r-- | src/lib/entropy/dev_random/dev_random.cpp | 75 | ||||
-rw-r--r-- | src/lib/entropy/dev_random/dev_random.h | 6 | ||||
-rw-r--r-- | src/lib/prov/tpm/tpm.h | 5 | ||||
-rw-r--r-- | src/lib/rng/auto_rng.h (renamed from src/lib/rng/auto_rng/auto_rng.h) | 14 | ||||
-rw-r--r-- | src/lib/rng/auto_rng/info.txt | 9 | ||||
-rw-r--r-- | src/lib/rng/hmac_drbg/hmac_drbg.cpp | 14 | ||||
-rw-r--r-- | src/lib/rng/hmac_drbg/hmac_drbg.h | 10 | ||||
-rw-r--r-- | src/lib/rng/hmac_rng/hmac_rng.cpp | 109 | ||||
-rw-r--r-- | src/lib/rng/hmac_rng/hmac_rng.h | 14 | ||||
-rw-r--r-- | src/lib/rng/rng.cpp | 59 | ||||
-rw-r--r-- | src/lib/rng/rng.h | 46 |
13 files changed, 199 insertions, 170 deletions
diff --git a/src/lib/entropy/darwin_secrandom/darwin_secrandom.cpp b/src/lib/entropy/darwin_secrandom/darwin_secrandom.cpp index 0a6b85955..7dde17155 100644 --- a/src/lib/entropy/darwin_secrandom/darwin_secrandom.cpp +++ b/src/lib/entropy/darwin_secrandom/darwin_secrandom.cpp @@ -16,11 +16,11 @@ namespace Botan { */ void Darwin_SecRandom::poll(Entropy_Accumulator& accum) { - secure_vector<byte>& buf = accum.get_io_buf(BOTAN_SYSTEM_RNG_POLL_REQUEST); + m_io_buf.resize(BOTAN_SYSTEM_RNG_POLL_REQUEST); - if(0 == SecRandomCopyBytes(kSecRandomDefault, buf.size(), buf.data())) + if(0 == SecRandomCopyBytes(kSecRandomDefault, m_io_buf.size(), m_io_buf.data())) { - accum.add(buf.data(), buf.size(), BOTAN_ENTROPY_ESTIMATE_STRONG_RNG); + accum.add(m_io_buf.data(), m_io_buf.size(), BOTAN_ENTROPY_ESTIMATE_STRONG_RNG); } } diff --git a/src/lib/entropy/darwin_secrandom/darwin_secrandom.h b/src/lib/entropy/darwin_secrandom/darwin_secrandom.h index 09cdc208d..267d177f0 100644 --- a/src/lib/entropy/darwin_secrandom/darwin_secrandom.h +++ b/src/lib/entropy/darwin_secrandom/darwin_secrandom.h @@ -21,6 +21,8 @@ class Darwin_SecRandom final : public Entropy_Source std::string name() const override { return "darwin_secrandom"; } void poll(Entropy_Accumulator& accum) override; + private: + secure_vector<uint8_t> m_io_buf; }; } diff --git a/src/lib/entropy/dev_random/dev_random.cpp b/src/lib/entropy/dev_random/dev_random.cpp index aca161d64..ff746f34e 100644 --- a/src/lib/entropy/dev_random/dev_random.cpp +++ b/src/lib/entropy/dev_random/dev_random.cpp @@ -6,6 +6,7 @@ */ #include <botan/internal/dev_random.h> +#include <botan/exceptn.h> #include <sys/types.h> #include <sys/select.h> @@ -31,15 +32,39 @@ Device_EntropySource::Device_EntropySource(const std::vector<std::string>& fsnam const int flags = O_RDONLY | O_NONBLOCK | O_NOCTTY; + m_max_fd = 0; + for(auto fsname : fsnames) { - fd_type fd = ::open(fsname.c_str(), flags); + int fd = ::open(fsname.c_str(), flags); - if(fd >= 0 && fd < FD_SETSIZE) - m_devices.push_back(fd); - else if(fd >= 0) - ::close(fd); + if(fd > 0) + { + if(fd > FD_SETSIZE) + { + ::close(fd); + throw Exception("Open of OS RNG succeeded but fd is too large for fd_set"); + } + + m_dev_fds.push_back(fd); + m_max_fd = std::max(m_max_fd, fd); + } + else + { + /* + ENOENT or EACCES is normal as some of the named devices may not exist + on this system. But any other errno value probably indicates + either a bug in the application or file descriptor exhaustion. + */ + if(errno != ENOENT && errno != EACCES) + { + throw Exception("Opening OS RNG device failed with errno " + + std::to_string(errno)); + } + } } + + m_io_buf.resize(BOTAN_SYSTEM_RNG_POLL_REQUEST); } /** @@ -47,8 +72,11 @@ Device_EntropySource destructor: close all open devices */ Device_EntropySource::~Device_EntropySource() { - for(size_t i = 0; i != m_devices.size(); ++i) - ::close(m_devices[i]); + for(int fd : m_dev_fds) + { + // ignoring return value here, can't throw in destructor anyway + ::close(fd); + } } /** @@ -56,35 +84,36 @@ Device_EntropySource::~Device_EntropySource() */ void Device_EntropySource::poll(Entropy_Accumulator& accum) { - if(m_devices.empty()) + if(m_dev_fds.empty()) return; - fd_type max_fd = m_devices[0]; fd_set read_set; FD_ZERO(&read_set); - for(size_t i = 0; i != m_devices.size(); ++i) + + for(int dev_fd : m_dev_fds) { - FD_SET(m_devices[i], &read_set); - max_fd = std::max(m_devices[i], max_fd); + FD_SET(dev_fd, &read_set); } struct ::timeval timeout; - timeout.tv_sec = (BOTAN_SYSTEM_RNG_POLL_TIMEOUT_MS / 1000); timeout.tv_usec = (BOTAN_SYSTEM_RNG_POLL_TIMEOUT_MS % 1000) * 1000; - if(::select(max_fd + 1, &read_set, nullptr, nullptr, &timeout) < 0) - return; - - secure_vector<byte>& buf = accum.get_io_buf(BOTAN_SYSTEM_RNG_POLL_REQUEST); - - for(size_t i = 0; i != m_devices.size(); ++i) + if(::select(m_max_fd + 1, &read_set, nullptr, nullptr, &timeout) > 0) { - if(FD_ISSET(m_devices[i], &read_set)) + for(int dev_fd : m_dev_fds) { - const ssize_t got = ::read(m_devices[i], buf.data(), buf.size()); - if(got > 0) - accum.add(buf.data(), got, BOTAN_ENTROPY_ESTIMATE_STRONG_RNG); + if(FD_ISSET(dev_fd, &read_set)) + { + const ssize_t got = ::read(dev_fd, m_io_buf.data(), m_io_buf.size()); + + if(got > 0) + { + accum.add(m_io_buf.data(), + static_cast<size_t>(got), + BOTAN_ENTROPY_ESTIMATE_STRONG_RNG); + } + } } } } diff --git a/src/lib/entropy/dev_random/dev_random.h b/src/lib/entropy/dev_random/dev_random.h index 1f29b2f64..05b36f3eb 100644 --- a/src/lib/entropy/dev_random/dev_random.h +++ b/src/lib/entropy/dev_random/dev_random.h @@ -25,10 +25,12 @@ class Device_EntropySource final : public Entropy_Source void poll(Entropy_Accumulator& accum) override; Device_EntropySource(const std::vector<std::string>& fsnames); + ~Device_EntropySource(); private: - typedef int fd_type; - std::vector<fd_type> m_devices; + secure_vector<uint8_t> m_io_buf; + std::vector<int> m_dev_fds; + int m_max_fd; }; } diff --git a/src/lib/prov/tpm/tpm.h b/src/lib/prov/tpm/tpm.h index 15bc216ab..b8093518c 100644 --- a/src/lib/prov/tpm/tpm.h +++ b/src/lib/prov/tpm/tpm.h @@ -1,3 +1,4 @@ + /* * TPM 1.2 interface * (C) 2015 Jack Lloyd @@ -71,7 +72,7 @@ class BOTAN_DLL TPM_Context TSS_HTPM m_tpm; }; -class BOTAN_DLL TPM_RNG : public RandomNumberGenerator +class BOTAN_DLL TPM_RNG : public Hardware_RNG { public: TPM_RNG(TPM_Context& ctx) : m_ctx(ctx) {} @@ -90,7 +91,7 @@ class BOTAN_DLL TPM_RNG : public RandomNumberGenerator bool is_seeded() const override { return true; } - void clear() const override {} + void clear() override {} private: TPM_Context& m_ctx; diff --git a/src/lib/rng/auto_rng/auto_rng.h b/src/lib/rng/auto_rng.h index 72ea88d3e..b51390ae2 100644 --- a/src/lib/rng/auto_rng/auto_rng.h +++ b/src/lib/rng/auto_rng.h @@ -9,19 +9,20 @@ #define BOTAN_AUTO_SEEDING_RNG_H__ #include <botan/rng.h> -#include <string> namespace Botan { -class AutoSeeded_RNG : public RandomNumberGenerator +class BOTAN_DLL AutoSeeded_RNG final : public RandomNumberGenerator { public: - void randomize(byte out[], size_t len) override - { m_rng->randomize(out, len); } + void randomize(byte out[], size_t len) override; + + void randomize_with_input(byte output[], size_t output_len, + const byte input[], size_t input_len) override; bool is_seeded() const override { return m_rng->is_seeded(); } - void clear() override { m_rng->clear(); } + void clear() override { m_rng->clear(); m_counter = 0; } std::string name() const override { return m_rng->name(); } @@ -35,9 +36,10 @@ class AutoSeeded_RNG : public RandomNumberGenerator void add_entropy(const byte in[], size_t len) override { m_rng->add_entropy(in, len); } - AutoSeeded_RNG() : m_rng(RandomNumberGenerator::make_rng()) {} + AutoSeeded_RNG(size_t bytes_before_reseed = BOTAN_RNG_MAX_OUTPUT_BEFORE_RESEED); private: std::unique_ptr<RandomNumberGenerator> m_rng; + uint32_t m_counter = 0; }; } diff --git a/src/lib/rng/auto_rng/info.txt b/src/lib/rng/auto_rng/info.txt deleted file mode 100644 index 4f48f484b..000000000 --- a/src/lib/rng/auto_rng/info.txt +++ /dev/null @@ -1,9 +0,0 @@ -define AUTO_SEEDING_RNG 20131128 - -<requires> -hmac_rng -hmac -sha2_32 -sha2_64 -#dev_random|cryptoapi_rng|unix_procs|proc_walk -</requires> diff --git a/src/lib/rng/hmac_drbg/hmac_drbg.cpp b/src/lib/rng/hmac_drbg/hmac_drbg.cpp index 201a9f39b..6fdd7daf9 100644 --- a/src/lib/rng/hmac_drbg/hmac_drbg.cpp +++ b/src/lib/rng/hmac_drbg/hmac_drbg.cpp @@ -10,9 +10,14 @@ namespace Botan { -HMAC_DRBG::HMAC_DRBG(const std::string& hmac_hash) : - HMAC_DRBG(hmac_hash, BOTAN_RNG_MAX_OUTPUT_BEFORE_RESEED) - {} +HMAC_DRBG::HMAC_DRBG(MessageAuthenticationCode* hmac, + size_t max_bytes_before_reseed) : + Stateful_RNG(max_bytes_before_reseed), + m_mac(hmac) + { + m_V.resize(m_mac->output_length()); + clear(); + } HMAC_DRBG::HMAC_DRBG(const std::string& hmac_hash, size_t max_bytes_before_reseed) : @@ -27,12 +32,13 @@ HMAC_DRBG::HMAC_DRBG(const std::string& hmac_hash, } m_V.resize(m_mac->output_length()); - clear(); } void HMAC_DRBG::clear() { + Stateful_RNG::clear(); + for(size_t i = 0; i != m_V.size(); ++i) m_V[i] = 0x01; m_mac->set_key(std::vector<byte>(m_mac->output_length(), 0x00)); diff --git a/src/lib/rng/hmac_drbg/hmac_drbg.h b/src/lib/rng/hmac_drbg/hmac_drbg.h index f52ae9de1..8ee598470 100644 --- a/src/lib/rng/hmac_drbg/hmac_drbg.h +++ b/src/lib/rng/hmac_drbg/hmac_drbg.h @@ -19,10 +19,14 @@ namespace Botan { class BOTAN_DLL HMAC_DRBG final : public Stateful_RNG { public: - HMAC_DRBG(const std::string& hmac_hash); - + /** + * Initialize an HMAC_DRBG instance with the given hash function + */ HMAC_DRBG(const std::string& hmac_hash, - size_t max_bytes_before_reseed); + size_t max_bytes_before_reseed = BOTAN_RNG_MAX_OUTPUT_BEFORE_RESEED); + + HMAC_DRBG(MessageAuthenticationCode* hmac, + size_t max_bytes_before_reseed = BOTAN_RNG_MAX_OUTPUT_BEFORE_RESEED); std::string name() const override; diff --git a/src/lib/rng/hmac_rng/hmac_rng.cpp b/src/lib/rng/hmac_rng/hmac_rng.cpp index 7a9e4dbc5..410e3040a 100644 --- a/src/lib/rng/hmac_rng/hmac_rng.cpp +++ b/src/lib/rng/hmac_rng/hmac_rng.cpp @@ -9,15 +9,35 @@ #include <botan/entropy_src.h> #include <botan/internal/os_utils.h> #include <algorithm> -#include <chrono> namespace Botan { +HMAC_RNG::HMAC_RNG(const std::string& hash, size_t max_before_reseed) : + Stateful_RNG(max_before_reseed) + { + m_extractor = MAC::create("HMAC(" + hash + ")"); + if(!m_extractor) + throw Invalid_Argument("HMAC_RNG hash not found"); + + m_prf.reset(m_extractor->clone()); + + 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()); + } + + this->clear(); + } + /* * HMAC_RNG Constructor */ HMAC_RNG::HMAC_RNG(MessageAuthenticationCode* extractor, MessageAuthenticationCode* prf) : + Stateful_RNG(BOTAN_RNG_MAX_OUTPUT_BEFORE_RESEED), m_extractor(extractor), m_prf(prf) { if(!m_prf->valid_keylength(m_extractor->output_length()) || @@ -33,7 +53,7 @@ HMAC_RNG::HMAC_RNG(MessageAuthenticationCode* extractor, void HMAC_RNG::clear() { - m_collected_entropy_estimate = 0; + Stateful_RNG::clear(); m_counter = 0; // First PRF inputs are all zero, as specified in section 2 @@ -71,7 +91,7 @@ void HMAC_RNG::clear() void HMAC_RNG::new_K_value(byte label) { m_prf->update(m_K); - m_prf->update_be(m_pid); + m_prf->update_be(last_pid()); m_prf->update_be(OS::get_processor_timestamp()); m_prf->update_be(OS::get_system_timestamp_ns()); m_prf->update_be(m_counter++); @@ -84,76 +104,38 @@ void HMAC_RNG::new_K_value(byte label) */ void HMAC_RNG::randomize(byte out[], size_t length) { - if(!is_seeded() || m_pid != OS::get_process_id()) - { - reseed(256); - if(!is_seeded()) - throw PRNG_Unseeded(name()); - } - - const size_t max_per_prf_iter = m_prf->output_length() / 2; - - m_output_since_reseed += length; - - if(m_output_since_reseed >= BOTAN_RNG_MAX_OUTPUT_BEFORE_RESEED) - { - reseed_with_sources(Entropy_Sources::global_sources(), - BOTAN_RNG_RESEED_POLL_BITS, - BOTAN_RNG_AUTO_RESEED_TIMEOUT); - } + reseed_check(length); - /* - HMAC KDF as described in E-t-E, using a CTXinfo of "rng" - */ while(length) { new_K_value(Running); - const size_t copied = std::min<size_t>(length, max_per_prf_iter); + const size_t copied = std::min<size_t>(length, m_prf->output_length()); copy_mem(out, m_K.data(), copied); out += copied; length -= copied; } + + new_K_value(BlockFinished); } size_t HMAC_RNG::reseed_with_sources(Entropy_Sources& srcs, size_t poll_bits, std::chrono::milliseconds timeout) { + new_K_value(Reseed); + m_extractor->update(m_K); // m_K is the PRF output + /* - 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 - polling as many sources as we think needed to reach our polling - goal. We then also include feedback of the current PRK so that - a bad poll doesn't wipe us out. + * This ends up calling add_entropy which provides input to the extractor */ - - typedef std::chrono::system_clock clock; - auto deadline = clock::now() + timeout; - - double bits_collected = 0; - - Entropy_Accumulator accum([&](const byte in[], size_t in_len, double entropy_estimate) { - m_extractor->update(in, in_len); - bits_collected += entropy_estimate; - return (bits_collected >= poll_bits || clock::now() > deadline); - }); - - srcs.poll(accum); + size_t bits_collected = Stateful_RNG::reseed_with_sources(srcs, poll_bits, timeout); /* - * 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. + Now derive the new PRK using everything that has been fed into + the extractor, and set the PRF key to that */ - new_K_value(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 */ m_prf->set_key(m_extractor->final()); // Now generate a new PRF output to use as the XTS extractor salt @@ -164,32 +146,17 @@ size_t HMAC_RNG::reseed_with_sources(Entropy_Sources& srcs, zeroise(m_K); m_counter = 0; - m_collected_entropy_estimate = - std::min<size_t>(m_collected_entropy_estimate + static_cast<size_t>(bits_collected), - m_extractor->output_length() * 8); - - m_output_since_reseed = 0; - m_pid = OS::get_process_id(); - - return static_cast<size_t>(bits_collected); - } - -bool HMAC_RNG::is_seeded() const - { - return (m_collected_entropy_estimate >= 256); + return bits_collected; } /* -* Add user-supplied entropy to the extractor input then reseed -* to incorporate it into the state +* Add user-supplied entropy to the extractor input then set remaining +* output length to for a reseed on next use. */ void HMAC_RNG::add_entropy(const byte input[], size_t length) { m_extractor->update(input, length); - - reseed_with_sources(Entropy_Sources::global_sources(), - BOTAN_RNG_RESEED_POLL_BITS, - BOTAN_RNG_RESEED_DEFAULT_TIMEOUT); + force_reseed(); } /* diff --git a/src/lib/rng/hmac_rng/hmac_rng.h b/src/lib/rng/hmac_rng/hmac_rng.h index 95ae25e39..f2f8a610d 100644 --- a/src/lib/rng/hmac_rng/hmac_rng.h +++ b/src/lib/rng/hmac_rng/hmac_rng.h @@ -24,11 +24,10 @@ namespace Botan { * 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 +class BOTAN_DLL HMAC_RNG : public Stateful_RNG { public: void randomize(byte buf[], size_t len) override; - bool is_seeded() const override; void clear() override; std::string name() const override; @@ -44,23 +43,26 @@ class BOTAN_DLL HMAC_RNG : public RandomNumberGenerator */ HMAC_RNG(MessageAuthenticationCode* extractor, MessageAuthenticationCode* prf); + + /** + * Use the specified hash for both the extractor and PRF functions + */ + HMAC_RNG(const std::string& hash, + size_t max_before_reseed = BOTAN_RNG_MAX_OUTPUT_BEFORE_RESEED); private: std::unique_ptr<MessageAuthenticationCode> m_extractor; std::unique_ptr<MessageAuthenticationCode> m_prf; enum HMAC_PRF_Label { Running, + BlockFinished, Reseed, ExtractorSeed, }; void new_K_value(byte label); - size_t m_collected_entropy_estimate = 0; - size_t m_output_since_reseed = 0; - secure_vector<byte> m_K; u32bit m_counter = 0; - u32bit m_pid = 0; }; } diff --git a/src/lib/rng/rng.cpp b/src/lib/rng/rng.cpp index 526693561..8144ac293 100644 --- a/src/lib/rng/rng.cpp +++ b/src/lib/rng/rng.cpp @@ -6,12 +6,18 @@ */ #include <botan/rng.h> -#include <botan/hmac_drbg.h> #include <botan/auto_rng.h> #include <botan/entropy_src.h> #include <botan/loadstor.h> #include <botan/internal/os_utils.h> -#include <chrono> + +#if defined(BOTAN_HAS_HMAC_DRBG) + #include <botan/hmac_drbg.h> +#endif + +#if defined(BOTAN_HAS_HMAC_RNG) + #include <botan/hmac_rng.h> +#endif namespace Botan { @@ -50,9 +56,15 @@ size_t RandomNumberGenerator::reseed_with_sources(Entropy_Sources& srcs, return bits_collected; } -Stateful_RNG::Stateful_RNG(size_t bytes_before_reseed) : - m_max_bytes_before_reseed_required(bytes_before_reseed) +Stateful_RNG::Stateful_RNG(size_t bytes_before_reseed) : m_bytes_before_reseed(bytes_before_reseed) + { + } + +void Stateful_RNG::clear() { + m_successful_initialization = false; + m_bytes_since_reseed = 0; + m_last_pid = 0; } size_t Stateful_RNG::reseed_with_sources(Entropy_Sources& srcs, @@ -81,10 +93,9 @@ void Stateful_RNG::reseed_check(size_t bytes_requested) { this->reseed(BOTAN_RNG_RESEED_POLL_BITS); } - else if(m_max_bytes_before_reseed_required > 0 && - m_bytes_since_reseed >= m_max_bytes_before_reseed_required) + else if(m_bytes_before_reseed > 0 && m_bytes_since_reseed >= m_bytes_before_reseed) { - this->reseed_with_timeout(BOTAN_RNG_AUTO_RESEED_POLL_BITS, + this->reseed_with_timeout(BOTAN_RNG_RESEED_POLL_BITS, BOTAN_RNG_AUTO_RESEED_TIMEOUT); } @@ -112,8 +123,10 @@ RandomNumberGenerator* RandomNumberGenerator::make_rng() AutoSeeded_RNG::AutoSeeded_RNG(size_t max_bytes_before_reseed) { - m_rng.reset(new HMAC_DRBG(BOTAN_AUTO_RNG_DRBG_HASH_FUNCTION, max_bytes_before_reseed)); - size_t bits = m_rng->reseed(384); + m_rng.reset(new BOTAN_AUTO_RNG_DRBG(BOTAN_AUTO_RNG_HASH, max_bytes_before_reseed)); + + size_t bits = m_rng->reseed(BOTAN_AUTO_RNG_ENTROPY_TARGET); + if(!m_rng->is_seeded()) { throw Exception("AutoSeeded_RNG failed to gather enough entropy only got " + @@ -124,24 +137,22 @@ AutoSeeded_RNG::AutoSeeded_RNG(size_t max_bytes_before_reseed) void AutoSeeded_RNG::randomize(byte output[], size_t output_len) { /* - This data is not secret so skipping a vector/secure_vector allows - avoiding an allocation. + Form additional input which is provided to the PRNG implementation + to paramaterize the KDF output. */ - typedef std::chrono::high_resolution_clock clock; - - byte nonce_buf[16] = { 0 }; - const uint32_t cur_ctr = m_counter++; - const uint32_t cur_pid = OS::get_process_id(); - const uint64_t cur_time = clock::now().time_since_epoch().count(); - - store_le(cur_ctr, nonce_buf); - store_le(cur_pid, nonce_buf + 4); - store_le(cur_time, nonce_buf + 8); + byte additional_input[24] = { 0 }; + store_le(OS::get_system_timestamp_ns(), additional_input); + store_le(OS::get_processor_timestamp(), additional_input + 8); + store_le(OS::get_process_id(), additional_input + 16); + store_le(m_counter++, additional_input + 20); - m_rng->randomize_with_input(output, output_len, - nonce_buf, sizeof(nonce_buf)); + randomize_with_input(output, output_len, additional_input, sizeof(additional_input)); + } - ++m_counter; +void AutoSeeded_RNG::randomize_with_input(byte output[], size_t output_len, + const byte ad[], size_t ad_len) + { + m_rng->randomize_with_input(output, output_len, ad, ad_len); } } diff --git a/src/lib/rng/rng.h b/src/lib/rng/rng.h index 2e08ce553..d5fae0261 100644 --- a/src/lib/rng/rng.h +++ b/src/lib/rng/rng.h @@ -154,7 +154,7 @@ class BOTAN_DLL RandomNumberGenerator * bytes have been output. * * Not implemented by RNGs which access an external RNG, such as the -* system PRNG or an hardware RNG. +* system PRNG or a hardware RNG. */ class BOTAN_DLL Stateful_RNG : public RandomNumberGenerator { @@ -182,16 +182,37 @@ class BOTAN_DLL Stateful_RNG : public RandomNumberGenerator protected: void reseed_check(size_t bytes_requested); + void clear() override; + + /** + * Mark state as requiring a reseed on next use + */ + void force_reseed() { m_bytes_since_reseed = m_bytes_before_reseed; } + + uint32_t last_pid() const { return m_last_pid; } + + mutable std::mutex m_mutex; + private: - const size_t m_max_bytes_before_reseed_required; + const size_t m_bytes_before_reseed; size_t m_bytes_since_reseed = 0; uint32_t m_last_pid = 0; bool m_successful_initialization = false; }; +/** +* Convenience typedef +*/ typedef RandomNumberGenerator RNG; /** +* Hardware RNG has no members but exists to tag hardware RNG types +*/ +class BOTAN_DLL Hardware_RNG : public RandomNumberGenerator + { + }; + +/** * Null/stub RNG - fails if you try to use it for anything * This is not generally useful except for in certain tests */ @@ -212,7 +233,6 @@ class BOTAN_DLL Null_RNG final : public RandomNumberGenerator std::string name() const override { return "Null_RNG"; } }; - /** * Wraps access to a RNG in a mutex */ @@ -225,20 +245,6 @@ class BOTAN_DLL Serialized_RNG final : public RandomNumberGenerator m_rng->randomize(out, len); } - void randomize_with_input(byte output[], size_t output_length, - const byte input[], size_t input_length) override - { - std::lock_guard<std::mutex> lock(m_mutex); - m_rng->randomize_with_input(output, output_length, - input, input_length); - } - - void add_entropy(const byte in[], size_t len) override - { - std::lock_guard<std::mutex> lock(m_mutex); - m_rng->add_entropy(in, len); - } - bool is_seeded() const override { std::lock_guard<std::mutex> lock(m_mutex); @@ -265,6 +271,12 @@ class BOTAN_DLL Serialized_RNG final : public RandomNumberGenerator return m_rng->reseed_with_sources(src, bits, msec); } + void add_entropy(const byte in[], size_t len) override + { + std::lock_guard<std::mutex> lock(m_mutex); + m_rng->add_entropy(in, len); + } + Serialized_RNG() : m_rng(RandomNumberGenerator::make_rng()) {} explicit Serialized_RNG(RandomNumberGenerator* rng) : m_rng(rng) {} private: |