Crypto++ 7.0 Free C++ class library of cryptographic schemes

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