Botan
1.11.15
|
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 }