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 MY_ALIGN (16)
63 CSha256 hash;
64 Sha256_Init(&hash);
65
66 unsigned numIterations = 1000;
67
68 {
69 #ifndef UNDER_CE
70 const unsigned kNumIterations_Small = 100;
71 const unsigned kBufSize = 32;
72 MY_ALIGN (16)
73 Byte buf[kBufSize];
74 #endif
75
76 #ifdef _WIN32
77
78 DWORD w = ::GetCurrentProcessId();
79 HASH_UPD(w);
80 w = ::GetCurrentThreadId();
81 HASH_UPD(w);
82
83 #ifdef UNDER_CE
84 /*
85 if (CeGenRandom(kBufSize, buf))
86 {
87 numIterations = kNumIterations_Small;
88 Sha256_Update(&hash, buf, kBufSize);
89 }
90 */
91 #elif defined(USE_STATIC_RtlGenRandom)
92 if (RtlGenRandom(buf, kBufSize))
93 {
94 numIterations = kNumIterations_Small;
95 Sha256_Update(&hash, buf, kBufSize);
96 }
97 #else
98 {
99 HMODULE hModule = ::LoadLibrary(TEXT("Advapi32.dll"));
100 if (hModule)
101 {
102 // SystemFunction036() is real name of RtlGenRandom() function
103 Func_RtlGenRandom my_RtlGenRandom = (Func_RtlGenRandom)(void *)GetProcAddress(hModule, "SystemFunction036");
104 if (my_RtlGenRandom)
105 {
106 if (my_RtlGenRandom(buf, kBufSize))
107 {
108 numIterations = kNumIterations_Small;
109 Sha256_Update(&hash, buf, kBufSize);
110 }
111 }
112 ::FreeLibrary(hModule);
113 }
114 }
115 #endif
116
117 #else
118
119 pid_t pid = getpid();
120 HASH_UPD(pid);
121 pid = getppid();
122 HASH_UPD(pid);
123
124 {
125 int f = open("/dev/urandom", O_RDONLY);
126 unsigned numBytes = kBufSize;
127 if (f >= 0)
128 {
129 do
130 {
131 ssize_t n = read(f, buf, numBytes);
132 if (n <= 0)
133 break;
134 Sha256_Update(&hash, buf, (size_t)n);
135 numBytes -= (unsigned)n;
136 }
137 while (numBytes);
138 close(f);
139 if (numBytes == 0)
140 numIterations = kNumIterations_Small;
141 }
142 }
143 /*
144 {
145 int n = getrandom(buf, kBufSize, 0);
146 if (n > 0)
147 {
148 Sha256_Update(&hash, buf, n);
149 if (n == kBufSize)
150 numIterations = kNumIterations_Small;
151 }
152 }
153 */
154
155 #endif
156 }
157
158 #ifdef _DEBUG
159 numIterations = 2;
160 #endif
161
162 do
163 {
164 #ifdef _WIN32
165 LARGE_INTEGER v;
166 if (::QueryPerformanceCounter(&v))
167 HASH_UPD(v.QuadPart);
168 #endif
169
170 #ifdef USE_POSIX_TIME
171 #ifdef USE_POSIX_TIME2
172 timeval v;
173 if (gettimeofday(&v, 0) == 0)
174 {
175 HASH_UPD(v.tv_sec);
176 HASH_UPD(v.tv_usec);
177 }
178 #endif
179 time_t v2 = time(NULL);
180 HASH_UPD(v2);
181 #endif
182
183 #ifdef _WIN32
184 DWORD tickCount = ::GetTickCount();
185 HASH_UPD(tickCount);
186 #endif
187
188 for (unsigned j = 0; j < 100; j++)
189 {
190 Sha256_Final(&hash, _buff);
191 Sha256_Init(&hash);
192 Sha256_Update(&hash, _buff, SHA256_DIGEST_SIZE);
193 }
194 }
195 while (--numIterations);
196
197 Sha256_Final(&hash, _buff);
198 _needInit = false;
199 }
200
201 #ifndef _7ZIP_ST
202 static NWindows::NSynchronization::CCriticalSection g_CriticalSection;
203 #define MT_LOCK NWindows::NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
204 #else
205 #define MT_LOCK
206 #endif
207
Generate(Byte * data,unsigned size)208 void CRandomGenerator::Generate(Byte *data, unsigned size)
209 {
210 MT_LOCK
211
212 if (_needInit)
213 Init();
214 while (size != 0)
215 {
216 MY_ALIGN (16)
217 CSha256 hash;
218
219 Sha256_Init(&hash);
220 Sha256_Update(&hash, _buff, SHA256_DIGEST_SIZE);
221 Sha256_Final(&hash, _buff);
222
223 Sha256_Init(&hash);
224 UInt32 salt = 0xF672ABD1;
225 HASH_UPD(salt);
226 Sha256_Update(&hash, _buff, SHA256_DIGEST_SIZE);
227 MY_ALIGN (16)
228 Byte buff[SHA256_DIGEST_SIZE];
229 Sha256_Final(&hash, buff);
230 for (unsigned i = 0; i < SHA256_DIGEST_SIZE && size != 0; i++, size--)
231 *data++ = buff[i];
232 }
233 }
234
235 CRandomGenerator g_RandomGenerator;
236
237 #endif
238