diff options
37 files changed, 700 insertions, 776 deletions
diff --git a/checks/common.h b/checks/common.h index ac3daaf76..fa41882ee 100644 --- a/checks/common.h +++ b/checks/common.h @@ -67,6 +67,8 @@ class Fixed_Output_RNG : public Botan::RandomNumberGenerator return out; } + void reseed(u32bit) {} + void randomize(byte out[], u32bit len) { for(u32bit j = 0; j != len; j++) diff --git a/doc/examples/test_es.cpp b/doc/examples/test_es.cpp index 18531b326..cae47a853 100644 --- a/doc/examples/test_es.cpp +++ b/doc/examples/test_es.cpp @@ -32,30 +32,36 @@ using namespace Botan; -void test_entropy_source(EntropySource* es) +void test_entropy_source(EntropySource* es, + EntropySource* es2 = 0) { // sometimes iostreams really is just a pain - // upper buffer size of 96 to match HMAC_RNG's - byte buf[96] = { 0 }; - printf("Polling '%s':\n", es->name().c_str()); - printf(" Fast poll... "); - u32bit fast_poll_got = es->fast_poll(buf, sizeof(buf)); - printf("got %d bytes: ", fast_poll_got); - for(u32bit i = 0; i != fast_poll_got; ++i) - printf("%02X", buf[i]); - printf("\n"); + Entropy_Accumulator accum1(256); + es->poll(accum1); + + Entropy_Accumulator accum2(256); + if(es2) + es2->poll(accum2); + else + es->poll(accum2); + + SecureVector<byte> polled1 = accum1.get_entropy_buffer(); + SecureVector<byte> polled2 = accum2.get_entropy_buffer(); + + SecureVector<byte> compare(std::min(polled1.size(), polled2.size())); + + for(u32bit i = 0; i != compare.size(); ++i) + compare[i] = polled1[i] ^ polled2[i]; - printf(" Slow poll... "); - u32bit slow_poll_got = es->slow_poll(buf, sizeof(buf)); - printf("got %d bytes: ", slow_poll_got); - for(u32bit i = 0; i != slow_poll_got; ++i) - printf("%02X", buf[i]); + for(u32bit i = 0; i != compare.size(); ++i) + printf("%02X", compare[i]); printf("\n"); delete es; + delete es2; } int main() @@ -81,7 +87,8 @@ int main() #endif #if defined(BOTAN_HAS_ENTROPY_SRC_FTW) - test_entropy_source(new FTW_EntropySource("/proc")); + test_entropy_source(new FTW_EntropySource("/proc"), + new FTW_EntropySource("/proc")); #endif diff --git a/doc/license.txt b/doc/license.txt index 0f281171c..4c3fc1999 100644 --- a/doc/license.txt +++ b/doc/license.txt @@ -1,4 +1,4 @@ -Copyright (C) 1999-2008 Jack Lloyd +Copyright (C) 1999-2009 Jack Lloyd 2001 Peter J Jones 2004-2007 Justin Karneges 2005 Matthew Gregan diff --git a/src/entropy/beos_stats/es_beos.cpp b/src/entropy/beos_stats/es_beos.cpp index b5a5e7fee..d7c0c6cd6 100644 --- a/src/entropy/beos_stats/es_beos.cpp +++ b/src/entropy/beos_stats/es_beos.cpp @@ -4,7 +4,6 @@ */ #include <botan/es_beos.h> -#include <botan/xor_buf.h> #include <kernel/OS.h> #include <kernel/image.h> @@ -13,69 +12,49 @@ namespace Botan { /** -* BeOS Fast Poll +* BeOS entropy poll */ -u32bit BeOS_EntropySource::fast_poll(byte buf[], u32bit length) +void BeOS_EntropySource::poll(Entropy_Accumulator& accum) { - if(length == 0) - return 0; - length = std::min<u32bit>(length, 32); - - u32bit buf_i = 0; - system_info info_sys; get_system_info(&info_sys); - buf_i = xor_into_buf(buf, buf_i, length, info_sys); + accum.add(info_sys, 2); - key_info info_key; + key_info info_key; // current state of the keyboard get_key_info(&info_key); - buf_i = xor_into_buf(buf, buf_i, length, key_info); + accum.add(info_key, 0); - buf_i = xor_into_buf(buf, buf_i, length, idle_time()); + accum.add(idle_time(), 0); - return length; - } - -/** -* BeOS slow poll -*/ -u32bit BeOS_EntropySource::slow_poll(byte buf[], u32bit length) - { - if(length == 0) - return 0; - - u32bit buf_i = 0; team_info info_team; int32 cookie_team = 0; while(get_next_team_info(&cookie_team, &info_team) == B_OK) { - buf_i = xor_into_buf(buf, buf_i, length, info_team); + 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) - buf_i = xor_into_buf(buf, buf_i, length, info_thr); + accum.add(info_thr, 1); cookie = 0; image_info info_img; while(get_next_image_info(id, &cookie, &info_img) == B_OK) - buf_i = xor_into_buf(buf, buf_i, length, info_img); + accum.add(info_img, 1); cookie = 0; sem_info info_sem; while(get_next_sem_info(id, &cookie, &info_sem) == B_OK) - buf_i = xor_into_buf(buf, buf_i, length, info_sem); + accum.add(info_sem, 1); cookie = 0; area_info info_area; while(get_next_area_info(id, &cookie, &info_area) == B_OK) - buf_i = xor_into_buf(buf, buf_i, length, info_area); + accum.add(info_area, 2); } - - return length; } } diff --git a/src/entropy/beos_stats/es_beos.h b/src/entropy/beos_stats/es_beos.h index 686ac5c38..0ae670e94 100644 --- a/src/entropy/beos_stats/es_beos.h +++ b/src/entropy/beos_stats/es_beos.h @@ -18,8 +18,7 @@ class BOTAN_DLL BeOS_EntropySource : public EntropySource private: std::string name() const { return "BeOS Statistics"; } - u32bit fast_poll(byte buf[], u32bit length); - u32bit slow_poll(byte buf[], u32bit length); + void poll(Entropy_Accumulator& accum); }; } diff --git a/src/entropy/cryptoapi_rng/es_capi.cpp b/src/entropy/cryptoapi_rng/es_capi.cpp index ca0e1b95e..7cc4d015b 100644 --- a/src/entropy/cryptoapi_rng/es_capi.cpp +++ b/src/entropy/cryptoapi_rng/es_capi.cpp @@ -1,7 +1,7 @@ -/************************************************* -* Win32 CryptoAPI EntropySource Source File * -* (C) 1999-2007 Jack Lloyd * -*************************************************/ +/* +* Win32 CryptoAPI EntropySource +* (C) 1999-2009 Jack Lloyd +*/ #include <botan/es_capi.h> #include <botan/parsing.h> @@ -10,71 +10,68 @@ namespace Botan { -/** -* Gather Entropy from Win32 CAPI -*/ -u32bit Win32_CAPI_EntropySource::slow_poll(byte output[], u32bit length) +namespace { + +class CSP_Handle { - return fast_poll(output, length); - } + 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); + } + + u32bit gen_random(byte out[], u32bit n) const + { + if(is_valid() && CryptGenRandom(handle, 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 */ -u32bit Win32_CAPI_EntropySource::fast_poll(byte output[], u32bit length) +void Win32_CAPI_EntropySource::poll(Entropy_Accumulator& accum) { - 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); - } - - void gen_random(byte out[], u32bit n) const - { - if(is_valid()) - CryptGenRandom(handle, n, out); - } - - bool is_valid() const { return valid; } - - HCRYPTPROV get_handle() const { return handle; } - private: - HCRYPTPROV handle; - bool valid; - }; - - - if(length > 64) - length = 64; + MemoryRegion<byte>& io_buffer = accum.get_io_buffer(32); for(u32bit j = 0; j != prov_types.size(); ++j) { CSP_Handle csp(prov_types[j]); - if(!csp.is_valid()) - continue; - csp.gen_random(output, length); - break; + u32bit got = csp.gen_random(io_buffer.begin(), io_buffer.length()); + + if(got) + { + accum.add(io_buffer.begin(), io_buffer.length(), 8); + break; + } } - return length; } -/************************************************* -* Gather Entropy from Win32 CAPI * -*************************************************/ +/** +* Win32_Capi_Entropysource Constructor +*/ Win32_CAPI_EntropySource::Win32_CAPI_EntropySource(const std::string& provs) { std::vector<std::string> capi_provs = split_on(provs, ':'); diff --git a/src/entropy/cryptoapi_rng/es_capi.h b/src/entropy/cryptoapi_rng/es_capi.h index b8bbb7507..d727de5dd 100644 --- a/src/entropy/cryptoapi_rng/es_capi.h +++ b/src/entropy/cryptoapi_rng/es_capi.h @@ -11,16 +11,15 @@ namespace Botan { -/************************************************* -* Win32 CAPI Entropy Source * -*************************************************/ +/** +* Win32 CAPI Entropy Source +*/ class BOTAN_DLL Win32_CAPI_EntropySource : public EntropySource { public: std::string name() const { return "Win32 CryptoGenRandom"; } - u32bit fast_poll(byte[], u32bit); - u32bit slow_poll(byte[], u32bit); + void poll(Entropy_Accumulator& accum); Win32_CAPI_EntropySource(const std::string& = ""); private: diff --git a/src/entropy/dev_random/es_dev.cpp b/src/entropy/dev_random/es_dev.cpp index 7b936dbaa..60e1a4df6 100644 --- a/src/entropy/dev_random/es_dev.cpp +++ b/src/entropy/dev_random/es_dev.cpp @@ -1,7 +1,7 @@ -/************************************************* -* Device EntropySource Source File * -* (C) 1999-2008 Jack Lloyd * -*************************************************/ +/* +* /dev/random EntropySource +* (C) 1999-2009 Jack Lloyd +*/ #include <botan/es_dev.h> @@ -79,6 +79,7 @@ Device_EntropySource::Device_Reader::open(const std::string& pathname) /** Device_EntropySource constructor +Open a file descriptor to each (available) device in fsnames */ Device_EntropySource::Device_EntropySource( const std::vector<std::string>& fsnames) @@ -92,41 +93,36 @@ Device_EntropySource::Device_EntropySource( } /** -* Gather entropy from a RNG device +Device_EntropySource destructor: close all open devices */ -u32bit Device_EntropySource::slow_poll(byte output[], u32bit length) +Device_EntropySource::~Device_EntropySource() { for(size_t i = 0; i != devices.size(); ++i) - { - const u32bit got = devices[i].get(output, length, 20); - - if(got) - return got; - } - - return 0; + devices[i].close(); } /** -* Fast poll: try limit to 10 ms wait +* Gather entropy from a RNG device */ -u32bit Device_EntropySource::fast_poll(byte output[], u32bit length) +void Device_EntropySource::poll(Entropy_Accumulator& accum) { + const u32bit MAX_READ_WAIT_MILLISECONDS = 50; + + u32bit go_get = std::min<u32bit>(accum.desired_remaining_bits() / 8, 32); + + MemoryRegion<byte>& io_buffer = accum.get_io_buffer(go_get); + for(size_t i = 0; i != devices.size(); ++i) { - const u32bit got = devices[i].get(output, length, 5); + u32bit got = devices[i].get(io_buffer.begin(), io_buffer.size(), + MAX_READ_WAIT_MILLISECONDS); if(got) - return got; + { + accum.add(io_buffer.begin(), got, 8); + break; + } } - - return 0; - } - -Device_EntropySource::~Device_EntropySource() - { - for(size_t i = 0; i != devices.size(); ++i) - devices[i].close(); } } diff --git a/src/entropy/dev_random/es_dev.h b/src/entropy/dev_random/es_dev.h index db64b75fa..139f8ec52 100644 --- a/src/entropy/dev_random/es_dev.h +++ b/src/entropy/dev_random/es_dev.h @@ -1,7 +1,7 @@ -/************************************************* -* Device EntropySource Header File * -* (C) 1999-2007 Jack Lloyd * -*************************************************/ +/* +* /dev/random EntropySource +* (C) 1999-2009 Jack Lloyd +*/ #ifndef BOTAN_ENTROPY_SRC_DEVICE_H__ #define BOTAN_ENTROPY_SRC_DEVICE_H__ @@ -12,19 +12,15 @@ namespace Botan { -/************************************************* -* Device Based Entropy Source * -*************************************************/ class BOTAN_DLL 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(); - - u32bit slow_poll(byte[], u32bit); - u32bit fast_poll(byte[], u32bit); private: /** diff --git a/src/entropy/egd/es_egd.cpp b/src/entropy/egd/es_egd.cpp index 84773c215..17e366f2b 100644 --- a/src/entropy/egd/es_egd.cpp +++ b/src/entropy/egd/es_egd.cpp @@ -1,6 +1,6 @@ -/** +/* * EGD EntropySource Source File -* (C) 1999-2008 Jack Lloyd +* (C) 1999-2009 Jack Lloyd */ #include <botan/es_egd.h> @@ -8,6 +8,7 @@ #include <botan/parsing.h> #include <botan/exceptn.h> #include <cstring> +#include <stdexcept> #include <sys/types.h> #include <sys/stat.h> @@ -23,28 +24,86 @@ namespace Botan { -EGD_EntropySource::EGD_Socket::EGD_Socket(const std::string& path) +EGD_EntropySource::EGD_Socket::EGD_Socket(const std::string& path) : + socket_path(path), m_fd(-1) { - m_fd = ::socket(PF_LOCAL, SOCK_STREAM, 0); + } - if(m_fd > 0) +/** +* 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 Exception("EGD_EntropySource: Socket path is too long"); + throw std::invalid_argument("EGD socket path is too long"); + std::strcpy(addr.sun_path, path.c_str()); int len = sizeof(addr.sun_family) + std::strlen(addr.sun_path) + 1; - if(::connect(m_fd, reinterpret_cast<struct ::sockaddr*>(&addr), len) < 0) + if(::connect(fd, reinterpret_cast<struct ::sockaddr*>(&addr), len) < 0) { - ::close(m_fd); - m_fd = -1; + ::close(fd); + fd = -1; } } + + return fd; + } + +/** +* Attempt to read entropy from EGD +*/ +u32bit EGD_EntropySource::EGD_Socket::read(byte outbuf[], u32bit 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<u32bit>(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 recieved 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<u32bit>(count); + } + catch(std::exception& e) + { + this->close(); + // Will attempt to reopen next poll + } + + return 0; } void EGD_EntropySource::EGD_Socket::close() @@ -62,12 +121,7 @@ void EGD_EntropySource::EGD_Socket::close() EGD_EntropySource::EGD_EntropySource(const std::vector<std::string>& paths) { for(size_t i = 0; i != paths.size(); ++i) - { - EGD_Socket sock(paths[i]); - - if(sock.fd() != -1) - sockets.push_back(sock); - } + sockets.push_back(EGD_Socket(paths[i])); } EGD_EntropySource::~EGD_EntropySource() @@ -80,46 +134,22 @@ EGD_EntropySource::~EGD_EntropySource() /** * Gather Entropy from EGD */ -u32bit EGD_EntropySource::slow_poll(byte output[], u32bit length) +void EGD_EntropySource::poll(Entropy_Accumulator& accum) { - if(length > 128) - length = 128; + u32bit go_get = std::min<u32bit>(accum.desired_remaining_bits() / 8, 32); + + MemoryRegion<byte>& io_buffer = accum.get_io_buffer(go_get); for(size_t i = 0; i != sockets.size(); ++i) { - EGD_Socket& socket = sockets[i]; + u32bit got = sockets[i].read(io_buffer.begin(), io_buffer.size()); - byte buffer[2]; - buffer[0] = 1; - buffer[1] = static_cast<byte>(length); - - if(::write(socket.fd(), buffer, 2) != 2) - return 0; - - byte out_len = 0; - if(::read(socket.fd(), &out_len, 1) != 1) - return 0; - - if(out_len > length) - return 0; - - ssize_t count = ::read(socket.fd(), output, out_len); - - if(count < 0) - return 0; - - return static_cast<u32bit>(count); + if(got) + { + accum.add(io_buffer.begin(), got, 8); + break; + } } - - return 0; - } - -/** -* Gather Entropy from EGD, limiting to 64 bytes -*/ -u32bit EGD_EntropySource::fast_poll(byte output[], u32bit length) - { - return slow_poll(output, std::min<u32bit>(length, 64)); } } diff --git a/src/entropy/egd/es_egd.h b/src/entropy/egd/es_egd.h index de80374cc..5fb09fc57 100644 --- a/src/entropy/egd/es_egd.h +++ b/src/entropy/egd/es_egd.h @@ -20,8 +20,7 @@ class BOTAN_DLL EGD_EntropySource : public EntropySource public: std::string name() const { return "EGD/PRNGD"; } - u32bit fast_poll(byte[], u32bit); - u32bit slow_poll(byte[], u32bit); + void poll(Entropy_Accumulator& accum); EGD_EntropySource(const std::vector<std::string>&); ~EGD_EntropySource(); @@ -32,9 +31,12 @@ class BOTAN_DLL EGD_EntropySource : public EntropySource EGD_Socket(const std::string& path); void close(); - int fd() const { return m_fd; } + u32bit read(byte outbuf[], u32bit length); private: - int m_fd; + static int open_socket(const std::string& path); + + std::string socket_path; + int m_fd; // cached fd }; std::vector<EGD_Socket> sockets; diff --git a/src/entropy/entropy_acc.cpp b/src/entropy/entropy_acc.cpp new file mode 100644 index 000000000..9dc0f1405 --- /dev/null +++ b/src/entropy/entropy_acc.cpp @@ -0,0 +1,87 @@ +/** +* Entropy Accumulator +* (C) 1999-2009 Jack Lloyd +*/ + +#include <botan/entropy_src.h> + +namespace Botan { + +void Entropy_Accumulator::reset_goal(u32bit entropy_goal) + { + goal_bits = entropy_goal; + collected_bits = 0; + + /* + * The buffer is large enough to hold 2*goal_bits of entropy, + * or 128 bits, whichever is larger + */ + entropy_buf.create(std::max<u32bit>(goal_bits / 4, 16)); + io_buffer.destroy(); + } + +MemoryRegion<byte>& Entropy_Accumulator::get_io_buffer(u32bit size) + { + io_buffer.create(size); + return io_buffer; + } + +u32bit Entropy_Accumulator::desired_remaining_bits() const + { + if(collected_bits >= goal_bits) + return 0; + return (goal_bits - collected_bits); + } + +bool Entropy_Accumulator::polling_goal_achieved() const + { + return (collected_bits >= goal_bits); + } + +void Entropy_Accumulator::add(const void* in_void, + u32bit length, + double entropy_bits_per_byte) + { + if(length == 0) + return; + + entropy_bits_per_byte = std::max(0.0, std::min(entropy_bits_per_byte, 8.0)); + + const byte* in = static_cast<const byte*>(in_void); + + u32bit buf_i = 0; // write index into entropy_buf + u32bit bytes_collected = 0; + + byte last = 0; + byte count = 0; + + for(u32bit i = 0; i != length; ++i) + { + if(in[i] != last) // run length encode the input + { + entropy_buf[buf_i] ^= last; + buf_i = (buf_i + 1) % entropy_buf.size(); + + if(count > 1) + { + entropy_buf[buf_i] ^= count; + buf_i = (buf_i + 1) % entropy_buf.size(); + } + + ++bytes_collected; + + last = in[i]; + count = 1; + } + else + ++count; + } + + entropy_buf[0] ^= last; + entropy_buf[1] ^= count; + + collected_bits += static_cast<u32bit>(entropy_bits_per_byte * bytes_collected); + collected_bits = std::min(collected_bits, 8 * entropy_buf.size()); + } + +} diff --git a/src/entropy/entropy_src.h b/src/entropy/entropy_src.h index 0891e393f..603bbae15 100644 --- a/src/entropy/entropy_src.h +++ b/src/entropy/entropy_src.h @@ -1,26 +1,59 @@ -/************************************************* -* EntropySource Header File * -* (C) 2008 Jack Lloyd * -*************************************************/ +/** +* EntropySource Header File +* (C) 2008-2009 Jack Lloyd +*/ #ifndef BOTAN_ENTROPY_SOURCE_BASE_H__ #define BOTAN_ENTROPY_SOURCE_BASE_H__ -#include <botan/types.h> +#include <botan/buf_comp.h> #include <string> +#include <utility> namespace Botan { /** +* Class used to accumulate the poll results of EntropySources +*/ +class Entropy_Accumulator + { + public: + Entropy_Accumulator(u32bit entropy_goal) + { reset_goal(entropy_goal); } + + const MemoryRegion<byte>& get_entropy_buffer() const + { return entropy_buf; } + + MemoryRegion<byte>& get_io_buffer(u32bit size); + + void reset_goal(u32bit entropy_goal); + + u32bit bits_collected() const { return collected_bits; } + + bool polling_goal_achieved() const; + + u32bit desired_remaining_bits() const; + + void add(const void* bytes, u32bit length, double bits_per_byte); + + template<typename T> + void add(const T& v, double bits_per_byte) + { + add(&v, sizeof(T), bits_per_byte); + } + private: + SecureVector<byte> io_buffer, entropy_buf; + u32bit collected_bits, goal_bits; + }; + +/** * Abstract interface to a source of (hopefully unpredictable) system entropy */ class BOTAN_DLL EntropySource { public: virtual std::string name() const = 0; - - virtual u32bit slow_poll(byte buf[], u32bit len) = 0; - virtual u32bit fast_poll(byte buf[], u32bit len) = 0; + virtual void poll(Entropy_Accumulator& accum) = 0; virtual ~EntropySource() {} }; diff --git a/src/entropy/info.txt b/src/entropy/info.txt index bac1d593f..e0b0320b1 100644 --- a/src/entropy/info.txt +++ b/src/entropy/info.txt @@ -4,4 +4,5 @@ load_on auto <add> entropy_src.h +entropy_acc.cpp </add> diff --git a/src/entropy/proc_walk/es_ftw.cpp b/src/entropy/proc_walk/es_ftw.cpp index 1ad6c56b6..406e84cb0 100644 --- a/src/entropy/proc_walk/es_ftw.cpp +++ b/src/entropy/proc_walk/es_ftw.cpp @@ -5,7 +5,6 @@ #include <botan/es_ftw.h> #include <botan/secmem.h> -#include <botan/xor_buf.h> #include <cstring> #include <deque> @@ -110,49 +109,36 @@ FTW_EntropySource::~FTW_EntropySource() delete dir; } -u32bit FTW_EntropySource::slow_poll(byte buf[], u32bit length) +void FTW_EntropySource::poll(Entropy_Accumulator& accum) { + const u32bit MAX_FILES_READ_PER_POLL = 1024; + if(!dir) dir = new Directory_Walker(path); - SecureVector<byte> read_buf(4096); - - u32bit bytes_read = 0; - u32bit buf_i = 0; + MemoryRegion<byte>& io_buffer = accum.get_io_buffer(2048); - while(bytes_read < length * 32) + for(u32bit i = 0; i != MAX_FILES_READ_PER_POLL; ++i) { int fd = dir->next_fd(); - if(fd == -1) // re-walk + // If we've exhaused this walk of the directory, halt the poll + if(fd == -1) { delete dir; - dir = new Directory_Walker(path); - fd = dir->next_fd(); - - if(fd == -1) // still fails (directory not mounted, etc) -> fail - return 0; + dir = 0; + break; } - ssize_t got = ::read(fd, read_buf.begin(), read_buf.size()); + ssize_t got = ::read(fd, io_buffer.begin(), io_buffer.size()); + ::close(fd); if(got > 0) - { - buf_i = xor_into_buf(buf, buf_i, length, read_buf, got); - - // never count any one file for more than 128 bytes - bytes_read += std::min<u32bit>(got, 128); - } + accum.add(io_buffer.begin(), got, .005); - ::close(fd); + if(accum.polling_goal_achieved()) + break; } - - return length; - } - -u32bit FTW_EntropySource::fast_poll(byte[], u32bit) - { - return 0; // no op } } diff --git a/src/entropy/proc_walk/es_ftw.h b/src/entropy/proc_walk/es_ftw.h index 5b127943f..a764462c6 100644 --- a/src/entropy/proc_walk/es_ftw.h +++ b/src/entropy/proc_walk/es_ftw.h @@ -10,16 +10,15 @@ namespace Botan { -/************************************************* -* File Tree Walking Entropy Source * -*************************************************/ +/** +* File Tree Walking Entropy Source +*/ class BOTAN_DLL FTW_EntropySource : public EntropySource { public: std::string name() const { return "Proc Walker"; } - u32bit slow_poll(byte buf[], u32bit len); - u32bit fast_poll(byte buf[], u32bit len); + void poll(Entropy_Accumulator& accum); FTW_EntropySource(const std::string& root_dir); ~FTW_EntropySource(); diff --git a/src/entropy/unix_procs/es_unix.cpp b/src/entropy/unix_procs/es_unix.cpp index 124a08da7..3ac8cd8d3 100644 --- a/src/entropy/unix_procs/es_unix.cpp +++ b/src/entropy/unix_procs/es_unix.cpp @@ -1,12 +1,11 @@ -/************************************************* -* Unix EntropySource Source File * -* (C) 1999-2008 Jack Lloyd * -*************************************************/ +/* +* Unix EntropySource Source File +* (C) 1999-2009 Jack Lloyd +*/ #include <botan/es_unix.h> #include <botan/unix_cmd.h> #include <botan/parsing.h> -#include <botan/xor_buf.h> #include <algorithm> #include <sys/time.h> #include <sys/stat.h> @@ -17,43 +16,40 @@ namespace Botan { namespace { -/************************************************* -* Sort ordering by priority * -*************************************************/ +/** +* Sort ordering by priority +*/ bool Unix_Program_Cmp(const Unix_Program& a, const Unix_Program& b) { return (a.priority < b.priority); } } -/************************************************* -* Unix_EntropySource Constructor * -*************************************************/ +/** +* Unix_EntropySource Constructor +*/ Unix_EntropySource::Unix_EntropySource(const std::vector<std::string>& path) : PATH(path) { add_default_sources(sources); } -/************************************************* -* Add sources to the list * -*************************************************/ +/** +* Add sources to the list +*/ void Unix_EntropySource::add_sources(const Unix_Program srcs[], u32bit count) { sources.insert(sources.end(), srcs, srcs + count); std::sort(sources.begin(), sources.end(), Unix_Program_Cmp); } -/************************************************* -* Unix Fast Poll * -*************************************************/ -u32bit Unix_EntropySource::fast_poll(byte buf[], u32bit length) +/** +* Poll for entropy on a generic Unix system, first by grabbing various +* statistics (stat on common files, getrusage, etc), and then, if more +* is required, by exec'ing various programs like uname and rpcinfo and +* reading the output. +*/ +void Unix_EntropySource::poll(Entropy_Accumulator& accum) { - if(length == 0) - return 0; - length = std::min<u32bit>(length, 32); - - u32bit buf_i = 0; - const char* stat_targets[] = { "/", "/tmp", @@ -70,67 +66,50 @@ u32bit Unix_EntropySource::fast_poll(byte buf[], u32bit length) struct stat statbuf; clear_mem(&statbuf, 1); ::stat(stat_targets[j], &statbuf); - buf_i = xor_into_buf(buf, buf_i, length, statbuf); + accum.add(&statbuf, sizeof(statbuf), .05); } - u32bit ids[] = { - ::getpid(), - ::getppid(), - ::getuid(), - ::geteuid(), - ::getegid(), - ::getpgrp(), - ::getsid(0) - }; - - for(u32bit i = 0; i != sizeof(ids) / sizeof(ids[0]); ++i) - buf_i = xor_into_buf(buf, buf_i, length, ids[i]); + accum.add(::getpid(), 0); + accum.add(::getppid(), 0); + accum.add(::getuid(), 0); + accum.add(::geteuid(), 0); + accum.add(::getegid(), 0); + accum.add(::getpgrp(), 0); + accum.add(::getsid(0), 0); struct ::rusage usage; ::getrusage(RUSAGE_SELF, &usage); - buf_i = xor_into_buf(buf, buf_i, length, usage); + accum.add(usage, .05); ::getrusage(RUSAGE_CHILDREN, &usage); - buf_i = xor_into_buf(buf, buf_i, length, usage); - - return length; - } + accum.add(usage, .05); -/************************************************* -* Unix Slow Poll * -*************************************************/ -u32bit Unix_EntropySource::slow_poll(byte buf[], u32bit length) - { - if(length == 0) - return 0; + if(accum.desired_remaining_bits() < 128) + return; - const u32bit MINIMAL_WORKING = 32; + const u32bit MINIMAL_WORKING = 16; - u32bit total_got = 0; - u32bit buf_i = 0; + MemoryRegion<byte>& io_buffer = accum.get_io_buffer(DEFAULT_BUFFERSIZE); for(u32bit j = 0; j != sources.size(); j++) { DataSource_Command pipe(sources[j].name_and_args, PATH); - SecureVector<byte> buffer(DEFAULT_BUFFERSIZE); u32bit got_from_src = 0; while(!pipe.end_of_data()) { - u32bit this_loop = pipe.read(buffer, buffer.size()); - buf_i = xor_into_buf(buf, buf_i, length, buffer, this_loop); - got_from_src += this_loop; + u32bit got_this_loop = pipe.read(io_buffer, io_buffer.size()); + got_from_src += got_this_loop; + + accum.add(io_buffer.begin(), got_this_loop, .005); } sources[j].working = (got_from_src >= MINIMAL_WORKING) ? true : false; - total_got += got_from_src; - if(total_got >= 128*length) + if(accum.polling_goal_achieved()) break; } - - return length; } } diff --git a/src/entropy/unix_procs/es_unix.h b/src/entropy/unix_procs/es_unix.h index f4af255ca..ba3fd51c2 100644 --- a/src/entropy/unix_procs/es_unix.h +++ b/src/entropy/unix_procs/es_unix.h @@ -1,7 +1,7 @@ -/************************************************* -* Unix EntropySource Header File * -* (C) 1999-2007 Jack Lloyd * -*************************************************/ +/* +* Unix EntropySource Header File +* (C) 1999-2009 Jack Lloyd +*/ #ifndef BOTAN_ENTROPY_SRC_UNIX_H__ #define BOTAN_ENTROPY_SRC_UNIX_H__ @@ -12,21 +12,21 @@ namespace Botan { -/************************************************* -* Unix Entropy Source * -*************************************************/ +/** +* Unix Entropy Source +*/ class BOTAN_DLL Unix_EntropySource : public EntropySource { public: std::string name() const { return "Unix Entropy Source"; } + void poll(Entropy_Accumulator& accum); + void add_sources(const Unix_Program[], u32bit); Unix_EntropySource(const std::vector<std::string>& path); private: static void add_default_sources(std::vector<Unix_Program>&); - - u32bit fast_poll(byte buf[], u32bit length); - u32bit slow_poll(byte buf[], u32bit length); + void fast_poll(Entropy_Accumulator& accum); const std::vector<std::string> PATH; std::vector<Unix_Program> sources; diff --git a/src/entropy/unix_procs/unix_cmd.cpp b/src/entropy/unix_procs/unix_cmd.cpp index 4c7f674db..b9558b35c 100644 --- a/src/entropy/unix_procs/unix_cmd.cpp +++ b/src/entropy/unix_procs/unix_cmd.cpp @@ -1,7 +1,7 @@ -/************************************************* -* Unix Command Execution Source File * -* (C) 1999-2007 Jack Lloyd * -*************************************************/ +/* +* Unix Command Execution Source File +* (C) 1999-2007 Jack Lloyd +*/ #include <botan/unix_cmd.h> #include <botan/parsing.h> @@ -18,9 +18,9 @@ namespace Botan { namespace { -/************************************************* -* Attempt to execute the command * -************************************************/ +/** +* Attempt to execute the command +*/ void do_exec(const std::vector<std::string>& arg_list, const std::vector<std::string>& paths) { @@ -41,9 +41,9 @@ void do_exec(const std::vector<std::string>& arg_list, } -/************************************************* -* Local information about the pipe * -*************************************************/ +/** +* Local information about the pipe +*/ struct pipe_wrapper { int fd; @@ -51,9 +51,9 @@ struct pipe_wrapper pipe_wrapper() { fd = -1; pid = 0; } }; -/************************************************* -* Read from the pipe * -*************************************************/ +/** +* Read from the pipe +*/ u32bit DataSource_Command::read(byte buf[], u32bit length) { if(end_of_data()) @@ -83,9 +83,9 @@ u32bit DataSource_Command::read(byte buf[], u32bit length) return static_cast<u32bit>(got); } -/************************************************* -* Peek at the pipe contents * -*************************************************/ +/** +* Peek at the pipe contents +*/ u32bit DataSource_Command::peek(byte[], u32bit, u32bit) const { if(end_of_data()) @@ -93,17 +93,17 @@ u32bit DataSource_Command::peek(byte[], u32bit, u32bit) const throw Stream_IO_Error("Cannot peek/seek on a command pipe"); } -/************************************************* -* Check if we reached EOF * -*************************************************/ +/** +* Check if we reached EOF +*/ bool DataSource_Command::end_of_data() const { return (pipe) ? false : true; } -/************************************************* -* Return the Unix file descriptor of the pipe * -*************************************************/ +/** +* Return the Unix file descriptor of the pipe +*/ int DataSource_Command::fd() const { if(!pipe) @@ -111,17 +111,17 @@ int DataSource_Command::fd() const return pipe->fd; } -/************************************************* -* Return a human-readable ID for this stream * -*************************************************/ +/** +* Return a human-readable ID for this stream +*/ std::string DataSource_Command::id() const { return "Unix command: " + arg_list[0]; } -/************************************************* -* Create the pipe * -*************************************************/ +/** +* Create the pipe +*/ void DataSource_Command::create_pipe(const std::vector<std::string>& paths) { bool found_something = false; @@ -169,9 +169,9 @@ void DataSource_Command::create_pipe(const std::vector<std::string>& paths) } } -/************************************************* -* Shutdown the pipe * -*************************************************/ +/** +* Shutdown the pipe +*/ void DataSource_Command::shutdown_pipe() { if(pipe) @@ -204,9 +204,9 @@ void DataSource_Command::shutdown_pipe() } } -/************************************************* -* DataSource_Command Constructor * -*************************************************/ +/** +* DataSource_Command Constructor +*/ DataSource_Command::DataSource_Command(const std::string& prog_and_args, const std::vector<std::string>& paths) : MAX_BLOCK_USECS(100000), KILL_WAIT(10000) @@ -222,9 +222,9 @@ DataSource_Command::DataSource_Command(const std::string& prog_and_args, create_pipe(paths); } -/************************************************* -* DataSource_Command Destructor * -*************************************************/ +/** +* DataSource_Command Destructor +*/ DataSource_Command::~DataSource_Command() { if(!end_of_data()) diff --git a/src/entropy/unix_procs/unix_cmd.h b/src/entropy/unix_procs/unix_cmd.h index 8544e7879..66122ea49 100644 --- a/src/entropy/unix_procs/unix_cmd.h +++ b/src/entropy/unix_procs/unix_cmd.h @@ -1,7 +1,7 @@ -/************************************************* -* Unix Command Execution Header File * -* (C) 1999-2007 Jack Lloyd * -*************************************************/ +/** +* Unix Command Execution Header File +* (C) 1999-2007 Jack Lloyd +*/ #ifndef BOTAN_UNIX_CMD_H__ #define BOTAN_UNIX_CMD_H__ @@ -13,9 +13,9 @@ namespace Botan { -/************************************************* -* Unix Program Info * -*************************************************/ +/** +* Unix Program Info +*/ struct Unix_Program { Unix_Program(const char* n, u32bit p) @@ -26,9 +26,9 @@ struct Unix_Program bool working; }; -/************************************************* -* Command Output DataSource * -*************************************************/ +/** +* Command Output DataSource +*/ class BOTAN_DLL DataSource_Command : public DataSource { public: diff --git a/src/entropy/unix_procs/unix_src.cpp b/src/entropy/unix_procs/unix_src.cpp index 9d44dbf4f..5e48ba41d 100644 --- a/src/entropy/unix_procs/unix_src.cpp +++ b/src/entropy/unix_procs/unix_src.cpp @@ -1,15 +1,15 @@ -/************************************************* -* Program List for Unix_EntropySource * -* (C) 1999-2007 Jack Lloyd * -*************************************************/ +/* +* Program List for Unix_EntropySource +* (C) 1999-2007 Jack Lloyd +*/ #include <botan/es_unix.h> namespace Botan { -/************************************************* -* Default Commands for Entropy Gathering * -*************************************************/ +/** +* Default Commands for Entropy Gathering +*/ void Unix_EntropySource::add_default_sources(std::vector<Unix_Program>& srcs) { srcs.push_back(Unix_Program("vmstat", 1)); diff --git a/src/entropy/win32_stats/es_win32.cpp b/src/entropy/win32_stats/es_win32.cpp index a529ccc1a..0c17f7b02 100644 --- a/src/entropy/win32_stats/es_win32.cpp +++ b/src/entropy/win32_stats/es_win32.cpp @@ -1,43 +1,69 @@ /** * Win32 EntropySource Source File -* (C) 1999-2008 Jack Lloyd +* (C) 1999-2009 Jack Lloyd */ #include <botan/es_win32.h> -#include <botan/xor_buf.h> #include <windows.h> #include <tlhelp32.h> namespace Botan { /** -* Win32 slow poll using Tooltip32 +* Win32 poll using stats functions including Tooltip32 */ -u32bit Win32_EntropySource::slow_poll(byte buf[], u32bit length) +void Win32_EntropySource::poll(Entropy_Accumulator& accum) { - if(length == 0) - return 0; + /* + 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); - const u32bit MAX_ITEMS = length / 4; + 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_count, 0); - u32bit buf_i = 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) \ - { \ - u32bit items = 0; \ - DATA_TYPE info; \ - info.dwSize = sizeof(DATA_TYPE); \ - if(FUNC_FIRST(snapshot, &info)) \ + if(!accum.polling_goal_achieved()) \ { \ - do \ + DATA_TYPE info; \ + info.dwSize = sizeof(DATA_TYPE); \ + if(FUNC_FIRST(snapshot, &info)) \ { \ - if(items++ > MAX_ITEMS) break; \ - buf_i = xor_into_buf(buf, buf_i, length, info); \ - } while(FUNC_NEXT(snapshot, &info)); \ - } \ - } + do \ + { \ + accum.add(info, 1); \ + } while(FUNC_NEXT(snapshot, &info)); \ + } \ + } TOOLHELP32_ITER(MODULEENTRY32, Module32First, Module32Next); TOOLHELP32_ITER(PROCESSENTRY32, Process32First, Process32Next); @@ -45,85 +71,46 @@ u32bit Win32_EntropySource::slow_poll(byte buf[], u32bit length) #undef TOOLHELP32_ITER - u32bit heap_lists_found = 0; - HEAPLIST32 heap_list; - heap_list.dwSize = sizeof(HEAPLIST32); - - const u32bit HEAP_LISTS_MAX = 32; - const u32bit HEAP_OBJS_PER_LIST = 128; - if(Heap32ListFirst(snapshot, &heap_list)) + if(!accum.polling_goal_achieved()) { - do - { - buf_i = xor_into_buf(buf, buf_i, length, heap_list); + u32bit heap_lists_found = 0; + HEAPLIST32 heap_list; + heap_list.dwSize = sizeof(HEAPLIST32); - if(heap_lists_found++ > HEAP_LISTS_MAX) - break; + const u32bit HEAP_LISTS_MAX = 32; + const u32bit HEAP_OBJS_PER_LIST = 128; - u32bit heap_objs_found = 0; - HEAPENTRY32 heap_entry; - heap_entry.dwSize = sizeof(HEAPENTRY32); - if(Heap32First(&heap_entry, heap_list.th32ProcessID, - heap_list.th32HeapID)) + if(Heap32ListFirst(snapshot, &heap_list)) + { + do { - do + accum.add(heap_list, 1); + + if(++heap_lists_found > HEAP_LISTS_MAX) + break; + + u32bit heap_objs_found = 0; + HEAPENTRY32 heap_entry; + heap_entry.dwSize = sizeof(HEAPENTRY32); + if(Heap32First(&heap_entry, heap_list.th32ProcessID, + heap_list.th32HeapID)) { - if(heap_objs_found++ > HEAP_OBJS_PER_LIST) - break; - buf_i = xor_into_buf(buf, buf_i, length, heap_entry); - } while(Heap32Next(&heap_entry)); - } - } while(Heap32ListNext(snapshot, &heap_list)); + 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); - - return length; - } - -/** -* Win32 fast poll -*/ -u32bit Win32_EntropySource::fast_poll(byte buf[], u32bit length) - { - if(length == 0) - return 0; - length = std::min<u32bit>(length, 32); - - u32bit buf_i = 0; - - u32bit stats[] = { - GetTickCount(), - GetMessagePos(), - GetMessageTime(), - GetInputState(), - GetCurrentProcessId(), - GetCurrentThreadId() - }; - - for(u32bit i = 0; i != sizeof(stats) / sizeof(stats[0]); ++i) - buf_i = xor_into_buf(buf, buf_i, length, stats[i]); - - SYSTEM_INFO sys_info; - GetSystemInfo(&sys_info); - buf_i = xor_into_buf(buf, buf_i, length, sys_info); - - MEMORYSTATUS mem_info; - GlobalMemoryStatus(&mem_info); - buf_i = xor_into_buf(buf, buf_i, length, mem_info); - - POINT point; - GetCursorPos(&point); - buf_i = xor_into_buf(buf, buf_i, length, point); - - GetCaretPos(&point); - buf_i = xor_into_buf(buf, buf_i, length, point); - - LARGE_INTEGER perf_counter; - QueryPerformanceCounter(&perf_counter); - buf_i = xor_into_buf(buf, buf_i, length, perf_counter); - - return length; } } diff --git a/src/entropy/win32_stats/es_win32.h b/src/entropy/win32_stats/es_win32.h index 3124bd414..06e3b88cc 100644 --- a/src/entropy/win32_stats/es_win32.h +++ b/src/entropy/win32_stats/es_win32.h @@ -1,6 +1,6 @@ /** * Win32 EntropySource Header File -* (C) 1999-2008 Jack Lloyd +* (C) 1999-2009 Jack Lloyd */ #ifndef BOTAN_ENTROPY_SRC_WIN32_H__ @@ -17,9 +17,7 @@ class BOTAN_DLL Win32_EntropySource : public EntropySource { public: std::string name() const { return "Win32 Statistics"; } - - u32bit fast_poll(byte buf[], u32bit length); - u32bit slow_poll(byte buf[], u32bit length); + void poll(Entropy_Accumulator& accum); }; } diff --git a/src/rng/auto_rng/auto_rng.cpp b/src/rng/auto_rng/auto_rng.cpp index 845d958e2..620cc1f61 100644 --- a/src/rng/auto_rng/auto_rng.cpp +++ b/src/rng/auto_rng/auto_rng.cpp @@ -76,19 +76,15 @@ namespace { */ void add_entropy_sources(RandomNumberGenerator* rng) { + + // Add a high resolution timer, if available #if defined(BOTAN_HAS_TIMER_HARDWARE) rng->add_entropy_source(new Hardware_Timer); -#endif - -#if defined(BOTAN_HAS_TIMER_POSIX) +#elif defined(BOTAN_HAS_TIMER_POSIX) rng->add_entropy_source(new POSIX_Timer); -#endif - -#if defined(BOTAN_HAS_TIMER_UNIX) +#elif defined(BOTAN_HAS_TIMER_UNIX) rng->add_entropy_source(new Unix_Timer); -#endif - -#if defined(BOTAN_HAS_TIMER_WIN32) +#elif defined(BOTAN_HAS_TIMER_WIN32) rng->add_entropy_source(new Win32_Timer); #endif @@ -114,7 +110,6 @@ void add_entropy_sources(RandomNumberGenerator* rng) rng->add_entropy_source(new FTW_EntropySource("/proc")); #endif - #if defined(BOTAN_HAS_ENTROPY_SRC_WIN32) rng->add_entropy_source(new Win32_EntropySource); #endif @@ -132,7 +127,7 @@ void add_entropy_sources(RandomNumberGenerator* rng) } -AutoSeeded_RNG::AutoSeeded_RNG() +AutoSeeded_RNG::AutoSeeded_RNG(u32bit poll_bits) { rng = 0; @@ -152,7 +147,7 @@ AutoSeeded_RNG::AutoSeeded_RNG() add_entropy_sources(rng); - rng->reseed(); + rng->reseed(poll_bits); } } diff --git a/src/rng/auto_rng/auto_rng.h b/src/rng/auto_rng/auto_rng.h index dea735470..5536f2b8e 100644 --- a/src/rng/auto_rng/auto_rng.h +++ b/src/rng/auto_rng/auto_rng.h @@ -25,13 +25,13 @@ class BOTAN_DLL AutoSeeded_RNG : public RandomNumberGenerator std::string name() const { return "AutoSeeded(" + rng->name() + ")"; } - void reseed() { rng->reseed(); } + void reseed(u32bit poll_bits) { rng->reseed(poll_bits); } void add_entropy_source(EntropySource* es) { rng->add_entropy_source(es); } void add_entropy(const byte in[], u32bit len) { rng->add_entropy(in, len); } - AutoSeeded_RNG(); + AutoSeeded_RNG(u32bit poll_bits = 256); ~AutoSeeded_RNG() { delete rng; } private: RandomNumberGenerator* rng; diff --git a/src/rng/hmac_rng/hmac_rng.cpp b/src/rng/hmac_rng/hmac_rng.cpp index 188c32689..245a4039e 100644 --- a/src/rng/hmac_rng/hmac_rng.cpp +++ b/src/rng/hmac_rng/hmac_rng.cpp @@ -1,7 +1,7 @@ -/************************************************* -* HMAC_RNG Source File * -* (C) 2008 Jack Lloyd * -*************************************************/ +/* +* HMAC_RNG +* (C) 2008-2009 Jack Lloyd +*/ #include <botan/hmac_rng.h> #include <botan/loadstor.h> @@ -16,9 +16,9 @@ namespace Botan { namespace { void hmac_prf(MessageAuthenticationCode* prf, - MemoryRegion<byte>& K, - u32bit& counter, - const std::string& label) + MemoryRegion<byte>& K, + u32bit& counter, + const std::string& label) { prf->update(K, K.size()); prf->update(label); @@ -31,9 +31,9 @@ void hmac_prf(MessageAuthenticationCode* prf, } -/************************************************* -* Generate a buffer of random bytes * -*************************************************/ +/** +* Generate a buffer of random bytes +*/ void HMAC_RNG::randomize(byte out[], u32bit length) { /* Attempt to seed if we are currently not seeded, or if the @@ -44,7 +44,7 @@ void HMAC_RNG::randomize(byte out[], u32bit length) */ if(!is_seeded() || counter >= 0x100000) { - reseed(); + reseed(8 * prf->OUTPUT_LENGTH); if(!is_seeded()) throw PRNG_Unseeded(name() + " seeding attempt failed"); @@ -63,94 +63,45 @@ void HMAC_RNG::randomize(byte out[], u32bit length) out += copied; length -= copied; } - - /* Every once in a while do a fast poll of a entropy source */ - if(entropy_sources.size() && (counter % 65536 == 0)) - { - u32bit got = entropy_sources.at(source_index)-> - fast_poll(io_buffer, io_buffer.size()); - - source_index = (source_index + 1) % entropy_sources.size(); - extractor->update(io_buffer, got); - io_buffer.clear(); - } } /** * Reseed the internal state, also accepting user input to include */ -void HMAC_RNG::reseed_with_input(const byte input[], u32bit input_length) +void HMAC_RNG::reseed_with_input(u32bit poll_bits, + const byte input[], u32bit input_length) { - if(entropy_sources.size()) + /** + Using the terminology of E-t-E, XTR is the MAC function (normally + HMAC) seeded with XTS (below) and we form SKM, the key material, by + fast polling each source, and then slow polling as many as we think + we need (in the following loop), and feeding all of the poll + results, along with any optional user input, along with, finally, + feedback of the current PRK value, into the extractor function. + */ + + Entropy_Accumulator accum(poll_bits); + + for(u32bit i = 0; i < entropy_sources.size(); ++i) { - /** - Using the terminology of E-t-E, XTR is the MAC function (normally - HMAC) seeded with XTS (below) and we form SKM, the key material, by - fast polling each source, and then slow polling as many as we think - we need (in the following loop), and feeding all of the poll - results, along with any optional user input, along with, finally, - feedback of the current PRK value, into the extractor function. - */ - - /* - Previously this function did entropy estimation. However the paper - - "Boaz Barak, Shai Halevi: A model and architecture for - pseudo-random generation with applications to /dev/random. ACM - Conference on Computer and Communications Security 2005." - - provides a pretty strong case to not even try, since what we are - really interested in is the *conditional* entropy from the point - of view of an unknown attacker, which is impossible to - calculate. They recommend, if an entropy estimate of some kind - is needed, to use a low static estimate instead. We use here an - estimate of 1 bit per byte. - - One thing I had been concerned about initially was that people - without any randomness source enabled (much more likely in the - days when you had to enable them manually) would find the RNG - was unseeded and then pull the manuever some OpenSSL users did - and seed the RNG with a constant string. However, upon further - thought, I've decided that people who do that deserve to lose - anyway. - */ - - for(u32bit j = 0; j < entropy_sources.size(); ++j) - { - const u32bit got = - entropy_sources[j]->fast_poll(io_buffer, io_buffer.size()); - - entropy += got; - extractor->update(io_buffer, got); - io_buffer.clear(); - } - - for(u32bit j = 0; j != entropy_sources.size(); ++j) - { - const u32bit got = - entropy_sources[j]->slow_poll(io_buffer, io_buffer.size()); - - entropy += got; - extractor->update(io_buffer, got); - io_buffer.clear(); - } + if(accum.polling_goal_achieved()) + break; + + entropy_sources[i]->poll(accum); } - /* - And now add the user-provided input, if any - */ + // And now add the user-provided input, if any if(input_length) - { - extractor->update(input, input_length); - entropy += input_length; - } + accum.add(input, input_length, 1); + + extractor->update(accum.get_entropy_buffer()); /* - It is necessary to feed forward poll data. Otherwise, a good - poll (collecting a large amount of conditional entropy) followed - by a bad one (collecting little) would be unsafe. Do this by - generating new PRF outputs using the previous key and feeding them - into the extractor function. + It is necessary to feed forward poll data. Otherwise, a good poll + (collecting a large amount of conditional entropy) followed by a + bad one (collecting little) would be unsafe. Do this by generating + new PRF outputs using the previous key and feeding them into the + extractor function. Cycle the RNG once (CTXinfo="rng"), then generate a new PRF output using the CTXinfo "reseed". Provide these values as input to the @@ -175,45 +126,46 @@ void HMAC_RNG::reseed_with_input(const byte input[], u32bit input_length) counter = 0; // Upper bound entropy estimate at the extractor output size - entropy = std::min<u32bit>(entropy, 8 * extractor->OUTPUT_LENGTH); + entropy = std::min<u32bit>(entropy + accum.bits_collected(), + 8 * extractor->OUTPUT_LENGTH); } /** * Reseed the internal state */ -void HMAC_RNG::reseed() +void HMAC_RNG::reseed(u32bit poll_bits) { - reseed_with_input(0, 0); + reseed_with_input(poll_bits, 0, 0); } /** -Add user-supplied entropy by reseeding and including this -input among the poll data +* Add user-supplied entropy by reseeding and including this +* input among the poll data */ void HMAC_RNG::add_entropy(const byte input[], u32bit length) { - reseed_with_input(input, length); + reseed_with_input(0, input, length); } -/************************************************* -* Add another entropy source to the list * -*************************************************/ +/** +* Add another entropy source to the list +*/ void HMAC_RNG::add_entropy_source(EntropySource* src) { entropy_sources.push_back(src); } -/************************************************* -* Check if the the pool is seeded * -*************************************************/ +/** +* Check if the the pool is seeded +*/ bool HMAC_RNG::is_seeded() const { return (entropy >= 8 * prf->OUTPUT_LENGTH); } - /************************************************* -* Clear memory of sensitive data * -*************************************************/ +/* +* Clear memory of sensitive data +*/ void HMAC_RNG::clear() throw() { extractor->clear(); @@ -221,30 +173,28 @@ void HMAC_RNG::clear() throw() K.clear(); entropy = 0; counter = 0; - source_index = 0; } -/************************************************* -* Return the name of this type * -*************************************************/ +/** +* Return the name of this type +*/ std::string HMAC_RNG::name() const { return "HMAC_RNG(" + extractor->name() + "," + prf->name() + ")"; } -/************************************************* -* HMAC_RNG Constructor * -*************************************************/ +/** +* HMAC_RNG Constructor +*/ HMAC_RNG::HMAC_RNG(MessageAuthenticationCode* extractor_mac, MessageAuthenticationCode* prf_mac) : - extractor(extractor_mac), prf(prf_mac), io_buffer(96) + extractor(extractor_mac), prf(prf_mac) { entropy = 0; // First PRF inputs are all zero, as specified in section 2 K.create(prf->OUTPUT_LENGTH); counter = 0; - source_index = 0; /* Normally we want to feedback PRF output into the input to the @@ -275,9 +225,9 @@ HMAC_RNG::HMAC_RNG(MessageAuthenticationCode* extractor_mac, xts.length()); } -/************************************************* -* HMAC_RNG Destructor * -*************************************************/ +/** +* HMAC_RNG Destructor +*/ HMAC_RNG::~HMAC_RNG() { delete extractor; diff --git a/src/rng/hmac_rng/hmac_rng.h b/src/rng/hmac_rng/hmac_rng.h index b9ea064c3..fbfa8df19 100644 --- a/src/rng/hmac_rng/hmac_rng.h +++ b/src/rng/hmac_rng/hmac_rng.h @@ -1,7 +1,7 @@ -/************************************************* -* HMAC RNG * -* (C) 2008 Jack Lloyd * -*************************************************/ +/* +* HMAC RNG +* (C) 2008 Jack Lloyd +*/ #ifndef BOTAN_HMAC_RNG_H__ #define BOTAN_HMAC_RNG_H__ @@ -30,7 +30,7 @@ class BOTAN_DLL HMAC_RNG : public RandomNumberGenerator void clear() throw(); std::string name() const; - void reseed(); + void reseed(u32bit poll_bits); void add_entropy_source(EntropySource* es); void add_entropy(const byte[], u32bit); @@ -39,7 +39,8 @@ class BOTAN_DLL HMAC_RNG : public RandomNumberGenerator ~HMAC_RNG(); private: - void reseed_with_input(const byte input[], u32bit length); + void reseed_with_input(u32bit poll_bits, + const byte input[], u32bit length); MessageAuthenticationCode* extractor; MessageAuthenticationCode* prf; diff --git a/src/rng/randpool/randpool.cpp b/src/rng/randpool/randpool.cpp index e35ee22ca..594916a84 100644 --- a/src/rng/randpool/randpool.cpp +++ b/src/rng/randpool/randpool.cpp @@ -1,7 +1,7 @@ -/************************************************* -* Randpool Source File * -* (C) 1999-2008 Jack Lloyd * -*************************************************/ +/* +* Randpool Source File +* (C) 1999-2009 Jack Lloyd +*/ #include <botan/randpool.h> #include <botan/loadstor.h> @@ -14,9 +14,9 @@ namespace Botan { namespace { -/************************************************* -* PRF based on a MAC * -*************************************************/ +/** +* PRF based on a MAC +*/ enum RANDPOOL_PRF_TAG { CIPHER_KEY = 0, MAC_KEY = 1, @@ -25,14 +25,14 @@ enum RANDPOOL_PRF_TAG { } -/************************************************* -* Generate a buffer of random bytes * -*************************************************/ +/** +* Generate a buffer of random bytes +*/ void Randpool::randomize(byte out[], u32bit length) { if(!is_seeded()) { - reseed(); + reseed(8 * mac->OUTPUT_LENGTH); if(!is_seeded()) throw PRNG_Unseeded(name()); @@ -49,15 +49,15 @@ void Randpool::randomize(byte out[], u32bit length) } } -/************************************************* -* Refill the output buffer * -*************************************************/ +/** +* Refill the output buffer +*/ void Randpool::update_buffer() { const u64bit timestamp = system_time(); - for(u32bit j = 0; j != counter.size(); ++j) - if(++counter[j]) + for(u32bit i = 0; i != counter.size(); ++i) + if(++counter[i]) break; store_be(timestamp, counter + 4); @@ -65,17 +65,17 @@ void Randpool::update_buffer() mac->update(counter, counter.size()); SecureVector<byte> mac_val = mac->final(); - for(u32bit j = 0; j != mac_val.size(); ++j) - buffer[j % buffer.size()] ^= mac_val[j]; + for(u32bit i = 0; i != mac_val.size(); ++i) + buffer[i % buffer.size()] ^= mac_val[i]; cipher->encrypt(buffer); if(counter[0] % ITERATIONS_BEFORE_RESEED == 0) mix_pool(); } -/************************************************* -* Mix the entropy pool * -*************************************************/ +/** +* Mix the entropy pool +*/ void Randpool::mix_pool() { const u32bit BLOCK_SIZE = cipher->BLOCK_SIZE; @@ -90,10 +90,10 @@ void Randpool::mix_pool() xor_buf(pool, buffer, BLOCK_SIZE); cipher->encrypt(pool); - for(u32bit j = 1; j != POOL_BLOCKS; ++j) + for(u32bit i = 1; i != POOL_BLOCKS; ++i) { - const byte* previous_block = pool + BLOCK_SIZE*(j-1); - byte* this_block = pool + BLOCK_SIZE*j; + const byte* previous_block = pool + BLOCK_SIZE*(i-1); + byte* this_block = pool + BLOCK_SIZE*i; xor_buf(this_block, previous_block, BLOCK_SIZE); cipher->encrypt(this_block); } @@ -101,61 +101,33 @@ void Randpool::mix_pool() update_buffer(); } -/************************************************* -* Reseed the internal state * -*************************************************/ -void Randpool::reseed() +/** +* Reseed the internal state +*/ +void Randpool::reseed(u32bit poll_bits) { - SecureVector<byte> buffer(128); + Entropy_Accumulator accum(poll_bits); - u32bit entropy_est = 0; - - /* - When we reseed, assume we get 1 bit per byte sampled. - - This class used to perform entropy estimation, but what we really - want to measure is the conditional entropy of the data with respect - to an unknown attacker with unknown capabilities. For this reason - making any sort of sane estimate is impossible. See also - "Boaz Barak, Shai Halevi: A model and architecture for - pseudo-random generation with applications to /dev/random. ACM - Conference on Computer and Communications Security 2005." - */ - - // First do a fast poll of all sources (no matter what) - for(u32bit j = 0; j != entropy_sources.size(); ++j) + for(u32bit i = 0; i != entropy_sources.size(); ++i) { - u32bit got = entropy_sources[j]->fast_poll(buffer, buffer.size()); - - mac->update(buffer, got); - entropy_est += got; - buffer.clear(); - } + entropy_sources[i]->poll(accum); - // Then do a slow poll, until we think we have got enough entropy - for(u32bit j = 0; j != entropy_sources.size(); ++j) - { - u32bit got = entropy_sources[j]->slow_poll(buffer, buffer.size()); - - mac->update(buffer, got); - entropy_est += got; - - if(entropy_est > 512) + if(accum.polling_goal_achieved()) break; - buffer.clear(); } - SecureVector<byte> mac_val = mac->final(); + SecureVector<byte> mac_val = mac->process(accum.get_entropy_buffer()); xor_buf(pool, mac_val, mac_val.size()); mix_pool(); - entropy = std::min<u32bit>(entropy + entropy_est, 8 * mac_val.size()); + entropy = std::min<u32bit>(entropy + accum.bits_collected(), + 8 * mac_val.size()); } -/************************************************* -* Add user-supplied entropy * -*************************************************/ +/** +* Add user-supplied entropy +*/ void Randpool::add_entropy(const byte input[], u32bit length) { SecureVector<byte> mac_val = mac->process(input, length); @@ -166,25 +138,25 @@ void Randpool::add_entropy(const byte input[], u32bit length) entropy = std::min<u32bit>(entropy + length, 8 * mac_val.size()); } -/************************************************* -* Add another entropy source to the list * -*************************************************/ +/** +* Add another entropy source to the list +*/ void Randpool::add_entropy_source(EntropySource* src) { entropy_sources.push_back(src); } -/************************************************* -* Check if the the pool is seeded * -*************************************************/ +/** +* Check if the the pool is seeded +*/ bool Randpool::is_seeded() const { return (entropy >= 7 * mac->OUTPUT_LENGTH); } -/************************************************* -* Clear memory of sensitive data * -*************************************************/ +/** +* Clear memory of sensitive data +*/ void Randpool::clear() throw() { cipher->clear(); @@ -195,17 +167,17 @@ void Randpool::clear() throw() entropy = 0; } -/************************************************* -* Return the name of this type * -*************************************************/ +/** +* Return the name of this type +*/ std::string Randpool::name() const { return "Randpool(" + cipher->name() + "," + mac->name() + ")"; } -/************************************************* -* Randpool Constructor * -*************************************************/ +/** +* Randpool Constructor +*/ Randpool::Randpool(BlockCipher* cipher_in, MessageAuthenticationCode* mac_in, u32bit pool_blocks, @@ -234,9 +206,9 @@ Randpool::Randpool(BlockCipher* cipher_in, entropy = 0; } -/************************************************* -* Randpool Destructor * -*************************************************/ +/** +* Randpool Destructor +*/ Randpool::~Randpool() { delete cipher; diff --git a/src/rng/randpool/randpool.h b/src/rng/randpool/randpool.h index f6bae9d52..46683934e 100644 --- a/src/rng/randpool/randpool.h +++ b/src/rng/randpool/randpool.h @@ -1,7 +1,7 @@ -/************************************************* -* Randpool Header File * -* (C) 1999-2008 Jack Lloyd * -*************************************************/ +/* +* Randpool Header File +* (C) 1999-2008 Jack Lloyd +*/ #ifndef BOTAN_RANDPOOL_H__ #define BOTAN_RANDPOOL_H__ @@ -13,9 +13,9 @@ namespace Botan { -/************************************************* -* Randpool * -*************************************************/ +/** +* Randpool +*/ class BOTAN_DLL Randpool : public RandomNumberGenerator { public: @@ -24,11 +24,11 @@ class BOTAN_DLL Randpool : public RandomNumberGenerator void clear() throw(); std::string name() const; - void reseed(); - void add_entropy_source(EntropySource*); - void add_entropy(const byte[], u32bit); + void reseed(u32bit bits_to_collect); + void add_entropy_source(EntropySource* es); + void add_entropy(const byte input[], u32bit length); - Randpool(BlockCipher*, MessageAuthenticationCode*, + Randpool(BlockCipher* cipher, MessageAuthenticationCode* mac, u32bit pool_blocks = 32, u32bit iterations_before_reseed = 128); diff --git a/src/rng/rng.h b/src/rng/rng.h index fb92bb3c5..7fc6ee439 100644 --- a/src/rng/rng.h +++ b/src/rng/rng.h @@ -1,7 +1,7 @@ -/************************************************* -* RandomNumberGenerator Header File * -* (C) 1999-2008 Jack Lloyd * -*************************************************/ +/* +* RandomNumberGenerator Header File +* (C) 1999-2009 Jack Lloyd +*/ #ifndef BOTAN_RANDOM_NUMBER_GENERATOR_H__ #define BOTAN_RANDOM_NUMBER_GENERATOR_H__ @@ -54,8 +54,10 @@ class BOTAN_DLL RandomNumberGenerator /** * Seed this RNG using the entropy sources it contains. + * @param bits_to_collect is the number of bits of entropy to + attempt to gather from the entropy sources */ - virtual void reseed() {} + virtual void reseed(u32bit bits_to_collect) = 0; /** * Add this entropy source to the RNG object @@ -88,6 +90,7 @@ class BOTAN_DLL Null_RNG : public RandomNumberGenerator void clear() throw() {} std::string name() const { return "Null_RNG"; } + void reseed(u32bit) {} bool is_seeded() const { return false; } void add_entropy(const byte[], u32bit) {} void add_entropy_source(EntropySource* es) { delete es; } diff --git a/src/rng/x931_rng/x931_rng.cpp b/src/rng/x931_rng/x931_rng.cpp index 619c37e57..b947f525d 100644 --- a/src/rng/x931_rng/x931_rng.cpp +++ b/src/rng/x931_rng/x931_rng.cpp @@ -15,7 +15,7 @@ namespace Botan { void ANSI_X931_RNG::randomize(byte out[], u32bit length) { if(!is_seeded()) - reseed(); + reseed(8 * cipher->BLOCK_SIZE); while(length) { @@ -53,9 +53,9 @@ void ANSI_X931_RNG::update_buffer() /************************************************* * Reseed the internal state * *************************************************/ -void ANSI_X931_RNG::reseed() +void ANSI_X931_RNG::reseed(u32bit poll_bits) { - prng->reseed(); + prng->reseed(poll_bits); if(prng->is_seeded()) { diff --git a/src/rng/x931_rng/x931_rng.h b/src/rng/x931_rng/x931_rng.h index e1d090c3c..2c68b9cb4 100644 --- a/src/rng/x931_rng/x931_rng.h +++ b/src/rng/x931_rng/x931_rng.h @@ -22,7 +22,7 @@ class BOTAN_DLL ANSI_X931_RNG : public RandomNumberGenerator void clear() throw(); std::string name() const; - void reseed(); + void reseed(u32bit poll_bits); void add_entropy_source(EntropySource*); void add_entropy(const byte[], u32bit); diff --git a/src/timer/timer.cpp b/src/timer/timer.cpp index 8758aad21..a801761cf 100644 --- a/src/timer/timer.cpp +++ b/src/timer/timer.cpp @@ -1,6 +1,6 @@ /** * Timestamp Functions Source File -* (C) 1999-2008 Jack Lloyd +* (C) 1999-2009 Jack Lloyd */ #include <botan/timer.h> @@ -21,19 +21,10 @@ u64bit system_time() /** * Read the clock and return the output */ -u32bit Timer::fast_poll(byte out[], u32bit length) +void Timer::poll(Entropy_Accumulator& accum) { const u64bit clock_value = this->clock(); - - for(u32bit j = 0; j != sizeof(clock_value); ++j) - out[j % length] ^= get_byte(j, clock_value); - - return (length < 8) ? length : 8; - } - -u32bit Timer::slow_poll(byte out[], u32bit length) - { - return fast_poll(out, length); + accum.add(clock_value, 0); } /** @@ -56,5 +47,4 @@ u64bit ANSI_Clock_Timer::clock() const return combine_timers(std::time(0), std::clock(), CLOCKS_PER_SEC); } - } diff --git a/src/timer/timer.h b/src/timer/timer.h index af2c58dcb..0e0dcc62e 100644 --- a/src/timer/timer.h +++ b/src/timer/timer.h @@ -1,6 +1,6 @@ /** * Timestamp Functions Header File -* (C) 1999-2008 Jack Lloyd +* (C) 1999-2009 Jack Lloyd */ #ifndef BOTAN_TIMERS_H__ @@ -21,8 +21,7 @@ class BOTAN_DLL Timer : public EntropySource */ virtual u64bit clock() const = 0; - u32bit slow_poll(byte[], u32bit); - u32bit fast_poll(byte[], u32bit); + void poll(Entropy_Accumulator& accum); virtual ~Timer() {} protected: diff --git a/src/utils/info.txt b/src/utils/info.txt index 915ce50b0..ffc19c852 100644 --- a/src/utils/info.txt +++ b/src/utils/info.txt @@ -42,6 +42,5 @@ util.cpp util.h version.cpp version.h -xor_buf.cpp xor_buf.h </add> diff --git a/src/utils/xor_buf.cpp b/src/utils/xor_buf.cpp deleted file mode 100644 index 779be81c3..000000000 --- a/src/utils/xor_buf.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/** -* XOR operations -* (C) 1999-2008 Jack Lloyd -*/ - -#include <botan/xor_buf.h> -#include <botan/loadstor.h> - -namespace Botan { - -/** -* Xor values into buffer -*/ -u32bit xor_into_buf(byte buf[], u32bit buf_i, u32bit length, - const void* in_void, u32bit in_len) - { - const byte* in = static_cast<const byte*>(in_void); - - byte last = 0; - byte count = 0; - - for(u32bit i = 0; i != in_len; ++i) - { - if(in[i] != last) - { - buf[buf_i] ^= last; - buf_i = (buf_i + 1) % length; - - buf[buf_i] ^= count; - buf_i = (buf_i + 1) % length; - - last = in[i]; - count = 1; - } - else - ++count; - } - - // final values of last, count are thrown away - - return buf_i; - } - -} diff --git a/src/utils/xor_buf.h b/src/utils/xor_buf.h index 076877e02..2bf6ced59 100644 --- a/src/utils/xor_buf.h +++ b/src/utils/xor_buf.h @@ -67,24 +67,6 @@ inline void xor_buf(byte out[], out[j] = in[j] ^ in2[j]; } -/** -* XOR values into buffer. Uses RLE compression -* Intended for use in entropy sources to gather collected -* data into a buffer to pass to an RNG. -*/ -u32bit xor_into_buf(byte buf[], u32bit buf_i, u32bit length, - const void* in_void, u32bit in_len); - -/** -* XOR integer value (or something else, I guess) into buffer -*/ -template<typename T> -u32bit xor_into_buf(byte buf[], u32bit buf_i, - u32bit length, const T& in) - { - return xor_into_buf(buf, buf_i, length, &in, sizeof(in)); - } - } #endif |