aboutsummaryrefslogtreecommitdiffstats
path: root/src/entropy/dev_random/dev_random.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/entropy/dev_random/dev_random.cpp')
-rw-r--r--src/entropy/dev_random/dev_random.cpp125
1 files changed, 125 insertions, 0 deletions
diff --git a/src/entropy/dev_random/dev_random.cpp b/src/entropy/dev_random/dev_random.cpp
new file mode 100644
index 000000000..d0babfd1e
--- /dev/null
+++ b/src/entropy/dev_random/dev_random.cpp
@@ -0,0 +1,125 @@
+/*
+* /dev/random EntropySource
+* (C) 1999-2009 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/internal/dev_random.h>
+
+#include <sys/types.h>
+#include <sys/select.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+namespace Botan {
+
+/**
+Close the device, if open
+*/
+void Device_EntropySource::Device_Reader::close()
+ {
+ if(fd > 0) { ::close(fd); fd = -1; }
+ }
+
+/**
+Read bytes from a device file
+*/
+u32bit Device_EntropySource::Device_Reader::get(byte out[], u32bit length,
+ u32bit ms_wait_time)
+ {
+ if(fd < 0)
+ return 0;
+
+ if(fd >= FD_SETSIZE)
+ return 0;
+
+ fd_set read_set;
+ FD_ZERO(&read_set);
+ FD_SET(fd, &read_set);
+
+ struct ::timeval timeout;
+
+ timeout.tv_sec = (ms_wait_time / 1000);
+ timeout.tv_usec = (ms_wait_time % 1000) * 1000;
+
+ if(::select(fd + 1, &read_set, 0, 0, &timeout) < 0)
+ return 0;
+
+ if(!(FD_ISSET(fd, &read_set)))
+ return 0;
+
+ const ssize_t got = ::read(fd, out, length);
+ if(got <= 0)
+ return 0;
+
+ return static_cast<u32bit>(got);
+ }
+
+/**
+Attempt to open a device
+*/
+Device_EntropySource::Device_Reader::fd_type
+Device_EntropySource::Device_Reader::open(const std::string& pathname)
+ {
+#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;
+ return ::open(pathname.c_str(), flags);
+ }
+
+/**
+Device_EntropySource constructor
+Open a file descriptor to each (available) device in fsnames
+*/
+Device_EntropySource::Device_EntropySource(
+ const std::vector<std::string>& fsnames)
+ {
+ for(u32bit i = 0; i != fsnames.size(); ++i)
+ {
+ Device_Reader::fd_type fd = Device_Reader::open(fsnames[i]);
+ if(fd > 0)
+ devices.push_back(Device_Reader(fd));
+ }
+ }
+
+/**
+Device_EntropySource destructor: close all open devices
+*/
+Device_EntropySource::~Device_EntropySource()
+ {
+ for(size_t i = 0; i != devices.size(); ++i)
+ devices[i].close();
+ }
+
+/**
+* Gather entropy from a RNG device
+*/
+void Device_EntropySource::poll(Entropy_Accumulator& accum)
+ {
+ u32bit go_get = std::min<u32bit>(accum.desired_remaining_bits() / 8, 48);
+
+ u32bit read_wait_ms = std::max<u32bit>(go_get, 1000);
+ MemoryRegion<byte>& io_buffer = accum.get_io_buffer(go_get);
+
+ for(size_t i = 0; i != devices.size(); ++i)
+ {
+ u32bit got = devices[i].get(io_buffer.begin(), io_buffer.size(),
+ read_wait_ms);
+
+ if(got)
+ {
+ accum.add(io_buffer.begin(), got, 8);
+ break;
+ }
+ }
+ }
+
+}