![]() |
Shadowrun: Awakened 29 September 2011 - Build 871
|
00001 /* 00002 Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved. 00003 00004 Redistribution and use in source and binary forms, with or without 00005 modification, are permitted provided that the following conditions are met: 00006 00007 * Redistributions of source code must retain the above copyright notice, 00008 this list of conditions and the following disclaimer. 00009 * Redistributions in binary form must reproduce the above copyright notice, 00010 this list of conditions and the following disclaimer in the documentation 00011 and/or other materials provided with the distribution. 00012 * Neither the name of LibCat nor the names of its contributors may be used 00013 to endorse or promote products derived from this software without 00014 specific prior written permission. 00015 00016 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00017 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00018 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00019 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 00020 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00021 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00022 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00023 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00024 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00025 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00026 POSSIBILITY OF SUCH DAMAGE. 00027 */ 00028 00029 /* 00030 Based on Fortuna algorithm from "Practical Cryptography" section 10.3 00031 Published 2003 by Niels Ferguson and Bruce Schneier 00032 00033 Fortuna supplements the operating system (OS) pseudo-random number generator (PRNG) 00034 by incorporating additional entropy into the seeds that the OS provides. 00035 00036 Modified for use with Skein in PRNG mode, sharing the strengths of both algorithms. 00037 00038 My implementation of Fortuna (call it Cat For Tuna) has the following components: 00039 00040 + Entropy Pools 00041 + 32 pools numbered 0..31 00042 + Implemented as 32 instances of the 256-bit Skein hash 00043 + Entropy hashed into pools in a round-robin fashion 00044 + Scheme allows for recovery against attacker with knowledge of some sources 00045 00046 + Entropy Sources 00047 + Uses best OS random number generator 00048 + And a variable number of OS-dependent entropy sources 00049 + Mainly cycle counts and other timing information 00050 00051 + Output Generator 00052 + Implemented as a 512-bit Skein hash of some combination of the entropy pools 00053 + The output is produced by the PRNG mode of Skein keyed by the pools 00054 + Hashing all of these pools together and keying the output is called "seeding" 00055 + Reseeded after sufficient entropy has been collected in pool 0 00056 + Pool 0 is always used for reseeding 00057 + Reseed X uses pools numbered by the 1-bits in X (except MSB) 00058 + Previous seed keys the next seed 00059 + Diverges from normal Fortuna due to use of Skein instead of a block cipher 00060 + Reseeds only once every ~51.2 seconds 00061 + Does not have a limit of 2^16 output blocks 00062 + Skein-PRNG is guaranteed sufficient security properties anyway 00063 00064 The Fortuna algorithm is broken up into two objects for efficient thread-safety: 00065 00066 + FortunaFactory 00067 + Must be initialized on startup and shut down on shutdown 00068 + Spawns a thread to periodically collect additional entropy 00069 + Can create FortunaOutput objects 00070 00071 + FortunaOutput 00072 + Reseeds based on master seed in the FortunaFactory 00073 + Reseeds after master seed is updated 00074 + Provides a unique random stream for each thread that uses Fortuna 00075 */ 00076 00077 #ifndef FORTUNA_HPP 00078 #define FORTUNA_HPP 00079 00080 #include <cat/rand/IRandom.hpp> 00081 #include <cat/crypt/hash/Skein.hpp> 00082 #include <cat/Singleton.hpp> 00083 #include <cat/threads/Mutex.hpp> 00084 00085 00086 // Defining CAT_NO_ENTROPY_THREAD will remove dependencies on pthreads and not 00087 // run a thread to collect more entropy. This is recommended for low-power targets 00088 // and other systems where no thread library is available 00089 #if defined(CAT_OS_WINDOWS_CE) 00090 # define CAT_NO_ENTROPY_THREAD 00091 #endif 00092 00093 00094 #if defined(CAT_OS_WINDOWS) 00095 # include <cat/port/WindowsInclude.hpp> 00096 # include <wincrypt.h> 00097 #endif 00098 00099 #if !defined(CAT_NO_ENTROPY_THREAD) 00100 # include <cat/threads/Thread.hpp> 00101 # include <cat/threads/WaitableFlag.hpp> 00102 #endif 00103 00104 00105 namespace cat { 00106 00107 class FortunaOutput; 00108 class FortunaFactory; 00109 00110 00111 // Factory for constructing FortunaOutput objects 00112 class FortunaFactory : public Singleton<FortunaFactory> 00113 #if !defined(CAT_NO_ENTROPY_THREAD) 00114 , public Thread 00115 #endif 00116 { 00117 CAT_SINGLETON(FortunaFactory) 00118 { 00119 _initialized = false; 00120 } 00121 00122 Mutex _lock; 00123 00124 friend class FortunaOutput; 00125 00126 #if defined(CAT_OS_WINDOWS) && !defined(CAT_OS_WINDOWS_CE) 00127 00128 typedef LONG (WINAPI *PtNtQuerySystemInformation)( 00129 int SystemInformationClass, 00130 PVOID SystemInformation, 00131 ULONG SystemInformationLength, 00132 PULONG ReturnLength 00133 ); 00134 00135 HANDLE CurrentProcess; 00136 HMODULE NTDLL; 00137 PtNtQuerySystemInformation NtQuerySystemInformation; 00138 HCRYPTPROV hCryptProv; 00139 00140 #elif defined(CAT_OS_WINDOWS_CE) 00141 00142 HCRYPTPROV hCryptProv; 00143 00144 #elif defined(CAT_OS_LINUX) 00145 00146 int urandom_fd; 00147 00148 #endif 00149 00150 #if !defined(CAT_NO_ENTROPY_THREAD) 00151 static const int ENTROPY_THREAD_KILL_TIMEOUT = 10000; // 10 seconds 00152 00153 WaitableFlag _kill_flag; 00154 00155 bool ThreadFunction(void *param); 00156 #endif 00157 00158 protected: 00159 static const int ENTROPY_POOLS = 32; // Setting this higher would break something 00160 static const int POOL_BITS = 512; 00161 static const int POOL_BYTES = POOL_BITS / 8; 00162 static const int POOL_QWORDS = POOL_BYTES / sizeof(u64); 00163 00164 static u32 MasterSeedRevision; // Should not roll over for 13 years if incremented once every RESEED_MIN_TIME 00165 static Skein MasterSeed; 00166 00167 bool _initialized; 00168 u32 reseed_counter; 00169 Skein Pool[ENTROPY_POOLS]; 00170 00171 bool Reseed(); 00172 void GetNextKey(FortunaOutput *output); 00173 bool InitializeEntropySources(); 00174 void PollInvariantSources(int pool); 00175 void PollSlowEntropySources(int pool); 00176 void PollFastEntropySources(int pool); 00177 void ShutdownEntropySources(); 00178 00179 public: 00180 // Start the entropy generator 00181 bool Initialize(); 00182 00183 // Stop the entropy generator 00184 void Shutdown(); 00185 00186 // Create a new Fortuna object 00187 static FortunaOutput *Create(); 00188 }; 00189 00190 00191 // LoopThread-safe output object for Fortuna 00192 class FortunaOutput : public IRandom 00193 { 00194 friend class FortunaFactory; 00195 00196 static const int OUTPUT_CACHE_BYTES = FortunaFactory::POOL_BYTES * 8; // Arbitrary 00197 00198 u32 thread_id, SeedRevision; 00199 Skein OutputHash; 00200 u8 CachedRandomBytes[OUTPUT_CACHE_BYTES]; 00201 int used_bytes; 00202 00203 void Reseed(); 00204 00205 FortunaOutput(); 00206 FortunaOutput(FortunaOutput&) {} 00207 FortunaOutput &operator=(FortunaOutput &) {} 00208 00209 public: 00210 ~FortunaOutput(); 00211 00212 // Generate a 32-bit random number 00213 u32 Generate(); 00214 00215 // Generate a variable number of random bytes 00216 void Generate(void *buffer, int bytes); 00217 }; 00218 00219 00220 } // namespace cat 00221 00222 #endif // FORTUNA_HPP
Copyright © 2007-2010 by The Shadowrun: Awakened Team. This work is licensed under the GNU Lesser General Public License 3.