1/* boost random_device.cpp implementation
2 *
3 * Copyright Jens Maurer 2000
4 * Copyright Steven Watanabe 2010-2011
5 * Distributed under the Boost Software License, Version 1.0. (See
6 * accompanying file LICENSE_1_0.txt or copy at
7 * http://www.boost.org/LICENSE_1_0.txt)
8 *
9 * $Id$
10 *
11 */
12
13#define BOOST_RANDOM_SOURCE
14
15#include <boost/random/random_device.hpp>
16#include <boost/config.hpp>
17#include <boost/throw_exception.hpp>
18#include <boost/assert.hpp>
19#include <boost/detail/workaround.hpp>
20#include <boost/system/system_error.hpp>
21#include <boost/system/error_code.hpp>
22#include <string>
23
24#if !defined(BOOST_NO_INCLASS_MEMBER_INITIALIZATION) && !BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600))
25// A definition is required even for integral static constants
26const bool boost::random::random_device::has_fixed_range;
27#endif
28
29// WinRT target.
30#if !defined(BOOST_RANDOM_WINDOWS_RUNTIME)
31# if defined(__cplusplus_winrt)
32# include <winapifamily.h>
33# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
34# define BOOST_RANDOM_WINDOWS_RUNTIME 1
35# endif
36# endif
37#endif
38
39#if defined(BOOST_WINDOWS)
40
41#if !defined(BOOST_RANDOM_WINDOWS_RUNTIME)
42#include <windows.h>
43#include <wincrypt.h>
44#include <stdexcept> // std::invalid_argument
45#else
46using namespace Platform;
47using namespace Windows::Security::Cryptography;
48#endif
49
50#define BOOST_AUTO_LINK_NOMANGLE
51#define BOOST_LIB_NAME Advapi32
52#include <boost/config/auto_link.hpp>
53
54#ifdef __MINGW32__
55
56extern "C" {
57
58// mingw's wincrypt.h appears to be missing some things
59WINADVAPI
60BOOL
61WINAPI
62CryptEnumProvidersA(
63 DWORD dwIndex,
64 DWORD *pdwReserved,
65 DWORD dwFlags,
66 DWORD *pdwProvType,
67 LPSTR szProvName,
68 DWORD *pcbProvName
69 );
70
71}
72
73#endif
74
75namespace {
76#if !defined(BOOST_RANDOM_WINDOWS_RUNTIME)
77const char * const default_token = MS_DEF_PROV_A;
78#else
79const char * const default_token = "";
80#endif
81}
82
83class boost::random::random_device::impl
84{
85public:
86 impl(const std::string & token) : provider(token) {
87#if !defined(BOOST_RANDOM_WINDOWS_RUNTIME)
88 char buffer[80];
89 DWORD type;
90 DWORD len;
91
92 // Find the type of a specific provider
93 for(DWORD i = 0; ; ++i) {
94 len = sizeof(buffer);
95 if(!CryptEnumProvidersA(i, NULL, 0, &type, buffer, &len)) {
96 if (GetLastError() == ERROR_NO_MORE_ITEMS) break;
97 continue;
98 }
99 if(buffer == provider) {
100 break;
101 }
102 }
103
104 if(!CryptAcquireContextA(&hProv, NULL, provider.c_str(), type,
105 CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
106 error("Could not acquire CSP context");
107 }
108#endif
109 }
110
111#if !defined(BOOST_RANDOM_WINDOWS_RUNTIME)
112 ~impl() {
113 if(!CryptReleaseContext(hProv, 0)) error("Could not release CSP context");
114 }
115#endif
116
117 unsigned int next() {
118 unsigned int result;
119
120#if !defined(BOOST_RANDOM_WINDOWS_RUNTIME)
121 if(!CryptGenRandom(hProv, sizeof(result),
122 static_cast<BYTE*>(static_cast<void*>(&result)))) {
123 error("error while reading");
124 }
125#else
126 auto buffer = CryptographicBuffer::GenerateRandom(sizeof(result));
127 auto data = ref new Array<unsigned char>(buffer->Length);
128 CryptographicBuffer::CopyToByteArray(buffer, &data);
129 memcpy(&result, data->begin(), data->end() - data->begin());
130#endif
131
132 return result;
133 }
134
135private:
136#if !defined(BOOST_RANDOM_WINDOWS_RUNTIME)
137 void error(const char * msg) {
138 DWORD error_code = GetLastError();
139 boost::throw_exception(
140 boost::system::system_error(
141 error_code, boost::system::system_category(),
142 std::string("boost::random_device: ") + msg +
143 " Cryptographic Service Provider " + provider));
144 }
145 HCRYPTPROV hProv;
146#endif
147 const std::string provider;
148};
149
150#else
151
152namespace {
153// the default is the unlimited capacity device, using some secure hash
154// try "/dev/random" for blocking when the entropy pool has drained
155const char * const default_token = "/dev/urandom";
156}
157
158/*
159 * This uses the POSIX interface for unbuffered reading.
160 * Using buffered std::istream would consume entropy which may
161 * not actually be used. Entropy is a precious good we avoid
162 * wasting.
163 */
164
165#if defined(__GNUC__) && defined(_CXXRT_STD_NAME)
166// I have severe difficulty to get the POSIX includes to work with
167// -fhonor-std and Dietmar Kuhl's standard C++ library. Hack around that
168// problem for now.
169extern "C" {
170static const int O_RDONLY = 0;
171extern int open(const char *__file, int __oflag, ...);
172extern int read(int __fd, __ptr_t __buf, size_t __nbytes);
173extern int close(int __fd);
174}
175#else
176#include <sys/types.h>
177#include <sys/stat.h>
178#include <fcntl.h> // open
179#include <unistd.h> // read, close
180#endif
181
182#include <errno.h> // errno
183#include <string.h> // strerror
184#include <stdexcept> // std::invalid_argument
185
186
187class boost::random::random_device::impl
188{
189public:
190 impl(const std::string & token) : path(token) {
191 fd = open(file: token.c_str(), O_RDONLY);
192 if(fd < 0)
193 error(msg: "cannot open");
194 }
195
196 ~impl() { if(close(fd: fd) < 0) error(msg: "could not close"); }
197
198 unsigned int next() {
199 unsigned int result;
200 std::size_t offset = 0;
201 do {
202 long sz = read(fd: fd, buf: reinterpret_cast<char *>(&result) + offset, nbytes: sizeof(result) - offset);
203 if(sz == -1)
204 error(msg: "error while reading");
205 else if(sz == 0) {
206 errno = 0;
207 error(msg: "EOF while reading");
208 }
209 offset += sz;
210 } while(offset < sizeof(result));
211 return result;
212 }
213
214private:
215 void error(const char * msg) {
216 int error_code = errno;
217 boost::throw_exception(
218 e: boost::system::system_error(
219 error_code, boost::system::system_category(),
220 std::string("boost::random_device: ") + msg +
221 " random-number pseudo-device " + path));
222 }
223 const std::string path;
224 int fd;
225};
226
227#endif // BOOST_WINDOWS
228
229BOOST_RANDOM_DECL boost::random::random_device::random_device()
230 : pimpl(new impl(default_token))
231{}
232
233BOOST_RANDOM_DECL boost::random::random_device::random_device(const std::string& token)
234 : pimpl(new impl(token))
235{}
236
237BOOST_RANDOM_DECL boost::random_device::~random_device()
238{
239 delete pimpl;
240}
241
242BOOST_RANDOM_DECL double boost::random_device::entropy() const
243{
244 return 10;
245}
246
247BOOST_RANDOM_DECL unsigned int boost::random_device::operator()()
248{
249 return pimpl->next();
250}
251

source code of boost/libs/random/src/random_device.cpp