• 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   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