00001
00002
00003
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 byte NonblockingRng::GenerateByte()
00078 {
00079 byte b;
00080 GenerateBlock(&b, 1);
00081 return b;
00082 }
00083
00084 void NonblockingRng::GenerateBlock(byte *output, unsigned int size)
00085 {
00086 #ifdef CRYPTOPP_WIN32_AVAILABLE
00087 # ifdef WORKAROUND_MS_BUG_Q258000
00088 static MicrosoftCryptoProvider m_Provider;
00089 # endif
00090 if (!CryptGenRandom(m_Provider.GetProviderHandle(), size, output))
00091 throw OS_RNG_Err("CryptGenRandom");
00092 #else
00093 if (std::size_t(size) > std::size_t(SSIZE_MAX)
00094 || read(m_fd, output, size) != ssize_t(size))
00095 throw OS_RNG_Err("read /dev/urandom");
00096 #endif
00097 }
00098
00099 #endif
00100
00101
00102
00103 #ifdef BLOCKING_RNG_AVAILABLE
00104
00105 BlockingRng::BlockingRng()
00106 {
00107 m_fd = open("/dev/random",O_RDONLY);
00108 if (m_fd == -1)
00109 throw OS_RNG_Err("open /dev/random");
00110 }
00111
00112 BlockingRng::~BlockingRng()
00113 {
00114 close(m_fd);
00115 }
00116
00117 byte BlockingRng::GenerateByte()
00118 {
00119 byte b;
00120 GenerateBlock(&b, 1);
00121 return b;
00122 }
00123
00124 void BlockingRng::GenerateBlock(byte *output, unsigned int size)
00125 {
00126 while (size)
00127 {
00128
00129
00130 int len = read(m_fd, output, STDMIN(size, (unsigned int)INT_MAX));
00131 if (len == -1)
00132 throw OS_RNG_Err("read /dev/random");
00133 size -= len;
00134 output += len;
00135 if (size)
00136 sleep(1);
00137 }
00138 }
00139
00140 #endif
00141
00142
00143
00144 void OS_GenerateRandomBlock(bool blocking, byte *output, unsigned int size)
00145 {
00146 #ifdef NONBLOCKING_RNG_AVAILABLE
00147 if (blocking)
00148 #endif
00149 {
00150 #ifdef BLOCKING_RNG_AVAILABLE
00151 BlockingRng rng;
00152 rng.GenerateBlock(output, size);
00153 #endif
00154 }
00155
00156 #ifdef BLOCKING_RNG_AVAILABLE
00157 if (!blocking)
00158 #endif
00159 {
00160 #ifdef NONBLOCKING_RNG_AVAILABLE
00161 NonblockingRng rng;
00162 rng.GenerateBlock(output, size);
00163 #endif
00164 }
00165 }
00166
00167 void AutoSeededRandomPool::Reseed(bool blocking, unsigned int seedSize)
00168 {
00169 SecByteBlock seed(seedSize);
00170 OS_GenerateRandomBlock(blocking, seed, seedSize);
00171 Put(seed, seedSize);
00172 }
00173
00174 NAMESPACE_END
00175
00176 #endif
00177
00178 #endif