• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // RandGen.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "RandGen.h"
6 
7 #ifndef USE_STATIC_SYSTEM_RAND
8 
9 #ifndef _7ZIP_ST
10 #include "../../Windows/Synchronization.h"
11 #endif
12 
13 
14 #ifdef _WIN32
15 
16 #ifdef _WIN64
17 #define USE_STATIC_RtlGenRandom
18 #endif
19 
20 #ifdef USE_STATIC_RtlGenRandom
21 
22 #include <ntsecapi.h>
23 
24 EXTERN_C_BEGIN
25 #ifndef RtlGenRandom
26   #define RtlGenRandom SystemFunction036
27   BOOLEAN WINAPI RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength);
28 #endif
29 EXTERN_C_END
30 
31 #else
32 EXTERN_C_BEGIN
33 typedef BOOLEAN (WINAPI * Func_RtlGenRandom)(PVOID RandomBuffer, ULONG RandomBufferLength);
34 EXTERN_C_END
35 #endif
36 
37 
38 #else
39 #include <unistd.h>
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <fcntl.h>
43 #define USE_POSIX_TIME
44 #define USE_POSIX_TIME2
45 #endif
46 
47 #ifdef USE_POSIX_TIME
48 #include <time.h>
49 #ifdef USE_POSIX_TIME2
50 #include <sys/time.h>
51 #endif
52 #endif
53 
54 // The seed and first generated data block depend from processID,
55 // theadID, timer and system random generator, if available.
56 // Other generated data blocks depend from previous state
57 
58 #define HASH_UPD(x) Sha256_Update(&hash, (const Byte *)&x, sizeof(x));
59 
Init()60 void CRandomGenerator::Init()
61 {
62   CSha256 hash;
63   Sha256_Init(&hash);
64 
65   unsigned numIterations = 1000;
66 
67   {
68   #ifndef UNDER_CE
69   const unsigned kNumIterations_Small = 100;
70   const unsigned kBufSize = 32;
71   Byte buf[kBufSize];
72   #endif
73 
74   #ifdef _WIN32
75 
76   DWORD w = ::GetCurrentProcessId();
77   HASH_UPD(w);
78   w = ::GetCurrentThreadId();
79   HASH_UPD(w);
80 
81   #ifdef UNDER_CE
82   /*
83   if (CeGenRandom(kBufSize, buf))
84   {
85     numIterations = kNumIterations_Small;
86     Sha256_Update(&hash, buf, kBufSize);
87   }
88   */
89   #elif defined(USE_STATIC_RtlGenRandom)
90   if (RtlGenRandom(buf, kBufSize))
91   {
92     numIterations = kNumIterations_Small;
93     Sha256_Update(&hash, buf, kBufSize);
94   }
95   #else
96   {
97     HMODULE hModule = ::LoadLibrary(TEXT("Advapi32.dll"));
98     if (hModule)
99     {
100       // SystemFunction036() is real name of RtlGenRandom() function
101       Func_RtlGenRandom my_RtlGenRandom = (Func_RtlGenRandom)GetProcAddress(hModule, "SystemFunction036");
102       if (my_RtlGenRandom)
103       {
104         if (my_RtlGenRandom(buf, kBufSize))
105         {
106           numIterations = kNumIterations_Small;
107           Sha256_Update(&hash, buf, kBufSize);
108         }
109       }
110       ::FreeLibrary(hModule);
111     }
112   }
113   #endif
114 
115   #else
116 
117   pid_t pid = getpid();
118   HASH_UPD(pid);
119   pid = getppid();
120   HASH_UPD(pid);
121 
122   {
123     int f = open("/dev/urandom", O_RDONLY);
124     unsigned numBytes = kBufSize;
125     if (f >= 0)
126     {
127       do
128       {
129         int n = read(f, buf, numBytes);
130         if (n <= 0)
131           break;
132         Sha256_Update(&hash, buf, n);
133         numBytes -= n;
134       }
135       while (numBytes);
136       close(f);
137       if (numBytes == 0)
138         numIterations = kNumIterations_Small;
139     }
140   }
141   /*
142   {
143     int n = getrandom(buf, kBufSize, 0);
144     if (n > 0)
145     {
146       Sha256_Update(&hash, buf, n);
147       if (n == kBufSize)
148         numIterations = kNumIterations_Small;
149     }
150   }
151   */
152 
153   #endif
154   }
155 
156   #ifdef _DEBUG
157   numIterations = 2;
158   #endif
159 
160   do
161   {
162     #ifdef _WIN32
163     LARGE_INTEGER v;
164     if (::QueryPerformanceCounter(&v))
165       HASH_UPD(v.QuadPart);
166     #endif
167 
168     #ifdef USE_POSIX_TIME
169     #ifdef USE_POSIX_TIME2
170     timeval v;
171     if (gettimeofday(&v, 0) == 0)
172     {
173       HASH_UPD(v.tv_sec);
174       HASH_UPD(v.tv_usec);
175     }
176     #endif
177     time_t v2 = time(NULL);
178     HASH_UPD(v2);
179     #endif
180 
181     #ifdef _WIN32
182     DWORD tickCount = ::GetTickCount();
183     HASH_UPD(tickCount);
184     #endif
185 
186     for (unsigned j = 0; j < 100; j++)
187     {
188       Sha256_Final(&hash, _buff);
189       Sha256_Init(&hash);
190       Sha256_Update(&hash, _buff, SHA256_DIGEST_SIZE);
191     }
192   }
193   while (--numIterations);
194 
195   Sha256_Final(&hash, _buff);
196   _needInit = false;
197 }
198 
199 #ifndef _7ZIP_ST
200   static NWindows::NSynchronization::CCriticalSection g_CriticalSection;
201   #define MT_LOCK NWindows::NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
202 #else
203   #define MT_LOCK
204 #endif
205 
Generate(Byte * data,unsigned size)206 void CRandomGenerator::Generate(Byte *data, unsigned size)
207 {
208   MT_LOCK
209 
210   if (_needInit)
211     Init();
212   while (size != 0)
213   {
214     CSha256 hash;
215 
216     Sha256_Init(&hash);
217     Sha256_Update(&hash, _buff, SHA256_DIGEST_SIZE);
218     Sha256_Final(&hash, _buff);
219 
220     Sha256_Init(&hash);
221     UInt32 salt = 0xF672ABD1;
222     HASH_UPD(salt);
223     Sha256_Update(&hash, _buff, SHA256_DIGEST_SIZE);
224     Byte buff[SHA256_DIGEST_SIZE];
225     Sha256_Final(&hash, buff);
226     for (unsigned i = 0; i < SHA256_DIGEST_SIZE && size != 0; i++, size--)
227       *data++ = buff[i];
228   }
229 }
230 
231 CRandomGenerator g_RandomGenerator;
232 
233 #endif
234