/* * Reader of /dev/random and company * (C) 1999-2009,2013 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #include #include #include #include #include #include #include namespace Botan { /** Device_EntropySource constructor Open a file descriptor to each (available) device in fsnames */ Device_EntropySource::Device_EntropySource(const std::vector& 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; m_max_fd = 0; for(auto fsname : fsnames) { int fd = ::open(fsname.c_str(), flags); if(fd > 0) { if(fd > FD_SETSIZE) { ::close(fd); throw Exception("Open of OS RNG succeeded but fd is too large for fd_set"); } m_dev_fds.push_back(fd); m_max_fd = std::max(m_max_fd, fd); } else { /* ENOENT or EACCES is normal as some of the named devices may not exist on this system. But any other errno value probably indicates either a bug in the application or file descriptor exhaustion. */ if(errno != ENOENT && errno != EACCES) { throw Exception("Opening OS RNG device failed with errno " + std::to_string(errno)); } } } } /** Device_EntropySource destructor: close all open devices */ Device_EntropySource::~Device_EntropySource() { for(int fd : m_dev_fds) { // ignoring return value here, can't throw in destructor anyway ::close(fd); } } /** * Gather entropy from a RNG device */ size_t Device_EntropySource::poll(RandomNumberGenerator& rng) { size_t bits = 0; if(m_dev_fds.size() > 0) { fd_set read_set; FD_ZERO(&read_set); for(int dev_fd : m_dev_fds) { FD_SET(dev_fd, &read_set); } secure_vector io_buf(BOTAN_SYSTEM_RNG_POLL_REQUEST); struct ::timeval timeout; timeout.tv_sec = (BOTAN_SYSTEM_RNG_POLL_TIMEOUT_MS / 1000); timeout.tv_usec = (BOTAN_SYSTEM_RNG_POLL_TIMEOUT_MS % 1000) * 1000; if(::select(m_max_fd + 1, &read_set, nullptr, nullptr, &timeout) > 0) { for(int dev_fd : m_dev_fds) { if(FD_ISSET(dev_fd, &read_set)) { const ssize_t got = ::read(dev_fd, io_buf.data(), io_buf.size()); if(got > 0) { rng.add_entropy(io_buf.data(), static_cast(got)); bits += got * 8; } } } } } return bits; } }