Fortuna PRNG C++ Source Code

Main Page | Namespace List | Class Hierarchy | Class List | File List | Namespace Members | Class Members | File Members

Pool.cpp

Go to the documentation of this file.
00001 /*
00002         (c) Citadel Software Inc, 2003, www.citadelsoftware.ca
00003 */
00004 
00012 #include "stdafx.h"
00013 #include "Pool.h"
00014 #include "Fortuna.h"
00015 #include "FortunaUtils.h"
00016 #include "Sha2.h"
00017 #include "Timer.h"
00018 
00019 namespace CitadelSoftwareInc {
00020 
00021 Pool::Pool(Fortuna* pFortuna, PoolMgr* pOwner, int iPoolNum)
00022         :
00023         m_pFortuna(pFortuna),
00024         m_pOwner(pOwner),
00025         m_pThread(NULL),
00026         m_PoolMutex(),
00027         m_CompactPoolDataSize(1024),
00028         m_hPoolMutex(0),
00029         m_CompactPoolEvent(TRUE),  // manual reset event
00030         m_hCompactPoolEvent(0),
00031         m_TotalBytes(0),
00032         m_hShutdownEvent(0),
00033         m_iPoolNum(iPoolNum),
00034         m_CompactPoolCount(0)
00035 {
00036         for (int i=0; i<32; ++i)
00037                 m_redherring[i] = 0xcd;
00038 }
00039 
00040 Pool::~Pool()
00041 {
00042         if (m_pThread)
00043         {
00044                 delete m_pThread;
00045                 m_pThread = NULL;
00046         }
00047 
00048 }
00049 
00050 // Starts the thread running
00051 bool Pool::StartThread()
00052 {
00053         m_hCompactPoolEvent = m_CompactPoolEvent.GetHandle();
00054         m_hPoolMutex = m_PoolMutex.GetHandle();
00055 
00056         m_pThread = new CMclThread(this);
00057 
00058         return true;
00059 }
00060 
00061 // Overloaded from CMclThreadHandler - this is the thread entry point
00062 unsigned Pool::ThreadHandlerProc(void)
00063 {
00064         // give each thread a different seed for rand()
00065         unsigned int seed = GetCurrentThreadId();
00066         seed += (unsigned int)this;
00067         seed += (unsigned int)time(NULL);
00068         {
00069                 Timer hptimer;
00070                 hptimer.Curr();
00071                 seed += hptimer.m_currTime.LowPart;
00072         }
00073 
00074         srand(seed);
00075 
00076         m_hShutdownEvent = m_pFortuna->GetShutdownEventHandle();
00077         
00078         HANDLE harray[2] = {m_hShutdownEvent, m_hCompactPoolEvent};
00079 
00080         while(1)
00081         {
00082                 DWORD dwResult = WaitForMultipleObjects(2, harray, FALSE, INFINITE);
00083                 if (dwResult == WAIT_OBJECT_0)
00084                 {
00085                         // shutdown
00086 //                      printf("Pool %d shutting down\n", m_iPoolNum);
00087                         break;
00088                 }
00089                 else if (dwResult == WAIT_OBJECT_0 + 1)
00090                 {
00091                         CompactPool();
00092                 }
00093         }
00094 
00095         return 0;
00096 }
00097 
00098 bool Pool::CompactPool()
00099 {
00100         // first aquire the mutex that protects the pool
00101         // copy the data from the pool
00102         vecuc poolData;
00103         DWORD dwResult = WaitForSingleObject(m_hPoolMutex, INFINITE);
00104 
00105         const unsigned int modnum = 255;
00106         m_pool.ExtractAndErase(poolData, modnum);
00107 
00108         // now compact the pool
00109         sha256_ctx ctx[1];
00110     sha256_begin(ctx);
00111 
00112         vecuc hashData;
00113         m_hashPool.ExtractAndErase(hashData, modnum);
00114 
00115         // add in the existing hash data
00116         if (!hashData.empty())
00117         {
00118                 unsigned long size = (unsigned long)hashData.size();
00119                 sha256_hash(&hashData[0], size, ctx);
00120         }
00121 
00122         // add in the new raw data
00123         if (!poolData.empty())
00124         {
00125                 unsigned long size = (unsigned long)poolData.size();
00126                 sha256_hash(&poolData[0], size, ctx);
00127         }
00128 
00129         unsigned char hval[32];
00130         sha256_end(hval, ctx);
00131 
00132         int i=0;
00133         for (i=0; i<32; ++i)
00134         {
00135                 m_hashPool.Add(hval[i]);  // this is the real hashed pool data
00136                 hval[i] = rand() % 256;
00137         }
00138 
00139         EraseHash(ctx);
00140 
00141         // update the red herring data each cycle so an attacker will see something changing at this memory location
00142         for (i=0; i<32; ++i)
00143                 m_redherring[i] = rand() % 256;
00144 
00145         ++m_CompactPoolCount;
00146 
00147         // release the pool mutex
00148         // having two mutexes to protect the raw data pool and the hashed data pool didn't seem to offer many benefits
00149         // because the reseed operation requires access to both pools simultaneously
00150         m_PoolMutex.Release();
00151 
00152         m_CompactPoolEvent.Reset();
00153 
00154         return true;
00155 }
00156 
00157 // add a byte to the pool
00158 bool Pool::AddByte(const unsigned char byte)
00159 {
00160         DWORD dwResult = WaitForSingleObject(m_hPoolMutex, INFINITE);
00161 
00162         unsigned int size = m_pool.Add(byte);
00163         ++m_TotalBytes;
00164 
00165         m_PoolMutex.Release();
00166 
00167         // when the pool grows beyond a certain size, compact the pool 
00168         // using the Pool's thread to do that actual work
00169         if (size > m_CompactPoolDataSize)
00170         {
00171                 m_CompactPoolEvent.Set();
00172         }
00173 
00174         return true;
00175 }
00176 
00177 // add an array of bytes to the pool
00178 bool Pool::AddBytes(const unsigned char* pData, unsigned int size)
00179 {
00180         DWORD dwResult = WaitForSingleObject(m_hPoolMutex, INFINITE);
00181 
00182         for (unsigned int i=0; i<size; ++i)
00183         {
00184                 m_pool.Add(pData[i]);
00185         }
00186 
00187         unsigned int poolSize = m_pool.Size();
00188 
00189         m_TotalBytes += size;
00190 
00191         m_PoolMutex.Release();
00192 
00193         // when the pool grows beyond a certain size, compact the pool 
00194         // using the Pool's thread to do that actual work
00195         if (poolSize > m_CompactPoolDataSize)
00196         {
00197                 m_CompactPoolEvent.Set();
00198         }
00199 
00200         return true;
00201 }
00202 
00203 
00204 // Extract the pools and erase the pool data.
00205 // This is used when reseeding the generator.
00206 bool Pool::ExtractAndErase(std::vector<unsigned char>& vBytes, bool& bShuttingDown)
00207 {
00208         HANDLE hVec[2] = {m_hShutdownEvent, m_hPoolMutex };
00209 
00210         DWORD dwResult = WaitForMultipleObjects(2, hVec, FALSE, INFINITE);
00211 
00212         if (dwResult == WAIT_OBJECT_0)
00213         {
00214                 bShuttingDown = true;
00215                 return false;           // shutting down
00216         }
00217         else if(dwResult == WAIT_OBJECT_0 + 1)
00218         {
00219                 bShuttingDown = false;          // pool mutex aquired
00220         }
00221 
00222         // reserve space for the pools 
00223         vBytes.resize(m_pool.Size() + m_hashPool.Size());
00224 
00225         std::vector<unsigned char> bytes;
00226         m_pool.ExtractAndErase(bytes, (unsigned int)256);
00227 
00228         std::copy(bytes.begin(), bytes.end(), vBytes.begin());
00229 
00230         size_t i=0;
00231         size_t size = bytes.size();
00232         for (i=0; i<size; ++i)
00233                 bytes[i] = (unsigned char)(rand() % 256);
00234 
00235         m_hashPool.ExtractAndErase(bytes, (unsigned int)256);
00236 
00237         std::copy(bytes.begin(), bytes.end(), vBytes.begin() + size);
00238 
00239         size = bytes.size();
00240         for (i=0; i<size; ++i)
00241                 bytes[i] = (unsigned char)(rand() % 256);
00242 
00243         m_TotalBytes = 0;
00244         m_CompactPoolCount = 0;
00245 
00246         m_PoolMutex.Release();
00247 
00248         return true;
00249 }
00250 
00251 // Extract the HashedPoolData
00252 // This is used by the seed file to get the current state to write out to the seed file
00253 bool Pool::GetHashedPoolData(std::vector<unsigned char>& vData)
00254 {
00255         HANDLE hVec[2] = {m_hShutdownEvent, m_hPoolMutex };
00256 
00257         DWORD dwResult = WaitForMultipleObjects(2, hVec, FALSE, INFINITE);
00258 
00259         if (dwResult == WAIT_OBJECT_0)
00260         {
00261                 return false;           // shutting down
00262         }
00263         else if(dwResult == WAIT_OBJECT_0 + 1)
00264         {
00265                 ;       // pool mutex aquired, do nothing
00266         }
00267         else
00268         {
00269                 assert(0);
00270         }
00271 
00272         vData.clear();
00273         m_hashPool.Extract(vData);      // note that the data is not being erased
00274 
00275         m_PoolMutex.Release();
00276 
00277         return true;
00278 }
00279 
00280 bool Pool::SetHashPoolState(vecuc& vState)
00281 {
00282         size_t size = vState.size();
00283         if (size != 32)
00284         {
00285                 assert(0);
00286                 return false;
00287         }
00288 
00289         m_hashPool.Reset();
00290         for (size_t i=0; i<size; ++i)
00291                 m_hashPool.Add(vState[i]);
00292 
00293         return true;
00294 }
00295 
00296 
00297 // this method is not thread safe - it is used after reading in the seed file 
00298 // to protect against the same seed file being used twice.
00299 // The machine signature contains a signature that is common to the machine 
00300 // and when adding to the pool some other pool specific data is also added
00301 void Pool::AddMachineSignatureToPool(vecuc& vMachineSig)
00302 {
00303         vecuc vPool;            // pool specific data
00304         unsigned int iThis = (unsigned int)this;
00305         const unsigned char* pData = (unsigned char*)&iThis;
00306         AddBinaryData(vPool, pData, sizeof(unsigned int));
00307 
00308         // adds in bytes for each of the linked list items
00309         m_hashPool.AddRandomData(vPool);
00310 
00311         vecuc vHashPool;
00312         vHashPool.reserve(1024);
00313         m_hashPool.ExtractAndErase(vHashPool);
00314         m_hashPool.Reset();
00315 
00316         AddToVector(vHashPool, vPool);
00317         EraseVector(vPool);
00318 
00319         AddToVector(vHashPool, vMachineSig);
00320         EraseVector(vMachineSig);
00321 
00322         vecuc vHash;
00323         HashVector(vHashPool, vHash);
00324         EraseVector(vHashPool);
00325 
00326         size_t size = vHash.size();
00327         assert( size == 32);
00328 
00329         for (size_t i=0; i<size; ++i)
00330                 m_hashPool.Add(vHash[i]);
00331 
00332         EraseVector(vHash);
00333 }
00334 
00335 #ifdef FORTUNAMONITOR
00336 std::string Pool::GetName() const
00337 {
00338         char buffer[64] = {'\0'};
00339         sprintf(buffer,"Pool %d", m_iPoolNum);
00340 
00341         return std::string(buffer);
00342 }
00343 #endif
00344 
00345 #ifdef FORTUNAMONITOR
00346 std::string Pool::GetRawPool()
00347 {
00348         std::string str;
00349 
00350         HANDLE hVec[2] = {m_hShutdownEvent, m_hPoolMutex };
00351         DWORD dwResult = WaitForMultipleObjects(2, hVec, FALSE, INFINITE);
00352 
00353         if (dwResult == WAIT_OBJECT_0)
00354                 return str;             // shutting down
00355         else if(dwResult == WAIT_OBJECT_0 + 1)
00356         {
00357                 ;       // pool mutex aquired, do nothing
00358         }
00359 
00360         vecuc vData;
00361         m_pool.Extract(vData);
00362 
00363         str = BinaryToString(&vData[0], (int)vData.size());
00364 
00365         m_PoolMutex.Release();
00366 
00367         return str;
00368 }
00369 #endif
00370 
00371 #ifdef FORTUNAMONITOR
00372 std::string Pool::GetHashedPool()
00373 {
00374         std::string str;
00375 
00376         HANDLE hVec[2] = {m_hShutdownEvent, m_hPoolMutex };
00377         DWORD dwResult = WaitForMultipleObjects(2, hVec, FALSE, INFINITE);
00378 
00379         if (dwResult == WAIT_OBJECT_0)
00380                 return str;             // shutting down
00381         else if(dwResult == WAIT_OBJECT_0 + 1)
00382         {
00383                 ;       // pool mutex aquired, do nothing
00384         }
00385 
00386         vecuc vData;
00387         m_hashPool.Extract(vData);
00388 
00389         str = BinaryToString(&vData[0], (int)vData.size());
00390 
00391         m_PoolMutex.Release();
00392 
00393         return str;
00394 }
00395 #endif
00396 
00397 }       // end namespace CitadelSoftwareInc

Generated on Sat Feb 28 17:24:40 2004 for Fortuna by doxygen 1.3.5