Botan  1.11.15
src/lib/entropy/dev_random/dev_random.cpp
Go to the documentation of this file.
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 }