Fabcoin Core  0.16.2
P2P Digital Currency
osrng.cpp
Go to the documentation of this file.
1 // osrng.cpp - written and placed in the public domain by Wei Dai
2 
3 // Thanks to Leonard Janke for the suggestion for AutoSeededRandomPool.
4 
5 #include "pch.h"
6 #include "config.h"
7 
8 #ifndef CRYPTOPP_IMPORTS
9 
10 // Win32 has CryptoAPI and <wincrypt.h>. Windows 10 and Windows Store 10 have CNG and <bcrypt.h>.
11 // There's a hole for Windows Phone 8 and Windows Store 8. There is no userland crypto available.
12 // Also see http://stackoverflow.com/questions/36974545/random-numbers-for-windows-phone-8-and-windows-store-8
13 #if defined(CRYPTOPP_WIN32_AVAILABLE) && !defined(OS_RNG_AVAILABLE)
14 # pragma message("WARNING: Compiling for Windows but an OS RNG is not available. This is likely a Windows Phone 8 or Windows Store 8 app.")
15 #endif
16 
17 #if !defined(OS_NO_DEPENDENCE) && defined(OS_RNG_AVAILABLE)
18 
19 #include "osrng.h"
20 #include "rng.h"
21 
22 #ifdef CRYPTOPP_WIN32_AVAILABLE
23 //#ifndef _WIN32_WINNT
24 //#define _WIN32_WINNT 0x0400
25 //#endif
26 #define WIN32_LEAN_AND_MEAN
27 #include <windows.h>
28 #if defined(USE_MS_CRYPTOAPI)
29 #include <wincrypt.h>
30 #ifndef CRYPT_NEWKEYSET
31 # define CRYPT_NEWKEYSET 0x00000008
32 #endif
33 #ifndef CRYPT_MACHINE_KEYSET
34 # define CRYPT_MACHINE_KEYSET 0x00000020
35 #endif
36 #elif defined(USE_MS_CNGAPI)
37 //#include <ntdef.h>
38 #include <bcrypt.h>
39 #ifndef BCRYPT_SUCCESS
40 # define BCRYPT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
41 #endif
42 #ifndef STATUS_INVALID_PARAMETER
43 # define STATUS_INVALID_PARAMETER 0xC000000D
44 #endif
45 #ifndef STATUS_INVALID_HANDLE
46 # define STATUS_INVALID_HANDLE 0xC0000008
47 #endif
48 #endif
49 #endif
50 
51 #ifdef CRYPTOPP_UNIX_AVAILABLE
52 #include <errno.h>
53 #include <fcntl.h>
54 #include <unistd.h>
55 #endif
56 
58 
59 #if defined(NONBLOCKING_RNG_AVAILABLE) || defined(BLOCKING_RNG_AVAILABLE)
60 OS_RNG_Err::OS_RNG_Err(const std::string &operation)
61  : Exception(OTHER_ERROR, "OS_Rng: " + operation + " operation failed with error " +
62 #ifdef CRYPTOPP_WIN32_AVAILABLE
63  "0x" + IntToString(GetLastError(), 16)
64 #else
65  IntToString(errno)
66 #endif
67  )
68 {
69 }
70 #endif
71 
72 #ifdef NONBLOCKING_RNG_AVAILABLE
73 
74 #ifdef CRYPTOPP_WIN32_AVAILABLE
75 
76 #if defined(USE_MS_CNGAPI)
77 inline DWORD NtStatusToErrorCode(NTSTATUS status)
78 {
79  if (status == STATUS_INVALID_PARAMETER)
80  return ERROR_INVALID_PARAMETER;
81  else if (status == STATUS_INVALID_HANDLE)
82  return ERROR_INVALID_HANDLE;
83  else
84  return (DWORD)status;
85 }
86 #endif
87 
88 #if defined(UNICODE) || defined(_UNICODE)
89 # define CRYPTOPP_CONTAINER L"Crypto++ RNG"
90 #else
91 # define CRYPTOPP_CONTAINER "Crypto++ RNG"
92 #endif
93 
94 MicrosoftCryptoProvider::MicrosoftCryptoProvider() : m_hProvider(0)
95 {
96 #if defined(USE_MS_CRYPTOAPI)
97  // See http://support.microsoft.com/en-us/kb/238187 for CRYPT_NEWKEYSET fallback strategy
98  if (!CryptAcquireContext(&m_hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
99  {
100  const DWORD firstErr = GetLastError();
101  if (!CryptAcquireContext(&m_hProvider, CRYPTOPP_CONTAINER, 0, PROV_RSA_FULL, CRYPT_NEWKEYSET /*user*/) &&
102  !CryptAcquireContext(&m_hProvider, CRYPTOPP_CONTAINER, 0, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET|CRYPT_NEWKEYSET))
103  {
104  // Set original error with original code
105  SetLastError(firstErr);
106  throw OS_RNG_Err("CryptAcquireContext");
107  }
108  }
109 #elif defined(USE_MS_CNGAPI)
110  NTSTATUS ret = BCryptOpenAlgorithmProvider(&m_hProvider, BCRYPT_RNG_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0);
111  if (!(BCRYPT_SUCCESS(ret)))
112  {
113  // Hack... OS_RNG_Err calls GetLastError()
114  SetLastError(NtStatusToErrorCode(ret));
115  throw OS_RNG_Err("BCryptOpenAlgorithmProvider");
116  }
117 #endif
118 }
119 
120 MicrosoftCryptoProvider::~MicrosoftCryptoProvider()
121 {
122 #if defined(USE_MS_CRYPTOAPI)
123  if (m_hProvider)
124  CryptReleaseContext(m_hProvider, 0);
125 #elif defined(USE_MS_CNGAPI)
126  if (m_hProvider)
127  BCryptCloseAlgorithmProvider(m_hProvider, 0);
128 #endif
129 }
130 
131 #endif // CRYPTOPP_WIN32_AVAILABLE
132 
133 NonblockingRng::NonblockingRng()
134 {
135 #ifndef CRYPTOPP_WIN32_AVAILABLE
136  m_fd = open("/dev/urandom",O_RDONLY);
137  if (m_fd == -1)
138  throw OS_RNG_Err("open /dev/urandom");
139 #endif
140 }
141 
142 NonblockingRng::~NonblockingRng()
143 {
144 #ifndef CRYPTOPP_WIN32_AVAILABLE
145  close(m_fd);
146 #endif
147 }
148 
149 void NonblockingRng::GenerateBlock(byte *output, size_t size)
150 {
151 #ifdef CRYPTOPP_WIN32_AVAILABLE
152  // Acquiring a provider is expensive. Do it once and retain the reference.
153  static const MicrosoftCryptoProvider &hProvider = Singleton<MicrosoftCryptoProvider>().Ref();
154 # if defined(USE_MS_CRYPTOAPI)
155  if (!CryptGenRandom(hProvider.GetProviderHandle(), (DWORD)size, output))
156  throw OS_RNG_Err("CryptGenRandom");
157 # elif defined(USE_MS_CNGAPI)
158  NTSTATUS ret = BCryptGenRandom(hProvider.GetProviderHandle(), output, (ULONG)size, 0);
159  if (!(BCRYPT_SUCCESS(ret)))
160  {
161  // Hack... OS_RNG_Err calls GetLastError()
162  SetLastError(NtStatusToErrorCode(ret));
163  throw OS_RNG_Err("BCryptGenRandom");
164  }
165 # endif
166 #else
167  while (size)
168  {
169  ssize_t len = read(m_fd, output, size);
170  if (len < 0)
171  {
172  // /dev/urandom reads CAN give EAGAIN errors! (maybe EINTR as well)
173  if (errno != EINTR && errno != EAGAIN)
174  throw OS_RNG_Err("read /dev/urandom");
175 
176  continue;
177  }
178 
179  output += len;
180  size -= len;
181  }
182 #endif // CRYPTOPP_WIN32_AVAILABLE
183 }
184 
185 #endif // NONBLOCKING_RNG_AVAILABLE
186 
187 // *************************************************************
188 
189 #ifdef BLOCKING_RNG_AVAILABLE
190 
191 #ifndef CRYPTOPP_BLOCKING_RNG_FILENAME
192 #ifdef __OpenBSD__
193 #define CRYPTOPP_BLOCKING_RNG_FILENAME "/dev/srandom"
194 #else
195 #define CRYPTOPP_BLOCKING_RNG_FILENAME "/dev/random"
196 #endif
197 #endif
198 
199 BlockingRng::BlockingRng()
200 {
201  m_fd = open(CRYPTOPP_BLOCKING_RNG_FILENAME,O_RDONLY);
202  if (m_fd == -1)
203  throw OS_RNG_Err("open " CRYPTOPP_BLOCKING_RNG_FILENAME);
204 }
205 
206 BlockingRng::~BlockingRng()
207 {
208  close(m_fd);
209 }
210 
211 void BlockingRng::GenerateBlock(byte *output, size_t size)
212 {
213  while (size)
214  {
215  // on some systems /dev/random will block until all bytes
216  // are available, on others it returns immediately
217  ssize_t len = read(m_fd, output, size);
218  if (len < 0)
219  {
220  // /dev/random reads CAN give EAGAIN errors! (maybe EINTR as well)
221  if (errno != EINTR && errno != EAGAIN)
222  throw OS_RNG_Err("read " CRYPTOPP_BLOCKING_RNG_FILENAME);
223 
224  continue;
225  }
226 
227  size -= len;
228  output += len;
229  if (size)
230  sleep(1);
231  }
232 }
233 
234 #endif // BLOCKING_RNG_AVAILABLE
235 
236 // *************************************************************
237 
238 void OS_GenerateRandomBlock(bool blocking, byte *output, size_t size)
239 {
240 #ifdef NONBLOCKING_RNG_AVAILABLE
241  if (blocking)
242 #endif
243  {
244 #ifdef BLOCKING_RNG_AVAILABLE
245  BlockingRng rng;
246  rng.GenerateBlock(output, size);
247 #endif
248  }
249 
250 #ifdef BLOCKING_RNG_AVAILABLE
251  if (!blocking)
252 #endif
253  {
254 #ifdef NONBLOCKING_RNG_AVAILABLE
255  NonblockingRng rng;
256  rng.GenerateBlock(output, size);
257 #endif
258  }
259 }
260 
261 void AutoSeededRandomPool::Reseed(bool blocking, unsigned int seedSize)
262 {
263  SecByteBlock seed(seedSize);
264  OS_GenerateRandomBlock(blocking, seed, seedSize);
265  IncorporateEntropy(seed, seedSize);
266 }
267 
269 
270 #endif // OS_RNG_AVAILABLE
271 
272 #endif // CRYPTOPP_IMPORTS
Base class for all exceptions thrown by the library.
Definition: cryptlib.h:140
uint8_t byte
Definition: Common.h:57
Restricts the instantiation of a class to one static object without locks.
Definition: misc.h:274
#define NAMESPACE_BEGIN(x)
Definition: config.h:200
Library configuration file.
bool read(const std::string &s, Value &value)
else
Definition: equihash.cpp:246
Miscellaneous classes for RNGs.
uint8_t const size_t const size
Definition: sha3.h:20
std::string IntToString(T value, unsigned int base=10)
Converts a value to a string.
Definition: misc.h:539
#define NAMESPACE_END
Definition: config.h:201
Classes for access to the operating system&#39;s random number generators.