aboutsummaryrefslogtreecommitdiffstats
path: root/src/entropy/egd/es_egd.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/entropy/egd/es_egd.cpp')
-rw-r--r--src/entropy/egd/es_egd.cpp128
1 files changed, 79 insertions, 49 deletions
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));
}
}