Fortuna.hpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /*
  2. Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved.
  3. Redistribution and use in source and binary forms, with or without
  4. modification, are permitted provided that the following conditions are met:
  5. * Redistributions of source code must retain the above copyright notice,
  6. this list of conditions and the following disclaimer.
  7. * Redistributions in binary form must reproduce the above copyright notice,
  8. this list of conditions and the following disclaimer in the documentation
  9. and/or other materials provided with the distribution.
  10. * Neither the name of LibCat nor the names of its contributors may be used
  11. to endorse or promote products derived from this software without
  12. specific prior written permission.
  13. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  14. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  15. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  16. ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
  17. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  18. CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  19. SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  20. INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  21. CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  22. ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  23. POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. /*
  26. Based on Fortuna algorithm from "Practical Cryptography" section 10.3
  27. Published 2003 by Niels Ferguson and Bruce Schneier
  28. Fortuna supplements the operating system (OS) pseudo-random number generator (PRNG)
  29. by incorporating additional entropy into the seeds that the OS provides.
  30. Modified for use with Skein in PRNG mode, sharing the strengths of both algorithms.
  31. My implementation of Fortuna (call it Cat For Tuna) has the following components:
  32. + Entropy Pools
  33. + 32 pools numbered 0..31
  34. + Implemented as 32 instances of the 256-bit Skein hash
  35. + Entropy hashed into pools in a round-robin fashion
  36. + Scheme allows for recovery against attacker with knowledge of some sources
  37. + Entropy Sources
  38. + Uses best OS random number generator
  39. + And a variable number of OS-dependent entropy sources
  40. + Mainly cycle counts and other timing information
  41. + Output Generator
  42. + Implemented as a 512-bit Skein hash of some combination of the entropy pools
  43. + The output is produced by the PRNG mode of Skein keyed by the pools
  44. + Hashing all of these pools together and keying the output is called "seeding"
  45. + Reseeded after sufficient entropy has been collected in pool 0
  46. + Pool 0 is always used for reseeding
  47. + Reseed X uses pools numbered by the 1-bits in X (except MSB)
  48. + Previous seed keys the next seed
  49. + Diverges from normal Fortuna due to use of Skein instead of a block cipher
  50. + Reseeds only once every ~512 seconds
  51. + Does not have a limit of 2^16 output blocks
  52. + Skein-PRNG is guaranteed sufficient security properties anyway
  53. The Fortuna algorithm is broken up into two objects for efficient thread-safety:
  54. + FortunaFactory
  55. + Must be initialized on startup and shut down on shutdown
  56. + Spawns a thread to periodically collect additional entropy
  57. + Can create FortunaOutput objects
  58. + FortunaOutput
  59. + Reseeds based on master seed in the FortunaFactory
  60. + Reseeds after master seed is updated
  61. + Provides a unique random stream for each thread that uses Fortuna
  62. */
  63. #ifndef CAT_FOR_TUNA_HPP
  64. #define CAT_FOR_TUNA_HPP
  65. #include <cat/rand/IRandom.hpp>
  66. #include <cat/crypt/hash/Skein.hpp>
  67. #include <cat/Singleton.hpp>
  68. #include <cat/threads/Mutex.hpp>
  69. // Defining CAT_NO_ENTROPY_THREAD will remove dependencies on pthreads and not
  70. // run a thread to collect more entropy. This is recommended for low-power targets
  71. // and other systems where no thread library is available
  72. #if defined(CAT_OS_WINDOWS_CE)
  73. # define CAT_NO_ENTROPY_THREAD
  74. #endif
  75. #if defined(CAT_OS_WINDOWS)
  76. # include <cat/port/WindowsInclude.hpp>
  77. # include <wincrypt.h>
  78. #endif
  79. #if !defined(CAT_NO_ENTROPY_THREAD)
  80. # include <cat/threads/Thread.hpp>
  81. # include <cat/threads/WaitableFlag.hpp>
  82. #endif
  83. namespace cat {
  84. class FortunaOutput;
  85. class FortunaFactory;
  86. // Factory for constructing FortunaOutput objects
  87. class FortunaFactory : public Singleton<FortunaFactory>
  88. #if !defined(CAT_NO_ENTROPY_THREAD)
  89. , public Thread
  90. #endif
  91. {
  92. CAT_SINGLETON(FortunaFactory)
  93. {
  94. _initialized = false;
  95. }
  96. Mutex _lock;
  97. friend class FortunaOutput;
  98. #if defined(CAT_OS_WINDOWS) && !defined(CAT_OS_WINDOWS_CE)
  99. typedef LONG (WINAPI *PtNtQuerySystemInformation)(
  100. int SystemInformationClass,
  101. PVOID SystemInformation,
  102. ULONG SystemInformationLength,
  103. PULONG ReturnLength
  104. );
  105. HANDLE CurrentProcess;
  106. HMODULE NTDLL;
  107. PtNtQuerySystemInformation NtQuerySystemInformation;
  108. HCRYPTPROV hCryptProv;
  109. #elif defined(CAT_OS_WINDOWS_CE)
  110. HCRYPTPROV hCryptProv;
  111. #elif defined(CAT_OS_LINUX)
  112. int urandom_fd;
  113. #endif
  114. #if !defined(CAT_NO_ENTROPY_THREAD)
  115. static const int ENTROPY_THREAD_KILL_TIMEOUT = 10000; // 10 seconds
  116. WaitableFlag _kill_flag;
  117. bool ThreadFunction(void *param);
  118. #endif
  119. protected:
  120. static const int ENTROPY_POOLS = 32; // Setting this higher would break something
  121. static const int POOL_BITS = 512;
  122. static const int POOL_BYTES = POOL_BITS / 8;
  123. static const int POOL_QWORDS = POOL_BYTES / sizeof(u64);
  124. static u32 MasterSeedRevision; // Should not roll over for 13 years if incremented once every RESEED_MIN_TIME
  125. static Skein MasterSeed;
  126. bool _initialized;
  127. u32 reseed_counter;
  128. Skein Pool[ENTROPY_POOLS];
  129. bool Reseed();
  130. void GetNextKey(FortunaOutput *output);
  131. bool InitializeEntropySources();
  132. void PollInvariantSources(int pool);
  133. void PollSlowEntropySources(int pool);
  134. void PollFastEntropySources(int pool);
  135. void ShutdownEntropySources();
  136. public:
  137. // Start the entropy generator
  138. bool Initialize();
  139. // Stop the entropy generator
  140. void Shutdown();
  141. // Create a new Fortuna object
  142. static FortunaOutput *Create();
  143. };
  144. // LoopThread-safe output object for Fortuna
  145. class FortunaOutput : public IRandom
  146. {
  147. friend class FortunaFactory;
  148. static const int OUTPUT_CACHE_BYTES = FortunaFactory::POOL_BYTES * 8; // Arbitrary
  149. u32 thread_id, SeedRevision;
  150. Skein OutputHash;
  151. u8 CachedRandomBytes[OUTPUT_CACHE_BYTES];
  152. int used_bytes;
  153. void Reseed();
  154. FortunaOutput();
  155. FortunaOutput(FortunaOutput&) {}
  156. FortunaOutput &operator=(FortunaOutput &) { return *this; }
  157. public:
  158. ~FortunaOutput();
  159. // Generate a 32-bit random number
  160. u32 Generate();
  161. // Generate a variable number of random bytes
  162. void Generate(void *buffer, int bytes);
  163. };
  164. } // namespace cat
  165. #endif // CAT_FOR_TUNA_HPP
粤ICP备19079148号