From c055f425107cf20c1b8b7c692d5133509dfad52e Mon Sep 17 00:00:00 2001 From: lloyd Date: Tue, 27 Jan 2009 00:16:49 +0000 Subject: Check in a branch with a major redesign on how entropy polling is performed. Combine the fast and slow polls, into a single poll() operation. Instead of being given a buffer to write output into, the EntropySource is passed an Entropy_Accumulator. This handles the RLE encoding that xor_into_buf used to do. It also contains a cached I/O buffer so entropy sources do not individually need to allocate memory for that with each poll. When data is added to the accumulator, the source specifies an estimate of the number of bits of entropy per byte, as a double. This is tracked in the accumulator. Once the estimated entropy hits a target (set by the constructor), the accumulator's member function predicate polling_goal_achieved flips to true. This signals to the PRNG that it can stop performing polling on sources, also polls that take a long time periodically check this flag and return immediately. The Win32 and BeOS entropy sources have been updated, but blindly; testing is needed. The test_es example program has been modified: now it polls twice and outputs the XOR of the two collected results. That helps show if the output is consistent across polls (not a good thing). I have noticed on the Unix entropy source, occasionally there are many 0x00 bytes in the output, which is not optimal. This also needs to be investigated. The RLE is not actually RLE anymore. It works well for non-random inputs (ASCII text, etc), but I noticed that when /dev/random output was fed into it, the output buffer would end up being RR01RR01RR01 where RR is a random byte and 00 is the byte count. The buffer sizing also needs to be examined carefully. It might be useful to choose a prime number for the size to XOR stuff into, to help ensure an even distribution of entropy across the entire buffer space. Or: feed it all into a hash function? This change should (perhaps with further modifications) help WRT the concerns Zack W raised about the RNG on the monotone-dev list. --- checks/common.h | 2 + doc/examples/test_es.cpp | 39 +++++--- doc/license.txt | 2 +- src/entropy/beos_stats/es_beos.cpp | 43 +++----- src/entropy/beos_stats/es_beos.h | 3 +- src/entropy/cryptoapi_rng/es_capi.cpp | 107 ++++++++++---------- src/entropy/cryptoapi_rng/es_capi.h | 9 +- src/entropy/dev_random/es_dev.cpp | 48 +++++---- src/entropy/dev_random/es_dev.h | 16 ++- src/entropy/egd/es_egd.cpp | 128 ++++++++++++++---------- src/entropy/egd/es_egd.h | 10 +- src/entropy/entropy_acc.cpp | 87 +++++++++++++++++ src/entropy/entropy_src.h | 49 ++++++++-- src/entropy/info.txt | 1 + src/entropy/proc_walk/es_ftw.cpp | 42 +++----- src/entropy/proc_walk/es_ftw.h | 9 +- src/entropy/unix_procs/es_unix.cpp | 99 ++++++++----------- src/entropy/unix_procs/es_unix.h | 20 ++-- src/entropy/unix_procs/unix_cmd.cpp | 74 +++++++------- src/entropy/unix_procs/unix_cmd.h | 20 ++-- src/entropy/unix_procs/unix_src.cpp | 14 +-- src/entropy/win32_stats/es_win32.cpp | 167 +++++++++++++++---------------- src/entropy/win32_stats/es_win32.h | 6 +- src/rng/auto_rng/auto_rng.cpp | 19 ++-- src/rng/auto_rng/auto_rng.h | 4 +- src/rng/hmac_rng/hmac_rng.cpp | 178 ++++++++++++---------------------- src/rng/hmac_rng/hmac_rng.h | 13 +-- src/rng/randpool/randpool.cpp | 140 +++++++++++--------------- src/rng/randpool/randpool.h | 22 ++--- src/rng/rng.h | 13 ++- src/rng/x931_rng/x931_rng.cpp | 6 +- src/rng/x931_rng/x931_rng.h | 2 +- src/timer/timer.cpp | 16 +-- src/timer/timer.h | 5 +- src/utils/info.txt | 1 - src/utils/xor_buf.cpp | 44 --------- src/utils/xor_buf.h | 18 ---- 37 files changed, 700 insertions(+), 776 deletions(-) create mode 100644 src/entropy/entropy_acc.cpp delete mode 100644 src/utils/xor_buf.cpp 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 polled1 = accum1.get_entropy_buffer(); + SecureVector polled2 = accum2.get_entropy_buffer(); + + SecureVector 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 -#include #include #include @@ -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(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 #include @@ -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& 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 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 @@ -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& 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(accum.desired_remaining_bits() / 8, 32); + + MemoryRegion& 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& 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 @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -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(&addr), len) < 0) + if(::connect(fd, reinterpret_cast(&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(std::min(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(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& 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(accum.desired_remaining_bits() / 8, 32); + + MemoryRegion& 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(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(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(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&); ~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 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 + +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(goal_bits / 4, 16)); + io_buffer.destroy(); + } + +MemoryRegion& 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(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(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,16 +1,51 @@ -/************************************************* -* 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 +#include #include +#include 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& get_entropy_buffer() const + { return entropy_buf; } + + MemoryRegion& 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 + void add(const T& v, double bits_per_byte) + { + add(&v, sizeof(T), bits_per_byte); + } + private: + SecureVector io_buffer, entropy_buf; + u32bit collected_bits, goal_bits; + }; + /** * Abstract interface to a source of (hopefully unpredictable) system entropy */ @@ -18,9 +53,7 @@ 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 entropy_src.h +entropy_acc.cpp 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 #include -#include #include #include @@ -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 read_buf(4096); - - u32bit bytes_read = 0; - u32bit buf_i = 0; + MemoryRegion& 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(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 #include #include -#include #include #include #include @@ -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& 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(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& 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 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& path); private: static void add_default_sources(std::vector&); - - u32bit fast_poll(byte buf[], u32bit length); - u32bit slow_poll(byte buf[], u32bit length); + void fast_poll(Entropy_Accumulator& accum); const std::vector PATH; std::vector 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 #include @@ -18,9 +18,9 @@ namespace Botan { namespace { -/************************************************* -* Attempt to execute the command * -************************************************/ +/** +* Attempt to execute the command +*/ void do_exec(const std::vector& arg_list, const std::vector& paths) { @@ -41,9 +41,9 @@ void do_exec(const std::vector& 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(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& paths) { bool found_something = false; @@ -169,9 +169,9 @@ void DataSource_Command::create_pipe(const std::vector& 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& 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 namespace Botan { -/************************************************* -* Default Commands for Entropy Gathering * -*************************************************/ +/** +* Default Commands for Entropy Gathering +*/ void Unix_EntropySource::add_default_sources(std::vector& 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 -#include #include #include 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(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 #include @@ -16,9 +16,9 @@ namespace Botan { namespace { void hmac_prf(MessageAuthenticationCode* prf, - MemoryRegion& K, - u32bit& counter, - const std::string& label) + MemoryRegion& 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(entropy, 8 * extractor->OUTPUT_LENGTH); + entropy = std::min(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 #include @@ -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 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 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 mac_val = mac->final(); + SecureVector mac_val = mac->process(accum.get_entropy_buffer()); xor_buf(pool, mac_val, mac_val.size()); mix_pool(); - entropy = std::min(entropy + entropy_est, 8 * mac_val.size()); + entropy = std::min(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 mac_val = mac->process(input, length); @@ -166,25 +138,25 @@ void Randpool::add_entropy(const byte input[], u32bit length) entropy = std::min(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 @@ -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 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 -#include - -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(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 -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 -- cgit v1.2.3