]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/random/src/random_device.cpp
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / libs / random / src / random_device.cpp
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
26 const 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
46 using namespace Platform;
47 using 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
56 extern "C" {
57
58 // mingw's wincrypt.h appears to be missing some things
59 WINADVAPI
60 BOOL
61 WINAPI
62 CryptEnumProvidersA(
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
75 namespace {
76 #if !defined(BOOST_RANDOM_WINDOWS_RUNTIME)
77 const char * const default_token = MS_DEF_PROV_A;
78 #else
79 const char * const default_token = "";
80 #endif
81 }
82
83 class boost::random::random_device::impl
84 {
85 public:
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
135 private:
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
152 namespace {
153 // the default is the unlimited capacity device, using some secure hash
154 // try "/dev/random" for blocking when the entropy pool has drained
155 const 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.
169 extern "C" {
170 static const int O_RDONLY = 0;
171 extern int open(const char *__file, int __oflag, ...);
172 extern int read(int __fd, __ptr_t __buf, size_t __nbytes);
173 extern 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
187 class boost::random::random_device::impl
188 {
189 public:
190 impl(const std::string & token) : path(token) {
191 fd = open(token.c_str(), O_RDONLY);
192 if(fd < 0)
193 error("cannot open");
194 }
195
196 ~impl() { if(close(fd) < 0) error("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, reinterpret_cast<char *>(&result) + offset, sizeof(result) - offset);
203 if(sz == -1)
204 error("error while reading");
205 else if(sz == 0) {
206 errno = 0;
207 error("EOF while reading");
208 }
209 offset += sz;
210 } while(offset < sizeof(result));
211 return result;
212 }
213
214 private:
215 void error(const char * msg) {
216 int error_code = errno;
217 boost::throw_exception(
218 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
229 BOOST_RANDOM_DECL boost::random::random_device::random_device()
230 : pimpl(new impl(default_token))
231 {}
232
233 BOOST_RANDOM_DECL boost::random::random_device::random_device(const std::string& token)
234 : pimpl(new impl(token))
235 {}
236
237 BOOST_RANDOM_DECL boost::random_device::~random_device()
238 {
239 delete pimpl;
240 }
241
242 BOOST_RANDOM_DECL double boost::random_device::entropy() const
243 {
244 return 10;
245 }
246
247 BOOST_RANDOM_DECL unsigned int boost::random_device::operator()()
248 {
249 return pimpl->next();
250 }