aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/entropy
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/entropy')
-rw-r--r--src/lib/entropy/beos_stats/es_beos.cpp63
-rw-r--r--src/lib/entropy/beos_stats/es_beos.h28
-rw-r--r--src/lib/entropy/beos_stats/info.txt17
-rw-r--r--src/lib/entropy/cryptoapi_rng/es_capi.cpp93
-rw-r--r--src/lib/entropy/cryptoapi_rng/es_capi.h37
-rw-r--r--src/lib/entropy/cryptoapi_rng/info.txt20
-rw-r--r--src/lib/entropy/dev_random/dev_random.cpp97
-rw-r--r--src/lib/entropy/dev_random/dev_random.h37
-rw-r--r--src/lib/entropy/dev_random/info.txt27
-rw-r--r--src/lib/entropy/egd/es_egd.cpp156
-rw-r--r--src/lib/entropy/egd/es_egd.h49
-rw-r--r--src/lib/entropy/egd/info.txt30
-rw-r--r--src/lib/entropy/entropy_src.h141
-rw-r--r--src/lib/entropy/hres_timer/hres_timer.cpp117
-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.txt3
-rw-r--r--src/lib/entropy/proc_walk/info.txt30
-rw-r--r--src/lib/entropy/proc_walk/proc_walk.cpp173
-rw-r--r--src/lib/entropy/proc_walk/proc_walk.h37
-rw-r--r--src/lib/entropy/rdrand/info.txt22
-rw-r--r--src/lib/entropy/rdrand/rdrand.cpp60
-rw-r--r--src/lib/entropy/rdrand/rdrand.h28
-rw-r--r--src/lib/entropy/unix_procs/info.txt25
-rw-r--r--src/lib/entropy/unix_procs/unix_proc_sources.cpp65
-rw-r--r--src/lib/entropy/unix_procs/unix_procs.cpp258
-rw-r--r--src/lib/entropy/unix_procs/unix_procs.h89
-rw-r--r--src/lib/entropy/win32_stats/es_win32.cpp118
-rw-r--r--src/lib/entropy/win32_stats/es_win32.h27
-rw-r--r--src/lib/entropy/win32_stats/info.txt19
30 files changed, 1909 insertions, 0 deletions
diff --git a/src/lib/entropy/beos_stats/es_beos.cpp b/src/lib/entropy/beos_stats/es_beos.cpp
new file mode 100644
index 000000000..e514eb121
--- /dev/null
+++ b/src/lib/entropy/beos_stats/es_beos.cpp
@@ -0,0 +1,63 @@
+/*
+* BeOS EntropySource
+* (C) 1999-2008 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/internal/es_beos.h>
+
+#include <kernel/OS.h>
+#include <kernel/image.h>
+#include <interface/InterfaceDefs.h>
+
+namespace Botan {
+
+/**
+* BeOS entropy poll
+*/
+void BeOS_EntropySource::poll(Entropy_Accumulator& accum)
+ {
+ system_info info_sys;
+ get_system_info(&info_sys);
+ accum.add(info_sys, 2);
+
+ key_info info_key; // current state of the keyboard
+ get_key_info(&info_key);
+ accum.add(info_key, 0);
+
+ team_info info_team;
+ int32 cookie_team = 0;
+
+ while(get_next_team_info(&cookie_team, &info_team) == B_OK)
+ {
+ accum.add(info_team, 2);
+
+ 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, 1);
+
+ cookie = 0;
+ image_info info_img;
+ while(get_next_image_info(id, &cookie, &info_img) == B_OK)
+ accum.add(info_img, 1);
+
+ cookie = 0;
+ sem_info info_sem;
+ while(get_next_sem_info(id, &cookie, &info_sem) == B_OK)
+ accum.add(info_sem, 1);
+
+ cookie = 0;
+ area_info info_area;
+ while(get_next_area_info(id, &cookie, &info_area) == B_OK)
+ accum.add(info_area, 2);
+
+ if(accum.polling_goal_achieved())
+ break;
+ }
+ }
+
+}
diff --git a/src/lib/entropy/beos_stats/es_beos.h b/src/lib/entropy/beos_stats/es_beos.h
new file mode 100644
index 000000000..5ccb430a5
--- /dev/null
+++ b/src/lib/entropy/beos_stats/es_beos.h
@@ -0,0 +1,28 @@
+/*
+* BeOS EntropySource
+* (C) 1999-2008 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_ENTROPY_SRC_BEOS_H__
+#define BOTAN_ENTROPY_SRC_BEOS_H__
+
+#include <botan/entropy_src.h>
+
+namespace Botan {
+
+/**
+* BeOS Entropy Source
+*/
+class BeOS_EntropySource : public EntropySource
+ {
+ private:
+ std::string name() const { return "BeOS Statistics"; }
+
+ void poll(Entropy_Accumulator& accum);
+ };
+
+}
+
+#endif
diff --git a/src/lib/entropy/beos_stats/info.txt b/src/lib/entropy/beos_stats/info.txt
new file mode 100644
index 000000000..9ae527f49
--- /dev/null
+++ b/src/lib/entropy/beos_stats/info.txt
@@ -0,0 +1,17 @@
+define ENTROPY_SRC_BEOS 20131128
+
+<source>
+es_beos.cpp
+</source>
+
+<header:internal>
+es_beos.h
+</header:internal>
+
+<os>
+haiku
+</os>
+
+<libs>
+haiku -> root,be
+</libs>
diff --git a/src/lib/entropy/cryptoapi_rng/es_capi.cpp b/src/lib/entropy/cryptoapi_rng/es_capi.cpp
new file mode 100644
index 000000000..a706b4d5c
--- /dev/null
+++ b/src/lib/entropy/cryptoapi_rng/es_capi.cpp
@@ -0,0 +1,93 @@
+/*
+* Win32 CryptoAPI EntropySource
+* (C) 1999-2009 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/internal/es_capi.h>
+#include <botan/parsing.h>
+#include <windows.h>
+#include <wincrypt.h>
+
+namespace Botan {
+
+namespace {
+
+class CSP_Handle
+ {
+ public:
+ CSP_Handle(u64bit capi_provider)
+ {
+ valid = false;
+ DWORD prov_type = (DWORD)capi_provider;
+
+ if(CryptAcquireContext(&handle, 0, 0,
+ prov_type, CRYPT_VERIFYCONTEXT))
+ valid = true;
+ }
+
+ ~CSP_Handle()
+ {
+ if(is_valid())
+ CryptReleaseContext(handle, 0);
+ }
+
+ size_t gen_random(byte out[], size_t n) const
+ {
+ if(is_valid() && CryptGenRandom(handle, static_cast<DWORD>(n), out))
+ return n;
+ return 0;
+ }
+
+ bool is_valid() const { return valid; }
+
+ HCRYPTPROV get_handle() const { return handle; }
+ private:
+ HCRYPTPROV handle;
+ bool valid;
+ };
+
+}
+
+/*
+* Gather Entropy from Win32 CAPI
+*/
+void Win32_CAPI_EntropySource::poll(Entropy_Accumulator& accum)
+ {
+ secure_vector<byte>& io_buffer = accum.get_io_buffer(32);
+
+ for(size_t i = 0; i != prov_types.size(); ++i)
+ {
+ CSP_Handle csp(prov_types[i]);
+
+ size_t got = csp.gen_random(&io_buffer[0], io_buffer.size());
+
+ if(got)
+ {
+ accum.add(&io_buffer[0], io_buffer.size(), 6);
+ break;
+ }
+ }
+ }
+
+/*
+* Win32_Capi_Entropysource Constructor
+*/
+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)
+ {
+ if(capi_provs[i] == "RSA_FULL") prov_types.push_back(PROV_RSA_FULL);
+ if(capi_provs[i] == "INTEL_SEC") prov_types.push_back(PROV_INTEL_SEC);
+ if(capi_provs[i] == "FORTEZZA") prov_types.push_back(PROV_FORTEZZA);
+ if(capi_provs[i] == "RNG") prov_types.push_back(PROV_RNG);
+ }
+
+ if(prov_types.size() == 0)
+ 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
new file mode 100644
index 000000000..d75101923
--- /dev/null
+++ b/src/lib/entropy/cryptoapi_rng/es_capi.h
@@ -0,0 +1,37 @@
+/*
+* Win32 CAPI EntropySource
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_ENTROPY_SRC_WIN32_CAPI_H__
+#define BOTAN_ENTROPY_SRC_WIN32_CAPI_H__
+
+#include <botan/entropy_src.h>
+#include <vector>
+
+namespace Botan {
+
+/**
+* Win32 CAPI Entropy Source
+*/
+class Win32_CAPI_EntropySource : public EntropySource
+ {
+ public:
+ std::string name() const { return "Win32 CryptoGenRandom"; }
+
+ void poll(Entropy_Accumulator& accum);
+
+ /**
+ * Win32_Capi_Entropysource Constructor
+ * @param provs list of providers, separated by ':'
+ */
+ Win32_CAPI_EntropySource(const std::string& provs = "");
+ private:
+ std::vector<u64bit> prov_types;
+ };
+
+}
+
+#endif
diff --git a/src/lib/entropy/cryptoapi_rng/info.txt b/src/lib/entropy/cryptoapi_rng/info.txt
new file mode 100644
index 000000000..d4ee13aea
--- /dev/null
+++ b/src/lib/entropy/cryptoapi_rng/info.txt
@@ -0,0 +1,20 @@
+define ENTROPY_SRC_CAPI 20131128
+
+<source>
+es_capi.cpp
+</source>
+
+<header:internal>
+es_capi.h
+</header:internal>
+
+# We'll just assume CAPI is there; this is OK except for 3.x, early
+# versions of 95, and maybe NT 3.5
+<os>
+windows
+cygwin
+</os>
+
+<libs>
+windows -> advapi32.lib
+</libs>
diff --git a/src/lib/entropy/dev_random/dev_random.cpp b/src/lib/entropy/dev_random/dev_random.cpp
new file mode 100644
index 000000000..3f8df8749
--- /dev/null
+++ b/src/lib/entropy/dev_random/dev_random.cpp
@@ -0,0 +1,97 @@
+/*
+* Reader of /dev/random and company
+* (C) 1999-2009,2013 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/internal/dev_random.h>
+#include <botan/internal/rounding.h>
+
+#include <sys/types.h>
+#include <sys/select.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+
+namespace Botan {
+
+/**
+Device_EntropySource constructor
+Open a file descriptor to each (available) device in fsnames
+*/
+Device_EntropySource::Device_EntropySource(const std::vector<std::string>& fsnames)
+ {
+#ifndef O_NONBLOCK
+ #define O_NONBLOCK 0
+#endif
+
+#ifndef O_NOCTTY
+ #define O_NOCTTY 0
+#endif
+
+ const int flags = O_RDONLY | O_NONBLOCK | O_NOCTTY;
+
+ for(auto fsname : fsnames)
+ {
+ fd_type fd = ::open(fsname.c_str(), flags);
+
+ if(fd >= 0 && fd < FD_SETSIZE)
+ m_devices.push_back(fd);
+ else if(fd >= 0)
+ ::close(fd);
+ }
+ }
+
+/**
+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]);
+ }
+
+/**
+* Gather entropy from a RNG device
+*/
+void Device_EntropySource::poll(Entropy_Accumulator& accum)
+ {
+ if(m_devices.empty())
+ return;
+
+ const size_t ENTROPY_BITS_PER_BYTE = 8;
+ const size_t MS_WAIT_TIME = 32;
+ const size_t READ_ATTEMPT = std::max<size_t>(accum.desired_remaining_bits() / 8, 16);
+
+ int max_fd = m_devices[0];
+ fd_set read_set;
+ FD_ZERO(&read_set);
+ for(size_t i = 0; i != m_devices.size(); ++i)
+ {
+ FD_SET(m_devices[i], &read_set);
+ max_fd = std::max(m_devices[i], max_fd);
+ }
+
+ struct ::timeval timeout;
+
+ timeout.tv_sec = (MS_WAIT_TIME / 1000);
+ timeout.tv_usec = (MS_WAIT_TIME % 1000) * 1000;
+
+ if(::select(max_fd + 1, &read_set, nullptr, nullptr, &timeout) < 0)
+ return;
+
+ secure_vector<byte>& io_buffer = accum.get_io_buffer(READ_ATTEMPT);
+
+ 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], &io_buffer[0], io_buffer.size());
+ accum.add(&io_buffer[0], 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
new file mode 100644
index 000000000..d74412b27
--- /dev/null
+++ b/src/lib/entropy/dev_random/dev_random.h
@@ -0,0 +1,37 @@
+/*
+* /dev/random EntropySource
+* (C) 1999-2009 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_ENTROPY_SRC_DEVICE_H__
+#define BOTAN_ENTROPY_SRC_DEVICE_H__
+
+#include <botan/entropy_src.h>
+#include <vector>
+#include <string>
+
+namespace Botan {
+
+/**
+* Entropy source reading from kernel devices like /dev/random
+*/
+class Device_EntropySource : public EntropySource
+ {
+ public:
+ std::string name() const { return "RNG Device Reader"; }
+
+ void poll(Entropy_Accumulator& accum);
+
+ Device_EntropySource(const std::vector<std::string>& fsnames);
+ ~Device_EntropySource();
+ private:
+ typedef int fd_type;
+
+ std::vector<fd_type> m_devices;
+ };
+
+}
+
+#endif
diff --git a/src/lib/entropy/dev_random/info.txt b/src/lib/entropy/dev_random/info.txt
new file mode 100644
index 000000000..98a6a7e61
--- /dev/null
+++ b/src/lib/entropy/dev_random/info.txt
@@ -0,0 +1,27 @@
+define ENTROPY_SRC_DEV_RANDOM 20131128
+
+<source>
+dev_random.cpp
+</source>
+
+<header:internal>
+dev_random.h
+</header:internal>
+
+<os>
+aix
+cygwin
+darwin
+dragonfly
+freebsd
+haiku
+hpux
+hurd
+irix
+linux
+netbsd
+openbsd
+qnx
+solaris
+tru64
+</os>
diff --git a/src/lib/entropy/egd/es_egd.cpp b/src/lib/entropy/egd/es_egd.cpp
new file mode 100644
index 000000000..d8dbecd44
--- /dev/null
+++ b/src/lib/entropy/egd/es_egd.cpp
@@ -0,0 +1,156 @@
+/*
+* EGD EntropySource
+* (C) 1999-2009 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/internal/es_egd.h>
+#include <botan/parsing.h>
+#include <botan/exceptn.h>
+#include <cstring>
+#include <stdexcept>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#ifndef PF_LOCAL
+ #define PF_LOCAL PF_UNIX
+#endif
+
+namespace Botan {
+
+EGD_EntropySource::EGD_Socket::EGD_Socket(const std::string& path) :
+ socket_path(path), m_fd(-1)
+ {
+ }
+
+/**
+* Attempt a connection to an EGD/PRNGD socket
+*/
+int EGD_EntropySource::EGD_Socket::open_socket(const std::string& path)
+ {
+ int fd = ::socket(PF_LOCAL, SOCK_STREAM, 0);
+
+ if(fd >= 0)
+ {
+ sockaddr_un addr;
+ std::memset(&addr, 0, sizeof(addr));
+ addr.sun_family = PF_LOCAL;
+
+ if(sizeof(addr.sun_path) < path.length() + 1)
+ throw std::invalid_argument("EGD socket path is too long");
+
+ std::strncpy(addr.sun_path, path.c_str(), sizeof(addr.sun_path));
+
+ int len = sizeof(addr.sun_family) + std::strlen(addr.sun_path) + 1;
+
+ if(::connect(fd, reinterpret_cast<struct ::sockaddr*>(&addr), len) < 0)
+ {
+ ::close(fd);
+ fd = -1;
+ }
+ }
+
+ return fd;
+ }
+
+/**
+* Attempt to read entropy from EGD
+*/
+size_t EGD_EntropySource::EGD_Socket::read(byte outbuf[], size_t length)
+ {
+ if(length == 0)
+ return 0;
+
+ if(m_fd < 0)
+ {
+ m_fd = open_socket(socket_path);
+ if(m_fd < 0)
+ return 0;
+ }
+
+ try
+ {
+ // 1 == EGD command for non-blocking read
+ byte egd_read_command[2] = {
+ 1, static_cast<byte>(std::min<size_t>(length, 255)) };
+
+ if(::write(m_fd, egd_read_command, 2) != 2)
+ throw std::runtime_error("Writing entropy read command to EGD failed");
+
+ byte out_len = 0;
+ if(::read(m_fd, &out_len, 1) != 1)
+ throw std::runtime_error("Reading response length from EGD failed");
+
+ if(out_len > egd_read_command[1])
+ throw std::runtime_error("Bogus length field received from EGD");
+
+ ssize_t count = ::read(m_fd, outbuf, out_len);
+
+ if(count != out_len)
+ throw std::runtime_error("Reading entropy result from EGD failed");
+
+ return static_cast<size_t>(count);
+ }
+ catch(std::exception)
+ {
+ this->close();
+ // Will attempt to reopen next poll
+ }
+
+ return 0;
+ }
+
+void EGD_EntropySource::EGD_Socket::close()
+ {
+ if(m_fd > 0)
+ {
+ ::close(m_fd);
+ m_fd = -1;
+ }
+ }
+
+/**
+* EGD_EntropySource constructor
+*/
+EGD_EntropySource::EGD_EntropySource(const std::vector<std::string>& paths)
+ {
+ for(size_t i = 0; i != paths.size(); ++i)
+ sockets.push_back(EGD_Socket(paths[i]));
+ }
+
+EGD_EntropySource::~EGD_EntropySource()
+ {
+ for(size_t i = 0; i != sockets.size(); ++i)
+ sockets[i].close();
+ sockets.clear();
+ }
+
+/**
+* Gather Entropy from EGD
+*/
+void EGD_EntropySource::poll(Entropy_Accumulator& accum)
+ {
+ size_t go_get = std::min<size_t>(accum.desired_remaining_bits() / 8, 32);
+
+ secure_vector<byte>& io_buffer = accum.get_io_buffer(go_get);
+
+ for(size_t i = 0; i != sockets.size(); ++i)
+ {
+ size_t got = sockets[i].read(&io_buffer[0], io_buffer.size());
+
+ if(got)
+ {
+ accum.add(&io_buffer[0], got, 6);
+ break;
+ }
+ }
+ }
+
+}
diff --git a/src/lib/entropy/egd/es_egd.h b/src/lib/entropy/egd/es_egd.h
new file mode 100644
index 000000000..02c52b9a3
--- /dev/null
+++ b/src/lib/entropy/egd/es_egd.h
@@ -0,0 +1,49 @@
+/*
+* EGD EntropySource
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_ENTROPY_SRC_EGD_H__
+#define BOTAN_ENTROPY_SRC_EGD_H__
+
+#include <botan/entropy_src.h>
+#include <string>
+#include <vector>
+
+namespace Botan {
+
+/**
+* EGD Entropy Source
+*/
+class EGD_EntropySource : public EntropySource
+ {
+ public:
+ std::string name() const { return "EGD/PRNGD"; }
+
+ void poll(Entropy_Accumulator& accum);
+
+ EGD_EntropySource(const std::vector<std::string>&);
+ ~EGD_EntropySource();
+ private:
+ class EGD_Socket
+ {
+ public:
+ EGD_Socket(const std::string& path);
+
+ void close();
+ size_t read(byte outbuf[], size_t length);
+ private:
+ static int open_socket(const std::string& path);
+
+ std::string socket_path;
+ int m_fd; // cached fd
+ };
+
+ std::vector<EGD_Socket> sockets;
+ };
+
+}
+
+#endif
diff --git a/src/lib/entropy/egd/info.txt b/src/lib/entropy/egd/info.txt
new file mode 100644
index 000000000..b93c4526d
--- /dev/null
+++ b/src/lib/entropy/egd/info.txt
@@ -0,0 +1,30 @@
+define ENTROPY_SRC_EGD 20131128
+
+<source>
+es_egd.cpp
+</source>
+
+<header:internal>
+es_egd.h
+</header:internal>
+
+<libs>
+solaris -> socket
+qnx -> socket
+</libs>
+
+<os>
+aix
+cygwin
+darwin
+freebsd
+dragonfly
+hpux
+irix
+linux
+netbsd
+openbsd
+qnx
+solaris
+tru64
+</os>
diff --git a/src/lib/entropy/entropy_src.h b/src/lib/entropy/entropy_src.h
new file mode 100644
index 000000000..552eca9de
--- /dev/null
+++ b/src/lib/entropy/entropy_src.h
@@ -0,0 +1,141 @@
+/*
+* EntropySource
+* (C) 2008-2009 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_ENTROPY_SOURCE_BASE_H__
+#define BOTAN_ENTROPY_SOURCE_BASE_H__
+
+#include <botan/buf_comp.h>
+#include <string>
+
+namespace Botan {
+
+/**
+* Class used to accumulate the poll results of EntropySources
+*/
+class BOTAN_DLL Entropy_Accumulator
+ {
+ public:
+ /**
+ * Initialize an Entropy_Accumulator
+ * @param goal is how many bits we would like to collect
+ */
+ Entropy_Accumulator(size_t goal) :
+ entropy_goal(goal), collected_bits(0) {}
+
+ virtual ~Entropy_Accumulator() {}
+
+ /**
+ * Get a cached I/O buffer (purely for minimizing allocation
+ * overhead to polls)
+ *
+ * @param size requested size for the I/O buffer
+ * @return cached I/O buffer for repeated polls
+ */
+ secure_vector<byte>& get_io_buffer(size_t size)
+ { io_buffer.resize(size); return io_buffer; }
+
+ /**
+ * @return number of bits collected so far
+ */
+ size_t bits_collected() const
+ { return static_cast<size_t>(collected_bits); }
+
+ /**
+ * @return if our polling goal has been achieved
+ */
+ bool polling_goal_achieved() const
+ { return (collected_bits >= entropy_goal); }
+
+ /**
+ * @return how many bits we need to reach our polling goal
+ */
+ size_t desired_remaining_bits() const
+ {
+ if(collected_bits >= entropy_goal)
+ return 0;
+ return static_cast<size_t>(entropy_goal - collected_bits);
+ }
+
+ /**
+ * 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)
+ {
+ add_bytes(reinterpret_cast<const byte*>(bytes), length);
+ collected_bits += entropy_bits_per_byte * length;
+ }
+
+ /**
+ * 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);
+ }
+ private:
+ virtual void add_bytes(const byte bytes[], size_t length) = 0;
+
+ secure_vector<byte> io_buffer;
+ size_t entropy_goal;
+ double collected_bits;
+ };
+
+/**
+* Entropy accumulator that puts the input into a Buffered_Computation
+*/
+class BOTAN_DLL Entropy_Accumulator_BufferedComputation :
+ public Entropy_Accumulator
+ {
+ public:
+ /**
+ * @param sink the hash or MAC we are feeding the poll data into
+ * @param goal is how many bits we want to collect in this poll
+ */
+ Entropy_Accumulator_BufferedComputation(Buffered_Computation& sink,
+ size_t goal) :
+ Entropy_Accumulator(goal), entropy_sink(sink) {}
+
+ private:
+ void add_bytes(const byte bytes[], size_t length) override
+ {
+ entropy_sink.update(bytes, length);
+ }
+
+ Buffered_Computation& entropy_sink;
+ };
+
+/**
+* Abstract interface to a source of entropy
+*/
+class BOTAN_DLL EntropySource
+ {
+ public:
+ /**
+ * @return name identifying this entropy source
+ */
+ virtual std::string name() const = 0;
+
+ /**
+ * Perform an entropy gathering poll
+ * @param accum is an accumulator object that will be given entropy
+ */
+ virtual void poll(Entropy_Accumulator& accum) = 0;
+
+ virtual ~EntropySource() {}
+ };
+
+}
+
+#endif
diff --git a/src/lib/entropy/hres_timer/hres_timer.cpp b/src/lib/entropy/hres_timer/hres_timer.cpp
new file mode 100644
index 000000000..7295a119b
--- /dev/null
+++ b/src/lib/entropy/hres_timer/hres_timer.cpp
@@ -0,0 +1,117 @@
+/*
+* High Resolution Timestamp Entropy Source
+* (C) 1999-2009,2011 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/internal/hres_timer.h>
+#include <botan/cpuid.h>
+
+#if defined(BOTAN_TARGET_OS_HAS_QUERY_PERF_COUNTER)
+ #include <windows.h>
+#endif
+
+namespace Botan {
+
+/*
+* Get the timestamp
+*/
+void High_Resolution_Timestamp::poll(Entropy_Accumulator& accum)
+ {
+ // Don't count the timestamp as contributing any entropy
+ const double ESTIMATED_ENTROPY_PER_BYTE = 0.0;
+
+#if defined(BOTAN_TARGET_OS_HAS_QUERY_PERF_COUNTER)
+ {
+ LARGE_INTEGER tv;
+ ::QueryPerformanceCounter(&tv);
+ accum.add(tv.QuadPart, ESTIMATED_ENTROPY_PER_BYTE);
+ }
+#endif
+
+#if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME)
+
+#define CLOCK_POLL(src) \
+ do { \
+ struct timespec ts; \
+ ::clock_gettime(src, &ts); \
+ accum.add(&ts, sizeof(ts), ESTIMATED_ENTROPY_PER_BYTE); \
+ } while(0)
+
+#if defined(CLOCK_REALTIME)
+ CLOCK_POLL(CLOCK_REALTIME);
+#endif
+
+#if defined(CLOCK_REALTIME_COARSE)
+ CLOCK_POLL(CLOCK_REALTIME_COARSE);
+#endif
+
+#if defined(CLOCK_MONOTONIC)
+ CLOCK_POLL(CLOCK_MONOTONIC);
+#endif
+
+#if defined(CLOCK_MONOTONIC_COARSE)
+ CLOCK_POLL(CLOCK_MONOTONIC_COARSE);
+#endif
+
+#if defined(CLOCK_MONOTONIC_RAW)
+ CLOCK_POLL(CLOCK_MONOTONIC_RAW);
+#endif
+
+#if defined(CLOCK_BOOTTIME)
+ CLOCK_POLL(CLOCK_BOOTTIME);
+#endif
+
+#if defined(CLOCK_PROCESS_CPUTIME_ID)
+ CLOCK_POLL(CLOCK_PROCESS_CPUTIME_ID);
+#endif
+
+#if defined(CLOCK_THREAD_CPUTIME_ID)
+ CLOCK_POLL(CLOCK_THREAD_CPUTIME_ID);
+#endif
+
+#undef CLOCK_POLL
+
+#endif
+
+#if BOTAN_USE_GCC_INLINE_ASM
+
+ u64bit rtc = 0;
+
+#if defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
+ if(CPUID::has_rdtsc()) // not availble on all x86 CPUs
+ {
+ u32bit rtc_low = 0, rtc_high = 0;
+ asm volatile("rdtsc" : "=d" (rtc_high), "=a" (rtc_low));
+ rtc = (static_cast<u64bit>(rtc_high) << 32) | rtc_low;
+ }
+
+#elif defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
+ u32bit rtc_low = 0, rtc_high = 0;
+ asm volatile("mftbu %0; mftb %1" : "=r" (rtc_high), "=r" (rtc_low));
+ rtc = (static_cast<u64bit>(rtc_high) << 32) | rtc_low;
+
+#elif defined(BOTAN_TARGET_ARCH_IS_ALPHA)
+ asm volatile("rpcc %0" : "=r" (rtc));
+
+#elif defined(BOTAN_TARGET_ARCH_IS_SPARC64) && !defined(BOTAN_TARGET_OS_IS_OPENBSD)
+ asm volatile("rd %%tick, %0" : "=r" (rtc));
+
+#elif defined(BOTAN_TARGET_ARCH_IS_IA64)
+ asm volatile("mov %0=ar.itc" : "=r" (rtc));
+
+#elif defined(BOTAN_TARGET_ARCH_IS_S390X)
+ asm volatile("stck 0(%0)" : : "a" (&rtc) : "memory", "cc");
+
+#elif defined(BOTAN_TARGET_ARCH_IS_HPPA)
+ asm volatile("mfctl 16,%0" : "=r" (rtc)); // 64-bit only?
+
+#endif
+
+ accum.add(rtc, ESTIMATED_ENTROPY_PER_BYTE);
+
+#endif
+ }
+
+}
diff --git a/src/lib/entropy/hres_timer/hres_timer.h b/src/lib/entropy/hres_timer/hres_timer.h
new file mode 100644
index 000000000..8b95c8308
--- /dev/null
+++ b/src/lib/entropy/hres_timer/hres_timer.h
@@ -0,0 +1,30 @@
+/*
+* High Resolution Timestamp Entropy Source
+* (C) 1999-2009 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#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 : public EntropySource
+ {
+ public:
+ std::string name() const { return "High Resolution Timestamp"; }
+ void poll(Entropy_Accumulator& accum);
+ };
+
+}
+
+#endif
diff --git a/src/lib/entropy/hres_timer/info.txt b/src/lib/entropy/hres_timer/info.txt
new file mode 100644
index 000000000..dfe8fab0b
--- /dev/null
+++ b/src/lib/entropy/hres_timer/info.txt
@@ -0,0 +1,13 @@
+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
new file mode 100644
index 000000000..d991577f7
--- /dev/null
+++ b/src/lib/entropy/info.txt
@@ -0,0 +1,3 @@
+<requires>
+algo_base
+</requires>
diff --git a/src/lib/entropy/proc_walk/info.txt b/src/lib/entropy/proc_walk/info.txt
new file mode 100644
index 000000000..2a53a7ed8
--- /dev/null
+++ b/src/lib/entropy/proc_walk/info.txt
@@ -0,0 +1,30 @@
+define ENTROPY_SRC_PROC_WALKER 20131128
+
+<source>
+proc_walk.cpp
+</source>
+
+<header:internal>
+proc_walk.h
+</header:internal>
+
+<os>
+aix
+cygwin
+darwin
+dragonfly
+freebsd
+hpux
+hurd
+irix
+linux
+netbsd
+openbsd
+qnx
+solaris
+tru64
+</os>
+
+<requires>
+alloc
+</requires>
diff --git a/src/lib/entropy/proc_walk/proc_walk.cpp b/src/lib/entropy/proc_walk/proc_walk.cpp
new file mode 100644
index 000000000..050d9dcf7
--- /dev/null
+++ b/src/lib/entropy/proc_walk/proc_walk.cpp
@@ -0,0 +1,173 @@
+/*
+* Entropy source based on reading files in /proc on the assumption
+* that a remote attacker will have difficulty guessing some of them.
+*
+* (C) 1999-2008,2012 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/internal/proc_walk.h>
+#include <botan/secmem.h>
+#include <cstring>
+#include <deque>
+
+#ifndef _POSIX_C_SOURCE
+ #define _POSIX_C_SOURCE 199309
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <fcntl.h>
+
+namespace Botan {
+
+/**
+* Returns file descriptors. Until it doesn't
+*/
+class File_Descriptor_Source
+ {
+ public:
+ /**
+ * @return next file descriptor, or -1 if done
+ */
+ virtual int next_fd() = 0;
+
+ virtual ~File_Descriptor_Source() {}
+ };
+
+namespace {
+
+class Directory_Walker : public File_Descriptor_Source
+ {
+ public:
+ Directory_Walker(const std::string& root) :
+ m_cur_dir(std::make_pair<DIR*, std::string>(nullptr, ""))
+ {
+ if(DIR* root_dir = ::opendir(root.c_str()))
+ m_cur_dir = std::make_pair(root_dir, root);
+ }
+
+ ~Directory_Walker()
+ {
+ if(m_cur_dir.first)
+ ::closedir(m_cur_dir.first);
+ }
+
+ int next_fd();
+ private:
+ void add_directory(const std::string& dirname)
+ {
+ m_dirlist.push_back(dirname);
+ }
+
+ std::pair<struct dirent*, std::string> get_next_dirent();
+
+ std::pair<DIR*, std::string> m_cur_dir;
+ std::deque<std::string> m_dirlist;
+ };
+
+std::pair<struct dirent*, std::string> Directory_Walker::get_next_dirent()
+ {
+ while(m_cur_dir.first)
+ {
+ if(struct dirent* dir = ::readdir(m_cur_dir.first))
+ return std::make_pair(dir, m_cur_dir.second);
+
+ ::closedir(m_cur_dir.first);
+ m_cur_dir = std::make_pair<DIR*, std::string>(nullptr, "");
+
+ while(!m_dirlist.empty() && !m_cur_dir.first)
+ {
+ const std::string next_dir_name = m_dirlist[0];
+ m_dirlist.pop_front();
+
+ if(DIR* next_dir = ::opendir(next_dir_name.c_str()))
+ m_cur_dir = std::make_pair(next_dir, next_dir_name);
+ }
+ }
+
+ return std::make_pair<struct dirent*, std::string>(nullptr, ""); // nothing left
+ }
+
+int Directory_Walker::next_fd()
+ {
+ while(true)
+ {
+ std::pair<struct dirent*, std::string> entry = get_next_dirent();
+
+ if(!entry.first)
+ break; // no more dirs
+
+ const std::string filename = entry.first->d_name;
+
+ if(filename == "." || filename == "..")
+ continue;
+
+ const std::string full_path = entry.second + '/' + filename;
+
+ struct stat stat_buf;
+ if(::lstat(full_path.c_str(), &stat_buf) == -1)
+ continue;
+
+ if(S_ISDIR(stat_buf.st_mode))
+ {
+ add_directory(full_path);
+ }
+ else if(S_ISREG(stat_buf.st_mode) && (stat_buf.st_mode & S_IROTH))
+ {
+ int fd = ::open(full_path.c_str(), O_RDONLY | O_NOCTTY);
+
+ if(fd > 0)
+ return fd;
+ }
+ }
+
+ return -1;
+ }
+
+}
+
+/**
+* ProcWalking_EntropySource Destructor
+*/
+ProcWalking_EntropySource::~ProcWalking_EntropySource()
+ {
+ // for ~unique_ptr
+ }
+
+void ProcWalking_EntropySource::poll(Entropy_Accumulator& accum)
+ {
+ const size_t MAX_FILES_READ_PER_POLL = 2048;
+
+ if(!m_dir)
+ m_dir = new Directory_Walker(m_path);
+
+ secure_vector<byte>& io_buffer = accum.get_io_buffer(4096);
+
+ for(size_t i = 0; i != MAX_FILES_READ_PER_POLL; ++i)
+ {
+ int fd = m_dir->next_fd();
+
+ // If we've exhaused this walk of the directory, halt the poll
+ if(fd == -1)
+ {
+ delete m_dir;
+ m_dir = nullptr;
+ break;
+ }
+
+ ssize_t got = ::read(fd, &io_buffer[0], io_buffer.size());
+ ::close(fd);
+
+ if(got > 0)
+ accum.add(&io_buffer[0], got, .001);
+
+ if(accum.polling_goal_achieved())
+ break;
+ }
+ }
+
+}
diff --git a/src/lib/entropy/proc_walk/proc_walk.h b/src/lib/entropy/proc_walk/proc_walk.h
new file mode 100644
index 000000000..04c3b1bba
--- /dev/null
+++ b/src/lib/entropy/proc_walk/proc_walk.h
@@ -0,0 +1,37 @@
+/*
+* File Tree Walking EntropySource
+* (C) 1999-2008 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_ENTROPY_SRC_PROC_WALK_H__
+#define BOTAN_ENTROPY_SRC_PROC_WALK_H__
+
+#include <botan/entropy_src.h>
+#include <memory>
+
+namespace Botan {
+
+/**
+* File Tree Walking Entropy Source
+*/
+class ProcWalking_EntropySource : public EntropySource
+ {
+ public:
+ std::string name() const { return "Proc Walker"; }
+
+ void poll(Entropy_Accumulator& accum);
+
+ ProcWalking_EntropySource(const std::string& root_dir) :
+ m_path(root_dir), m_dir(nullptr) {}
+
+ ~ProcWalking_EntropySource();
+ private:
+ const std::string m_path;
+ class File_Descriptor_Source* m_dir;
+ };
+
+}
+
+#endif
diff --git a/src/lib/entropy/rdrand/info.txt b/src/lib/entropy/rdrand/info.txt
new file mode 100644
index 000000000..546ab699a
--- /dev/null
+++ b/src/lib/entropy/rdrand/info.txt
@@ -0,0 +1,22 @@
+define ENTROPY_SRC_RDRAND 20131128
+
+need_isa rdrand
+
+<source>
+rdrand.cpp
+</source>
+
+<header:internal>
+rdrand.h
+</header:internal>
+
+<arch>
+x86_32
+x86_64
+</arch>
+
+<cc>
+gcc
+clang
+icc
+</cc>
diff --git a/src/lib/entropy/rdrand/rdrand.cpp b/src/lib/entropy/rdrand/rdrand.cpp
new file mode 100644
index 000000000..0dae697c8
--- /dev/null
+++ b/src/lib/entropy/rdrand/rdrand.cpp
@@ -0,0 +1,60 @@
+/*
+* Entropy Source Using Intel's rdrand instruction
+* (C) 2012 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/internal/rdrand.h>
+#include <botan/cpuid.h>
+
+#if !defined(BOTAN_USE_GCC_INLINE_ASM)
+ #include <immintrin.h>
+#endif
+
+namespace Botan {
+
+/*
+* Get the timestamp
+*/
+void Intel_Rdrand::poll(Entropy_Accumulator& accum)
+ {
+ if(!CPUID::has_rdrand())
+ return;
+
+ /*
+ * Put an upper bound on the total entropy we're willing to claim
+ * for any one polling of rdrand to prevent it from swamping our
+ * poll. Internally, the rdrand system is a DRGB that reseeds at a
+ * somewhat unpredictable rate (the current conditions are
+ * documented, but that might not be true for different
+ * implementations, eg on Haswell or a future AMD chip, so I don't
+ * want to assume). This limit ensures we're going to poll at least
+ * one other source so we have some diversity in our inputs.
+ */
+
+ const size_t POLL_UPPER_BOUND = 96;
+ const size_t RDRAND_POLLS = 32;
+ const double ENTROPY_PER_POLL =
+ static_cast<double>(POLL_UPPER_BOUND) / (RDRAND_POLLS * 4);
+
+ for(size_t i = 0; i != RDRAND_POLLS; ++i)
+ {
+ unsigned int r = 0;
+
+#if BOTAN_USE_GCC_INLINE_ASM
+ int cf = 0;
+
+ // 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);
+#endif
+
+ if(cf == 1)
+ accum.add(r, ENTROPY_PER_POLL);
+ }
+ }
+
+}
diff --git a/src/lib/entropy/rdrand/rdrand.h b/src/lib/entropy/rdrand/rdrand.h
new file mode 100644
index 000000000..d7629d37f
--- /dev/null
+++ b/src/lib/entropy/rdrand/rdrand.h
@@ -0,0 +1,28 @@
+/*
+* Entropy Source Using Intel's rdrand instruction
+* (C) 2012 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_ENTROPY_SRC_RDRAND_H__
+#define BOTAN_ENTROPY_SRC_RDRAND_H__
+
+#include <botan/entropy_src.h>
+
+namespace Botan {
+
+/**
+* Entropy source using the rdrand instruction first introduced on
+* Intel's Ivy Bridge architecture.
+*/
+class Intel_Rdrand : public EntropySource
+ {
+ public:
+ std::string name() const { return "Intel Rdrand"; }
+ void poll(Entropy_Accumulator& accum);
+ };
+
+}
+
+#endif
diff --git a/src/lib/entropy/unix_procs/info.txt b/src/lib/entropy/unix_procs/info.txt
new file mode 100644
index 000000000..755d2565d
--- /dev/null
+++ b/src/lib/entropy/unix_procs/info.txt
@@ -0,0 +1,25 @@
+define ENTROPY_SRC_UNIX_PROCESS_RUNNER 20131128
+
+<source>
+unix_procs.cpp
+unix_proc_sources.cpp
+</source>
+
+<header:internal>
+unix_procs.h
+</header:internal>
+
+<os>
+aix
+cygwin
+darwin
+freebsd
+haiku
+hpux
+irix
+linux
+netbsd
+qnx
+solaris
+tru64
+</os>
diff --git a/src/lib/entropy/unix_procs/unix_proc_sources.cpp b/src/lib/entropy/unix_procs/unix_proc_sources.cpp
new file mode 100644
index 000000000..6cf185064
--- /dev/null
+++ b/src/lib/entropy/unix_procs/unix_proc_sources.cpp
@@ -0,0 +1,65 @@
+/*
+* Program List for Unix_EntropySource
+* (C) 1999-2007 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/internal/unix_procs.h>
+
+namespace Botan {
+
+/**
+* Default Commands for Entropy Gathering
+*/
+std::vector<std::vector<std::string>> Unix_EntropySource::get_default_sources()
+ {
+ std::vector<std::vector<std::string>> srcs;
+
+ srcs.push_back({ "netstat", "-in" });
+ srcs.push_back({ "pfstat" });
+ srcs.push_back({ "vmstat", "-s" });
+ srcs.push_back({ "vmstat" });
+
+ srcs.push_back({ "arp", "-a", "-n" });
+ srcs.push_back({ "ifconfig", "-a" });
+ srcs.push_back({ "iostat" });
+ srcs.push_back({ "ipcs", "-a" });
+ srcs.push_back({ "mpstat" });
+ srcs.push_back({ "netstat", "-an" });
+ srcs.push_back({ "netstat", "-s" });
+ srcs.push_back({ "nfsstat" });
+ srcs.push_back({ "portstat" });
+ srcs.push_back({ "procinfo", "-a" });
+ srcs.push_back({ "pstat", "-T" });
+ srcs.push_back({ "pstat", "-s" });
+ srcs.push_back({ "uname", "-a" });
+ srcs.push_back({ "uptime" });
+
+ srcs.push_back({ "listarea" });
+ srcs.push_back({ "listdev" });
+ srcs.push_back({ "ps", "-A" });
+ srcs.push_back({ "sysinfo" });
+
+ srcs.push_back({ "finger" });
+ srcs.push_back({ "mailstats" });
+ srcs.push_back({ "rpcinfo", "-p", "localhost" });
+ srcs.push_back({ "who" });
+
+ srcs.push_back({ "df", "-l" });
+ srcs.push_back({ "dmesg" });
+ srcs.push_back({ "last", "-5" });
+ srcs.push_back({ "ls", "-alni", "/proc" });
+ srcs.push_back({ "ls", "-alni", "/tmp" });
+ srcs.push_back({ "pstat", "-f" });
+
+ srcs.push_back({ "ps", "-elf" });
+ srcs.push_back({ "ps", "aux" });
+
+ srcs.push_back({ "lsof", "-n" });
+ srcs.push_back({ "sar", "-A" });
+
+ return srcs;
+ }
+
+}
diff --git a/src/lib/entropy/unix_procs/unix_procs.cpp b/src/lib/entropy/unix_procs/unix_procs.cpp
new file mode 100644
index 000000000..c36941f43
--- /dev/null
+++ b/src/lib/entropy/unix_procs/unix_procs.cpp
@@ -0,0 +1,258 @@
+ /*
+* Gather entropy by running various system commands in the hopes that
+* some of the output cannot be guessed by a remote attacker.
+*
+* (C) 1999-2009,2013 Jack Lloyd
+* 2012 Markus Wanner
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/internal/unix_procs.h>
+#include <botan/parsing.h>
+#include <algorithm>
+
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/resource.h>
+#include <unistd.h>
+#include <signal.h>
+#include <stdlib.h>
+
+namespace Botan {
+
+namespace {
+
+std::string find_full_path_if_exists(const std::vector<std::string>& trusted_path,
+ const std::string& proc)
+ {
+ for(auto dir : trusted_path)
+ {
+ const std::string full_path = dir + "/" + proc;
+ if(::access(full_path.c_str(), X_OK) == 0)
+ return full_path;
+ }
+
+ return "";
+ }
+
+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;
+
+ const long online_cpus = ::sysconf(_SC_NPROCESSORS_ONLN);
+
+ if(online_cpus > 0)
+ return static_cast<size_t>(online_cpus); // maybe fewer?
+
+ return DEFAULT_CONCURRENT;
+ }
+
+}
+
+/**
+* Unix_EntropySource Constructor
+*/
+Unix_EntropySource::Unix_EntropySource(const std::vector<std::string>& trusted_path,
+ size_t proc_cnt) :
+ m_trusted_paths(trusted_path),
+ m_concurrent(concurrent_processes(proc_cnt))
+ {
+ }
+
+void UnixProcessInfo_EntropySource::poll(Entropy_Accumulator& accum)
+ {
+ accum.add(::getpid(), 0.0);
+ accum.add(::getppid(), 0.0);
+ accum.add(::getuid(), 0.0);
+ accum.add(::getgid(), 0.0);
+ accum.add(::getsid(0), 0.0);
+ accum.add(::getpgrp(), 0.0);
+
+ struct ::rusage usage;
+ ::getrusage(RUSAGE_SELF, &usage);
+ accum.add(usage, 0.0);
+
+ ::getrusage(RUSAGE_CHILDREN, &usage);
+ accum.add(usage, 0.0);
+ }
+
+namespace {
+
+void do_exec(const std::vector<std::string>& args)
+ {
+ // cleaner way to do this?
+ const char* arg0 = (args.size() > 0) ? args[0].c_str() : nullptr;
+ const char* arg1 = (args.size() > 1) ? args[1].c_str() : nullptr;
+ const char* arg2 = (args.size() > 2) ? args[2].c_str() : nullptr;
+ const char* arg3 = (args.size() > 3) ? args[3].c_str() : nullptr;
+ const char* arg4 = (args.size() > 4) ? args[4].c_str() : nullptr;
+
+ ::execl(arg0, arg0, arg1, arg2, arg3, arg4, NULL);
+ }
+
+}
+
+void Unix_EntropySource::Unix_Process::spawn(const std::vector<std::string>& args)
+ {
+ shutdown();
+
+ int pipe[2];
+ if(::pipe(pipe) != 0)
+ return;
+
+ pid_t pid = ::fork();
+
+ if(pid == -1)
+ {
+ ::close(pipe[0]);
+ ::close(pipe[1]);
+ }
+ else if(pid > 0) // in parent
+ {
+ m_pid = pid;
+ m_fd = pipe[0];
+ ::close(pipe[1]);
+ }
+ else // in child
+ {
+ if(::dup2(pipe[1], STDOUT_FILENO) == -1)
+ ::exit(127);
+ if(::close(pipe[0]) != 0 || ::close(pipe[1]) != 0)
+ ::exit(127);
+ if(close(STDERR_FILENO) != 0)
+ ::exit(127);
+
+ do_exec(args);
+ ::exit(127);
+ }
+ }
+
+void Unix_EntropySource::Unix_Process::shutdown()
+ {
+ if(m_pid == -1)
+ return;
+
+ ::close(m_fd);
+ m_fd = -1;
+
+ pid_t reaped = waitpid(m_pid, nullptr, WNOHANG);
+
+ if(reaped == 0)
+ {
+ /*
+ * Child is still alive - send it SIGTERM, sleep for a bit and
+ * try to reap again, if still alive send SIGKILL
+ */
+ kill(m_pid, SIGTERM);
+
+ struct ::timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 1000;
+ select(0, nullptr, nullptr, nullptr, &tv);
+
+ reaped = ::waitpid(m_pid, nullptr, WNOHANG);
+
+ if(reaped == 0)
+ {
+ ::kill(m_pid, SIGKILL);
+ do
+ reaped = ::waitpid(m_pid, nullptr, 0);
+ while(reaped == -1);
+ }
+ }
+
+ m_pid = -1;
+ }
+
+const std::vector<std::string>& Unix_EntropySource::next_source()
+ {
+ const auto& src = m_sources.at(m_sources_idx);
+ m_sources_idx = (m_sources_idx + 1) % m_sources.size();
+ return src;
+ }
+
+void Unix_EntropySource::poll(Entropy_Accumulator& accum)
+ {
+ // refuse to run as root (maybe instead setuid to nobody before exec?)
+ // fixme: this should also check for setgid
+ if(::getuid() == 0 || ::geteuid() == 0)
+ return;
+
+ if(m_sources.empty())
+ {
+ auto sources = get_default_sources();
+
+ for(auto src : sources)
+ {
+ const std::string path = find_full_path_if_exists(m_trusted_paths, src[0]);
+ if(path != "")
+ {
+ src[0] = path;
+ m_sources.push_back(src);
+ }
+ }
+ }
+
+ if(m_sources.empty())
+ return; // still empty, really nothing to try
+
+ const size_t MS_WAIT_TIME = 32;
+ const double ENTROPY_ESTIMATE = 1.0 / 1024;
+
+ secure_vector<byte>& io_buffer = accum.get_io_buffer(4*1024); // page
+
+ while(!accum.polling_goal_achieved())
+ {
+ while(m_procs.size() < m_concurrent)
+ m_procs.emplace_back(Unix_Process(next_source()));
+
+ fd_set read_set;
+ FD_ZERO(&read_set);
+
+ std::vector<int> fds;
+
+ for(auto& proc : m_procs)
+ {
+ int fd = proc.fd();
+ if(fd > 0)
+ {
+ fds.push_back(fd);
+ FD_SET(fd, &read_set);
+ }
+ }
+
+ if(fds.empty())
+ break;
+
+ const int max_fd = *std::max_element(fds.begin(), fds.end());
+
+ struct ::timeval timeout;
+ timeout.tv_sec = (MS_WAIT_TIME / 1000);
+ timeout.tv_usec = (MS_WAIT_TIME % 1000) * 1000;
+
+ if(::select(max_fd + 1, &read_set, nullptr, nullptr, &timeout) < 0)
+ return; // or continue?
+
+ for(auto& proc : m_procs)
+ {
+ int fd = proc.fd();
+
+ if(FD_ISSET(fd, &read_set))
+ {
+ const ssize_t got = ::read(fd, &io_buffer[0], io_buffer.size());
+ if(got > 0)
+ accum.add(&io_buffer[0], got, ENTROPY_ESTIMATE);
+ else
+ proc.spawn(next_source());
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/lib/entropy/unix_procs/unix_procs.h b/src/lib/entropy/unix_procs/unix_procs.h
new file mode 100644
index 000000000..7c1ae8c65
--- /dev/null
+++ b/src/lib/entropy/unix_procs/unix_procs.h
@@ -0,0 +1,89 @@
+/*
+* Unix EntropySource
+* (C) 1999-2009,2013 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_ENTROPY_SRC_UNIX_H__
+#define BOTAN_ENTROPY_SRC_UNIX_H__
+
+#include <botan/entropy_src.h>
+#include <vector>
+#include <sys/types.h>
+
+namespace Botan {
+
+/**
+* Entropy source for generic Unix. Runs various programs trying to
+* gather data hard for a remote attacker to guess. Probably not too
+* effective against local attackers as they can sample from the same
+* distribution.
+*/
+class Unix_EntropySource : public EntropySource
+ {
+ public:
+ std::string name() const { return "Unix Process Runner"; }
+
+ void poll(Entropy_Accumulator& accum) override;
+
+ /**
+ * @param trusted_paths is a list of directories that are assumed
+ * to contain only 'safe' binaries. If an attacker can write
+ * an executable to one of these directories then we will
+ * run arbitrary code.
+ */
+ Unix_EntropySource(const std::vector<std::string>& trusted_paths,
+ size_t concurrent_processes = 0);
+ private:
+ static std::vector<std::vector<std::string>> get_default_sources();
+
+ class Unix_Process
+ {
+ public:
+ int fd() const { return m_fd; }
+
+ void spawn(const std::vector<std::string>& args);
+ void shutdown();
+
+ Unix_Process() {}
+
+ Unix_Process(const std::vector<std::string>& args) { spawn(args); }
+
+ ~Unix_Process() { shutdown(); }
+
+ Unix_Process(Unix_Process&& other)
+ {
+ std::swap(m_fd, other.m_fd);
+ std::swap(m_pid, other.m_pid);
+ }
+
+ Unix_Process(const Unix_Process&) = delete;
+ Unix_Process& operator=(const Unix_Process&) = delete;
+ private:
+ int m_fd = -1;
+ pid_t m_pid = -1;
+ };
+
+ const std::vector<std::string>& next_source();
+
+ const std::vector<std::string> m_trusted_paths;
+ const size_t m_concurrent;
+
+ std::vector<std::vector<std::string>> m_sources;
+ size_t m_sources_idx = 0;
+
+ std::vector<Unix_Process> m_procs;
+ };
+
+class UnixProcessInfo_EntropySource : public EntropySource
+ {
+ public:
+ std::string name() const { return "Unix Process Info"; }
+
+ void poll(Entropy_Accumulator& accum);
+ };
+
+}
+
+#endif
diff --git a/src/lib/entropy/win32_stats/es_win32.cpp b/src/lib/entropy/win32_stats/es_win32.cpp
new file mode 100644
index 000000000..fff11592d
--- /dev/null
+++ b/src/lib/entropy/win32_stats/es_win32.cpp
@@ -0,0 +1,118 @@
+/*
+* Win32 EntropySource
+* (C) 1999-2009 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/internal/es_win32.h>
+#include <windows.h>
+#include <tlhelp32.h>
+
+namespace Botan {
+
+/**
+* Win32 poll using stats functions including Tooltip32
+*/
+void Win32_EntropySource::poll(Entropy_Accumulator& accum)
+ {
+ /*
+ First query a bunch of basic statistical stuff, though
+ don't count it for much in terms of contributed entropy.
+ */
+ accum.add(GetTickCount(), 0);
+ accum.add(GetMessagePos(), 0);
+ accum.add(GetMessageTime(), 0);
+ accum.add(GetInputState(), 0);
+ accum.add(GetCurrentProcessId(), 0);
+ accum.add(GetCurrentThreadId(), 0);
+
+ SYSTEM_INFO sys_info;
+ GetSystemInfo(&sys_info);
+ accum.add(sys_info, 1);
+
+ MEMORYSTATUS mem_info;
+ GlobalMemoryStatus(&mem_info);
+ accum.add(mem_info, 1);
+
+ POINT point;
+ GetCursorPos(&point);
+ accum.add(point, 1);
+
+ GetCaretPos(&point);
+ accum.add(point, 1);
+
+ LARGE_INTEGER perf_counter;
+ QueryPerformanceCounter(&perf_counter);
+ accum.add(perf_counter, 0);
+
+ /*
+ Now use the Tooltip library to iterate throug various objects on
+ the system, including processes, threads, and heap objects.
+ */
+
+ HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
+
+#define TOOLHELP32_ITER(DATA_TYPE, FUNC_FIRST, FUNC_NEXT) \
+ if(!accum.polling_goal_achieved()) \
+ { \
+ DATA_TYPE info; \
+ info.dwSize = sizeof(DATA_TYPE); \
+ if(FUNC_FIRST(snapshot, &info)) \
+ { \
+ do \
+ { \
+ accum.add(info, 1); \
+ } while(FUNC_NEXT(snapshot, &info)); \
+ } \
+ }
+
+ TOOLHELP32_ITER(MODULEENTRY32, Module32First, Module32Next);
+ TOOLHELP32_ITER(PROCESSENTRY32, Process32First, Process32Next);
+ TOOLHELP32_ITER(THREADENTRY32, Thread32First, Thread32Next);
+
+#undef TOOLHELP32_ITER
+
+ if(!accum.polling_goal_achieved())
+ {
+ size_t heap_lists_found = 0;
+ 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))
+ {
+ do
+ {
+ accum.add(heap_list, 1);
+
+ if(++heap_lists_found > HEAP_LISTS_MAX)
+ break;
+
+ size_t heap_objs_found = 0;
+ HEAPENTRY32 heap_entry;
+ heap_entry.dwSize = sizeof(HEAPENTRY32);
+ if(Heap32First(&heap_entry, heap_list.th32ProcessID,
+ heap_list.th32HeapID))
+ {
+ do
+ {
+ if(heap_objs_found++ > HEAP_OBJS_PER_LIST)
+ break;
+ accum.add(heap_entry, 1);
+ } while(Heap32Next(&heap_entry));
+ }
+
+ if(accum.polling_goal_achieved())
+ break;
+
+ } while(Heap32ListNext(snapshot, &heap_list));
+ }
+ }
+
+ CloseHandle(snapshot);
+ }
+
+}
diff --git a/src/lib/entropy/win32_stats/es_win32.h b/src/lib/entropy/win32_stats/es_win32.h
new file mode 100644
index 000000000..6c7c9ee09
--- /dev/null
+++ b/src/lib/entropy/win32_stats/es_win32.h
@@ -0,0 +1,27 @@
+/*
+* Win32 EntropySource
+* (C) 1999-2009 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_ENTROPY_SRC_WIN32_H__
+#define BOTAN_ENTROPY_SRC_WIN32_H__
+
+#include <botan/entropy_src.h>
+
+namespace Botan {
+
+/**
+* Win32 Entropy Source
+*/
+class Win32_EntropySource : public EntropySource
+ {
+ public:
+ std::string name() const { return "Win32 Statistics"; }
+ void poll(Entropy_Accumulator& accum);
+ };
+
+}
+
+#endif
diff --git a/src/lib/entropy/win32_stats/info.txt b/src/lib/entropy/win32_stats/info.txt
new file mode 100644
index 000000000..48eb91faa
--- /dev/null
+++ b/src/lib/entropy/win32_stats/info.txt
@@ -0,0 +1,19 @@
+define ENTROPY_SRC_WIN32 20131128
+
+<source>
+es_win32.cpp
+</source>
+
+<header:internal>
+es_win32.h
+</header:internal>
+
+<os>
+windows
+cygwin
+mingw
+</os>
+
+<libs>
+windows -> user32.lib
+</libs>