1 // RandGen.cpp
2
3 #include "StdAfx.h"
4
5 #include "RandGen.h"
6
7 #ifndef USE_STATIC_SYSTEM_RAND
8
9 #ifndef Z7_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 const HMODULE hModule = ::LoadLibrary(TEXT("advapi32.dll"));
100 if (hModule)
101 {
102 // SystemFunction036() is real name of RtlGenRandom() function
103 const
104 Func_RtlGenRandom
105 my_RtlGenRandom = Z7_GET_PROC_ADDRESS(
106 Func_RtlGenRandom, hModule, "SystemFunction036");
107 if (my_RtlGenRandom)
108 {
109 if (my_RtlGenRandom(buf, kBufSize))
110 {
111 numIterations = kNumIterations_Small;
112 Sha256_Update(&hash, buf, kBufSize);
113 }
114 }
115 ::FreeLibrary(hModule);
116 }
117 }
118 #endif
119
120 #else
121
122 pid_t pid = getpid();
123 HASH_UPD(pid)
124 pid = getppid();
125 HASH_UPD(pid)
126
127 {
128 int f = open("/dev/urandom", O_RDONLY);
129 unsigned numBytes = kBufSize;
130 if (f >= 0)
131 {
132 do
133 {
134 ssize_t n = read(f, buf, numBytes);
135 if (n <= 0)
136 break;
137 Sha256_Update(&hash, buf, (size_t)n);
138 numBytes -= (unsigned)n;
139 }
140 while (numBytes);
141 close(f);
142 if (numBytes == 0)
143 numIterations = kNumIterations_Small;
144 }
145 }
146 /*
147 {
148 int n = getrandom(buf, kBufSize, 0);
149 if (n > 0)
150 {
151 Sha256_Update(&hash, buf, n);
152 if (n == kBufSize)
153 numIterations = kNumIterations_Small;
154 }
155 }
156 */
157
158 #endif
159 }
160
161 #ifdef _DEBUG
162 numIterations = 2;
163 #endif
164
165 do
166 {
167 #ifdef _WIN32
168 LARGE_INTEGER v;
169 if (::QueryPerformanceCounter(&v))
170 HASH_UPD(v.QuadPart)
171 #endif
172
173 #ifdef USE_POSIX_TIME
174 #ifdef USE_POSIX_TIME2
175 timeval v;
176 if (gettimeofday(&v, NULL) == 0)
177 {
178 HASH_UPD(v.tv_sec)
179 HASH_UPD(v.tv_usec)
180 }
181 #endif
182 const time_t v2 = time(NULL);
183 HASH_UPD(v2)
184 #endif
185
186 #ifdef _WIN32
187 const DWORD tickCount = ::GetTickCount();
188 HASH_UPD(tickCount)
189 #endif
190
191 for (unsigned j = 0; j < 100; j++)
192 {
193 Sha256_Final(&hash, _buff);
194 Sha256_Init(&hash);
195 Sha256_Update(&hash, _buff, SHA256_DIGEST_SIZE);
196 }
197 }
198 while (--numIterations);
199
200 Sha256_Final(&hash, _buff);
201 _needInit = false;
202 }
203
204 #ifndef Z7_ST
205 static NWindows::NSynchronization::CCriticalSection g_CriticalSection;
206 #define MT_LOCK NWindows::NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
207 #else
208 #define MT_LOCK
209 #endif
210
Generate(Byte * data,unsigned size)211 void CRandomGenerator::Generate(Byte *data, unsigned size)
212 {
213 MT_LOCK
214
215 if (_needInit)
216 Init();
217 while (size != 0)
218 {
219 MY_ALIGN (16)
220 CSha256 hash;
221
222 Sha256_Init(&hash);
223 Sha256_Update(&hash, _buff, SHA256_DIGEST_SIZE);
224 Sha256_Final(&hash, _buff);
225
226 Sha256_Init(&hash);
227 UInt32 salt = 0xF672ABD1;
228 HASH_UPD(salt)
229 Sha256_Update(&hash, _buff, SHA256_DIGEST_SIZE);
230 MY_ALIGN (16)
231 Byte buff[SHA256_DIGEST_SIZE];
232 Sha256_Final(&hash, buff);
233 for (unsigned i = 0; i < SHA256_DIGEST_SIZE && size != 0; i++, size--)
234 *data++ = buff[i];
235 }
236 }
237
238 MY_ALIGN (16)
239 CRandomGenerator g_RandomGenerator;
240
241 #endif
242