aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2015-11-24 17:51:59 -0500
committerJack Lloyd <[email protected]>2015-11-24 17:51:59 -0500
commit5f208fab1890e2ad64b52306eccd82f031425c7a (patch)
tree6bbbf1408e10538e441e3d603d80ebb2cabc6a78
parentbf59ffc4de374d7b27b7ab400789ab2723131b7a (diff)
New reseed_with_sources call on RNGs
Provides an easier way for an application to configure a list of entropy sources they'd like to use, or add a custom entropy source to their seeding. Exposes some toggles for the global/default entropy sources to build.h Adds basic entropy tests which runs the polls and does sanity checking on the results, including compression tests if available. These are less useful for the CSPRNG outputs but a good check for the ones producing plain ASCII like the /proc reader.
-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 = "");