aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/entropy/dev_random/dev_random.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/entropy/dev_random/dev_random.cpp')
-rw-r--r--src/lib/entropy/dev_random/dev_random.cpp97
1 files changed, 97 insertions, 0 deletions
diff --git a/src/lib/entropy/dev_random/dev_random.cpp b/src/lib/entropy/dev_random/dev_random.cpp
new file mode 100644
index 000000000..3f8df8749
--- /dev/null
+++ b/src/lib/entropy/dev_random/dev_random.cpp
@@ -0,0 +1,97 @@
+/*
+* Reader of /dev/random and company
+* (C) 1999-2009,2013 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/internal/dev_random.h>
+#include <botan/internal/rounding.h>
+
+#include <sys/types.h>
+#include <sys/select.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+
+namespace Botan {
+
+/**
+Device_EntropySource constructor
+Open a file descriptor to each (available) device in fsnames
+*/
+Device_EntropySource::Device_EntropySource(const std::vector<std::string>& fsnames)
+ {
+#ifndef O_NONBLOCK
+ #define O_NONBLOCK 0
+#endif
+
+#ifndef O_NOCTTY
+ #define O_NOCTTY 0
+#endif
+
+ const int flags = O_RDONLY | O_NONBLOCK | O_NOCTTY;
+
+ for(auto fsname : fsnames)
+ {
+ fd_type fd = ::open(fsname.c_str(), flags);
+
+ if(fd >= 0 && fd < FD_SETSIZE)
+ m_devices.push_back(fd);
+ else if(fd >= 0)
+ ::close(fd);
+ }
+ }
+
+/**
+Device_EntropySource destructor: close all open devices
+*/
+Device_EntropySource::~Device_EntropySource()
+ {
+ for(size_t i = 0; i != m_devices.size(); ++i)
+ ::close(m_devices[i]);
+ }
+
+/**
+* Gather entropy from a RNG device
+*/
+void Device_EntropySource::poll(Entropy_Accumulator& accum)
+ {
+ if(m_devices.empty())
+ return;
+
+ const size_t ENTROPY_BITS_PER_BYTE = 8;
+ const size_t MS_WAIT_TIME = 32;
+ const size_t READ_ATTEMPT = std::max<size_t>(accum.desired_remaining_bits() / 8, 16);
+
+ int max_fd = m_devices[0];
+ fd_set read_set;
+ FD_ZERO(&read_set);
+ for(size_t i = 0; i != m_devices.size(); ++i)
+ {
+ FD_SET(m_devices[i], &read_set);
+ max_fd = std::max(m_devices[i], max_fd);
+ }
+
+ struct ::timeval timeout;
+
+ timeout.tv_sec = (MS_WAIT_TIME / 1000);
+ timeout.tv_usec = (MS_WAIT_TIME % 1000) * 1000;
+
+ if(::select(max_fd + 1, &read_set, nullptr, nullptr, &timeout) < 0)
+ return;
+
+ secure_vector<byte>& io_buffer = accum.get_io_buffer(READ_ATTEMPT);
+
+ for(size_t i = 0; i != m_devices.size(); ++i)
+ {
+ if(FD_ISSET(m_devices[i], &read_set))
+ {
+ const ssize_t got = ::read(m_devices[i], &io_buffer[0], io_buffer.size());
+ accum.add(&io_buffer[0], got, ENTROPY_BITS_PER_BYTE);
+ }
+ }
+ }
+
+}