rlm@1: // RandGen.cpp rlm@1: rlm@1: #include "StdAfx.h" rlm@1: rlm@1: #include rlm@1: #include "Windows/Synchronization.h" rlm@1: #include "RandGen.h" rlm@1: rlm@1: #ifndef _WIN32 rlm@1: #include rlm@1: #define USE_POSIX_TIME rlm@1: #define USE_POSIX_TIME2 rlm@1: #endif rlm@1: rlm@1: #ifdef USE_POSIX_TIME rlm@1: #include rlm@1: #ifdef USE_POSIX_TIME2 rlm@1: #include rlm@1: #endif rlm@1: #endif rlm@1: rlm@1: // This is not very good random number generator. rlm@1: // Please use it only for salt. rlm@1: // First generated data block depends from timer and processID. rlm@1: // Other generated data blocks depend from previous state rlm@1: // Maybe it's possible to restore original timer value from generated value. rlm@1: rlm@1: void CRandomGenerator::Init() rlm@1: { rlm@1: NCrypto::NSha1::CContext hash; rlm@1: hash.Init(); rlm@1: rlm@1: #ifdef _WIN32 rlm@1: DWORD w = ::GetCurrentProcessId(); rlm@1: hash.Update((const Byte *)&w, sizeof(w)); rlm@1: w = ::GetCurrentThreadId(); rlm@1: hash.Update((const Byte *)&w, sizeof(w)); rlm@1: #else rlm@1: pid_t pid = getpid(); rlm@1: hash.Update((const Byte *)&pid, sizeof(pid)); rlm@1: pid = getppid(); rlm@1: hash.Update((const Byte *)&pid, sizeof(pid)); rlm@1: #endif rlm@1: rlm@1: for (int i = 0; i < 1000; i++) rlm@1: { rlm@1: #ifdef _WIN32 rlm@1: LARGE_INTEGER v; rlm@1: if (::QueryPerformanceCounter(&v)) rlm@1: hash.Update((const Byte *)&v.QuadPart, sizeof(v.QuadPart)); rlm@1: #endif rlm@1: rlm@1: #ifdef USE_POSIX_TIME rlm@1: #ifdef USE_POSIX_TIME2 rlm@1: timeval v; rlm@1: if (gettimeofday(&v, 0) == 0) rlm@1: { rlm@1: hash.Update((const Byte *)&v.tv_sec, sizeof(v.tv_sec)); rlm@1: hash.Update((const Byte *)&v.tv_usec, sizeof(v.tv_usec)); rlm@1: } rlm@1: #endif rlm@1: time_t v2 = time(NULL); rlm@1: hash.Update((const Byte *)&v2, sizeof(v2)); rlm@1: #endif rlm@1: rlm@1: DWORD tickCount = ::GetTickCount(); rlm@1: hash.Update((const Byte *)&tickCount, sizeof(tickCount)); rlm@1: rlm@1: for (int j = 0; j < 100; j++) rlm@1: { rlm@1: hash.Final(_buff); rlm@1: hash.Init(); rlm@1: hash.Update(_buff, NCrypto::NSha1::kDigestSize); rlm@1: } rlm@1: } rlm@1: hash.Final(_buff); rlm@1: _needInit = false; rlm@1: } rlm@1: rlm@1: static NWindows::NSynchronization::CCriticalSection g_CriticalSection; rlm@1: rlm@1: void CRandomGenerator::Generate(Byte *data, unsigned int size) rlm@1: { rlm@1: g_CriticalSection.Enter(); rlm@1: if (_needInit) rlm@1: Init(); rlm@1: while (size > 0) rlm@1: { rlm@1: NCrypto::NSha1::CContext hash; rlm@1: rlm@1: hash.Init(); rlm@1: hash.Update(_buff, NCrypto::NSha1::kDigestSize); rlm@1: hash.Final(_buff); rlm@1: rlm@1: hash.Init(); rlm@1: UInt32 salt = 0xF672ABD1; rlm@1: hash.Update((const Byte *)&salt, sizeof(salt)); rlm@1: hash.Update(_buff, NCrypto::NSha1::kDigestSize); rlm@1: Byte buff[NCrypto::NSha1::kDigestSize]; rlm@1: hash.Final(buff); rlm@1: for (unsigned int i = 0; i < NCrypto::NSha1::kDigestSize && size > 0; i++, size--) rlm@1: *data++ = buff[i]; rlm@1: } rlm@1: g_CriticalSection.Leave(); rlm@1: } rlm@1: rlm@1: CRandomGenerator g_RandomGenerator;