seed_rng.hpp 9.2 KB

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