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 #else
00022 #include <errno.h>
00023 #include <fcntl.h>
00024 #include <unistd.h>
00025 #endif
00026
00027 NAMESPACE_BEGIN(CryptoPP)
00028
00029 #if defined(NONBLOCKING_RNG_AVAILABLE) || defined(BLOCKING_RNG_AVAILABLE)
00030 OS_RNG_Err::OS_RNG_Err(const std::string &operation)
00031 : Exception(OTHER_ERROR, "OS_Rng: " + operation + " operation failed with error " +
00032 #ifdef CRYPTOPP_WIN32_AVAILABLE
00033 "0x" + IntToString(GetLastError(), 16)
00034 #else
00035 IntToString(errno)
00036 #endif
00037 )
00038 {
00039 }
00040 #endif
00041
00042 #ifdef NONBLOCKING_RNG_AVAILABLE
00043
00044 #ifdef CRYPTOPP_WIN32_AVAILABLE
00045
00046 MicrosoftCryptoProvider::MicrosoftCryptoProvider()
00047 {
00048 if(!CryptAcquireContext(&m_hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
00049 throw OS_RNG_Err("CryptAcquireContext");
00050 }
00051
00052 MicrosoftCryptoProvider::~MicrosoftCryptoProvider()
00053 {
00054 CryptReleaseContext(m_hProvider, 0);
00055 }
00056
00057 #endif
00058
00059 NonblockingRng::NonblockingRng()
00060 {
00061 #ifndef CRYPTOPP_WIN32_AVAILABLE
00062 m_fd = open("/dev/urandom",O_RDONLY);
00063 if (m_fd == -1)
00064 throw OS_RNG_Err("open /dev/urandom");
00065 #endif
00066 }
00067
00068 NonblockingRng::~NonblockingRng()
00069 {
00070 #ifndef CRYPTOPP_WIN32_AVAILABLE
00071 close(m_fd);
00072 #endif
00073 }
00074
00075 byte NonblockingRng::GenerateByte()
00076 {
00077 byte b;
00078 GenerateBlock(&b, 1);
00079 return b;
00080 }
00081
00082 void NonblockingRng::GenerateBlock(byte *output, unsigned int size)
00083 {
00084 #ifdef CRYPTOPP_WIN32_AVAILABLE
00085 # ifdef WORKAROUND_MS_BUG_Q258000
00086 static MicrosoftCryptoProvider m_Provider;
00087 # endif
00088 if (!CryptGenRandom(m_Provider.GetProviderHandle(), size, output))
00089 throw OS_RNG_Err("CryptGenRandom");
00090 #else
00091 if (read(m_fd, output, size) != size)
00092 throw OS_RNG_Err("read /dev/urandom");
00093 #endif
00094 }
00095
00096 #endif
00097
00098
00099
00100 #ifdef BLOCKING_RNG_AVAILABLE
00101
00102 BlockingRng::BlockingRng()
00103 {
00104 m_fd = open("/dev/random",O_RDONLY);
00105 if (m_fd == -1)
00106 throw OS_RNG_Err("open /dev/random");
00107 }
00108
00109 BlockingRng::~BlockingRng()
00110 {
00111 close(m_fd);
00112 }
00113
00114 byte BlockingRng::GenerateByte()
00115 {
00116 byte b;
00117 GenerateBlock(&b, 1);
00118 return b;
00119 }
00120
00121 void BlockingRng::GenerateBlock(byte *output, unsigned int size)
00122 {
00123 while (size)
00124 {
00125
00126
00127 int len = read(m_fd, output, STDMIN(size, (unsigned int)INT_MAX));
00128 if (len == -1)
00129 throw OS_RNG_Err("read /dev/random");
00130 size -= len;
00131 output += len;
00132 if (size)
00133 sleep(1);
00134 }
00135 }
00136
00137 #endif
00138
00139
00140
00141 void OS_GenerateRandomBlock(bool blocking, byte *output, unsigned int size)
00142 {
00143 #ifdef NONBLOCKING_RNG_AVAILABLE
00144 if (blocking)
00145 #endif
00146 {
00147 #ifdef BLOCKING_RNG_AVAILABLE
00148 BlockingRng rng;
00149 rng.GenerateBlock(output, size);
00150 #endif
00151 }
00152
00153 #ifdef BLOCKING_RNG_AVAILABLE
00154 if (!blocking)
00155 #endif
00156 {
00157 #ifdef NONBLOCKING_RNG_AVAILABLE
00158 NonblockingRng rng;
00159 rng.GenerateBlock(output, size);
00160 #endif
00161 }
00162 }
00163
00164 void AutoSeededRandomPool::Reseed(bool blocking, unsigned int seedSize)
00165 {
00166 SecByteBlock seed(seedSize);
00167 OS_GenerateRandomBlock(blocking, seed, seedSize);
00168 Put(seed, seedSize);
00169 }
00170
00171 NAMESPACE_END
00172
00173 #endif
00174
00175 #endif