aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/entropy/beos_stats/es_beos.cpp23
-rw-r--r--src/lib/entropy/beos_stats/es_beos.h2
-rw-r--r--src/lib/entropy/cryptoapi_rng/es_capi.cpp70
-rw-r--r--src/lib/entropy/cryptoapi_rng/es_capi.h18
-rw-r--r--src/lib/entropy/darwin_secrandom/darwin_secrandom.cpp7
-rw-r--r--src/lib/entropy/darwin_secrandom/darwin_secrandom.h2
-rw-r--r--src/lib/entropy/dev_random/dev_random.cpp92
-rw-r--r--src/lib/entropy/dev_random/dev_random.h7
-rw-r--r--src/lib/entropy/egd/es_egd.cpp12
-rw-r--r--src/lib/entropy/egd/es_egd.h3
-rw-r--r--src/lib/entropy/entropy_src.h79
-rw-r--r--src/lib/entropy/entropy_srcs.cpp29
-rw-r--r--src/lib/entropy/hres_timer/hres_timer.cpp60
-rw-r--r--src/lib/entropy/hres_timer/hres_timer.h30
-rw-r--r--src/lib/entropy/hres_timer/info.txt13
-rw-r--r--src/lib/entropy/info.txt4
-rw-r--r--src/lib/entropy/proc_walk/proc_walk.cpp12
-rw-r--r--src/lib/entropy/proc_walk/proc_walk.h2
-rw-r--r--src/lib/entropy/rdrand/rdrand.cpp35
-rw-r--r--src/lib/entropy/rdrand/rdrand.h2
-rw-r--r--src/lib/entropy/rdseed/rdseed.cpp34
-rw-r--r--src/lib/entropy/rdseed/rdseed.h2
-rw-r--r--src/lib/entropy/unix_procs/unix_procs.cpp69
-rw-r--r--src/lib/entropy/unix_procs/unix_procs.h4
-rw-r--r--src/lib/entropy/win32_stats/es_win32.cpp85
-rw-r--r--src/lib/entropy/win32_stats/es_win32.h2
-rw-r--r--src/lib/ffi/info.txt1
-rw-r--r--src/lib/prov/tpm/tpm.h24
-rw-r--r--src/lib/pubkey/dsa/dsa.cpp1
-rw-r--r--src/lib/pubkey/rfc6979/rfc6979.cpp9
-rw-r--r--src/lib/pubkey/rfc6979/rfc6979.h6
-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.txt9
-rw-r--r--src/lib/rng/hmac_drbg/hmac_drbg.cpp142
-rw-r--r--src/lib/rng/hmac_drbg/hmac_drbg.h39
-rw-r--r--src/lib/rng/hmac_rng/hmac_rng.cpp112
-rw-r--r--src/lib/rng/hmac_rng/hmac_rng.h17
-rw-r--r--src/lib/rng/info.txt5
-rw-r--r--src/lib/rng/rng.cpp120
-rw-r--r--src/lib/rng/rng.h215
-rw-r--r--src/lib/rng/system_rng/system_rng.cpp90
-rw-r--r--src/lib/rng/system_rng/system_rng.h23
-rw-r--r--src/lib/utils/zero_mem.cpp7
43 files changed, 837 insertions, 695 deletions
diff --git a/src/lib/entropy/beos_stats/es_beos.cpp b/src/lib/entropy/beos_stats/es_beos.cpp
index aa0e257a9..fb9be6f86 100644
--- a/src/lib/entropy/beos_stats/es_beos.cpp
+++ b/src/lib/entropy/beos_stats/es_beos.cpp
@@ -16,48 +16,51 @@ namespace Botan {
/**
* BeOS entropy poll
*/
-void BeOS_EntropySource::poll(Entropy_Accumulator& accum)
+size_t BeOS_EntropySource::poll(RandomNumberGenerator& rng)
{
+ size_t bits = 0;
+
system_info info_sys;
get_system_info(&info_sys);
- accum.add(info_sys, BOTAN_ENTROPY_ESTIMATE_SYSTEM_DATA);
+ rng.add_entropy(info_sys);
key_info info_key; // current state of the keyboard
get_key_info(&info_key);
- accum.add(info_key, BOTAN_ENTROPY_ESTIMATE_SYSTEM_DATA);
+ rng.add_entropy(info_key);
team_info info_team;
int32 cookie_team = 0;
while(get_next_team_info(&cookie_team, &info_team) == B_OK)
{
- accum.add(info_team, BOTAN_ENTROPY_ESTIMATE_SYSTEM_DATA);
+ rng.add_entropy(info_team);
team_id id = info_team.team;
int32 cookie = 0;
thread_info info_thr;
while(get_next_thread_info(id, &cookie, &info_thr) == B_OK)
- accum.add(info_thr, BOTAN_ENTROPY_ESTIMATE_SYSTEM_DATA);
+ rng.add_entropy(info_thr);
cookie = 0;
image_info info_img;
while(get_next_image_info(id, &cookie, &info_img) == B_OK)
- accum.add(info_img, BOTAN_ENTROPY_ESTIMATE_SYSTEM_DATA);
+ rng.add_entropy(info_img);
cookie = 0;
sem_info info_sem;
while(get_next_sem_info(id, &cookie, &info_sem) == B_OK)
- accum.add(info_sem, BOTAN_ENTROPY_ESTIMATE_SYSTEM_DATA);
+ rng.add_entropy(info_sem);
cookie = 0;
area_info info_area;
while(get_next_area_info(id, &cookie, &info_area) == B_OK)
- accum.add(info_area, BOTAN_ENTROPY_ESTIMATE_SYSTEM_DATA);
+ rng.add_entropy(info_area);
- if(accum.polling_finished())
- break;
+ bits += 32;
}
+
+ return bits;
}
}
diff --git a/src/lib/entropy/beos_stats/es_beos.h b/src/lib/entropy/beos_stats/es_beos.h
index a5b90a607..e40433b6c 100644
--- a/src/lib/entropy/beos_stats/es_beos.h
+++ b/src/lib/entropy/beos_stats/es_beos.h
@@ -20,7 +20,7 @@ class BeOS_EntropySource final : public Entropy_Source
private:
std::string name() const override { return "system_stats"; }
- void poll(Entropy_Accumulator& accum) override;
+ size_t poll(RandomNumberGenerator& rng) override;
};
}
diff --git a/src/lib/entropy/cryptoapi_rng/es_capi.cpp b/src/lib/entropy/cryptoapi_rng/es_capi.cpp
index c9d8fb7c4..a1d809d0d 100644
--- a/src/lib/entropy/cryptoapi_rng/es_capi.cpp
+++ b/src/lib/entropy/cryptoapi_rng/es_capi.cpp
@@ -1,6 +1,6 @@
/*
* Win32 CryptoAPI EntropySource
-* (C) 1999-2009 Jack Lloyd
+* (C) 1999-2009,2016 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -16,38 +16,34 @@ namespace Botan {
namespace {
-class CSP_Handle
+class CSP_Handle_Impl : public Win32_CAPI_EntropySource::CSP_Handle
{
public:
- explicit CSP_Handle(u64bit capi_provider)
+ explicit CSP_Handle_Impl(u64bit capi_provider)
{
- m_valid = false;
- DWORD prov_type = (DWORD)capi_provider;
-
- if(CryptAcquireContext(&m_handle, 0, 0,
- prov_type, CRYPT_VERIFYCONTEXT))
- m_valid = true;
+ m_valid = ::CryptAcquireContext(&m_handle,
+ 0,
+ 0,
+ static_cast<DWORD>(capi_provider),
+ CRYPT_VERIFYCONTEXT);
}
- ~CSP_Handle()
+ ~CSP_Handle_Impl()
{
- if(is_valid())
- CryptReleaseContext(m_handle, 0);
+ if(m_valid)
+ ::CryptReleaseContext(m_handle, 0);
}
size_t gen_random(byte out[], size_t n) const
{
- if(is_valid() && CryptGenRandom(m_handle, static_cast<DWORD>(n), out))
+ if(m_valid && ::CryptGenRandom(m_handle, static_cast<DWORD>(n), out))
return n;
return 0;
}
- bool is_valid() const { return m_valid; }
-
- HCRYPTPROV get_handle() const { return m_handle; }
private:
- HCRYPTPROV m_handle;
bool m_valid;
+ HCRYPTPROV m_handle;
};
}
@@ -55,20 +51,23 @@ class CSP_Handle
/*
* Gather Entropy from Win32 CAPI
*/
-void Win32_CAPI_EntropySource::poll(Entropy_Accumulator& accum)
+size_t Win32_CAPI_EntropySource::poll(RandomNumberGenerator& rng)
{
- secure_vector<byte>& buf = accum.get_io_buf(BOTAN_SYSTEM_RNG_POLL_REQUEST);
+ secure_vector<uint8_t> buf(BOTAN_SYSTEM_RNG_POLL_REQUEST);
+ size_t bits = 0;
- for(size_t i = 0; i != m_prov_types.size(); ++i)
+ for(size_t i = 0; i != m_csp_provs.size(); ++i)
{
- CSP_Handle csp(m_prov_types[i]);
+ size_t got = m_csp_provs[i]->gen_random(buf.data(), buf.size());
- if(size_t got = csp.gen_random(buf.data(), buf.size()))
+ if(got > 0)
{
- accum.add(buf.data(), got, BOTAN_ENTROPY_ESTIMATE_STRONG_RNG);
- break;
+ rng.add_entropy(buf.data(), got);
+ bits += got * 8;
}
}
+
+ return bits;
}
/*
@@ -76,18 +75,21 @@ void Win32_CAPI_EntropySource::poll(Entropy_Accumulator& accum)
*/
Win32_CAPI_EntropySource::Win32_CAPI_EntropySource(const std::string& provs)
{
- std::vector<std::string> capi_provs = split_on(provs, ':');
-
- for(size_t i = 0; i != capi_provs.size(); ++i)
+ for(std::string prov_name : split_on(provs, ':'))
{
- if(capi_provs[i] == "RSA_FULL") m_prov_types.push_back(PROV_RSA_FULL);
- if(capi_provs[i] == "INTEL_SEC") m_prov_types.push_back(PROV_INTEL_SEC);
- if(capi_provs[i] == "FORTEZZA") m_prov_types.push_back(PROV_FORTEZZA);
- if(capi_provs[i] == "RNG") m_prov_types.push_back(PROV_RNG);
+ DWORD prov_type;
+
+ if(prov_name == "RSA_FULL")
+ prov_type = PROV_RSA_FULL;
+ else if(prov_name == "INTEL_SEC")
+ prov_type = PROV_INTEL_SEC;
+ else if(prov_name == "RNG")
+ prov_type = PROV_RNG;
+ else
+ continue;
+
+ m_csp_provs.push_back(std::unique_ptr<CSP_Handle>(new CSP_Handle_Impl(prov_type)));
}
-
- if(m_prov_types.size() == 0)
- m_prov_types.push_back(PROV_RSA_FULL);
}
}
diff --git a/src/lib/entropy/cryptoapi_rng/es_capi.h b/src/lib/entropy/cryptoapi_rng/es_capi.h
index b1c60bfa1..82a779672 100644
--- a/src/lib/entropy/cryptoapi_rng/es_capi.h
+++ b/src/lib/entropy/cryptoapi_rng/es_capi.h
@@ -21,15 +21,21 @@ class Win32_CAPI_EntropySource final : public Entropy_Source
public:
std::string name() const override { return "win32_cryptoapi"; }
- void poll(Entropy_Accumulator& accum) override;
+ size_t poll(RandomNumberGenerator& rng) override;
- /**
- * Win32_Capi_Entropysource Constructor
- * @param provs list of providers, separated by ':'
- */
+ /**
+ * Win32_Capi_Entropysource Constructor
+ * @param provs list of providers, separated by ':'
+ */
explicit Win32_CAPI_EntropySource(const std::string& provs = "");
+
+ class CSP_Handle
+ {
+ public:
+ virtual size_t gen_random(byte out[], size_t n) const = 0;
+ };
private:
- std::vector<u64bit> m_prov_types;
+ std::vector<std::unique_ptr<CSP_Handle>> m_csp_provs;
};
}
diff --git a/src/lib/entropy/darwin_secrandom/darwin_secrandom.cpp b/src/lib/entropy/darwin_secrandom/darwin_secrandom.cpp
index 0a6b85955..b53e4061e 100644
--- a/src/lib/entropy/darwin_secrandom/darwin_secrandom.cpp
+++ b/src/lib/entropy/darwin_secrandom/darwin_secrandom.cpp
@@ -14,13 +14,14 @@ namespace Botan {
/**
* Gather entropy from SecRandomCopyBytes
*/
-void Darwin_SecRandom::poll(Entropy_Accumulator& accum)
+size_t Darwin_SecRandom::poll(RandomNumberGenerator& rng)
{
- secure_vector<byte>& buf = accum.get_io_buf(BOTAN_SYSTEM_RNG_POLL_REQUEST);
+ secure_vector<uint8_t> buf(BOTAN_SYSTEM_RNG_POLL_REQUEST);
if(0 == SecRandomCopyBytes(kSecRandomDefault, buf.size(), buf.data()))
{
- accum.add(buf.data(), buf.size(), BOTAN_ENTROPY_ESTIMATE_STRONG_RNG);
+ rng.add_entropy(buf.data(), buf.size());
+ return buf.size() * 8;
}
}
diff --git a/src/lib/entropy/darwin_secrandom/darwin_secrandom.h b/src/lib/entropy/darwin_secrandom/darwin_secrandom.h
index 09cdc208d..e1c012459 100644
--- a/src/lib/entropy/darwin_secrandom/darwin_secrandom.h
+++ b/src/lib/entropy/darwin_secrandom/darwin_secrandom.h
@@ -20,7 +20,7 @@ class Darwin_SecRandom final : public Entropy_Source
public:
std::string name() const override { return "darwin_secrandom"; }
- void poll(Entropy_Accumulator& accum) override;
+ size_t poll(RandomNumberGenerator& rng) override;
};
}
diff --git a/src/lib/entropy/dev_random/dev_random.cpp b/src/lib/entropy/dev_random/dev_random.cpp
index aca161d64..b51f19ecb 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,14 +32,36 @@ 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));
+ }
+ }
}
}
@@ -47,46 +70,55 @@ 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);
+ }
}
/**
* Gather entropy from a RNG device
*/
-void Device_EntropySource::poll(Entropy_Accumulator& accum)
+size_t Device_EntropySource::poll(RandomNumberGenerator& rng)
{
- if(m_devices.empty())
- return;
+ size_t bits = 0;
- 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)
+ if(m_dev_fds.size() > 0)
{
- FD_SET(m_devices[i], &read_set);
- max_fd = std::max(m_devices[i], max_fd);
- }
-
- struct ::timeval timeout;
+ fd_set read_set;
+ FD_ZERO(&read_set);
- timeout.tv_sec = (BOTAN_SYSTEM_RNG_POLL_TIMEOUT_MS / 1000);
- timeout.tv_usec = (BOTAN_SYSTEM_RNG_POLL_TIMEOUT_MS % 1000) * 1000;
+ for(int dev_fd : m_dev_fds)
+ {
+ FD_SET(dev_fd, &read_set);
+ }
- if(::select(max_fd + 1, &read_set, nullptr, nullptr, &timeout) < 0)
- return;
+ secure_vector<uint8_t> io_buf(BOTAN_SYSTEM_RNG_POLL_REQUEST);
- secure_vector<byte>& buf = accum.get_io_buf(BOTAN_SYSTEM_RNG_POLL_REQUEST);
+ struct ::timeval timeout;
+ timeout.tv_sec = (BOTAN_SYSTEM_RNG_POLL_TIMEOUT_MS / 1000);
+ timeout.tv_usec = (BOTAN_SYSTEM_RNG_POLL_TIMEOUT_MS % 1000) * 1000;
- for(size_t i = 0; i != m_devices.size(); ++i)
- {
- if(FD_ISSET(m_devices[i], &read_set))
+ if(::select(m_max_fd + 1, &read_set, nullptr, nullptr, &timeout) > 0)
{
- 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);
+ for(int dev_fd : m_dev_fds)
+ {
+ if(FD_ISSET(dev_fd, &read_set))
+ {
+ const ssize_t got = ::read(dev_fd, io_buf.data(), io_buf.size());
+
+ if(got > 0)
+ {
+ rng.add_entropy(io_buf.data(), static_cast<size_t>(got));
+ bits += got * 8;
+ }
+ }
+ }
}
}
+
+ return bits;
}
}
diff --git a/src/lib/entropy/dev_random/dev_random.h b/src/lib/entropy/dev_random/dev_random.h
index 1f29b2f64..7c8df0553 100644
--- a/src/lib/entropy/dev_random/dev_random.h
+++ b/src/lib/entropy/dev_random/dev_random.h
@@ -22,13 +22,14 @@ class Device_EntropySource final : public Entropy_Source
public:
std::string name() const override { return "dev_random"; }
- void poll(Entropy_Accumulator& accum) override;
+ size_t poll(RandomNumberGenerator& rng) override;
Device_EntropySource(const std::vector<std::string>& fsnames);
+
~Device_EntropySource();
private:
- typedef int fd_type;
- std::vector<fd_type> m_devices;
+ std::vector<int> m_dev_fds;
+ int m_max_fd;
};
}
diff --git a/src/lib/entropy/egd/es_egd.cpp b/src/lib/entropy/egd/es_egd.cpp
index 9bc6de6fe..384516aa8 100644
--- a/src/lib/entropy/egd/es_egd.cpp
+++ b/src/lib/entropy/egd/es_egd.cpp
@@ -134,22 +134,24 @@ EGD_EntropySource::~EGD_EntropySource()
/**
* Gather Entropy from EGD
*/
-void EGD_EntropySource::poll(Entropy_Accumulator& accum)
+size_t EGD_EntropySource::poll(RandomNumberGenerator& rng)
{
std::lock_guard<std::mutex> lock(m_mutex);
- secure_vector<byte>& buf = accum.get_io_buf(BOTAN_SYSTEM_RNG_POLL_REQUEST);
+ secure_vector<byte> buf(BOTAN_SYSTEM_RNG_POLL_REQUEST);
for(size_t i = 0; i != m_sockets.size(); ++i)
{
- size_t got = m_sockets[i].read(buf.data(), buf.size());
+ size_t got = m_sockets[i].read(m_io_buf.data(), m_io_buf.size());
if(got)
{
- accum.add(buf.data(), got, BOTAN_ENTROPY_ESTIMATE_STRONG_RNG);
- break;
+ rng.add_entropy(m_io_buf.data(), got);
+ return got * 8;
}
}
+
+ return 0;
}
}
diff --git a/src/lib/entropy/egd/es_egd.h b/src/lib/entropy/egd/es_egd.h
index 1a624713a..04b4591e3 100644
--- a/src/lib/entropy/egd/es_egd.h
+++ b/src/lib/entropy/egd/es_egd.h
@@ -23,7 +23,7 @@ class EGD_EntropySource final : public Entropy_Source
public:
std::string name() const override { return "egd"; }
- void poll(Entropy_Accumulator& accum) override;
+ size_t poll(RandomNumberGenerator& rng) override;
EGD_EntropySource(const std::vector<std::string>&);
~EGD_EntropySource();
@@ -44,6 +44,7 @@ class EGD_EntropySource final : public Entropy_Source
std::mutex m_mutex;
std::vector<EGD_Socket> m_sockets;
+ secure_vector<uint8_t> m_io_buf;
};
}
diff --git a/src/lib/entropy/entropy_src.h b/src/lib/entropy/entropy_src.h
index 539df809a..64d988e7c 100644
--- a/src/lib/entropy/entropy_src.h
+++ b/src/lib/entropy/entropy_src.h
@@ -1,6 +1,6 @@
/*
* EntropySource
-* (C) 2008,2009,2014,2015 Jack Lloyd
+* (C) 2008,2009,2014,2015,2016 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -8,71 +8,13 @@
#ifndef BOTAN_ENTROPY_H__
#define BOTAN_ENTROPY_H__
-#include <botan/secmem.h>
+#include <botan/rng.h>
#include <string>
-#include <functional>
+#include <chrono>
namespace Botan {
/**
-* Class used to accumulate the poll results of EntropySources
-*/
-class BOTAN_DLL Entropy_Accumulator final
- {
- public:
- /**
- * Initialize an Entropy_Accumulator
- *
- * @param accum will be called with poll results, first params the data and
- * length, the second a best estimate of min-entropy for the entire buffer;
- * out of an abundance of caution this will be zero for many sources.
- * accum should return true if it wants the polling to stop, though it may
- * still be called again a few more times, and should be careful to return
- * true then as well.
- */
- explicit Entropy_Accumulator(std::function<bool (const byte[], size_t, double)> accum) :
- m_accum_fn(accum) {}
-
- /**
- * @return if our polling goal has been achieved
- */
- bool polling_goal_achieved() const { return m_done; }
-
- bool polling_finished() const { return m_done; }
-
- /**
- * Add entropy to the accumulator
- * @param bytes the input bytes
- * @param length specifies how many bytes the input is
- * @param entropy_bits_per_byte is a best guess at how much
- * entropy per byte is in this input
- */
- void add(const void* bytes, size_t length, double entropy_bits_per_byte)
- {
- m_done = m_accum_fn(reinterpret_cast<const byte*>(bytes),
- length, entropy_bits_per_byte * length) || m_done;
- }
-
- /**
- * Add entropy to the accumulator
- * @param v is some value
- * @param entropy_bits_per_byte is a best guess at how much
- * entropy per byte is in this input
- */
- template<typename T>
- void add(const T& v, double entropy_bits_per_byte)
- {
- add(&v, sizeof(T), entropy_bits_per_byte);
- }
-
- secure_vector<byte>& get_io_buf(size_t sz) { m_io_buf.resize(sz); return m_io_buf; }
- private:
- std::function<bool (const byte[], size_t, double)> m_accum_fn;
- secure_vector<byte> m_io_buf;
- bool m_done = false;
- };
-
-/**
* Abstract interface to a source of entropy
*/
class BOTAN_DLL Entropy_Source
@@ -93,9 +35,10 @@ class BOTAN_DLL Entropy_Source
/**
* Perform an entropy gathering poll
- * @param accum is an accumulator object that will be given entropy
+ * @param rng will be provided with entropy via calls to add_entropy
+ @ @return conservative estimate of actual entropy added to rng during poll
*/
- virtual void poll(Entropy_Accumulator& accum) = 0;
+ virtual size_t poll(RandomNumberGenerator& rng) = 0;
virtual ~Entropy_Source() {}
};
@@ -109,8 +52,14 @@ class BOTAN_DLL Entropy_Sources final
std::vector<std::string> enabled_sources() const;
- void poll(Entropy_Accumulator& accum);
- bool poll_just(Entropy_Accumulator& accum, const std::string& src);
+ size_t poll(RandomNumberGenerator& rng,
+ size_t bits,
+ std::chrono::milliseconds timeout);
+
+ /**
+ * Poll just a single named source. Ordinally only used for testing
+ */
+ size_t poll_just(RandomNumberGenerator& rng, const std::string& src);
Entropy_Sources() {}
explicit Entropy_Sources(const std::vector<std::string>& sources);
diff --git a/src/lib/entropy/entropy_srcs.cpp b/src/lib/entropy/entropy_srcs.cpp
index a5dc0a819..22d2e5e4b 100644
--- a/src/lib/entropy/entropy_srcs.cpp
+++ b/src/lib/entropy/entropy_srcs.cpp
@@ -6,6 +6,7 @@
*/
#include <botan/entropy_src.h>
+#include <botan/rng.h>
#if defined(BOTAN_HAS_ENTROPY_SRC_HIGH_RESOLUTION_TIMER)
#include <botan/internal/hres_timer.h>
@@ -68,7 +69,7 @@ std::unique_ptr<Entropy_Source> Entropy_Source::create(const std::string& name)
return std::unique_ptr<Entropy_Source>(new Intel_Rdrand);
#endif
}
-
+
if(name == "rdseed")
{
#if defined(BOTAN_HAS_ENTROPY_SRC_RDSEED)
@@ -154,28 +155,38 @@ std::vector<std::string> Entropy_Sources::enabled_sources() const
return sources;
}
-void Entropy_Sources::poll(Entropy_Accumulator& accum)
+size_t Entropy_Sources::poll(RandomNumberGenerator& rng,
+ size_t poll_bits,
+ std::chrono::milliseconds timeout)
{
- for(size_t i = 0; i != m_srcs.size(); ++i)
+ typedef std::chrono::system_clock clock;
+
+ auto deadline = clock::now() + timeout;
+
+ size_t bits_collected = 0;
+
+ for(Entropy_Source* src : m_srcs)
{
- m_srcs[i]->poll(accum);
- if(accum.polling_goal_achieved())
+ bits_collected += src->poll(rng);
+
+ if (bits_collected >= poll_bits || clock::now() > deadline)
break;
}
+
+ return bits_collected;
}
-bool Entropy_Sources::poll_just(Entropy_Accumulator& accum, const std::string& the_src)
+size_t Entropy_Sources::poll_just(RandomNumberGenerator& rng, const std::string& the_src)
{
for(size_t i = 0; i != m_srcs.size(); ++i)
{
if(m_srcs[i]->name() == the_src)
{
- m_srcs[i]->poll(accum);
- return true;
+ return m_srcs[i]->poll(rng);
}
}
- return false;
+ return 0;
}
Entropy_Sources::Entropy_Sources(const std::vector<std::string>& sources)
diff --git a/src/lib/entropy/hres_timer/hres_timer.cpp b/src/lib/entropy/hres_timer/hres_timer.cpp
deleted file mode 100644
index e2a5ddbef..000000000
--- a/src/lib/entropy/hres_timer/hres_timer.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
-* High Resolution Timestamp Entropy Source
-* (C) 1999-2009,2011,2014,2016 Jack Lloyd
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#include <botan/internal/hres_timer.h>
-#include <botan/internal/os_utils.h>
-
-#if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME)
- #include <time.h>
-#endif
-
-namespace Botan {
-
-/*
-* Get the timestamp
-*/
-void High_Resolution_Timestamp::poll(Entropy_Accumulator& accum)
- {
- accum.add(OS::get_processor_timestamp(), BOTAN_ENTROPY_ESTIMATE_TIMESTAMPS);
-
- accum.add(OS::get_system_timestamp_ns(), BOTAN_ENTROPY_ESTIMATE_TIMESTAMPS);
-
-#if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME)
-
-#define CLOCK_GETTIME_POLL(src) \
- do { \
- struct timespec ts; \
- ::clock_gettime(src, &ts); \
- accum.add(&ts, sizeof(ts), BOTAN_ENTROPY_ESTIMATE_TIMESTAMPS); \
- } while(0)
-
-#if defined(CLOCK_REALTIME)
- CLOCK_GETTIME_POLL(CLOCK_REALTIME);
-#endif
-
-#if defined(CLOCK_MONOTONIC)
- CLOCK_GETTIME_POLL(CLOCK_MONOTONIC);
-#endif
-
-#if defined(CLOCK_MONOTONIC_RAW)
- CLOCK_GETTIME_POLL(CLOCK_MONOTONIC_RAW);
-#endif
-
-#if defined(CLOCK_PROCESS_CPUTIME_ID)
- CLOCK_GETTIME_POLL(CLOCK_PROCESS_CPUTIME_ID);
-#endif
-
-#if defined(CLOCK_THREAD_CPUTIME_ID)
- CLOCK_GETTIME_POLL(CLOCK_THREAD_CPUTIME_ID);
-#endif
-
-#undef CLOCK_GETTIME_POLL
-
-#endif
- }
-
-}
diff --git a/src/lib/entropy/hres_timer/hres_timer.h b/src/lib/entropy/hres_timer/hres_timer.h
deleted file mode 100644
index d297a87b1..000000000
--- a/src/lib/entropy/hres_timer/hres_timer.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
-* High Resolution Timestamp Entropy Source
-* (C) 1999-2009 Jack Lloyd
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#ifndef BOTAN_ENTROPY_SRC_HRES_TIMER_H__
-#define BOTAN_ENTROPY_SRC_HRES_TIMER_H__
-
-#include <botan/entropy_src.h>
-
-namespace Botan {
-
-/**
-* Entropy source using high resolution timers
-*
-* @note Any results from timers are marked as not contributing entropy
-* to the poll, as a local attacker could observe them directly.
-*/
-class High_Resolution_Timestamp final : public Entropy_Source
- {
- public:
- std::string name() const override { return "timestamp"; }
- void poll(Entropy_Accumulator& accum) override;
- };
-
-}
-
-#endif
diff --git a/src/lib/entropy/hres_timer/info.txt b/src/lib/entropy/hres_timer/info.txt
deleted file mode 100644
index dfe8fab0b..000000000
--- a/src/lib/entropy/hres_timer/info.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-define ENTROPY_SRC_HIGH_RESOLUTION_TIMER 20131128
-
-<source>
-hres_timer.cpp
-</source>
-
-<header:internal>
-hres_timer.h
-</header:internal>
-
-<libs>
-linux -> rt
-</libs>
diff --git a/src/lib/entropy/info.txt b/src/lib/entropy/info.txt
index ba5a4044d..d80176113 100644
--- a/src/lib/entropy/info.txt
+++ b/src/lib/entropy/info.txt
@@ -1 +1,5 @@
define ENTROPY_SOURCE 20151120
+
+<requires>
+rng
+</requires>
diff --git a/src/lib/entropy/proc_walk/proc_walk.cpp b/src/lib/entropy/proc_walk/proc_walk.cpp
index c59a8227b..a0c3f830a 100644
--- a/src/lib/entropy/proc_walk/proc_walk.cpp
+++ b/src/lib/entropy/proc_walk/proc_walk.cpp
@@ -110,7 +110,7 @@ int Directory_Walker::next_fd()
}
-void ProcWalking_EntropySource::poll(Entropy_Accumulator& accum)
+size_t ProcWalking_EntropySource::poll(RandomNumberGenerator& rng)
{
const size_t MAX_FILES_READ_PER_POLL = 2048;
@@ -121,6 +121,8 @@ void ProcWalking_EntropySource::poll(Entropy_Accumulator& accum)
m_buf.resize(4096);
+ size_t bits = 0;
+
for(size_t i = 0; i != MAX_FILES_READ_PER_POLL; ++i)
{
int fd = m_dir->next_fd();
@@ -136,11 +138,15 @@ void ProcWalking_EntropySource::poll(Entropy_Accumulator& accum)
::close(fd);
if(got > 0)
- accum.add(m_buf.data(), got, BOTAN_ENTROPY_ESTIMATE_SYSTEM_TEXT);
+ {
+ rng.add_entropy(m_buf.data(), static_cast<size_t>(got));
+ }
- if(accum.polling_finished())
+ if(bits > 128)
break;
}
+
+ return bits;
}
}
diff --git a/src/lib/entropy/proc_walk/proc_walk.h b/src/lib/entropy/proc_walk/proc_walk.h
index f6db8185a..369b52699 100644
--- a/src/lib/entropy/proc_walk/proc_walk.h
+++ b/src/lib/entropy/proc_walk/proc_walk.h
@@ -28,7 +28,7 @@ class ProcWalking_EntropySource final : public Entropy_Source
public:
std::string name() const override { return "proc_walk"; }
- void poll(Entropy_Accumulator& accum) override;
+ size_t poll(RandomNumberGenerator& rng) override;
ProcWalking_EntropySource(const std::string& root_dir) :
m_path(root_dir), m_dir(nullptr) {}
diff --git a/src/lib/entropy/rdrand/rdrand.cpp b/src/lib/entropy/rdrand/rdrand.cpp
index 89234b460..fb04d7b78 100644
--- a/src/lib/entropy/rdrand/rdrand.cpp
+++ b/src/lib/entropy/rdrand/rdrand.cpp
@@ -16,32 +16,35 @@
namespace Botan {
-void Intel_Rdrand::poll(Entropy_Accumulator& accum) {
- if(!CPUID::has_rdrand())
- return;
-
- for(size_t p = 0; p != BOTAN_ENTROPY_INTEL_RNG_POLLS; ++p)
+size_t Intel_Rdrand::poll(RandomNumberGenerator& rng) {
+ if(CPUID::has_rdrand())
{
- for(size_t i = 0; i != BOTAN_ENTROPY_RDRAND_RETRIES; ++i)
+ for(size_t p = 0; p != BOTAN_ENTROPY_INTEL_RNG_POLLS; ++p)
{
- uint32_t r = 0;
+ for(size_t i = 0; i != BOTAN_ENTROPY_RDRAND_RETRIES; ++i)
+ {
+ uint32_t r = 0;
#if defined(BOTAN_USE_GCC_INLINE_ASM)
- int cf = 0;
+ int cf = 0;
- // Encoding of rdrand %eax
- asm(".byte 0x0F, 0xC7, 0xF0; adcl $0,%1" :
- "=a" (r), "=r" (cf) : "0" (r), "1" (cf) : "cc");
+ // Encoding of rdrand %eax
+ asm(".byte 0x0F, 0xC7, 0xF0; adcl $0,%1" :
+ "=a" (r), "=r" (cf) : "0" (r), "1" (cf) : "cc");
#else
- int cf = _rdrand32_step(&r);
+ int cf = _rdrand32_step(&r);
#endif
- if(1 == cf)
- {
- accum.add(r, BOTAN_ENTROPY_ESTIMATE_HARDWARE_RNG);
- break;
+ if(1 == cf)
+ {
+ rng.add_entropy_T(r);
+ break;
+ }
}
}
}
+
+ // RDRAND is used but not trusted
+ return 0;
}
}
diff --git a/src/lib/entropy/rdrand/rdrand.h b/src/lib/entropy/rdrand/rdrand.h
index 48d090775..db9de39b6 100644
--- a/src/lib/entropy/rdrand/rdrand.h
+++ b/src/lib/entropy/rdrand/rdrand.h
@@ -20,7 +20,7 @@ class Intel_Rdrand final : public Entropy_Source
{
public:
std::string name() const override { return "rdrand"; }
- void poll(Entropy_Accumulator& accum) override;
+ size_t poll(RandomNumberGenerator& rng) override;
};
}
diff --git a/src/lib/entropy/rdseed/rdseed.cpp b/src/lib/entropy/rdseed/rdseed.cpp
index 2ba2075cc..325edfd41 100644
--- a/src/lib/entropy/rdseed/rdseed.cpp
+++ b/src/lib/entropy/rdseed/rdseed.cpp
@@ -15,32 +15,34 @@
namespace Botan {
-void Intel_Rdseed::poll(Entropy_Accumulator& accum) {
- if(!CPUID::has_rdseed())
- return;
-
- for(size_t p = 0; p != BOTAN_ENTROPY_INTEL_RNG_POLLS; ++p)
+size_t Intel_Rdseed::poll(RandomNumberGenerator& rng) {
+ if(CPUID::has_rdseed())
{
- for(size_t i = 0; i != BOTAN_ENTROPY_RDSEED_RETRIES; ++i)
+ for(size_t p = 0; p != BOTAN_ENTROPY_INTEL_RNG_POLLS; ++p)
{
- uint32_t r = 0;
+ for(size_t i = 0; i != BOTAN_ENTROPY_RDSEED_RETRIES; ++i)
+ {
+ uint32_t r = 0;
#if defined(BOTAN_USE_GCC_INLINE_ASM)
- int cf = 0;
+ int cf = 0;
- // Encoding of rdseed %eax
- asm(".byte 0x0F, 0xC7, 0xF8; adcl $0,%1" :
- "=a" (r), "=r" (cf) : "0" (r), "1" (cf) : "cc");
+ // Encoding of rdseed %eax
+ asm(".byte 0x0F, 0xC7, 0xF8; adcl $0,%1" :
+ "=a" (r), "=r" (cf) : "0" (r), "1" (cf) : "cc");
#else
- int cf = _rdseed32_step(&r);
+ int cf = _rdseed32_step(&r);
#endif
- if(1 == cf)
- {
- accum.add(r, BOTAN_ENTROPY_ESTIMATE_HARDWARE_RNG);
- break;
+ if(1 == cf)
+ {
+ rng.add_entropy_T(r);
+ break;
+ }
}
}
}
+
+ return 0;
}
}
diff --git a/src/lib/entropy/rdseed/rdseed.h b/src/lib/entropy/rdseed/rdseed.h
index f86c32768..4ea584354 100644
--- a/src/lib/entropy/rdseed/rdseed.h
+++ b/src/lib/entropy/rdseed/rdseed.h
@@ -20,7 +20,7 @@ class Intel_Rdseed final : public Entropy_Source
{
public:
std::string name() const override { return "rdseed"; }
- void poll(Entropy_Accumulator& accum) override;
+ size_t poll(RandomNumberGenerator& rng) override;
};
}
diff --git a/src/lib/entropy/unix_procs/unix_procs.cpp b/src/lib/entropy/unix_procs/unix_procs.cpp
index 55ad295cd..8f885cfcf 100644
--- a/src/lib/entropy/unix_procs/unix_procs.cpp
+++ b/src/lib/entropy/unix_procs/unix_procs.cpp
@@ -67,17 +67,52 @@ Unix_EntropySource::Unix_EntropySource(const std::vector<std::string>& trusted_p
{
}
-void UnixProcessInfo_EntropySource::poll(Entropy_Accumulator& accum)
+size_t UnixProcessInfo_EntropySource::poll(RandomNumberGenerator& rng)
{
- accum.add(::getpid(), BOTAN_ENTROPY_ESTIMATE_STATIC_SYSTEM_DATA);
- accum.add(::getppid(), BOTAN_ENTROPY_ESTIMATE_STATIC_SYSTEM_DATA);
- accum.add(::getuid(), BOTAN_ENTROPY_ESTIMATE_STATIC_SYSTEM_DATA);
- accum.add(::getgid(), BOTAN_ENTROPY_ESTIMATE_STATIC_SYSTEM_DATA);
- accum.add(::getpgrp(), BOTAN_ENTROPY_ESTIMATE_STATIC_SYSTEM_DATA);
+ rng.add_entropy_T(::getpid());
+ rng.add_entropy_T(::getppid());
+ rng.add_entropy_T(::getuid());
+ rng.add_entropy_T(::getgid());
+ rng.add_entropy_T(::getpgrp());
struct ::rusage usage;
::getrusage(RUSAGE_SELF, &usage);
- accum.add(usage, BOTAN_ENTROPY_ESTIMATE_STATIC_SYSTEM_DATA);
+ rng.add_entropy_T(usage);
+
+#if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME)
+
+#define CLOCK_GETTIME_POLL(src) \
+ do { \
+ struct timespec ts; \
+ ::clock_gettime(src, &ts); \
+ rng.add_entropy_T(ts); \
+ } while(0)
+
+#if defined(CLOCK_REALTIME)
+ CLOCK_GETTIME_POLL(CLOCK_REALTIME);
+#endif
+
+#if defined(CLOCK_MONOTONIC)
+ CLOCK_GETTIME_POLL(CLOCK_MONOTONIC);
+#endif
+
+#if defined(CLOCK_MONOTONIC_RAW)
+ CLOCK_GETTIME_POLL(CLOCK_MONOTONIC_RAW);
+#endif
+
+#if defined(CLOCK_PROCESS_CPUTIME_ID)
+ CLOCK_GETTIME_POLL(CLOCK_PROCESS_CPUTIME_ID);
+#endif
+
+#if defined(CLOCK_THREAD_CPUTIME_ID)
+ CLOCK_GETTIME_POLL(CLOCK_THREAD_CPUTIME_ID);
+#endif
+
+#undef CLOCK_GETTIME_POLL
+
+#endif
+
+ return 0;
}
void Unix_EntropySource::Unix_Process::spawn(const std::vector<std::string>& args)
@@ -168,11 +203,11 @@ const std::vector<std::string>& Unix_EntropySource::next_source()
return src;
}
-void Unix_EntropySource::poll(Entropy_Accumulator& accum)
+size_t Unix_EntropySource::poll(RandomNumberGenerator& rng)
{
// refuse to run setuid or setgid, or as root
if((getuid() != geteuid()) || (getgid() != getegid()) || (geteuid() == 0))
- return;
+ return 0;
std::lock_guard<std::mutex> lock(m_mutex);
@@ -192,13 +227,15 @@ void Unix_EntropySource::poll(Entropy_Accumulator& accum)
}
if(m_sources.empty())
- return; // still empty, really nothing to try
+ return 0; // still empty, really nothing to try
const size_t MS_WAIT_TIME = 32;
m_buf.resize(4096);
- while(!accum.polling_finished())
+ size_t bytes = 0;
+
+ while(bytes < 128 * 1024) // arbitrary limit...
{
while(m_procs.size() < m_concurrent)
m_procs.emplace_back(Unix_Process(next_source()));
@@ -228,7 +265,7 @@ void Unix_EntropySource::poll(Entropy_Accumulator& accum)
timeout.tv_usec = (MS_WAIT_TIME % 1000) * 1000;
if(::select(max_fd + 1, &read_set, nullptr, nullptr, &timeout) < 0)
- return; // or continue?
+ break; // or continue?
for(auto& proc : m_procs)
{
@@ -237,13 +274,19 @@ void Unix_EntropySource::poll(Entropy_Accumulator& accum)
if(FD_ISSET(fd, &read_set))
{
const ssize_t got = ::read(fd, m_buf.data(), m_buf.size());
+
if(got > 0)
- accum.add(m_buf.data(), got, BOTAN_ENTROPY_ESTIMATE_SYSTEM_TEXT);
+ {
+ rng.add_entropy(m_buf.data(), got);
+ bytes += got;
+ }
else
proc.spawn(next_source());
}
}
}
+
+ return bytes / 1024;
}
}
diff --git a/src/lib/entropy/unix_procs/unix_procs.h b/src/lib/entropy/unix_procs/unix_procs.h
index e1749af5f..27f7ab5bb 100644
--- a/src/lib/entropy/unix_procs/unix_procs.h
+++ b/src/lib/entropy/unix_procs/unix_procs.h
@@ -25,7 +25,7 @@ class Unix_EntropySource final : public Entropy_Source
public:
std::string name() const override { return "unix_procs"; }
- void poll(Entropy_Accumulator& accum) override;
+ size_t poll(RandomNumberGenerator& rng) override;
/**
* @param trusted_paths is a list of directories that are assumed
@@ -83,7 +83,7 @@ class UnixProcessInfo_EntropySource final : public Entropy_Source
public:
std::string name() const override { return "proc_info"; }
- void poll(Entropy_Accumulator& accum) override;
+ size_t poll(RandomNumberGenerator& rng) override;
};
}
diff --git a/src/lib/entropy/win32_stats/es_win32.cpp b/src/lib/entropy/win32_stats/es_win32.cpp
index ce0edea83..bbc64eaab 100644
--- a/src/lib/entropy/win32_stats/es_win32.cpp
+++ b/src/lib/entropy/win32_stats/es_win32.cpp
@@ -1,6 +1,6 @@
/*
* Win32 EntropySource
-* (C) 1999-2009 Jack Lloyd
+* (C) 1999-2009,2016 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -14,44 +14,44 @@ namespace Botan {
/**
* Win32 poll using stats functions including Tooltip32
*/
-void Win32_EntropySource::poll(Entropy_Accumulator& accum)
+size_t Win32_EntropySource::poll(RandomNumberGenerator& rng)
{
/*
- First query a bunch of basic statistical stuff, though
- don't count it for much in terms of contributed entropy.
+ First query a bunch of basic statistical stuff
*/
- accum.add(GetTickCount(), BOTAN_ENTROPY_ESTIMATE_SYSTEM_DATA);
- accum.add(GetMessagePos(), BOTAN_ENTROPY_ESTIMATE_SYSTEM_DATA);
- accum.add(GetMessageTime(), BOTAN_ENTROPY_ESTIMATE_SYSTEM_DATA);
- accum.add(GetInputState(), BOTAN_ENTROPY_ESTIMATE_SYSTEM_DATA);
+ rng.add_entropy_T(::GetTickCount());
+ rng.add_entropy_T(::GetMessagePos());
+ rng.add_entropy_T(::GetMessageTime());
+ rng.add_entropy_T(::GetInputState());
- accum.add(GetCurrentProcessId(), BOTAN_ENTROPY_ESTIMATE_STATIC_SYSTEM_DATA);
- accum.add(GetCurrentThreadId(), BOTAN_ENTROPY_ESTIMATE_STATIC_SYSTEM_DATA);
+ rng.add_entropy_T(::GetCurrentProcessId());
+ rng.add_entropy_T(::GetCurrentThreadId());
SYSTEM_INFO sys_info;
- GetSystemInfo(&sys_info);
- accum.add(sys_info, BOTAN_ENTROPY_ESTIMATE_STATIC_SYSTEM_DATA);
+ ::GetSystemInfo(&sys_info);
+ rng.add_entropy_T(sys_info);
MEMORYSTATUSEX mem_info;
- GlobalMemoryStatusEx(&mem_info);
- accum.add(mem_info, BOTAN_ENTROPY_ESTIMATE_SYSTEM_DATA);
+ ::GlobalMemoryStatusEx(&mem_info);
+ rng.add_entropy_T(mem_info);
POINT point;
- GetCursorPos(&point);
- accum.add(point, BOTAN_ENTROPY_ESTIMATE_SYSTEM_DATA);
+ ::GetCursorPos(&point);
+ rng.add_entropy_T(point);
- GetCaretPos(&point);
- accum.add(point, BOTAN_ENTROPY_ESTIMATE_SYSTEM_DATA);
+ ::GetCaretPos(&point);
+ rng.add_entropy_T(point);
/*
- Now use the Tooltip library to iterate throug various objects on
+ Now use the Tooltip library to iterate through various objects on
the system, including processes, threads, and heap objects.
*/
- HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
+ HANDLE snapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
+ size_t bits = 0;
#define TOOLHELP32_ITER(DATA_TYPE, FUNC_FIRST, FUNC_NEXT) \
- if(!accum.polling_finished()) \
+ if(bits < 256) \
{ \
DATA_TYPE info; \
info.dwSize = sizeof(DATA_TYPE); \
@@ -59,57 +59,52 @@ void Win32_EntropySource::poll(Entropy_Accumulator& accum)
{ \
do \
{ \
- accum.add(info, BOTAN_ENTROPY_ESTIMATE_SYSTEM_DATA); \
+ rng.add_entropy_T(info); \
+ bits += 4; \
} while(FUNC_NEXT(snapshot, &info)); \
} \
}
- TOOLHELP32_ITER(MODULEENTRY32, Module32First, Module32Next);
- TOOLHELP32_ITER(PROCESSENTRY32, Process32First, Process32Next);
- TOOLHELP32_ITER(THREADENTRY32, Thread32First, Thread32Next);
+ TOOLHELP32_ITER(MODULEENTRY32, ::Module32First, ::Module32Next);
+ TOOLHELP32_ITER(PROCESSENTRY32, ::Process32First, ::Process32Next);
+ TOOLHELP32_ITER(THREADENTRY32, ::Thread32First, ::Thread32Next);
#undef TOOLHELP32_ITER
- if(!accum.polling_finished())
+ if(bits <= 256)
{
HEAPLIST32 heap_list;
heap_list.dwSize = sizeof(HEAPLIST32);
- const size_t HEAP_LISTS_MAX = 32;
- const size_t HEAP_OBJS_PER_LIST = 128;
-
- if(Heap32ListFirst(snapshot, &heap_list))
+ if(::Heap32ListFirst(snapshot, &heap_list))
{
- size_t heap_lists_found = 0;
do
{
- accum.add(heap_list, BOTAN_ENTROPY_ESTIMATE_SYSTEM_DATA);
-
- if(++heap_lists_found > HEAP_LISTS_MAX)
- break;
+ rng.add_entropy_T(heap_list);
HEAPENTRY32 heap_entry;
heap_entry.dwSize = sizeof(HEAPENTRY32);
- if(Heap32First(&heap_entry, heap_list.th32ProcessID,
- heap_list.th32HeapID))
+ if(::Heap32First(&heap_entry,
+ heap_list.th32ProcessID,
+ heap_list.th32HeapID))
{
- size_t heap_objs_found = 0;
do
{
- if(heap_objs_found++ > HEAP_OBJS_PER_LIST)
- break;
- accum.add(heap_entry, BOTAN_ENTROPY_ESTIMATE_SYSTEM_DATA);
- } while(Heap32Next(&heap_entry));
+ rng.add_entropy_T(heap_entry);
+ bits += 4;
+ } while(::Heap32Next(&heap_entry));
}
- if(accum.polling_finished())
+ if(bits >= 256)
break;
- } while(Heap32ListNext(snapshot, &heap_list));
+ } while(::Heap32ListNext(snapshot, &heap_list));
}
}
- CloseHandle(snapshot);
+ ::CloseHandle(snapshot);
+
+ return bits;
}
}
diff --git a/src/lib/entropy/win32_stats/es_win32.h b/src/lib/entropy/win32_stats/es_win32.h
index 5dc3f7f17..26b904bbb 100644
--- a/src/lib/entropy/win32_stats/es_win32.h
+++ b/src/lib/entropy/win32_stats/es_win32.h
@@ -19,7 +19,7 @@ class Win32_EntropySource final : public Entropy_Source
{
public:
std::string name() const override { return "system_stats"; }
- void poll(Entropy_Accumulator& accum) override;
+ size_t poll(RandomNumberGenerator& rng) override;
};
}
diff --git a/src/lib/ffi/info.txt b/src/lib/ffi/info.txt
index 7c8968ff0..057bbd012 100644
--- a/src/lib/ffi/info.txt
+++ b/src/lib/ffi/info.txt
@@ -7,7 +7,6 @@ pbkdf
pubkey
x509
#tls
-auto_rng
system_rng
</requires>
diff --git a/src/lib/prov/tpm/tpm.h b/src/lib/prov/tpm/tpm.h
index 4a9dcd3c6..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,34 +72,27 @@ 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) {}
+ void add_entropy(const byte in[], size_t in_len) override
+ {
+ m_ctx.stir_random(in, in_len);
+ }
+
void randomize(byte out[], size_t out_len) override
{
m_ctx.gen_random(out, out_len);
}
- void clear() override {}
-
std::string name() const override { return "TPM_RNG"; }
- size_t reseed_with_sources(Entropy_Sources&,
- size_t,
- std::chrono::milliseconds) override
- {
- // TODO: poll and stir
- return 0;
- }
+ bool is_seeded() const override { return true; }
- void add_entropy(const byte in[], size_t in_len) override
- {
- m_ctx.stir_random(in, in_len);
- }
+ void clear() override {}
- bool is_seeded() const override { return true; }
private:
TPM_Context& m_ctx;
};
diff --git a/src/lib/pubkey/dsa/dsa.cpp b/src/lib/pubkey/dsa/dsa.cpp
index c42e70914..6effb81dd 100644
--- a/src/lib/pubkey/dsa/dsa.cpp
+++ b/src/lib/pubkey/dsa/dsa.cpp
@@ -116,6 +116,7 @@ DSA_Signature_Operation::raw_sign(const byte msg[], size_t msg_len,
i -= m_q;
#if defined(BOTAN_HAS_RFC6979_GENERATOR)
+ BOTAN_UNUSED(rng);
const BigInt k = generate_rfc6979_nonce(m_x, m_q, i, hash_for_emsa(m_emsa));
#else
const BigInt k = BigInt::random_integer(rng, 1, m_q);
diff --git a/src/lib/pubkey/rfc6979/rfc6979.cpp b/src/lib/pubkey/rfc6979/rfc6979.cpp
index 0b26aadb5..1173eefee 100644
--- a/src/lib/pubkey/rfc6979/rfc6979.cpp
+++ b/src/lib/pubkey/rfc6979/rfc6979.cpp
@@ -17,18 +17,23 @@ RFC6979_Nonce_Generator::RFC6979_Nonce_Generator(const std::string& hash,
m_order(order),
m_qlen(m_order.bits()),
m_rlen(m_qlen / 8 + (m_qlen % 8 ? 1 : 0)),
- m_hmac_drbg(new HMAC_DRBG(MessageAuthenticationCode::create("HMAC(" + hash + ")").release())),
+ m_hmac_drbg(new HMAC_DRBG(hash, 0)),
m_rng_in(m_rlen * 2),
m_rng_out(m_rlen)
{
BigInt::encode_1363(m_rng_in.data(), m_rlen, x);
}
+RFC6979_Nonce_Generator::~RFC6979_Nonce_Generator()
+ {
+ // for ~unique_ptr
+ }
+
const BigInt& RFC6979_Nonce_Generator::nonce_for(const BigInt& m)
{
BigInt::encode_1363(&m_rng_in[m_rlen], m_rlen, m);
m_hmac_drbg->clear();
- m_hmac_drbg->add_entropy(m_rng_in.data(), m_rng_in.size());
+ m_hmac_drbg->initialize_with(m_rng_in.data(), m_rng_in.size());
do
{
diff --git a/src/lib/pubkey/rfc6979/rfc6979.h b/src/lib/pubkey/rfc6979/rfc6979.h
index 32728befb..2518535f7 100644
--- a/src/lib/pubkey/rfc6979/rfc6979.h
+++ b/src/lib/pubkey/rfc6979/rfc6979.h
@@ -14,7 +14,7 @@
namespace Botan {
-class RandomNumberGenerator;
+class HMAC_DRBG;
class BOTAN_DLL RFC6979_Nonce_Generator
{
@@ -26,12 +26,14 @@ class BOTAN_DLL RFC6979_Nonce_Generator
const BigInt& order,
const BigInt& x);
+ ~RFC6979_Nonce_Generator();
+
const BigInt& nonce_for(const BigInt& m);
private:
const BigInt& m_order;
BigInt m_k;
size_t m_qlen, m_rlen;
- std::unique_ptr<RandomNumberGenerator> m_hmac_drbg;
+ std::unique_ptr<HMAC_DRBG> m_hmac_drbg;
secure_vector<byte> m_rng_in, m_rng_out;
};
diff --git a/src/lib/rng/auto_rng/auto_rng.h b/src/lib/rng/auto_rng.h
index 72ea88d3e..3085623ef 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 max_output_before_reseed = BOTAN_RNG_DEFAULT_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 67325ee1b..7325804e3 100644
--- a/src/lib/rng/hmac_drbg/hmac_drbg.cpp
+++ b/src/lib/rng/hmac_drbg/hmac_drbg.cpp
@@ -1,6 +1,6 @@
/*
* HMAC_DRBG
-* (C) 2014,2015 Jack Lloyd
+* (C) 2014,2015,2016 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -10,53 +10,81 @@
namespace Botan {
-HMAC_DRBG::HMAC_DRBG(MessageAuthenticationCode* mac,
- RandomNumberGenerator* prng) :
- m_mac(mac),
- m_prng(prng),
- m_V(m_mac->output_length(), 0x01),
- m_reseed_counter(0)
+HMAC_DRBG::HMAC_DRBG(MessageAuthenticationCode* hmac,
+ size_t max_output_before_reseed) :
+ Stateful_RNG(max_output_before_reseed),
+ m_mac(hmac)
{
- m_mac->set_key(std::vector<byte>(m_mac->output_length(), 0x00));
+ m_V.resize(m_mac->output_length());
+ clear();
}
-HMAC_DRBG::HMAC_DRBG(const std::string& mac_name,
- RandomNumberGenerator* prng) :
- m_prng(prng),
- m_reseed_counter(0)
+HMAC_DRBG::HMAC_DRBG(const std::string& hmac_hash,
+ size_t max_output_before_reseed) :
+ Stateful_RNG(max_output_before_reseed)
{
- m_mac = MessageAuthenticationCode::create(mac_name);
+ const std::string hmac = "HMAC(" + hmac_hash + ")";
+
+ m_mac = MessageAuthenticationCode::create(hmac);
if(!m_mac)
- throw Algorithm_Not_Found(mac_name);
- m_V = secure_vector<byte>(m_mac->output_length(), 0x01),
+ {
+ throw Algorithm_Not_Found(hmac);
+ }
+
+ 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));
}
-void HMAC_DRBG::randomize(byte out[], size_t length)
+std::string HMAC_DRBG::name() const
{
- if(!is_seeded() || m_reseed_counter > BOTAN_RNG_MAX_OUTPUT_BEFORE_RESEED)
- reseed(m_mac->output_length() * 8);
+ return "HMAC_DRBG(" + m_mac->name() + ")";
+ }
- if(!is_seeded())
- throw PRNG_Unseeded(name());
+void HMAC_DRBG::randomize(byte output[], size_t output_len)
+ {
+ randomize_with_input(output, output_len, nullptr, 0);
+ }
- while(length)
- {
- const size_t to_copy = std::min(length, m_V.size());
- m_V = m_mac->process(m_V);
- copy_mem(out, m_V.data(), to_copy);
+/*
+* HMAC_DRBG generation
+* See NIST SP800-90A section 10.1.2.5
+*/
+void HMAC_DRBG::randomize_with_input(byte output[], size_t output_len,
+ const byte input[], size_t input_len)
+ {
+ reseed_check(output_len);
- length -= to_copy;
- out += to_copy;
+ if(input_len > 0)
+ {
+ update(input, input_len);
}
- m_reseed_counter += length;
+ while(output_len)
+ {
+ const size_t to_copy = std::min(output_len, m_V.size());
+ m_mac->update(m_V.data(), m_V.size());
+ m_mac->final(m_V.data());
+ copy_mem(output, m_V.data(), to_copy);
+
+ output += to_copy;
+ output_len -= to_copy;
+ }
- update(nullptr, 0); // additional_data is always empty
+ update(input, input_len);
}
/*
* Reset V and the mac key with new values
+* See NIST SP800-90A section 10.1.2.2
*/
void HMAC_DRBG::update(const byte input[], size_t input_len)
{
@@ -65,66 +93,24 @@ void HMAC_DRBG::update(const byte input[], size_t input_len)
m_mac->update(input, input_len);
m_mac->set_key(m_mac->final());
- m_V = m_mac->process(m_V);
+ m_mac->update(m_V.data(), m_V.size());
+ m_mac->final(m_V.data());
- if(input_len)
+ if(input_len > 0)
{
m_mac->update(m_V);
m_mac->update(0x01);
m_mac->update(input, input_len);
m_mac->set_key(m_mac->final());
- m_V = m_mac->process(m_V);
+ m_mac->update(m_V.data(), m_V.size());
+ m_mac->final(m_V.data());
}
}
-size_t HMAC_DRBG::reseed_with_sources(Entropy_Sources& srcs,
- size_t poll_bits,
- std::chrono::milliseconds poll_timeout)
+void HMAC_DRBG::add_entropy(const byte input[], size_t input_len)
{
- if(m_prng)
- {
- size_t bits = m_prng->reseed_with_sources(srcs, poll_bits, poll_timeout);
-
- if(m_prng->is_seeded())
- {
- secure_vector<byte> input = m_prng->random_vec(m_mac->output_length());
- update(input.data(), input.size());
- m_reseed_counter = 1;
- }
-
- return bits;
- }
-
- return 0;
- }
-
-void HMAC_DRBG::add_entropy(const byte input[], size_t length)
- {
- update(input, length);
- m_reseed_counter = 1;
- }
-
-bool HMAC_DRBG::is_seeded() const
- {
- return m_reseed_counter > 0;
- }
-
-void HMAC_DRBG::clear()
- {
- m_reseed_counter = 0;
- 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));
-
- if(m_prng)
- m_prng->clear();
- }
-
-std::string HMAC_DRBG::name() const
- {
- return "HMAC_DRBG(" + m_mac->name() + ")";
+ update(input, input_len);
}
}
diff --git a/src/lib/rng/hmac_drbg/hmac_drbg.h b/src/lib/rng/hmac_drbg/hmac_drbg.h
index bd2d18d47..0e294dbdb 100644
--- a/src/lib/rng/hmac_drbg/hmac_drbg.h
+++ b/src/lib/rng/hmac_drbg/hmac_drbg.h
@@ -1,6 +1,6 @@
/*
* HMAC_DRBG (SP800-90A)
-* (C) 2014,2015 Jack Lloyd
+* (C) 2014,2015,2016 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -14,40 +14,35 @@
namespace Botan {
/**
-* HMAC_DRBG (SP800-90A)
+* HMAC_DRBG from NIST SP800-90A
*/
-class BOTAN_DLL HMAC_DRBG : public RandomNumberGenerator
+class BOTAN_DLL HMAC_DRBG final : public Stateful_RNG
{
public:
- void randomize(byte buf[], size_t buf_len) override;
- bool is_seeded() const override;
- void clear() override;
- std::string name() const override;
+ /**
+ * Initialize an HMAC_DRBG instance with the given hash function
+ */
+ HMAC_DRBG(const std::string& hmac_hash,
+ size_t max_output_before_reseed = BOTAN_RNG_DEFAULT_MAX_OUTPUT_BEFORE_RESEED);
- size_t reseed_with_sources(Entropy_Sources& srcs,
- size_t poll_bits,
- std::chrono::milliseconds poll_timeout) override;
+ HMAC_DRBG(MessageAuthenticationCode* hmac,
+ size_t max_output_before_reseed = BOTAN_RNG_DEFAULT_MAX_OUTPUT_BEFORE_RESEED);
- void add_entropy(const byte input[], size_t input_len) override;
+ std::string name() const override;
- /**
- * @param mac the underlying mac function (eg HMAC(SHA-512))
- * @param underlying_rng RNG used generating inputs (eg HMAC_RNG)
- */
- HMAC_DRBG(MessageAuthenticationCode* mac,
- RandomNumberGenerator* underlying_rng = nullptr);
+ void clear() override;
- HMAC_DRBG(const std::string& mac,
- RandomNumberGenerator* underlying_rng = nullptr);
+ void randomize(byte output[], size_t output_len) override;
+ void randomize_with_input(byte output[], size_t output_len,
+ const byte input[], size_t input_len) override;
+
+ void add_entropy(const byte input[], size_t input_len) override;
private:
void update(const byte input[], size_t input_len);
std::unique_ptr<MessageAuthenticationCode> m_mac;
- std::unique_ptr<RandomNumberGenerator> m_prng;
-
secure_vector<byte> m_V;
- size_t m_reseed_counter;
};
}
diff --git a/src/lib/rng/hmac_rng/hmac_rng.cpp b/src/lib/rng/hmac_rng/hmac_rng.cpp
index 7a9e4dbc5..c100cf70f 100644
--- a/src/lib/rng/hmac_rng/hmac_rng.cpp
+++ b/src/lib/rng/hmac_rng/hmac_rng.cpp
@@ -9,15 +9,36 @@
#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_output_before_reseed) :
+ Stateful_RNG(max_output_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) :
+ MessageAuthenticationCode* prf,
+ size_t max_output_before_reseed) :
+ Stateful_RNG(max_output_before_reseed),
m_extractor(extractor), m_prf(prf)
{
if(!m_prf->valid_keylength(m_extractor->output_length()) ||
@@ -33,7 +54,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 +92,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 +105,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 +147,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..a2538a83a 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;
@@ -43,24 +42,28 @@ class BOTAN_DLL HMAC_RNG : public RandomNumberGenerator
* @param prf a MAC used as a PRF using HKDF construction
*/
HMAC_RNG(MessageAuthenticationCode* extractor,
- MessageAuthenticationCode* prf);
+ MessageAuthenticationCode* prf,
+ size_t max_output_before_reseed = BOTAN_RNG_DEFAULT_MAX_OUTPUT_BEFORE_RESEED);
+
+ /**
+ * Use the specified hash for both the extractor and PRF functions
+ */
+ HMAC_RNG(const std::string& hash,
+ size_t max_output_before_reseed = BOTAN_RNG_DEFAULT_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/info.txt b/src/lib/rng/info.txt
index ba7aa8e6a..84ba3ce89 100644
--- a/src/lib/rng/info.txt
+++ b/src/lib/rng/info.txt
@@ -1,5 +1,6 @@
+define AUTO_SEEDING_RNG 20131128
+
<requires>
entropy
-auto_rng
-hmac_rng
+hmac_drbg
</requires>
diff --git a/src/lib/rng/rng.cpp b/src/lib/rng/rng.cpp
index c17f23dd0..5501c143e 100644
--- a/src/lib/rng/rng.cpp
+++ b/src/lib/rng/rng.cpp
@@ -1,13 +1,23 @@
/*
* Random Number Generator
-* (C) 1999-2008 Jack Lloyd
+* (C) 1999-2008,2016 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#include <botan/rng.h>
-#include <botan/hmac_rng.h>
+#include <botan/auto_rng.h>
#include <botan/entropy_src.h>
+#include <botan/loadstor.h>
+#include <botan/internal/os_utils.h>
+
+#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 {
@@ -25,18 +35,110 @@ size_t RandomNumberGenerator::reseed_with_timeout(size_t bits_to_collect,
timeout);
}
+size_t RandomNumberGenerator::reseed_with_sources(Entropy_Sources& srcs,
+ size_t poll_bits,
+ std::chrono::milliseconds poll_timeout)
+ {
+ return srcs.poll(*this, poll_bits, poll_timeout);
+ }
+
+Stateful_RNG::Stateful_RNG(size_t max_output_before_reseed) : m_max_output_before_reseed(max_output_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,
+ size_t poll_bits,
+ std::chrono::milliseconds poll_timeout)
+ {
+ size_t bits_collected = RandomNumberGenerator::reseed_with_sources(srcs, poll_bits, poll_timeout);
+
+ if(bits_collected >= poll_bits)
+ {
+ m_successful_initialization = true;
+ m_bytes_since_reseed = 0;
+ }
+
+ return bits_collected;
+ }
+
+void Stateful_RNG::reseed_check(size_t bytes_requested)
+ {
+ const bool fork_detected = (m_last_pid > 0) && (OS::get_process_id() != m_last_pid);
+
+ m_bytes_since_reseed += bytes_requested;
+ m_last_pid = OS::get_process_id();
+
+ if(!is_seeded() || fork_detected)
+ {
+ this->reseed(BOTAN_RNG_RESEED_POLL_BITS);
+ }
+ else if(m_max_output_before_reseed > 0 && m_bytes_since_reseed >= m_max_output_before_reseed)
+ {
+ this->reseed_with_timeout(BOTAN_RNG_RESEED_POLL_BITS,
+ BOTAN_RNG_AUTO_RESEED_TIMEOUT);
+ }
+
+ if(!is_seeded())
+ {
+ throw PRNG_Unseeded(name());
+ }
+ }
+
+void Stateful_RNG::initialize_with(const byte input[], size_t len)
+ {
+ add_entropy(input, len);
+ m_successful_initialization = true;
+ }
+
+bool Stateful_RNG::is_seeded() const
+ {
+ return m_successful_initialization;
+ }
+
RandomNumberGenerator* RandomNumberGenerator::make_rng()
{
- std::unique_ptr<MessageAuthenticationCode> h1(MessageAuthenticationCode::create("HMAC(SHA-512)"));
- std::unique_ptr<MessageAuthenticationCode> h2(MessageAuthenticationCode::create("HMAC(SHA-512)"));
+ return new AutoSeeded_RNG;
+ }
- if(!h1 || !h2)
- throw Algorithm_Not_Found("HMAC_RNG HMACs");
- std::unique_ptr<RandomNumberGenerator> rng(new HMAC_RNG(h1.release(), h2.release()));
+AutoSeeded_RNG::AutoSeeded_RNG(size_t max_output_before_reseed)
+ {
+ m_rng.reset(new BOTAN_AUTO_RNG_DRBG(BOTAN_AUTO_RNG_HASH, max_output_before_reseed));
- rng->reseed(256);
+ size_t bits = m_rng->reseed(BOTAN_AUTO_RNG_ENTROPY_TARGET);
- return rng.release();
+ if(!m_rng->is_seeded())
+ {
+ throw Exception("AutoSeeded_RNG failed to gather enough entropy only got " +
+ std::to_string(bits) + " bits");
+ }
+ }
+
+void AutoSeeded_RNG::randomize(byte output[], size_t output_len)
+ {
+ /*
+ Form additional input which is provided to the PRNG implementation
+ to paramaterize the KDF output.
+ */
+ 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);
+
+ randomize_with_input(output, output_len, additional_input, sizeof(additional_input));
+ }
+
+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 3fd3dcec8..7da560b85 100644
--- a/src/lib/rng/rng.h
+++ b/src/lib/rng/rng.h
@@ -1,6 +1,6 @@
/*
-* RandomNumberGenerator
-* (C) 1999-2009 Jack Lloyd
+* Random Number Generator base classes
+* (C) 1999-2009,2015,2016 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -19,16 +19,20 @@ namespace Botan {
class Entropy_Sources;
/**
-* This class represents a random number (RNG) generator object.
+* An interface to a generic RNG
*/
class BOTAN_DLL RandomNumberGenerator
{
public:
- /**
- * Create a seeded and active RNG object for general application use
- * Added in 1.8.0
+ virtual ~RandomNumberGenerator() = default;
+
+ RandomNumberGenerator() = default;
+
+ /*
+ * Never copy a RNG, create a new one
*/
- static RandomNumberGenerator* make_rng();
+ RandomNumberGenerator(const RandomNumberGenerator& rng) = delete;
+ RandomNumberGenerator& operator=(const RandomNumberGenerator& rng) = delete;
/**
* Randomize a byte array.
@@ -38,47 +42,38 @@ class BOTAN_DLL RandomNumberGenerator
virtual void randomize(byte output[], size_t length) = 0;
/**
- * Return a random vector
- * @param bytes number of bytes in the result
- * @return randomized vector of length bytes
+ * Incorporate some additional data into the RNG state. For
+ * example adding nonces or timestamps from a peer's protocol
+ * message can help hedge against VM state rollback attacks.
+ *
+ * @param inputs a byte array containg the entropy to be added
+ * @param length the length of the byte array in
*/
- virtual secure_vector<byte> random_vec(size_t bytes)
- {
- secure_vector<byte> output(bytes);
- randomize(output.data(), output.size());
- return output;
- }
+ virtual void add_entropy(const byte input[], size_t length) = 0;
/**
- * Only usable with POD types, only useful with integers
- * get_random<u64bit>()
+ * Incorporate some additional data into the RNG state.
*/
- template<typename T> T get_random()
+ template<typename T> void add_entropy_T(const T& t)
{
- T r;
- this->randomize(reinterpret_cast<byte*>(&r), sizeof(r));
- return r;
+ add_entropy(reinterpret_cast<const uint8_t*>(&t), sizeof(T));
}
/**
- * Return a random byte
- * @return random byte
+ * Incorporate entropy into the RNG state then produce output
+ * Some RNG types implement this using a single operation.
*/
- byte next_byte() { return get_random<byte>(); }
-
- byte next_nonzero_byte()
+ virtual void randomize_with_input(byte output[], size_t output_len,
+ const byte input[], size_t input_len)
{
- byte b = next_byte();
- while(b == 0)
- b = next_byte();
- return b;
+ this->add_entropy(input, input_len);
+ this->randomize(output, output_len);
}
/**
- * Check whether this RNG is seeded.
- * @return true if this RNG was already seeded, false otherwise.
+ * Return the name of this object
*/
- virtual bool is_seeded() const = 0;
+ virtual std::string name() const = 0;
/**
* Clear all internally held values of this RNG.
@@ -86,80 +81,170 @@ class BOTAN_DLL RandomNumberGenerator
virtual void clear() = 0;
/**
- * Return the name of this object
+ * Check whether this RNG is seeded.
+ * @return true if this RNG was already seeded, false otherwise.
*/
- virtual std::string name() const = 0;
+ virtual bool is_seeded() const = 0;
/**
- * Seed this RNG using the global entropy sources and default timeout
+ * Poll provided sources for up to poll_bits bits of entropy
+ * or until the timeout expires. Returns estimate of the number
+ * of bits collected.
+ */
+ virtual size_t reseed_with_sources(Entropy_Sources& srcs,
+ size_t poll_bits,
+ std::chrono::milliseconds poll_timeout);
+
+ /**
+ * Reseed this RNG from the default entropy sources and a default timeout
* @param bits_to_collect is the number of bits of entropy to
- attempt to gather from the entropy sources
+ * attempt to gather from the entropy sources
+ * @param poll_timeout try not to run longer than this, even if
+ * not enough entropy has been collected
*/
- size_t reseed(size_t bits_to_collect);
+ size_t reseed(size_t bits_to_collect = BOTAN_RNG_RESEED_POLL_BITS);
/**
- * Seed this RNG using the global entropy sources
+ * Reseed this RNG from the default entropy sources
* @param bits_to_collect is the number of bits of entropy to
- attempt to gather from the entropy sources
- * @param poll_timeout try not to run longer than this, no matter what
+ * attempt to gather from the entropy sources
+ * @param poll_timeout try not to run longer than this, even if
+ * not enough entropy has been collected
*/
size_t reseed_with_timeout(size_t bits_to_collect,
std::chrono::milliseconds poll_timeout);
/**
+ * Return a random vector
+ * @param bytes number of bytes in the result
+ * @return randomized vector of length bytes
+ */
+ secure_vector<byte> random_vec(size_t bytes)
+ {
+ secure_vector<byte> output(bytes);
+ randomize(output.data(), output.size());
+ return output;
+ }
+
+ /**
+ * Return a random byte
+ * @return random byte
+ */
+ byte next_byte()
+ {
+ byte b;
+ this->randomize(&b, 1);
+ return b;
+ }
+
+ byte next_nonzero_byte()
+ {
+ byte b = next_byte();
+ while(b == 0)
+ b = next_byte();
+ return b;
+ }
+
+ /**
+ * Create a seeded and active RNG object for general application use
+ * Added in 1.8.0
+ * Use AutoSeeded_RNG instead
+ */
+ static RandomNumberGenerator* make_rng();
+ };
+
+/**
+* Inherited by RNGs which maintain in-process state, like HMAC_DRBG.
+* On Unix these RNGs are vulnerable to problems with fork, where the
+* RNG state is duplicated, and the parent and child process RNGs will
+* produce identical output until one of them reseeds. Stateful_RNG
+* reseeds itself whenever a fork is detected, or after a set number of
+* bytes have been output.
+*
+* Not implemented by RNGs which access an external RNG, such as the
+* system PRNG or a hardware RNG.
+*/
+class BOTAN_DLL Stateful_RNG : public RandomNumberGenerator
+ {
+ public:
+ Stateful_RNG(size_t max_output_before_reseed);
+
+ virtual bool is_seeded() const override final;
+
+ /**
+ * Consume this input and mark the RNG as initialized regardless
+ * of the length of the input or the current seeded state of
+ * the RNG.
+ */
+ void initialize_with(const byte input[], size_t length);
+
+ /**
* Poll provided sources for up to poll_bits bits of entropy
* or until the timeout expires. Returns estimate of the number
* of bits collected.
*/
- virtual size_t reseed_with_sources(Entropy_Sources& srcs,
- size_t poll_bits,
- std::chrono::milliseconds poll_timeout) = 0;
+ size_t reseed_with_sources(Entropy_Sources& srcs,
+ size_t poll_bits,
+ std::chrono::milliseconds poll_timeout) override;
+
+ protected:
+ void reseed_check(size_t bytes_requested);
+
+ void clear() override;
/**
- * 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
+ * Mark state as requiring a reseed on next use
*/
- virtual void add_entropy(const byte in[], size_t length) = 0;
+ void force_reseed() { m_bytes_since_reseed = m_max_output_before_reseed; }
- /*
- * Never copy a RNG, create a new one
- */
- RandomNumberGenerator(const RandomNumberGenerator& rng) = delete;
- RandomNumberGenerator& operator=(const RandomNumberGenerator& rng) = delete;
+ uint32_t last_pid() const { return m_last_pid; }
+
+ mutable std::mutex m_mutex;
- RandomNumberGenerator() {}
- virtual ~RandomNumberGenerator() {}
+ private:
+ const size_t m_max_output_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
*/
-class BOTAN_DLL Null_RNG : public RandomNumberGenerator
+class BOTAN_DLL Null_RNG final : public RandomNumberGenerator
{
public:
- void randomize(byte[], size_t) override { throw PRNG_Unseeded("Null_RNG"); }
+ bool is_seeded() const override { return false; }
void clear() override {}
- std::string name() const override { return "Null_RNG"; }
-
- size_t reseed_with_sources(Entropy_Sources&, size_t,
- std::chrono::milliseconds) override
+ void randomize(byte[], size_t) override
{
- return 0;
+ throw Exception("Null_RNG called");
}
- bool is_seeded() const override { return false; }
void add_entropy(const byte[], size_t) override {}
+
+ std::string name() const override { return "Null_RNG"; }
};
/**
* Wraps access to a RNG in a mutex
*/
-class BOTAN_DLL Serialized_RNG : public RandomNumberGenerator
+class BOTAN_DLL Serialized_RNG final : public RandomNumberGenerator
{
public:
void randomize(byte out[], size_t len) override
diff --git a/src/lib/rng/system_rng/system_rng.cpp b/src/lib/rng/system_rng/system_rng.cpp
index 81e235a8c..135f4fabd 100644
--- a/src/lib/rng/system_rng/system_rng.cpp
+++ b/src/lib/rng/system_rng/system_rng.cpp
@@ -28,32 +28,23 @@ namespace Botan {
namespace {
-class System_RNG_Impl : public RandomNumberGenerator
+class System_RNG_Impl final : public RandomNumberGenerator
{
public:
System_RNG_Impl();
~System_RNG_Impl();
- void randomize(byte buf[], size_t len) override;
-
bool is_seeded() const override { return true; }
+
void clear() override {}
- std::string name() const override { return "system"; }
- size_t reseed_with_sources(Entropy_Sources&,
- size_t /*poll_bits*/,
- std::chrono::milliseconds /*timeout*/) override
- {
- // We ignore it and assert the PRNG is seeded.
- // TODO: could poll and write it to /dev/urandom to help seed it
- return 0;
- }
+ void randomize(uint8_t out[], size_t len) override;
- void add_entropy(const byte[], size_t) override
- {
- }
- private:
+ void add_entropy(const uint8_t in[], size_t length) override;
+
+ std::string name() const override;
+ private:
#if defined(BOTAN_TARGET_OS_HAS_CRYPTGENRANDOM)
HCRYPTPROV m_prov;
#else
@@ -61,6 +52,15 @@ class System_RNG_Impl : public RandomNumberGenerator
#endif
};
+std::string System_RNG_Impl::name() const
+ {
+#if defined(BOTAN_TARGET_OS_HAS_CRYPTGENRANDOM)
+ return "cryptoapi";
+#else
+ return BOTAN_SYSTEM_RNG_DEVICE;
+#endif
+ }
+
System_RNG_Impl::System_RNG_Impl()
{
#if defined(BOTAN_TARGET_OS_HAS_CRYPTGENRANDOM)
@@ -74,7 +74,7 @@ System_RNG_Impl::System_RNG_Impl()
#define O_NOCTTY 0
#endif
- m_fd = ::open(BOTAN_SYSTEM_RNG_DEVICE, O_RDONLY | O_NOCTTY);
+ m_fd = ::open(BOTAN_SYSTEM_RNG_DEVICE, O_RDWR | O_NOCTTY);
if(m_fd < 0)
throw Exception("System_RNG failed to open RNG device");
#endif
@@ -90,7 +90,61 @@ System_RNG_Impl::~System_RNG_Impl()
#endif
}
-void System_RNG_Impl::randomize(byte buf[], size_t len)
+void System_RNG_Impl::add_entropy(const uint8_t input[], size_t len)
+ {
+#if defined(BOTAN_TARGET_OS_HAS_CRYPTGENRANDOM)
+ /*
+ There is no explicit ConsumeRandom, but all values provided in
+ the call are incorporated into the state.
+
+ TODO: figure out a way to avoid this copy. Byte at a time updating
+ seems worse than the allocation.
+
+ for(size_t i = 0; i != len; ++i)
+ {
+ uint8_t b = input[i];
+ ::CryptGenRandom(m_prov, 1, &b);
+ }
+ */
+
+ if(len > 0)
+ {
+ secure_vector<uint8_t> buf(input, input + len);
+ ::CryptGenRandom(m_prov, static_cast<DWORD>(buf.size()), buf.data());
+ }
+#else
+ while(len)
+ {
+ ssize_t got = ::write(m_fd, input, len);
+
+ if(got < 0)
+ {
+ if(errno == EINTR)
+ continue;
+
+ /*
+ * This is seen on OS X CI, despite the fact that the man page
+ * for Darwin urandom explicitly states that writing to it is
+ * supported, and write(2) does not document EPERM at all.
+ * But in any case EPERM seems indicative of a policy decision
+ * by the OS or sysadmin that additional entropy is not wanted
+ * in the system pool, so we accept that and return here,
+ * since there is no corrective action possible.
+ */
+ if(errno == EPERM)
+ return;
+
+ // maybe just ignore any failure here and return?
+ throw Exception("System_RNG write failed error " + std::to_string(errno));
+ }
+
+ input += got;
+ len -= got;
+ }
+#endif
+ }
+
+void System_RNG_Impl::randomize(uint8_t buf[], size_t len)
{
#if defined(BOTAN_TARGET_OS_HAS_CRYPTGENRANDOM)
::CryptGenRandom(m_prov, static_cast<DWORD>(len), buf);
diff --git a/src/lib/rng/system_rng/system_rng.h b/src/lib/rng/system_rng/system_rng.h
index 6290b8769..9cf31e78b 100644
--- a/src/lib/rng/system_rng/system_rng.h
+++ b/src/lib/rng/system_rng/system_rng.h
@@ -22,29 +22,18 @@ BOTAN_DLL RandomNumberGenerator& system_rng();
/*
* Instantiatable reference to the system RNG.
*/
-class BOTAN_DLL System_RNG : public RandomNumberGenerator
+class BOTAN_DLL System_RNG final : public RandomNumberGenerator
{
public:
- System_RNG() : m_rng(system_rng()) {}
+ std::string name() const override { return system_rng().name(); }
- void randomize(Botan::byte out[], size_t len) override { m_rng.randomize(out, len); }
+ void randomize(uint8_t out[], size_t len) override { system_rng().randomize(out, len); }
- bool is_seeded() const override { return m_rng.is_seeded(); }
+ void add_entropy(const uint8_t in[], size_t length) override { system_rng().add_entropy(in, length); }
- void clear() override { m_rng.clear(); }
+ bool is_seeded() const override { return true; }
- std::string name() const override { return m_rng.name(); }
-
- size_t reseed_with_sources(Entropy_Sources& srcs,
- size_t poll_bits,
- std::chrono::milliseconds poll_timeout) override
- {
- return m_rng.reseed_with_sources(srcs, poll_bits, poll_timeout);
- }
-
- void add_entropy(const byte in[], size_t len) override { m_rng.add_entropy(in, len); }
- private:
- Botan::RandomNumberGenerator& m_rng;
+ void clear() override {}
};
}
diff --git a/src/lib/utils/zero_mem.cpp b/src/lib/utils/zero_mem.cpp
index 371c434ca..df195048a 100644
--- a/src/lib/utils/zero_mem.cpp
+++ b/src/lib/utils/zero_mem.cpp
@@ -18,6 +18,13 @@ void zero_mem(void* ptr, size_t n)
#if defined(BOTAN_TARGET_OS_HAS_RTLSECUREZEROMEMORY)
::RtlSecureZeroMemory(ptr, n);
#elif defined(BOTAN_USE_VOLATILE_MEMSET_FOR_ZERO) && (BOTAN_USE_VOLATILE_MEMSET_FOR_ZERO == 1)
+ /*
+ Call memset through a static volatile pointer, which the compiler
+ should not elide. This construct should be safe in conforming
+ compilers, but who knows. I did confirm that on x86-64 GCC 6.1 and
+ Clang 3.8 both create code that saves the memset address in the
+ data segment and uncondtionally loads and jumps to that address.
+ */
static void* (*const volatile memset_ptr)(void*, int, size_t) = std::memset;
(memset_ptr)(ptr, 0, n);
#else