aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/os.rst1
-rw-r--r--src/build-data/buildh.in37
-rw-r--r--src/build-data/os/aix.txt1
-rw-r--r--src/build-data/os/cygwin.txt1
-rw-r--r--src/build-data/os/darwin.txt1
-rw-r--r--src/build-data/os/freebsd.txt1
-rw-r--r--src/build-data/os/haiku.txt1
-rw-r--r--src/build-data/os/hpux.txt1
-rw-r--r--src/build-data/os/irix.txt1
-rw-r--r--src/build-data/os/linux.txt1
-rw-r--r--src/build-data/os/netbsd.txt1
-rw-r--r--src/build-data/os/qnx.txt1
-rw-r--r--src/build-data/os/solaris.txt1
-rw-r--r--src/cmd/rng.cpp2
-rw-r--r--src/lib/entropy/beos_stats/es_beos.h4
-rw-r--r--src/lib/entropy/cryptoapi_rng/es_capi.cpp8
-rw-r--r--src/lib/entropy/cryptoapi_rng/es_capi.h5
-rw-r--r--src/lib/entropy/darwin_secrandom/darwin_secrandom.cpp8
-rw-r--r--src/lib/entropy/darwin_secrandom/darwin_secrandom.h7
-rw-r--r--src/lib/entropy/dev_random/dev_random.cpp15
-rw-r--r--src/lib/entropy/dev_random/dev_random.h6
-rw-r--r--src/lib/entropy/egd/es_egd.cpp8
-rw-r--r--src/lib/entropy/egd/es_egd.h5
-rw-r--r--src/lib/entropy/entropy_src.h35
-rw-r--r--src/lib/entropy/entropy_srcs.cpp144
-rw-r--r--src/lib/entropy/hres_timer/hres_timer.h4
-rw-r--r--src/lib/entropy/info.txt2
-rw-r--r--src/lib/entropy/proc_walk/proc_walk.cpp2
-rw-r--r--src/lib/entropy/proc_walk/proc_walk.h4
-rw-r--r--src/lib/entropy/rdrand/rdrand.h4
-rw-r--r--src/lib/entropy/unix_procs/unix_procs.cpp7
-rw-r--r--src/lib/entropy/unix_procs/unix_procs.h8
-rw-r--r--src/lib/entropy/win32_stats/es_win32.h4
-rw-r--r--src/lib/rng/auto_rng/auto_rng.h7
-rw-r--r--src/lib/rng/hmac_drbg/hmac_drbg.cpp10
-rw-r--r--src/lib/rng/hmac_drbg/hmac_drbg.h4
-rw-r--r--src/lib/rng/hmac_rng/hmac_rng.cpp40
-rw-r--r--src/lib/rng/hmac_rng/hmac_rng.h6
-rw-r--r--src/lib/rng/rng.cpp15
-rw-r--r--src/lib/rng/rng.h40
-rw-r--r--src/lib/rng/system_rng/system_rng.cpp24
-rw-r--r--src/lib/rng/system_rng/system_rng.h7
-rw-r--r--src/lib/rng/x931_rng/x931_rng.cpp7
-rw-r--r--src/lib/rng/x931_rng/x931_rng.h5
-rw-r--r--src/tests/test_entropy.cpp107
-rw-r--r--src/tests/test_rng.h4
-rw-r--r--src/tests/tests.h9
47 files changed, 459 insertions, 157 deletions
diff --git a/doc/os.rst b/doc/os.rst
index 9e1ee641e..83fee9351 100644
--- a/doc/os.rst
+++ b/doc/os.rst
@@ -33,7 +33,6 @@ A summary of OS features as defined in ``src/build-data/os``.
"clock_gettime", " ", "X", " ", " ", "X", "X", " ", " ", " ", " ", "X", " ", " ", "X", "X", "X", " ", " "
"cryptgenrandom", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X", " ", " ", " ", " ", " ", "X"
"dlopen", " ", "X", " ", "X", " ", "X", " ", " ", " ", " ", "X", " ", " ", "X", "X", "X", " ", " "
- "getsid", "X", " ", "X", "X", " ", "X", "X", "X", " ", "X", "X", " ", " ", "X", " ", "X", "X", " "
"gettimeofday", "X", "X", "X", "X", "X", "X", "X", "X", " ", "X", "X", " ", "X", "X", "X", "X", "X", " "
"gmtime_r", " ", "X", " ", "X", " ", "X", "X", " ", " ", " ", "X", " ", " ", "X", "X", "X", " ", " "
"gmtime_s", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X"
diff --git a/src/build-data/buildh.in b/src/build-data/buildh.in
index 31277ff0c..a289fbcd8 100644
--- a/src/build-data/buildh.in
+++ b/src/build-data/buildh.in
@@ -101,10 +101,43 @@
* RNGs will automatically poll the system for additional seed material
* after producing this many bytes of output.
*/
-#define BOTAN_RNG_MAX_OUTPUT_BEFORE_RESEED 512
+#define BOTAN_RNG_MAX_OUTPUT_BEFORE_RESEED 4096
#define BOTAN_RNG_RESEED_POLL_BITS 128
#define BOTAN_RNG_AUTO_RESEED_TIMEOUT std::chrono::milliseconds(10)
-#define BOTAN_RNG_RESEED_DEFAULT_TIMEOUT std::chrono::milliseconds(100)
+#define BOTAN_RNG_RESEED_DEFAULT_TIMEOUT std::chrono::milliseconds(50)
+
+/*
+* Specifies (in order) the list of entropy sources that will be used
+* to seed an in-memory RNG. The first few in the default list
+* ("timer", "proc_info", etc) do not count as contributing any entropy
+* but are included as they are fast and help protect against a
+* seriously broken system RNG.
+*/
+#define BOTAN_ENTROPY_DEFAULT_SOURCES \
+ { "timestamp", "rdrand", "proc_info", \
+ "darwin_secrandom", "dev_random", "win32_cryptoapi", "egd", \
+ "proc_walk", "system_stats", "unix_procs" }
+
+/*
+* These control the RNG used by the system RNG interface
+*/
+#define BOTAN_SYSTEM_RNG_DEVICE "/dev/urandom"
+#define BOTAN_SYSTEM_RNG_CRYPTOAPI_PROV_TYPE PROV_RSA_FULL
+
+/*
+* These paramaters control how many bytes to read from the system
+* PRNG, and how long to block if applicable.
+*
+* Timeout is ignored on Windows as CryptGenRandom doesn't block
+*/
+#define BOTAN_SYSTEM_RNG_POLL_DEVICES { "/dev/urandom", "/dev/random", "/dev/srandom" }
+
+#define BOTAN_SYSTEM_RNG_POLL_REQUEST 64
+#define BOTAN_SYSTEM_RNG_POLL_TIMEOUT_MS 20
+
+#define BOTAN_ENTROPY_EGD_PATHS { "/var/run/egd-pool", "/dev/egd-pool" }
+#define BOTAN_ENTROPY_PROC_FS_PATH "/proc"
+#define BOTAN_ENTROPY_SAFE_PATHS { "/bin", "/sbin", "/usr/bin", "/usr/sbin" }
/* Should we use GCC-style inline assembler? */
#if !defined(BOTAN_USE_GCC_INLINE_ASM) && defined(__GNUG__)
diff --git a/src/build-data/os/aix.txt b/src/build-data/os/aix.txt
index 546fbf9ad..369b720c4 100644
--- a/src/build-data/os/aix.txt
+++ b/src/build-data/os/aix.txt
@@ -2,5 +2,4 @@ os_type unix
<target_features>
gettimeofday
-getsid
</target_features>
diff --git a/src/build-data/os/cygwin.txt b/src/build-data/os/cygwin.txt
index 7788cd3ca..ee934f787 100644
--- a/src/build-data/os/cygwin.txt
+++ b/src/build-data/os/cygwin.txt
@@ -12,6 +12,5 @@ doc_dir docs
<target_features>
gettimeofday
-getsid
timegm
</target_features>
diff --git a/src/build-data/os/darwin.txt b/src/build-data/os/darwin.txt
index 56285ccf7..b1f2363dc 100644
--- a/src/build-data/os/darwin.txt
+++ b/src/build-data/os/darwin.txt
@@ -16,7 +16,6 @@ gettimeofday
gmtime_r
memset_s
readdir
-getsid
timegm
</target_features>
diff --git a/src/build-data/os/freebsd.txt b/src/build-data/os/freebsd.txt
index 32767cb1f..510a7accd 100644
--- a/src/build-data/os/freebsd.txt
+++ b/src/build-data/os/freebsd.txt
@@ -7,6 +7,5 @@ posix_mlock
gmtime_r
dlopen
readdir
-getsid
timegm
</target_features>
diff --git a/src/build-data/os/haiku.txt b/src/build-data/os/haiku.txt
index 981ce6795..8e35e76eb 100644
--- a/src/build-data/os/haiku.txt
+++ b/src/build-data/os/haiku.txt
@@ -8,7 +8,6 @@ doc_dir system/documentation
<target_features>
gettimeofday
gmtime_r
-getsid
</target_features>
<aliases>
diff --git a/src/build-data/os/hpux.txt b/src/build-data/os/hpux.txt
index 726b0b960..22d51ef0a 100644
--- a/src/build-data/os/hpux.txt
+++ b/src/build-data/os/hpux.txt
@@ -2,7 +2,6 @@ os_type unix
<target_features>
gettimeofday
-getsid
</target_features>
<aliases>
diff --git a/src/build-data/os/irix.txt b/src/build-data/os/irix.txt
index 546fbf9ad..369b720c4 100644
--- a/src/build-data/os/irix.txt
+++ b/src/build-data/os/irix.txt
@@ -2,5 +2,4 @@ os_type unix
<target_features>
gettimeofday
-getsid
</target_features>
diff --git a/src/build-data/os/linux.txt b/src/build-data/os/linux.txt
index c83e57afa..bb65055e4 100644
--- a/src/build-data/os/linux.txt
+++ b/src/build-data/os/linux.txt
@@ -11,7 +11,6 @@ posix_mlock
gmtime_r
dlopen
readdir
-getsid
timegm
</target_features>
diff --git a/src/build-data/os/netbsd.txt b/src/build-data/os/netbsd.txt
index 32767cb1f..510a7accd 100644
--- a/src/build-data/os/netbsd.txt
+++ b/src/build-data/os/netbsd.txt
@@ -7,6 +7,5 @@ posix_mlock
gmtime_r
dlopen
readdir
-getsid
timegm
</target_features>
diff --git a/src/build-data/os/qnx.txt b/src/build-data/os/qnx.txt
index 71c85eb3c..4c0965764 100644
--- a/src/build-data/os/qnx.txt
+++ b/src/build-data/os/qnx.txt
@@ -6,5 +6,4 @@ gettimeofday
posix_mlock
gmtime_r
dlopen
-getsid
</target_features>
diff --git a/src/build-data/os/solaris.txt b/src/build-data/os/solaris.txt
index 52749e397..0ed785036 100644
--- a/src/build-data/os/solaris.txt
+++ b/src/build-data/os/solaris.txt
@@ -6,7 +6,6 @@ install_cmd_exec '/usr/ucb/install -m 755'
<target_features>
posix_mlock
gettimeofday
-getsid
</target_features>
<aliases>
diff --git a/src/cmd/rng.cpp b/src/cmd/rng.cpp
index 901607bea..b89376b4c 100644
--- a/src/cmd/rng.cpp
+++ b/src/cmd/rng.cpp
@@ -49,7 +49,7 @@ int rng(int argc, char* argv[])
return total_collected >= amt;
});
- EntropySource::poll_available_sources(accum);
+ Entropy_Sources::global_sources().poll(accum);
}
}
catch(std::exception& e)
diff --git a/src/lib/entropy/beos_stats/es_beos.h b/src/lib/entropy/beos_stats/es_beos.h
index 2565b9180..db5824f6f 100644
--- a/src/lib/entropy/beos_stats/es_beos.h
+++ b/src/lib/entropy/beos_stats/es_beos.h
@@ -15,10 +15,10 @@ namespace Botan {
/**
* BeOS Entropy Source
*/
-class BeOS_EntropySource : public EntropySource
+class BeOS_EntropySource : public Entropy_Source
{
private:
- std::string name() const override { return "BeOS Statistics"; }
+ std::string name() const override { return "system_stats"; }
void poll(Entropy_Accumulator& accum) override;
};
diff --git a/src/lib/entropy/cryptoapi_rng/es_capi.cpp b/src/lib/entropy/cryptoapi_rng/es_capi.cpp
index 019b55a10..6ffc03c12 100644
--- a/src/lib/entropy/cryptoapi_rng/es_capi.cpp
+++ b/src/lib/entropy/cryptoapi_rng/es_capi.cpp
@@ -57,15 +57,17 @@ class CSP_Handle
*/
void Win32_CAPI_EntropySource::poll(Entropy_Accumulator& accum)
{
- m_buf.resize(32);
+ const size_t ENTROPY_BITS_PER_BYTE = 8;
+
+ secure_vector<byte>& buf = accum.get_io_buf(BOTAN_SYSTEM_RNG_POLL_REQUEST);
for(size_t i = 0; i != prov_types.size(); ++i)
{
CSP_Handle csp(prov_types[i]);
- if(size_t got = csp.gen_random(m_buf.data(), m_buf.size()))
+ if(size_t got = csp.gen_random(buf.data(), buf.size()))
{
- accum.add(m_buf.data(), got, 6);
+ accum.add(buf.data(), got, ENTROPY_BITS_PER_BYTE);
break;
}
}
diff --git a/src/lib/entropy/cryptoapi_rng/es_capi.h b/src/lib/entropy/cryptoapi_rng/es_capi.h
index 81a5003b2..eb63183e9 100644
--- a/src/lib/entropy/cryptoapi_rng/es_capi.h
+++ b/src/lib/entropy/cryptoapi_rng/es_capi.h
@@ -16,10 +16,10 @@ namespace Botan {
/**
* Win32 CAPI Entropy Source
*/
-class Win32_CAPI_EntropySource : public EntropySource
+class Win32_CAPI_EntropySource : public Entropy_Source
{
public:
- std::string name() const override { return "Win32 CryptoGenRandom"; }
+ std::string name() const override { return "win32_cryptoapi"; }
void poll(Entropy_Accumulator& accum) override;
@@ -30,7 +30,6 @@ class Win32_CAPI_EntropySource : public EntropySource
Win32_CAPI_EntropySource(const std::string& provs = "");
private:
std::vector<u64bit> prov_types;
- secure_vector<byte> m_buf;
};
}
diff --git a/src/lib/entropy/darwin_secrandom/darwin_secrandom.cpp b/src/lib/entropy/darwin_secrandom/darwin_secrandom.cpp
index f04b75a12..08b464ff0 100644
--- a/src/lib/entropy/darwin_secrandom/darwin_secrandom.cpp
+++ b/src/lib/entropy/darwin_secrandom/darwin_secrandom.cpp
@@ -16,12 +16,12 @@ namespace Botan {
void Darwin_SecRandom::poll(Entropy_Accumulator& accum)
{
const size_t ENTROPY_BITS_PER_BYTE = 8;
- const size_t BUF_SIZE = 256;
- m_buf.resize(BUF_SIZE);
- if (0 == SecRandomCopyBytes(kSecRandomDefault, m_buf.size(), m_buf.data()))
+ secure_vector<byte>& buf = accum.get_io_buf(BOTAN_SYSTEM_RNG_POLL_REQUEST);
+
+ if(0 == SecRandomCopyBytes(kSecRandomDefault, buf.size(), buf.data()))
{
- accum.add(m_buf.data(), m_buf.size(), ENTROPY_BITS_PER_BYTE);
+ accum.add(buf.data(), buf.size(), ENTROPY_BITS_PER_BYTE);
}
}
diff --git a/src/lib/entropy/darwin_secrandom/darwin_secrandom.h b/src/lib/entropy/darwin_secrandom/darwin_secrandom.h
index 504d5cc64..970cd7941 100644
--- a/src/lib/entropy/darwin_secrandom/darwin_secrandom.h
+++ b/src/lib/entropy/darwin_secrandom/darwin_secrandom.h
@@ -15,15 +15,12 @@ namespace Botan {
/**
* Entropy source using SecRandomCopyBytes from Darwin's Security.framework
*/
-class Darwin_SecRandom : public EntropySource
+class Darwin_SecRandom : public Entropy_Source
{
public:
- std::string name() const override { return "Darwin SecRandomCopyBytes"; }
+ std::string name() const override { return "darwin_secrandom"; }
void poll(Entropy_Accumulator& accum) override;
-
- private:
- secure_vector<byte> m_buf;
};
}
diff --git a/src/lib/entropy/dev_random/dev_random.cpp b/src/lib/entropy/dev_random/dev_random.cpp
index 526835fea..0115368da 100644
--- a/src/lib/entropy/dev_random/dev_random.cpp
+++ b/src/lib/entropy/dev_random/dev_random.cpp
@@ -6,7 +6,6 @@
*/
#include <botan/internal/dev_random.h>
-#include <botan/internal/rounding.h>
#include <sys/types.h>
#include <sys/select.h>
@@ -61,10 +60,8 @@ void Device_EntropySource::poll(Entropy_Accumulator& accum)
return;
const size_t ENTROPY_BITS_PER_BYTE = 8;
- const size_t MS_WAIT_TIME = 32;
- const size_t READ_ATTEMPT = 32;
- int max_fd = m_devices[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)
@@ -75,21 +72,21 @@ void Device_EntropySource::poll(Entropy_Accumulator& accum)
struct ::timeval timeout;
- timeout.tv_sec = (MS_WAIT_TIME / 1000);
- timeout.tv_usec = (MS_WAIT_TIME % 1000) * 1000;
+ 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;
- m_buf.resize(READ_ATTEMPT);
+ secure_vector<byte>& buf = accum.get_io_buf(BOTAN_SYSTEM_RNG_POLL_REQUEST);
for(size_t i = 0; i != m_devices.size(); ++i)
{
if(FD_ISSET(m_devices[i], &read_set))
{
- const ssize_t got = ::read(m_devices[i], m_buf.data(), m_buf.size());
+ const ssize_t got = ::read(m_devices[i], buf.data(), buf.size());
if(got > 0)
- accum.add(m_buf.data(), got, ENTROPY_BITS_PER_BYTE);
+ accum.add(buf.data(), got, ENTROPY_BITS_PER_BYTE);
}
}
}
diff --git a/src/lib/entropy/dev_random/dev_random.h b/src/lib/entropy/dev_random/dev_random.h
index 0d0c2df60..f634cf16c 100644
--- a/src/lib/entropy/dev_random/dev_random.h
+++ b/src/lib/entropy/dev_random/dev_random.h
@@ -17,10 +17,10 @@ namespace Botan {
/**
* Entropy source reading from kernel devices like /dev/random
*/
-class Device_EntropySource : public EntropySource
+class Device_EntropySource : public Entropy_Source
{
public:
- std::string name() const override { return "RNG Device Reader"; }
+ std::string name() const override { return "dev_random"; }
void poll(Entropy_Accumulator& accum) override;
@@ -28,8 +28,6 @@ class Device_EntropySource : public EntropySource
~Device_EntropySource();
private:
typedef int fd_type;
-
- secure_vector<byte> m_buf;
std::vector<fd_type> m_devices;
};
diff --git a/src/lib/entropy/egd/es_egd.cpp b/src/lib/entropy/egd/es_egd.cpp
index d64b87ba1..9b625d051 100644
--- a/src/lib/entropy/egd/es_egd.cpp
+++ b/src/lib/entropy/egd/es_egd.cpp
@@ -137,19 +137,19 @@ EGD_EntropySource::~EGD_EntropySource()
*/
void EGD_EntropySource::poll(Entropy_Accumulator& accum)
{
- const size_t READ_ATTEMPT = 32;
+ const size_t ENTROPY_BITS_PER_BYTE = 8;
std::lock_guard<std::mutex> lock(m_mutex);
- m_buf.resize(READ_ATTEMPT);
+ secure_vector<byte>& buf = accum.get_io_buf(BOTAN_SYSTEM_RNG_POLL_REQUEST);
for(size_t i = 0; i != sockets.size(); ++i)
{
- size_t got = sockets[i].read(m_buf.data(), m_buf.size());
+ size_t got = sockets[i].read(buf.data(), buf.size());
if(got)
{
- accum.add(m_buf.data(), got, 6);
+ accum.add(buf.data(), got, ENTROPY_BITS_PER_BYTE);
break;
}
}
diff --git a/src/lib/entropy/egd/es_egd.h b/src/lib/entropy/egd/es_egd.h
index 7f7df1133..0b497a8bd 100644
--- a/src/lib/entropy/egd/es_egd.h
+++ b/src/lib/entropy/egd/es_egd.h
@@ -18,10 +18,10 @@ namespace Botan {
/**
* EGD Entropy Source
*/
-class EGD_EntropySource : public EntropySource
+class EGD_EntropySource : public Entropy_Source
{
public:
- std::string name() const override { return "EGD/PRNGD"; }
+ std::string name() const override { return "egd"; }
void poll(Entropy_Accumulator& accum) override;
@@ -44,7 +44,6 @@ class EGD_EntropySource : public EntropySource
std::mutex m_mutex;
std::vector<EGD_Socket> sockets;
- secure_vector<byte> m_buf;
};
}
diff --git a/src/lib/entropy/entropy_src.h b/src/lib/entropy/entropy_src.h
index c635b8756..0f4c38358 100644
--- a/src/lib/entropy/entropy_src.h
+++ b/src/lib/entropy/entropy_src.h
@@ -66,18 +66,27 @@ class BOTAN_DLL Entropy_Accumulator
{
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 EntropySource
+class BOTAN_DLL Entropy_Source
{
public:
- static void poll_available_sources(class Entropy_Accumulator& accum);
+ /*
+ * Return a new entropy source of a particular type, or null
+ * Each entropy source may require substantial resources (eg, a file handle
+ * or socket instance), so try to share them among multiple RNGs, or just
+ * use the preconfigured global list accessed by global_entropy_sources()
+ */
+ static std::unique_ptr<Entropy_Source> create(const std::string& type);
/**
* @return name identifying this entropy source
@@ -90,7 +99,27 @@ class BOTAN_DLL EntropySource
*/
virtual void poll(Entropy_Accumulator& accum) = 0;
- virtual ~EntropySource() {}
+ virtual ~Entropy_Source() {}
+ };
+
+class BOTAN_DLL Entropy_Sources
+ {
+ public:
+ static Entropy_Sources& global_sources();
+
+ void add_source(std::unique_ptr<Entropy_Source> src);
+
+ std::vector<std::string> enabled_sources() const;
+
+ void poll(Entropy_Accumulator& accum);
+ bool poll_just(Entropy_Accumulator& accum, const std::string& src);
+
+ Entropy_Sources() {}
+ Entropy_Sources(const std::vector<std::string>& sources);
+
+ ~Entropy_Sources();
+ private:
+ std::vector<Entropy_Source*> m_srcs;
};
}
diff --git a/src/lib/entropy/entropy_srcs.cpp b/src/lib/entropy/entropy_srcs.cpp
index d57160c88..cbf13d488 100644
--- a/src/lib/entropy/entropy_srcs.cpp
+++ b/src/lib/entropy/entropy_srcs.cpp
@@ -49,83 +49,147 @@
namespace Botan {
-namespace {
-
-std::vector<std::unique_ptr<EntropySource>> get_default_entropy_sources()
+std::unique_ptr<Entropy_Source> Entropy_Source::create(const std::string& name)
{
- std::vector<std::unique_ptr<EntropySource>> sources;
-
+ if(name == "timestamp")
+ {
#if defined(BOTAN_HAS_ENTROPY_SRC_HIGH_RESOLUTION_TIMER)
- sources.push_back(std::unique_ptr<EntropySource>(new High_Resolution_Timestamp));
+ return std::unique_ptr<Entropy_Source>(new High_Resolution_Timestamp);
#endif
+ }
+ if(name == "rdrand")
+ {
#if defined(BOTAN_HAS_ENTROPY_SRC_RDRAND)
- sources.push_back(std::unique_ptr<EntropySource>(new Intel_Rdrand));
+ return std::unique_ptr<Entropy_Source>(new Intel_Rdrand);
#endif
+ }
+ if(name == "proc_info")
+ {
#if defined(BOTAN_HAS_ENTROPY_SRC_UNIX_PROCESS_RUNNER)
- sources.push_back(std::unique_ptr<EntropySource>(new UnixProcessInfo_EntropySource));
+ return std::unique_ptr<Entropy_Source>(new UnixProcessInfo_EntropySource);
#endif
+ }
-#if defined(BOTAN_HAS_ENTROPY_SRC_DEV_RANDOM)
- sources.push_back(std::unique_ptr<EntropySource>(new Device_EntropySource(
- { "/dev/random", "/dev/srandom", "/dev/urandom" }
- )));
+ if(name == "darwin_secrandom")
+ {
+#if defined(BOTAN_HAS_ENTROPY_SRC_DARWIN_SECRANDOM)
+ return std::unique_ptr<Entropy_Source>(new Darwin_SecRandom);
#endif
+ }
-#if defined(BOTAN_HAS_ENTROPY_SRC_CAPI)
- sources.push_back(std::unique_ptr<EntropySource>(new Win32_CAPI_EntropySource));
+ if(name == "dev_random")
+ {
+#if defined(BOTAN_HAS_ENTROPY_SRC_DEV_RANDOM)
+ return std::unique_ptr<Entropy_Source>(new Device_EntropySource(BOTAN_SYSTEM_RNG_POLL_DEVICES));
+ }
+
+ if(name == "win32_cryptoapi")
+ {
+#elif defined(BOTAN_HAS_ENTROPY_SRC_CAPI)
+ return std::unique_ptr<Entropy_Source>(new Win32_CAPI_EntropySource);
#endif
+ }
+ if(name == "proc_walk")
+ {
#if defined(BOTAN_HAS_ENTROPY_SRC_PROC_WALKER)
- sources.push_back(std::unique_ptr<EntropySource>(new ProcWalking_EntropySource("/proc")));
+ return std::unique_ptr<Entropy_Source>(new ProcWalking_EntropySource("/proc"));
#endif
+ }
+ if(name == "system_stats")
+ {
#if defined(BOTAN_HAS_ENTROPY_SRC_WIN32)
- sources.push_back(std::unique_ptr<EntropySource>(new Win32_EntropySource));
-#endif
-
-#if defined(BOTAN_HAS_ENTROPY_SRC_BEOS)
- sources.push_back(std::unique_ptr<EntropySource>(new BeOS_EntropySource));
+ return std::unique_ptr<Entropy_Source>(new Win32_EntropySource);
+#elif defined(BOTAN_HAS_ENTROPY_SRC_BEOS)
+ return std::unique_ptr<Entropy_Source>(new BeOS_EntropySource);
#endif
+ }
+ if(name == "unix_procs")
+ {
#if defined(BOTAN_HAS_ENTROPY_SRC_UNIX_PROCESS_RUNNER)
- sources.push_back(std::unique_ptr<EntropySource>(new Unix_EntropySource(
- { "/bin", "/sbin", "/usr/bin", "/usr/sbin" }
- )));
+ return std::unique_ptr<Entropy_Source>(new Unix_EntropySource(BOTAN_ENTROPY_SAFE_PATHS));
#endif
+ }
+ if(name == "egd")
+ {
#if defined(BOTAN_HAS_ENTROPY_SRC_EGD)
- sources.push_back(std::unique_ptr<EntropySource>(
- new EGD_EntropySource({ "/var/run/egd-pool", "/dev/egd-pool" })
- ));
+ return std::unique_ptr<Entropy_Source>(new EGD_EntropySource(BOTAN_ENTROPY_EGD_PATHS));
#endif
+ }
-#if defined(BOTAN_HAS_ENTROPY_SRC_DARWIN_SECRANDOM)
- sources.push_back(std::unique_ptr<EntropySource>(new Darwin_SecRandom));
-#endif
+ return std::unique_ptr<Entropy_Source>();
+ }
+void Entropy_Sources::add_source(std::unique_ptr<Entropy_Source> src)
+ {
+ if(src.get())
+ {
+ m_srcs.push_back(src.release());
+ }
+ }
+
+std::vector<std::string> Entropy_Sources::enabled_sources() const
+ {
+ std::vector<std::string> sources;
+ for(size_t i = 0; i != m_srcs.size(); ++i)
+ {
+ sources.push_back(m_srcs[i]->name());
+ }
return sources;
}
-}
+void Entropy_Sources::poll(Entropy_Accumulator& accum)
+ {
+ for(size_t i = 0; i != m_srcs.size(); ++i)
+ {
+ m_srcs[i]->poll(accum);
+ if(accum.polling_goal_achieved())
+ break;
+ }
+ }
-//static
-void EntropySource::poll_available_sources(class Entropy_Accumulator& accum)
+bool Entropy_Sources::poll_just(Entropy_Accumulator& accum, const std::string& the_src)
{
- static std::vector<std::unique_ptr<EntropySource>> g_sources(get_default_entropy_sources());
+ for(size_t i = 0; i != m_srcs.size(); ++i)
+ {
+ if(m_srcs[i]->name() == the_src)
+ {
+ m_srcs[i]->poll(accum);
+ return true;
+ }
+ }
- if(g_sources.empty())
- throw std::runtime_error("No entropy sources enabled at build time, RNG poll failed");
+ return false;
+ }
- size_t poll_attempt = 0;
+Entropy_Sources::Entropy_Sources(const std::vector<std::string>& sources)
+ {
+ for(auto&& src_name : sources)
+ {
+ add_source(Entropy_Source::create(src_name));
+ }
+ }
- while(!accum.polling_finished() && poll_attempt < 16)
+Entropy_Sources::~Entropy_Sources()
+ {
+ for(size_t i = 0; i != m_srcs.size(); ++i)
{
- const size_t src_idx = poll_attempt % g_sources.size();
- g_sources[src_idx]->poll(accum);
- ++poll_attempt;
+ delete m_srcs[i];
+ m_srcs[i] = nullptr;
}
+ m_srcs.clear();
+ }
+
+Entropy_Sources& Entropy_Sources::global_sources()
+ {
+ static Entropy_Sources global_entropy_sources(BOTAN_ENTROPY_DEFAULT_SOURCES);
+
+ return global_entropy_sources;
}
}
diff --git a/src/lib/entropy/hres_timer/hres_timer.h b/src/lib/entropy/hres_timer/hres_timer.h
index b5b92fd97..93ced283a 100644
--- a/src/lib/entropy/hres_timer/hres_timer.h
+++ b/src/lib/entropy/hres_timer/hres_timer.h
@@ -18,10 +18,10 @@ namespace Botan {
* @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 : public EntropySource
+class High_Resolution_Timestamp : public Entropy_Source
{
public:
- std::string name() const override { return "High Resolution Timestamp"; }
+ std::string name() const override { return "timestamp"; }
void poll(Entropy_Accumulator& accum) override;
};
diff --git a/src/lib/entropy/info.txt b/src/lib/entropy/info.txt
index 77c2669e9..ba5a4044d 100644
--- a/src/lib/entropy/info.txt
+++ b/src/lib/entropy/info.txt
@@ -1 +1 @@
-define ENTROPY_SOURCE 20150201
+define ENTROPY_SOURCE 20151120
diff --git a/src/lib/entropy/proc_walk/proc_walk.cpp b/src/lib/entropy/proc_walk/proc_walk.cpp
index 3d63e5d5a..817aa80a5 100644
--- a/src/lib/entropy/proc_walk/proc_walk.cpp
+++ b/src/lib/entropy/proc_walk/proc_walk.cpp
@@ -113,7 +113,7 @@ int Directory_Walker::next_fd()
void ProcWalking_EntropySource::poll(Entropy_Accumulator& accum)
{
const size_t MAX_FILES_READ_PER_POLL = 2048;
- const double ENTROPY_ESTIMATE = 1.0 / (8*1024);
+ const double ENTROPY_ESTIMATE = 1.0 / 128;
std::lock_guard<std::mutex> lock(m_mutex);
diff --git a/src/lib/entropy/proc_walk/proc_walk.h b/src/lib/entropy/proc_walk/proc_walk.h
index ec56f9e2d..b67f71111 100644
--- a/src/lib/entropy/proc_walk/proc_walk.h
+++ b/src/lib/entropy/proc_walk/proc_walk.h
@@ -23,10 +23,10 @@ class File_Descriptor_Source
/**
* File Tree Walking Entropy Source
*/
-class ProcWalking_EntropySource : public EntropySource
+class ProcWalking_EntropySource : public Entropy_Source
{
public:
- std::string name() const override { return "Proc Walker"; }
+ std::string name() const override { return "proc_walk"; }
void poll(Entropy_Accumulator& accum) override;
diff --git a/src/lib/entropy/rdrand/rdrand.h b/src/lib/entropy/rdrand/rdrand.h
index 9ff6e557f..1fa928641 100644
--- a/src/lib/entropy/rdrand/rdrand.h
+++ b/src/lib/entropy/rdrand/rdrand.h
@@ -16,10 +16,10 @@ namespace Botan {
* Entropy source using the rdrand instruction first introduced on
* Intel's Ivy Bridge architecture.
*/
-class Intel_Rdrand : public EntropySource
+class Intel_Rdrand : public Entropy_Source
{
public:
- std::string name() const override { return "Intel Rdrand"; }
+ std::string name() const override { return "rdrand"; }
void poll(Entropy_Accumulator& accum) override;
};
diff --git a/src/lib/entropy/unix_procs/unix_procs.cpp b/src/lib/entropy/unix_procs/unix_procs.cpp
index c6ad6a700..abfe341e0 100644
--- a/src/lib/entropy/unix_procs/unix_procs.cpp
+++ b/src/lib/entropy/unix_procs/unix_procs.cpp
@@ -43,8 +43,8 @@ size_t concurrent_processes(size_t user_request)
const size_t DEFAULT_CONCURRENT = 2;
const size_t MAX_CONCURRENT = 8;
- if(user_request > 0 && user_request < MAX_CONCURRENT)
- return user_request;
+ if(user_request > 0)
+ return std::min(user_request, MAX_CONCURRENT);
const long online_cpus = ::sysconf(_SC_NPROCESSORS_ONLN);
@@ -72,9 +72,6 @@ void UnixProcessInfo_EntropySource::poll(Entropy_Accumulator& accum)
accum.add(::getppid(), 0.0);
accum.add(::getuid(), 0.0);
accum.add(::getgid(), 0.0);
-#if defined(BOTAN_TARGET_OS_HAS_GETSID)
- accum.add(::getsid(0), 0.0);
-#endif
accum.add(::getpgrp(), 0.0);
struct ::rusage usage;
diff --git a/src/lib/entropy/unix_procs/unix_procs.h b/src/lib/entropy/unix_procs/unix_procs.h
index 808d34221..bc2fd87d1 100644
--- a/src/lib/entropy/unix_procs/unix_procs.h
+++ b/src/lib/entropy/unix_procs/unix_procs.h
@@ -20,10 +20,10 @@ namespace Botan {
* effective against local attackers as they can sample from the same
* distribution.
*/
-class Unix_EntropySource : public EntropySource
+class Unix_EntropySource : public Entropy_Source
{
public:
- std::string name() const override { return "Unix Process Runner"; }
+ std::string name() const override { return "unix_procs"; }
void poll(Entropy_Accumulator& accum) override;
@@ -78,10 +78,10 @@ class Unix_EntropySource : public EntropySource
secure_vector<byte> m_buf;
};
-class UnixProcessInfo_EntropySource : public EntropySource
+class UnixProcessInfo_EntropySource : public Entropy_Source
{
public:
- std::string name() const override { return "Unix Process Info"; }
+ std::string name() const override { return "proc_info"; }
void poll(Entropy_Accumulator& accum) override;
};
diff --git a/src/lib/entropy/win32_stats/es_win32.h b/src/lib/entropy/win32_stats/es_win32.h
index 98bfb0e36..958a79e19 100644
--- a/src/lib/entropy/win32_stats/es_win32.h
+++ b/src/lib/entropy/win32_stats/es_win32.h
@@ -15,10 +15,10 @@ namespace Botan {
/**
* Win32 Entropy Source
*/
-class Win32_EntropySource : public EntropySource
+class Win32_EntropySource : public Entropy_Source
{
public:
- std::string name() const override { return "Win32 Statistics"; }
+ std::string name() const override { return "system_stats"; }
void poll(Entropy_Accumulator& accum) override;
};
diff --git a/src/lib/rng/auto_rng/auto_rng.h b/src/lib/rng/auto_rng/auto_rng.h
index a7b28af92..ce0c5a7d2 100644
--- a/src/lib/rng/auto_rng/auto_rng.h
+++ b/src/lib/rng/auto_rng/auto_rng.h
@@ -25,7 +25,12 @@ class BOTAN_DLL AutoSeeded_RNG : public RandomNumberGenerator
std::string name() const override { return m_rng->name(); }
- void reseed(size_t poll_bits = 256) override { m_rng->reseed(poll_bits); }
+ 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); }
diff --git a/src/lib/rng/hmac_drbg/hmac_drbg.cpp b/src/lib/rng/hmac_drbg/hmac_drbg.cpp
index ad731b6b3..67325ee1b 100644
--- a/src/lib/rng/hmac_drbg/hmac_drbg.cpp
+++ b/src/lib/rng/hmac_drbg/hmac_drbg.cpp
@@ -78,11 +78,13 @@ void HMAC_DRBG::update(const byte input[], size_t input_len)
}
}
-void HMAC_DRBG::reseed(size_t poll_bits)
+size_t HMAC_DRBG::reseed_with_sources(Entropy_Sources& srcs,
+ size_t poll_bits,
+ std::chrono::milliseconds poll_timeout)
{
if(m_prng)
{
- m_prng->reseed(poll_bits);
+ size_t bits = m_prng->reseed_with_sources(srcs, poll_bits, poll_timeout);
if(m_prng->is_seeded())
{
@@ -90,7 +92,11 @@ void HMAC_DRBG::reseed(size_t poll_bits)
update(input.data(), input.size());
m_reseed_counter = 1;
}
+
+ return bits;
}
+
+ return 0;
}
void HMAC_DRBG::add_entropy(const byte input[], size_t length)
diff --git a/src/lib/rng/hmac_drbg/hmac_drbg.h b/src/lib/rng/hmac_drbg/hmac_drbg.h
index c9d0e3d20..bd2d18d47 100644
--- a/src/lib/rng/hmac_drbg/hmac_drbg.h
+++ b/src/lib/rng/hmac_drbg/hmac_drbg.h
@@ -24,7 +24,9 @@ class BOTAN_DLL HMAC_DRBG : public RandomNumberGenerator
void clear() override;
std::string name() const override;
- void reseed(size_t poll_bits) override;
+ size_t reseed_with_sources(Entropy_Sources& srcs,
+ size_t poll_bits,
+ std::chrono::milliseconds poll_timeout) override;
void add_entropy(const byte input[], size_t input_len) override;
diff --git a/src/lib/rng/hmac_rng/hmac_rng.cpp b/src/lib/rng/hmac_rng/hmac_rng.cpp
index 5456b3bac..f5a782526 100644
--- a/src/lib/rng/hmac_rng/hmac_rng.cpp
+++ b/src/lib/rng/hmac_rng/hmac_rng.cpp
@@ -95,7 +95,11 @@ void HMAC_RNG::randomize(byte out[], size_t length)
m_output_since_reseed += length;
if(m_output_since_reseed >= BOTAN_RNG_MAX_OUTPUT_BEFORE_RESEED)
- reseed_with_timeout(BOTAN_RNG_RESEED_POLL_BITS, BOTAN_RNG_AUTO_RESEED_TIMEOUT);
+ {
+ reseed_with_sources(Entropy_Sources::global_sources(),
+ BOTAN_RNG_RESEED_POLL_BITS,
+ BOTAN_RNG_AUTO_RESEED_TIMEOUT);
+ }
/*
HMAC KDF as described in E-t-E, using a CTXinfo of "rng"
@@ -112,15 +116,9 @@ void HMAC_RNG::randomize(byte out[], size_t length)
}
}
-/*
-* Poll for entropy and reset the internal keys
-*/
-void HMAC_RNG::reseed(size_t poll_bits)
- {
- reseed_with_timeout(poll_bits, BOTAN_RNG_RESEED_DEFAULT_TIMEOUT);
- }
-
-void HMAC_RNG::reseed_with_timeout(size_t poll_bits, std::chrono::milliseconds timeout)
+size_t HMAC_RNG::reseed_with_sources(Entropy_Sources& srcs,
+ size_t poll_bits,
+ std::chrono::milliseconds timeout)
{
/*
Using the terminology of E-t-E, XTR is the MAC function (normally
@@ -130,20 +128,18 @@ void HMAC_RNG::reseed_with_timeout(size_t poll_bits, std::chrono::milliseconds t
a bad poll doesn't wipe us out.
*/
- double bits_collected = 0;
-
- typedef std::chrono::high_resolution_clock clock;
+ typedef std::chrono::system_clock clock;
auto deadline = clock::now() + timeout;
- Entropy_Accumulator accum(
- [&](const byte in[], size_t in_len, double entropy_estimate)
- {
+ 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);
});
- EntropySource::poll_available_sources(accum);
+ srcs.poll(accum);
/*
* It is necessary to feed forward poll data. Otherwise, a good poll
@@ -172,6 +168,8 @@ void HMAC_RNG::reseed_with_timeout(size_t poll_bits, std::chrono::milliseconds t
m_extractor->output_length() * 8);
m_output_since_reseed = 0;
+
+ return static_cast<size_t>(bits_collected);
}
bool HMAC_RNG::is_seeded() const
@@ -180,12 +178,16 @@ bool HMAC_RNG::is_seeded() const
}
/*
-* Add user-supplied entropy to the extractor input
+* Add user-supplied entropy to the extractor input then reseed
+* to incorporate it into the state
*/
void HMAC_RNG::add_entropy(const byte input[], size_t length)
{
m_extractor->update(input, length);
- reseed_with_timeout(BOTAN_RNG_RESEED_POLL_BITS, BOTAN_RNG_AUTO_RESEED_TIMEOUT);
+
+ reseed_with_sources(Entropy_Sources::global_sources(),
+ BOTAN_RNG_RESEED_POLL_BITS,
+ BOTAN_RNG_RESEED_DEFAULT_TIMEOUT);
}
/*
diff --git a/src/lib/rng/hmac_rng/hmac_rng.h b/src/lib/rng/hmac_rng/hmac_rng.h
index ba12e665d..1e38daa08 100644
--- a/src/lib/rng/hmac_rng/hmac_rng.h
+++ b/src/lib/rng/hmac_rng/hmac_rng.h
@@ -32,9 +32,9 @@ class BOTAN_DLL HMAC_RNG : public RandomNumberGenerator
void clear() override;
std::string name() const override;
- void reseed(size_t poll_bits) override;
-
- void reseed_with_timeout(size_t poll_bits, std::chrono::milliseconds ms);
+ size_t reseed_with_sources(Entropy_Sources& srcs,
+ size_t poll_bits,
+ std::chrono::milliseconds poll_timeout) override;
void add_entropy(const byte[], size_t) override;
diff --git a/src/lib/rng/rng.cpp b/src/lib/rng/rng.cpp
index d4fd5fb10..c17f23dd0 100644
--- a/src/lib/rng/rng.cpp
+++ b/src/lib/rng/rng.cpp
@@ -7,9 +7,24 @@
#include <botan/rng.h>
#include <botan/hmac_rng.h>
+#include <botan/entropy_src.h>
namespace Botan {
+size_t RandomNumberGenerator::reseed(size_t bits_to_collect)
+ {
+ return this->reseed_with_timeout(bits_to_collect,
+ BOTAN_RNG_RESEED_DEFAULT_TIMEOUT);
+ }
+
+size_t RandomNumberGenerator::reseed_with_timeout(size_t bits_to_collect,
+ std::chrono::milliseconds timeout)
+ {
+ return this->reseed_with_sources(Entropy_Sources::global_sources(),
+ bits_to_collect,
+ timeout);
+ }
+
RandomNumberGenerator* RandomNumberGenerator::make_rng()
{
std::unique_ptr<MessageAuthenticationCode> h1(MessageAuthenticationCode::create("HMAC(SHA-512)"));
diff --git a/src/lib/rng/rng.h b/src/lib/rng/rng.h
index a28a676a6..1ce0d5153 100644
--- a/src/lib/rng/rng.h
+++ b/src/lib/rng/rng.h
@@ -8,13 +8,16 @@
#ifndef BOTAN_RANDOM_NUMBER_GENERATOR_H__
#define BOTAN_RANDOM_NUMBER_GENERATOR_H__
-#include <botan/entropy_src.h>
+#include <botan/secmem.h>
#include <botan/exceptn.h>
+#include <chrono>
#include <string>
#include <mutex>
namespace Botan {
+class Entropy_Sources;
+
/**
* This class represents a random number (RNG) generator object.
*/
@@ -100,11 +103,29 @@ class BOTAN_DLL RandomNumberGenerator
virtual std::string name() const = 0;
/**
- * Seed this RNG using the entropy sources it contains.
+ * Seed this RNG using the global entropy sources and default timeout
+ * @param bits_to_collect is the number of bits of entropy to
+ attempt to gather from the entropy sources
+ */
+ size_t reseed(size_t bits_to_collect);
+
+ /**
+ * Seed this RNG using the global 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
*/
- virtual void reseed(size_t bits_to_collect) = 0;
+ size_t reseed_with_timeout(size_t bits_to_collect,
+ std::chrono::milliseconds poll_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) = 0;
/**
* Add entropy to this RNG.
@@ -135,7 +156,12 @@ class BOTAN_DLL Null_RNG : public RandomNumberGenerator
std::string name() const override { return "Null_RNG"; }
- void reseed(size_t) override {}
+ size_t reseed_with_sources(Entropy_Sources&, size_t,
+ std::chrono::milliseconds) override
+ {
+ return 0;
+ }
+
bool is_seeded() const override { return false; }
void add_entropy(const byte[], size_t) override {}
};
@@ -170,10 +196,12 @@ class BOTAN_DLL Serialized_RNG : public RandomNumberGenerator
return m_rng->name();
}
- void reseed(size_t poll_bits) override
+ size_t reseed_with_sources(Entropy_Sources& src,
+ size_t bits,
+ std::chrono::milliseconds msec) override
{
std::lock_guard<std::mutex> lock(m_mutex);
- m_rng->reseed(poll_bits);
+ return m_rng->reseed_with_sources(src, bits, msec);
}
void add_entropy(const byte in[], 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 8b949d071..02ad07736 100644
--- a/src/lib/rng/system_rng/system_rng.cpp
+++ b/src/lib/rng/system_rng/system_rng.cpp
@@ -40,8 +40,18 @@ class System_RNG_Impl : public RandomNumberGenerator
void clear() override {}
std::string name() const override { return "system"; }
- void reseed(size_t) override {}
- void add_entropy(const byte[], size_t) override {}
+ size_t reseed_with_sources(Entropy_Sources& srcs,
+ size_t poll_bits,
+ std::chrono::milliseconds poll_timeout) override
+ {
+ return 0;
+ }
+
+ void add_entropy(const byte[], size_t) override
+ {
+ // We could write this back to /dev/urandom to help seed the PRNG
+ // Unclear if this is valuable on current systems
+ }
private:
#if defined(BOTAN_TARGET_OS_HAS_CRYPTGENRANDOM)
@@ -55,14 +65,18 @@ System_RNG_Impl::System_RNG_Impl()
{
#if defined(BOTAN_TARGET_OS_HAS_CRYPTGENRANDOM)
- if(!CryptAcquireContext(&m_prov, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
+ if(!CryptAcquireContext(&m_prov, 0, 0, BOTAN_SYSTEM_RNG_CRYPTOAPI_PROV_TYPE, CRYPT_VERIFYCONTEXT))
throw std::runtime_error("System_RNG failed to acquire crypto provider");
#else
- m_fd = ::open("/dev/urandom", O_RDONLY);
+#ifndef O_NOCTTY
+ #define O_NOCTTY 0
+#endif
+
+ m_fd = ::open(BOTAN_SYSTEM_RNG_DEVICE, O_RDONLY | O_NOCTTY);
if(m_fd < 0)
- throw std::runtime_error("System_RNG failed to open /dev/urandom");
+ throw std::runtime_error("System_RNG failed to open RNG device");
#endif
}
diff --git a/src/lib/rng/system_rng/system_rng.h b/src/lib/rng/system_rng/system_rng.h
index 0f4b94725..6290b8769 100644
--- a/src/lib/rng/system_rng/system_rng.h
+++ b/src/lib/rng/system_rng/system_rng.h
@@ -35,7 +35,12 @@ class BOTAN_DLL System_RNG : public RandomNumberGenerator
std::string name() const override { return m_rng.name(); }
- void reseed(size_t poll_bits = 256) override { m_rng.reseed(poll_bits); }
+ 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:
diff --git a/src/lib/rng/x931_rng/x931_rng.cpp b/src/lib/rng/x931_rng/x931_rng.cpp
index d531cf4a9..020d9a5a5 100644
--- a/src/lib/rng/x931_rng/x931_rng.cpp
+++ b/src/lib/rng/x931_rng/x931_rng.cpp
@@ -72,10 +72,13 @@ void ANSI_X931_RNG::rekey()
}
}
-void ANSI_X931_RNG::reseed(size_t poll_bits)
+size_t ANSI_X931_RNG::reseed_with_sources(Entropy_Sources& srcs,
+ size_t poll_bits,
+ std::chrono::milliseconds poll_timeout)
{
- m_prng->reseed(poll_bits);
+ size_t bits = m_prng->reseed_with_sources(srcs, poll_bits, poll_timeout);
rekey();
+ return bits;
}
void ANSI_X931_RNG::add_entropy(const byte input[], size_t length)
diff --git a/src/lib/rng/x931_rng/x931_rng.h b/src/lib/rng/x931_rng/x931_rng.h
index 899fed956..ed7124a08 100644
--- a/src/lib/rng/x931_rng/x931_rng.h
+++ b/src/lib/rng/x931_rng/x931_rng.h
@@ -24,7 +24,10 @@ class BOTAN_DLL ANSI_X931_RNG : public RandomNumberGenerator
void clear() override;
std::string name() const override;
- void reseed(size_t poll_bits) override;
+ size_t reseed_with_sources(Entropy_Sources& srcs,
+ size_t poll_bits,
+ std::chrono::milliseconds poll_timeout) override;
+
void add_entropy(const byte[], size_t) override;
/**
diff --git a/src/tests/test_entropy.cpp b/src/tests/test_entropy.cpp
new file mode 100644
index 000000000..f2475e47e
--- /dev/null
+++ b/src/tests/test_entropy.cpp
@@ -0,0 +1,107 @@
+/*
+* (C) 2015 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include "tests.h"
+#include <botan/entropy_src.h>
+
+#if defined(BOTAN_HAS_COMPRESSION)
+ #include <botan/compression.h>
+#endif
+
+namespace Botan_Tests {
+
+namespace {
+
+class Entropy_Source_Tests : public Test
+ {
+ public:
+ std::vector<Test::Result> run() override
+ {
+ static const size_t MAX_ENTROPY = 512;
+ static const size_t MAX_SAMPLES = 256;
+ static const size_t MAX_ENTROPY_BYTES = 256*1024;
+
+ Botan::Entropy_Sources& srcs = Botan::Entropy_Sources::global_sources();
+
+ std::vector<std::string> src_names = srcs.enabled_sources();
+
+ std::vector<Test::Result> results;
+
+ for(auto&& src_name : src_names)
+ {
+ Test::Result result("Entropy source " + src_name);
+
+ result.start_timer();
+
+ std::vector<uint8_t> entropy;
+ size_t samples = 0;
+ size_t entropy_estimate = 0;
+
+ // TODO: add a timeout
+
+ Botan::Entropy_Accumulator accum([&](const uint8_t buf[], size_t buf_len, size_t buf_entropy) -> bool
+ {
+ entropy.insert(entropy.end(), buf, buf + buf_len);
+ entropy_estimate += buf_entropy;
+ ++samples;
+
+ result.test_note("sample " + std::to_string(samples) + " " +
+ Botan::hex_encode(buf, buf_len) + " " + std::to_string(buf_entropy));
+
+ result.test_gte("impossible entropy", buf_len * 8, buf_entropy);
+
+ return (entropy_estimate > MAX_ENTROPY ||
+ samples > MAX_SAMPLES ||
+ entropy.size() > MAX_ENTROPY_BYTES);
+ });
+
+ result.confirm("polled source", srcs.poll_just(accum, src_name));
+
+ result.test_note("saw " + std::to_string(samples) +
+ " samples with total estimated entropy " +
+ std::to_string(entropy_estimate));
+
+ //result.test_gte("impossible entropy", entropy.size() * 8, entropy_estimate);
+
+ if(!entropy.empty())
+ {
+#if defined(BOTAN_HAS_COMPRESSION)
+ for(auto comp_algo : { "zlib", "bzip2", "lzma" })
+ {
+ std::unique_ptr<Botan::Compressor_Transform> comp(Botan::make_compressor(comp_algo, 9));
+
+ if(comp)
+ {
+ Botan::secure_vector<byte> compressed;
+ compressed.assign(entropy.begin(), entropy.end());
+
+ comp->start();
+ comp->finish(compressed);
+
+ result.test_gte("compressed entropy better than advertised",
+ compressed.size() * 8, entropy_estimate);
+
+ // TODO: perform 2nd poll and check compression differential
+ }
+
+ }
+#endif
+ }
+
+ result.end_timer();
+
+ results.push_back(result);
+ }
+
+ return results;
+ }
+ };
+
+BOTAN_REGISTER_TEST("entropy", Entropy_Source_Tests);
+
+}
+
+}
diff --git a/src/tests/test_rng.h b/src/tests/test_rng.h
index f1d40f7f1..7d30fd6cc 100644
--- a/src/tests/test_rng.h
+++ b/src/tests/test_rng.h
@@ -30,7 +30,9 @@ class Fixed_Output_RNG : public Botan::RandomNumberGenerator
return out;
}
- void reseed(size_t) override {}
+ size_t reseed_with_sources(Botan::Entropy_Sources&,
+ size_t,
+ std::chrono::milliseconds) { return 0; }
void randomize(byte out[], size_t len) override
{
diff --git a/src/tests/tests.h b/src/tests/tests.h
index 9f511c4fb..1af278cce 100644
--- a/src/tests/tests.h
+++ b/src/tests/tests.h
@@ -99,7 +99,7 @@ class Test
else
{
Result r(result.who());
- r.test_note("Got expected failure " + result.result_string());
+ r.test_note("Got expected failure");
return r;
}
}
@@ -108,6 +108,13 @@ class Test
void test_note(const std::string& note, const char* extra = nullptr);
+ template<typename Alloc>
+ void test_note(const std::string& who, const std::vector<uint8_t, Alloc>& vec)
+ {
+ const std::string hex = Botan::hex_encode(vec);
+ return test_note(who, hex.c_str());
+ }
+
void note_missing(const std::string& thing);
bool test_success(const std::string& note = "");