]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/uuid/include/boost/uuid/seed_rng.hpp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / uuid / include / boost / uuid / seed_rng.hpp
1 // Boost seed_rng.hpp header file ----------------------------------------------//
2
3 // Copyright 2007 Andy Tompkins.
4 // Distributed under the Boost Software License, Version 1.0. (See
5 // accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
7
8 // Revision History
9 // 09 Nov 2007 - Initial Revision
10 // 25 Feb 2008 - moved to namespace boost::uuids::detail
11 // 28 Nov 2009 - disabled deprecated warnings for MSVC
12 // 28 Jul 2014 - fixed valgrind warnings and better entropy sources for MSVC
13
14 // seed_rng models a UniformRandomNumberGenerator (see Boost.Random).
15 // Random number generators are hard to seed well. This is intended to provide
16 // good seed values for random number generators.
17 // It creates random numbers from a sha1 hash of data from a variary of sources,
18 // all of which are standard function calls. It produces random numbers slowly.
19 // Peter Dimov provided the details of sha1_random_digest_().
20 // see http://archives.free.net.ph/message/20070507.175609.4c4f503a.en.html
21
22 #ifndef BOOST_UUID_SEED_RNG_HPP
23 #define BOOST_UUID_SEED_RNG_HPP
24
25 #include <boost/config.hpp>
26 #include <cstring> // for memcpy
27 #include <limits>
28 #include <ctime> // for time_t, time, clock_t, clock
29 #include <cstdlib> // for rand
30 #include <cstdio> // for FILE, fopen, fread, fclose
31 #include <boost/core/noncopyable.hpp>
32 #include <boost/uuid/sha1.hpp>
33 //#include <boost/nondet_random.hpp> //forward declare boost::random::random_device
34
35 // can't use boost::generator_iterator since boost::random number seed(Iter&, Iter)
36 // functions need a last iterator
37 //#include <boost/generator_iterator.hpp>
38 # include <boost/iterator/iterator_facade.hpp>
39
40 #if defined(_MSC_VER)
41 # pragma warning(push) // Save warning settings.
42 # pragma warning(disable : 4996) // Disable deprecated std::fopen
43 #if defined(_WIN32_WCE)
44 # pragma comment(lib, "coredll.lib")
45 #else
46 # pragma comment(lib, "advapi32.lib")
47 #endif
48 #endif
49
50 #if defined(BOOST_WINDOWS)
51 # include <boost/detail/winapi/crypt.hpp> // for CryptAcquireContextA, CryptGenRandom, CryptReleaseContext
52 # include <boost/detail/winapi/timers.hpp>
53 # include <boost/detail/winapi/get_current_process_id.hpp>
54 # include <boost/detail/winapi/get_current_thread_id.hpp>
55 #else
56 # include <sys/time.h> // for gettimeofday
57 # include <sys/types.h> // for pid_t
58 # include <unistd.h> // for getpid()
59 #endif
60
61 #ifdef BOOST_NO_STDC_NAMESPACE
62 namespace std {
63 using ::memcpy;
64 using ::time_t;
65 using ::time;
66 using ::clock_t;
67 using ::clock;
68 using ::rand;
69 using ::FILE;
70 using ::fopen;
71 using ::fread;
72 using ::fclose;
73 } //namespace std
74 #endif
75
76 // forward declare random number generators
77 namespace boost { namespace random {
78 class random_device;
79 }} //namespace boost::random
80
81 namespace boost {
82 namespace uuids {
83 namespace detail {
84
85 // should this be part of Boost.Random?
86 class seed_rng: private boost::noncopyable
87 {
88 public:
89 typedef unsigned int result_type;
90 BOOST_STATIC_CONSTANT(bool, has_fixed_range = false);
91
92 public:
93 // note: rd_ intentionally left uninitialized
94 seed_rng() BOOST_NOEXCEPT
95 : rd_index_(5)
96 , random_(NULL)
97 {
98 #if defined(BOOST_WINDOWS)
99 if (!boost::detail::winapi::CryptAcquireContextW(
100 &random_,
101 NULL,
102 NULL,
103 boost::detail::winapi::PROV_RSA_FULL_,
104 boost::detail::winapi::CRYPT_VERIFYCONTEXT_ | boost::detail::winapi::CRYPT_SILENT_))
105 {
106 random_ = NULL;
107 }
108 #else
109 random_ = std::fopen( "/dev/urandom", "rb" );
110 #endif
111
112 std::memset(rd_, 0, sizeof(rd_));
113 }
114
115 ~seed_rng() BOOST_NOEXCEPT
116 {
117 if (random_) {
118 #if defined(BOOST_WINDOWS)
119 boost::detail::winapi::CryptReleaseContext(random_, 0);
120 #else
121 std::fclose(random_);
122 #endif
123 }
124 }
125
126 result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const BOOST_NOEXCEPT
127 {
128 return (std::numeric_limits<result_type>::min)();
129 }
130 result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const BOOST_NOEXCEPT
131 {
132 return (std::numeric_limits<result_type>::max)();
133 }
134
135 result_type operator()()
136 {
137 if (rd_index_ >= 5) {
138 //get new digest
139 sha1_random_digest_();
140
141 rd_index_ = 0;
142 }
143
144 return rd_[rd_index_++];
145 }
146
147 private:
148 BOOST_STATIC_CONSTANT(std::size_t, internal_state_size = 5);
149 inline void ignore_size(size_t) {}
150
151 static unsigned int * sha1_random_digest_state_()
152 {
153 static unsigned int state[ internal_state_size ];
154 return state;
155 }
156
157 void sha1_random_digest_()
158 {
159 boost::uuids::detail::sha1 sha;
160
161
162 if (random_)
163 {
164 // intentionally left uninitialized
165 unsigned char state[ 20 ];
166 #if defined(BOOST_WINDOWS)
167 boost::detail::winapi::CryptGenRandom(random_, sizeof(state), state);
168 #else
169 ignore_size(std::fread( state, 1, sizeof(state), random_ ));
170 #endif
171 sha.process_bytes( state, sizeof( state ) );
172 }
173
174 {
175 // Getting enropy from some system specific sources
176 #if defined(BOOST_WINDOWS)
177 boost::detail::winapi::DWORD_ procid = boost::detail::winapi::GetCurrentProcessId();
178 sha.process_bytes( (unsigned char const*)&procid, sizeof( procid ) );
179
180 boost::detail::winapi::DWORD_ threadid = boost::detail::winapi::GetCurrentThreadId();
181 sha.process_bytes( (unsigned char const*)&threadid, sizeof( threadid ) );
182
183 boost::detail::winapi::LARGE_INTEGER_ ts;
184 ts.QuadPart = 0;
185 boost::detail::winapi::QueryPerformanceCounter( &ts );
186 sha.process_bytes( (unsigned char const*)&ts, sizeof( ts ) );
187
188 std::time_t tm = std::time( 0 );
189 sha.process_bytes( (unsigned char const*)&tm, sizeof( tm ) );
190 #else
191 pid_t pid = getpid();
192 sha.process_bytes( (unsigned char const*)&pid, sizeof( pid ) );
193
194 timeval ts;
195 gettimeofday(&ts, NULL); // We do not use `clock_gettime` to avoid linkage with -lrt
196 sha.process_bytes( (unsigned char const*)&ts, sizeof( ts ) );
197 #endif
198 }
199
200
201 unsigned int * ps = sha1_random_digest_state_();
202 sha.process_bytes( ps, internal_state_size * sizeof( unsigned int ) );
203 sha.process_bytes( (unsigned char const*)&ps, sizeof( ps ) );
204
205 {
206 std::clock_t ck = std::clock();
207 sha.process_bytes( (unsigned char const*)&ck, sizeof( ck ) );
208 }
209
210 {
211 unsigned int rn[] =
212 { static_cast<unsigned int>(std::rand())
213 , static_cast<unsigned int>(std::rand())
214 , static_cast<unsigned int>(std::rand())
215 };
216 sha.process_bytes( (unsigned char const*)rn, sizeof( rn ) );
217 }
218
219 {
220 unsigned int * p = new unsigned int;
221 sha.process_bytes( (unsigned char const*)&p, sizeof( p ) );
222 delete p;
223
224 const seed_rng* this_ptr = this;
225 sha.process_bytes( (unsigned char const*)&this_ptr, sizeof( this_ptr ) );
226 sha.process_bytes( (unsigned char const*)&std::rand, sizeof( void(*)() ) );
227 }
228
229 sha.process_bytes( (unsigned char const*)rd_, sizeof( rd_ ) );
230
231 unsigned int digest[ 5 ];
232 sha.get_digest( digest );
233
234 for( int i = 0; i < 5; ++i )
235 {
236 // harmless data race
237 ps[ i ] ^= digest[ i ];
238 rd_[ i ] ^= digest[ i ];
239 }
240 }
241
242 private:
243 unsigned int rd_[5];
244 int rd_index_;
245
246 #if defined(BOOST_WINDOWS)
247 boost::detail::winapi::HCRYPTPROV_ random_;
248 #else
249 std::FILE * random_;
250 #endif
251 };
252
253 // almost a copy of boost::generator_iterator
254 // but default constructor sets m_g to NULL
255 template <class Generator>
256 class generator_iterator
257 : public iterator_facade<
258 generator_iterator<Generator>
259 , typename Generator::result_type
260 , single_pass_traversal_tag
261 , typename Generator::result_type const&
262 >
263 {
264 typedef iterator_facade<
265 generator_iterator<Generator>
266 , typename Generator::result_type
267 , single_pass_traversal_tag
268 , typename Generator::result_type const&
269 > super_t;
270
271 public:
272 generator_iterator() : m_g(NULL), m_value(0) {}
273 generator_iterator(Generator* g) : m_g(g), m_value((*m_g)()) {}
274
275 void increment()
276 {
277 m_value = (*m_g)();
278 }
279
280 const typename Generator::result_type&
281 dereference() const
282 {
283 return m_value;
284 }
285
286 bool equal(generator_iterator const& y) const
287 {
288 return this->m_g == y.m_g && this->m_value == y.m_value;
289 }
290
291 private:
292 Generator* m_g;
293 typename Generator::result_type m_value;
294 };
295
296 // seed() seeds a random number generator with good seed values
297
298 template <typename UniformRandomNumberGenerator>
299 inline void seed(UniformRandomNumberGenerator& rng)
300 {
301 seed_rng seed_gen;
302 generator_iterator<seed_rng> begin(&seed_gen);
303 generator_iterator<seed_rng> end;
304 rng.seed(begin, end);
305 }
306
307 // random_device does not / can not be seeded
308 template <>
309 inline void seed<boost::random::random_device>(boost::random::random_device&) {}
310
311 // random_device does not / can not be seeded
312 template <>
313 inline void seed<seed_rng>(seed_rng&) {}
314
315 }}} //namespace boost::uuids::detail
316
317 #if defined(_MSC_VER)
318 #pragma warning(pop) // Restore warnings to previous state.
319 #endif
320
321 #endif