Crypto++
|
00001 // osrng.cpp - written and placed in the public domain by Wei Dai 00002 00003 // Thanks to Leonard Janke for the suggestion for AutoSeededRandomPool. 00004 00005 #include "pch.h" 00006 00007 #ifndef CRYPTOPP_IMPORTS 00008 00009 #include "osrng.h" 00010 00011 #ifdef OS_RNG_AVAILABLE 00012 00013 #include "rng.h" 00014 00015 #ifdef CRYPTOPP_WIN32_AVAILABLE 00016 #ifndef _WIN32_WINNT 00017 #define _WIN32_WINNT 0x0400 00018 #endif 00019 #include <windows.h> 00020 #include <wincrypt.h> 00021 #endif 00022 00023 #ifdef CRYPTOPP_UNIX_AVAILABLE 00024 #include <errno.h> 00025 #include <fcntl.h> 00026 #include <unistd.h> 00027 #endif 00028 00029 NAMESPACE_BEGIN(CryptoPP) 00030 00031 #if defined(NONBLOCKING_RNG_AVAILABLE) || defined(BLOCKING_RNG_AVAILABLE) 00032 OS_RNG_Err::OS_RNG_Err(const std::string &operation) 00033 : Exception(OTHER_ERROR, "OS_Rng: " + operation + " operation failed with error " + 00034 #ifdef CRYPTOPP_WIN32_AVAILABLE 00035 "0x" + IntToString(GetLastError(), 16) 00036 #else 00037 IntToString(errno) 00038 #endif 00039 ) 00040 { 00041 } 00042 #endif 00043 00044 #ifdef NONBLOCKING_RNG_AVAILABLE 00045 00046 #ifdef CRYPTOPP_WIN32_AVAILABLE 00047 00048 MicrosoftCryptoProvider::MicrosoftCryptoProvider() 00049 { 00050 if(!CryptAcquireContext(&m_hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) 00051 throw OS_RNG_Err("CryptAcquireContext"); 00052 } 00053 00054 MicrosoftCryptoProvider::~MicrosoftCryptoProvider() 00055 { 00056 CryptReleaseContext(m_hProvider, 0); 00057 } 00058 00059 #endif 00060 00061 NonblockingRng::NonblockingRng() 00062 { 00063 #ifndef CRYPTOPP_WIN32_AVAILABLE 00064 m_fd = open("/dev/urandom",O_RDONLY); 00065 if (m_fd == -1) 00066 throw OS_RNG_Err("open /dev/urandom"); 00067 #endif 00068 } 00069 00070 NonblockingRng::~NonblockingRng() 00071 { 00072 #ifndef CRYPTOPP_WIN32_AVAILABLE 00073 close(m_fd); 00074 #endif 00075 } 00076 00077 void NonblockingRng::GenerateBlock(byte *output, size_t size) 00078 { 00079 #ifdef CRYPTOPP_WIN32_AVAILABLE 00080 # ifdef WORKAROUND_MS_BUG_Q258000 00081 const MicrosoftCryptoProvider &m_Provider = Singleton<MicrosoftCryptoProvider>().Ref(); 00082 # endif 00083 if (!CryptGenRandom(m_Provider.GetProviderHandle(), (DWORD)size, output)) 00084 throw OS_RNG_Err("CryptGenRandom"); 00085 #else 00086 if (read(m_fd, output, size) != size) 00087 throw OS_RNG_Err("read /dev/urandom"); 00088 #endif 00089 } 00090 00091 #endif 00092 00093 // ************************************************************* 00094 00095 #ifdef BLOCKING_RNG_AVAILABLE 00096 00097 #ifndef CRYPTOPP_BLOCKING_RNG_FILENAME 00098 #ifdef __OpenBSD__ 00099 #define CRYPTOPP_BLOCKING_RNG_FILENAME "/dev/srandom" 00100 #else 00101 #define CRYPTOPP_BLOCKING_RNG_FILENAME "/dev/random" 00102 #endif 00103 #endif 00104 00105 BlockingRng::BlockingRng() 00106 { 00107 m_fd = open(CRYPTOPP_BLOCKING_RNG_FILENAME,O_RDONLY); 00108 if (m_fd == -1) 00109 throw OS_RNG_Err("open " CRYPTOPP_BLOCKING_RNG_FILENAME); 00110 } 00111 00112 BlockingRng::~BlockingRng() 00113 { 00114 close(m_fd); 00115 } 00116 00117 void BlockingRng::GenerateBlock(byte *output, size_t size) 00118 { 00119 while (size) 00120 { 00121 // on some systems /dev/random will block until all bytes 00122 // are available, on others it will returns immediately 00123 ssize_t len = read(m_fd, output, size); 00124 if (len < 0) 00125 throw OS_RNG_Err("read " CRYPTOPP_BLOCKING_RNG_FILENAME); 00126 size -= len; 00127 output += len; 00128 if (size) 00129 sleep(1); 00130 } 00131 } 00132 00133 #endif 00134 00135 // ************************************************************* 00136 00137 void OS_GenerateRandomBlock(bool blocking, byte *output, size_t size) 00138 { 00139 #ifdef NONBLOCKING_RNG_AVAILABLE 00140 if (blocking) 00141 #endif 00142 { 00143 #ifdef BLOCKING_RNG_AVAILABLE 00144 BlockingRng rng; 00145 rng.GenerateBlock(output, size); 00146 #endif 00147 } 00148 00149 #ifdef BLOCKING_RNG_AVAILABLE 00150 if (!blocking) 00151 #endif 00152 { 00153 #ifdef NONBLOCKING_RNG_AVAILABLE 00154 NonblockingRng rng; 00155 rng.GenerateBlock(output, size); 00156 #endif 00157 } 00158 } 00159 00160 void AutoSeededRandomPool::Reseed(bool blocking, unsigned int seedSize) 00161 { 00162 SecByteBlock seed(seedSize); 00163 OS_GenerateRandomBlock(blocking, seed, seedSize); 00164 IncorporateEntropy(seed, seedSize); 00165 } 00166 00167 NAMESPACE_END 00168 00169 #endif 00170 00171 #endif