Shadowrun: Awakened 29 September 2011 - Build 871
Fortuna.hpp
Go to the documentation of this file.
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.

GNU Lesser General Public License 3 Sourceforge.net