Botan
1.11.15
|
00001 /* 00002 * Reader of /dev/random and company 00003 * (C) 1999-2009,2013 Jack Lloyd 00004 * 00005 * Botan is released under the Simplified BSD License (see license.txt) 00006 */ 00007 00008 #include <botan/internal/dev_random.h> 00009 #include <botan/internal/rounding.h> 00010 00011 #include <sys/types.h> 00012 #include <sys/select.h> 00013 #include <sys/stat.h> 00014 #include <unistd.h> 00015 #include <fcntl.h> 00016 00017 namespace Botan { 00018 00019 /** 00020 Device_EntropySource constructor 00021 Open a file descriptor to each (available) device in fsnames 00022 */ 00023 Device_EntropySource::Device_EntropySource(const std::vector<std::string>& fsnames) 00024 { 00025 #ifndef O_NONBLOCK 00026 #define O_NONBLOCK 0 00027 #endif 00028 00029 #ifndef O_NOCTTY 00030 #define O_NOCTTY 0 00031 #endif 00032 00033 const int flags = O_RDONLY | O_NONBLOCK | O_NOCTTY; 00034 00035 for(auto fsname : fsnames) 00036 { 00037 fd_type fd = ::open(fsname.c_str(), flags); 00038 00039 if(fd >= 0 && fd < FD_SETSIZE) 00040 m_devices.push_back(fd); 00041 else if(fd >= 0) 00042 ::close(fd); 00043 } 00044 } 00045 00046 /** 00047 Device_EntropySource destructor: close all open devices 00048 */ 00049 Device_EntropySource::~Device_EntropySource() 00050 { 00051 for(size_t i = 0; i != m_devices.size(); ++i) 00052 ::close(m_devices[i]); 00053 } 00054 00055 /** 00056 * Gather entropy from a RNG device 00057 */ 00058 void Device_EntropySource::poll(Entropy_Accumulator& accum) 00059 { 00060 if(m_devices.empty()) 00061 return; 00062 00063 const size_t ENTROPY_BITS_PER_BYTE = 8; 00064 const size_t MS_WAIT_TIME = 32; 00065 const size_t READ_ATTEMPT = 32; 00066 00067 int max_fd = m_devices[0]; 00068 fd_set read_set; 00069 FD_ZERO(&read_set); 00070 for(size_t i = 0; i != m_devices.size(); ++i) 00071 { 00072 FD_SET(m_devices[i], &read_set); 00073 max_fd = std::max(m_devices[i], max_fd); 00074 } 00075 00076 struct ::timeval timeout; 00077 00078 timeout.tv_sec = (MS_WAIT_TIME / 1000); 00079 timeout.tv_usec = (MS_WAIT_TIME % 1000) * 1000; 00080 00081 if(::select(max_fd + 1, &read_set, nullptr, nullptr, &timeout) < 0) 00082 return; 00083 00084 secure_vector<byte>& io_buffer = accum.get_io_buffer(READ_ATTEMPT); 00085 00086 for(size_t i = 0; i != m_devices.size(); ++i) 00087 { 00088 if(FD_ISSET(m_devices[i], &read_set)) 00089 { 00090 const ssize_t got = ::read(m_devices[i], &io_buffer[0], io_buffer.size()); 00091 if(got > 0) 00092 accum.add(&io_buffer[0], got, ENTROPY_BITS_PER_BYTE); 00093 } 00094 } 00095 } 00096 00097 }