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