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