Botan  1.11.15
src/lib/rng/system_rng/system_rng.cpp
Go to the documentation of this file.
00001 /*
00002 * System RNG
00003 * (C) 2014 Jack Lloyd
00004 *
00005 * Botan is released under the Simplified BSD License (see license.txt)
00006 */
00007 
00008 #include <botan/system_rng.h>
00009 
00010 #if defined(BOTAN_TARGET_OS_HAS_CRYPTGENRANDOM)
00011 
00012 #include <windows.h>
00013 #include <wincrypt.h>
00014 #undef min
00015 #undef max
00016 
00017 #else
00018 
00019 #include <sys/types.h>
00020 #include <sys/stat.h>
00021 #include <fcntl.h>
00022 #include <unistd.h>
00023 #include <errno.h>
00024 
00025 #endif
00026 
00027 namespace Botan {
00028 
00029 namespace {
00030 
00031 class System_RNG : public RandomNumberGenerator
00032    {
00033    public:
00034       System_RNG();
00035       ~System_RNG();
00036 
00037       void randomize(byte buf[], size_t len);
00038 
00039       bool is_seeded() const { return true; }
00040       void clear() {}
00041       std::string name() const { return "system"; }
00042 
00043       void reseed(size_t) {}
00044       void add_entropy(const byte[], size_t) {}
00045    private:
00046 
00047 #if defined(BOTAN_TARGET_OS_HAS_CRYPTGENRANDOM)
00048       HCRYPTPROV m_prov;
00049 #else
00050       int m_fd;
00051 #endif
00052    };
00053 
00054 System_RNG::System_RNG()
00055    {
00056 #if defined(BOTAN_TARGET_OS_HAS_CRYPTGENRANDOM)
00057 
00058    if(!CryptAcquireContext(&m_prov, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
00059       throw std::runtime_error("System_RNG failed to acquire crypto provider");
00060 
00061 #else
00062 
00063    m_fd = ::open("/dev/urandom", O_RDONLY);
00064    if(m_fd < 0)
00065       throw std::runtime_error("System_RNG failed to open /dev/urandom");
00066 #endif
00067    }
00068 
00069 System_RNG::~System_RNG()
00070    {
00071 #if defined(BOTAN_TARGET_OS_HAS_CRYPTGENRANDOM)
00072    ::CryptReleaseContext(m_prov, 0);
00073 #else
00074    ::close(m_fd);
00075    m_fd = -1;
00076 #endif
00077    }
00078 
00079 void System_RNG::randomize(byte buf[], size_t len)
00080    {
00081 #if defined(BOTAN_TARGET_OS_HAS_CRYPTGENRANDOM)
00082    ::CryptGenRandom(m_prov, static_cast<DWORD>(len), buf);
00083 #else
00084    while(len)
00085       {
00086       ssize_t got = ::read(m_fd, buf, len);
00087 
00088       if(got < 0)
00089          {
00090          if(errno == EINTR)
00091             continue;
00092          throw std::runtime_error("System_RNG read failed error " + std::to_string(errno));
00093          }
00094       if(got == 0)
00095          throw std::runtime_error("System_RNG EOF on device"); // ?!?
00096 
00097       buf += got;
00098       len -= got;
00099       }
00100 #endif
00101    }
00102 
00103 }
00104 
00105 RandomNumberGenerator& system_rng()
00106    {
00107    static System_RNG g_system_rng;
00108    return g_system_rng;
00109    }
00110 
00111 }