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