Crypto++  5.6.3
Free C++ class library of cryptographic schemes
osrng.cpp
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 
7 #ifndef CRYPTOPP_IMPORTS
8 
9 #include "osrng.h"
10 
11 #ifdef OS_RNG_AVAILABLE
12 
13 #include "rng.h"
14 
15 #ifdef CRYPTOPP_WIN32_AVAILABLE
16 #ifndef _WIN32_WINNT
17 #define _WIN32_WINNT 0x0400
18 #endif
19 #include <windows.h>
20 #include <wincrypt.h>
21 #endif
22 
23 #ifdef CRYPTOPP_UNIX_AVAILABLE
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <unistd.h>
27 #endif
28 
29 NAMESPACE_BEGIN(CryptoPP)
30 
31 #if defined(NONBLOCKING_RNG_AVAILABLE) || defined(BLOCKING_RNG_AVAILABLE)
32 OS_RNG_Err::OS_RNG_Err(const std::string &operation)
33  : Exception(OTHER_ERROR, "OS_Rng: " + operation + " operation failed with error " +
34 #ifdef CRYPTOPP_WIN32_AVAILABLE
35  "0x" + IntToString(GetLastError(), 16)
36 #else
37  IntToString(errno)
38 #endif
39  )
40 {
41 }
42 #endif
43 
44 #ifdef NONBLOCKING_RNG_AVAILABLE
45 
46 #ifdef CRYPTOPP_WIN32_AVAILABLE
47 
49 {
50  if (!CryptAcquireContext(&m_hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
51  throw OS_RNG_Err("CryptAcquireContext");
52 }
53 
54 MicrosoftCryptoProvider::~MicrosoftCryptoProvider()
55 {
56  CryptReleaseContext(m_hProvider, 0);
57 }
58 
59 #endif
60 
62 {
63 #ifndef CRYPTOPP_WIN32_AVAILABLE
64  m_fd = open("/dev/urandom",O_RDONLY);
65  if (m_fd == -1)
66  throw OS_RNG_Err("open /dev/urandom");
67 #endif
68 }
69 
70 NonblockingRng::~NonblockingRng()
71 {
72 #ifndef CRYPTOPP_WIN32_AVAILABLE
73  close(m_fd);
74 #endif
75 }
76 
77 void NonblockingRng::GenerateBlock(byte *output, size_t size)
78 {
79 #ifdef CRYPTOPP_WIN32_AVAILABLE
80 # ifdef WORKAROUND_MS_BUG_Q258000
82 # endif
83  if (!CryptGenRandom(m_Provider.GetProviderHandle(), (DWORD)size, output))
84  throw OS_RNG_Err("CryptGenRandom");
85 #else
86  while (size)
87  {
88  ssize_t len = read(m_fd, output, size);
89 
90  if (len < 0)
91  {
92  // /dev/urandom reads CAN give EAGAIN errors! (maybe EINTR as well)
93  if (errno != EINTR && errno != EAGAIN)
94  throw OS_RNG_Err("read /dev/urandom");
95 
96  continue;
97  }
98 
99  output += len;
100  size -= len;
101  }
102 #endif
103 }
104 
105 #endif
106 
107 // *************************************************************
108 
109 #ifdef BLOCKING_RNG_AVAILABLE
110 
111 #ifndef CRYPTOPP_BLOCKING_RNG_FILENAME
112 #ifdef __OpenBSD__
113 #define CRYPTOPP_BLOCKING_RNG_FILENAME "/dev/srandom"
114 #else
115 #define CRYPTOPP_BLOCKING_RNG_FILENAME "/dev/random"
116 #endif
117 #endif
118 
120 {
121  m_fd = open(CRYPTOPP_BLOCKING_RNG_FILENAME,O_RDONLY);
122  if (m_fd == -1)
123  throw OS_RNG_Err("open " CRYPTOPP_BLOCKING_RNG_FILENAME);
124 }
125 
126 BlockingRng::~BlockingRng()
127 {
128  close(m_fd);
129 }
130 
131 void BlockingRng::GenerateBlock(byte *output, size_t size)
132 {
133  while (size)
134  {
135  // on some systems /dev/random will block until all bytes
136  // are available, on others it returns immediately
137  ssize_t len = read(m_fd, output, size);
138  if (len < 0)
139  {
140  // /dev/random reads CAN give EAGAIN errors! (maybe EINTR as well)
141  if (errno != EINTR && errno != EAGAIN)
142  throw OS_RNG_Err("read " CRYPTOPP_BLOCKING_RNG_FILENAME);
143 
144  continue;
145  }
146 
147  size -= len;
148  output += len;
149  if (size)
150  sleep(1);
151  }
152 }
153 
154 #endif
155 
156 // *************************************************************
157 
158 void OS_GenerateRandomBlock(bool blocking, byte *output, size_t size)
159 {
160 #ifdef NONBLOCKING_RNG_AVAILABLE
161  if (blocking)
162 #endif
163  {
164 #ifdef BLOCKING_RNG_AVAILABLE
165  BlockingRng rng;
166  rng.GenerateBlock(output, size);
167 #endif
168  }
169 
170 #ifdef BLOCKING_RNG_AVAILABLE
171  if (!blocking)
172 #endif
173  {
174 #ifdef NONBLOCKING_RNG_AVAILABLE
175  NonblockingRng rng;
176  rng.GenerateBlock(output, size);
177 #endif
178  }
179 }
180 
181 void AutoSeededRandomPool::Reseed(bool blocking, unsigned int seedSize)
182 {
183  SecByteBlock seed(seedSize);
184  OS_GenerateRandomBlock(blocking, seed, seedSize);
185  IncorporateEntropy(seed, seedSize);
186 }
187 
188 NAMESPACE_END
189 
190 #endif
191 
192 #endif
void IncorporateEntropy(const byte *input, size_t length)
Update RNG state with additional unpredictable values.
Definition: randpool.cpp:26
Base class for all exceptions thrown by the library.
Definition: cryptlib.h:139
Wrapper for Microsoft crypto service provider.
Definition: osrng.h:40
BlockingRng()
Construct a BlockingRng.
Definition: osrng.cpp:119
OS_RNG_Err(const std::string &operation)
Constructs an OS_RNG_Err.
Definition: osrng.cpp:32
Restricts the instantiation of a class to one static object without locks.
Definition: misc.h:238
Wrapper class for /dev/random and /dev/srandom.
Definition: osrng.h:75
void Reseed(bool blocking=false, unsigned int seedSize=32)
Reseed an AutoSeededRandomPool.
Definition: osrng.cpp:181
SecBlock typedef.
Definition: secblock.h:730
void GenerateBlock(byte *output, size_t size)
Generate random array of bytes.
Definition: osrng.cpp:77
void GenerateBlock(byte *output, size_t size)
Generate random array of bytes.
Definition: osrng.cpp:131
NonblockingRng()
Construct a NonblockingRng.
Definition: osrng.cpp:61
Exception thrown when an operating system error is encountered.
Definition: osrng.h:26
Miscellaneous classes for RNGs.
MicrosoftCryptoProvider()
Construct a MicrosoftCryptoProvider.
Definition: osrng.cpp:48
Wrapper class for /dev/random and /dev/srandom.
Definition: osrng.h:105
void OS_GenerateRandomBlock(bool blocking, byte *output, size_t size)
OS_GenerateRandomBlock.
Definition: osrng.cpp:158
std::string IntToString(T value, unsigned int base=10)
Converts a value to a string.
Definition: misc.h:460
ProviderHandle GetProviderHandle() const
Retrieves the CryptoAPI provider handle.
Definition: osrng.h:60
Crypto++ library namespace.
Classes for access to the operating system's random number generators.