diff options
Diffstat (limited to 'src/lib/entropy')
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> |