1 |
twoaday |
2 |
/* rndw32.c - W32 entropy gatherer |
2 |
|
|
* Copyright (C) 1999, 2000 Free Software Foundation, Inc. |
3 |
|
|
* Copyright Peter Gutmann, Matt Thomlinson and Blake Coverett 1996-1999 |
4 |
|
|
* |
5 |
|
|
* This file is part of Libgcrypt. |
6 |
|
|
* |
7 |
|
|
* Libgcrypt is free software; you can redistribute it and/or modify |
8 |
|
|
* it under the terms of the GNU General Public License as published by |
9 |
|
|
* the Free Software Foundation; either version 2 of the License, or |
10 |
|
|
* (at your option) any later version. |
11 |
|
|
* |
12 |
|
|
* Libgcrypt is distributed in the hope that it will be useful, |
13 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 |
|
|
* GNU General Public License for more details. |
16 |
|
|
* |
17 |
|
|
* You should have received a copy of the GNU General Public License |
18 |
|
|
* along with this program; if not, write to the Free Software |
19 |
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA |
20 |
|
|
* |
21 |
|
|
************************************************************************* |
22 |
|
|
* The code here is based on code from Cryptlib 3.0 beta by Peter Gutmann. |
23 |
|
|
* Source file misc/rndwin32.c "Win32 Randomness-Gathering Code" with this |
24 |
|
|
* copyright notice: |
25 |
|
|
* |
26 |
|
|
* This module is part of the cryptlib continuously seeded pseudorandom |
27 |
|
|
* number generator. For usage conditions, see lib_rand.c |
28 |
|
|
* |
29 |
|
|
* [Here is the notice from lib_rand.c, which is now called dev_sys.c] |
30 |
|
|
* |
31 |
|
|
* This module and the misc/rnd*.c modules represent the cryptlib |
32 |
|
|
* continuously seeded pseudorandom number generator (CSPRNG) as described in |
33 |
|
|
* my 1998 Usenix Security Symposium paper "The generation of random numbers |
34 |
|
|
* for cryptographic purposes". |
35 |
|
|
* |
36 |
|
|
* The CSPRNG code is copyright Peter Gutmann (and various others) 1996, |
37 |
|
|
* 1997, 1998, 1999, all rights reserved. Redistribution of the CSPRNG |
38 |
|
|
* modules and use in source and binary forms, with or without modification, |
39 |
|
|
* are permitted provided that the following conditions are met: |
40 |
|
|
* |
41 |
|
|
* 1. Redistributions of source code must retain the above copyright notice |
42 |
|
|
* and this permission notice in its entirety. |
43 |
|
|
* |
44 |
|
|
* 2. Redistributions in binary form must reproduce the copyright notice in |
45 |
|
|
* the documentation and/or other materials provided with the distribution. |
46 |
|
|
* |
47 |
|
|
* 3. A copy of any bugfixes or enhancements made must be provided to the |
48 |
|
|
* author, <[email protected]> to allow them to be added to the |
49 |
|
|
* baseline version of the code. |
50 |
|
|
* |
51 |
|
|
* ALTERNATIVELY, the code may be distributed under the terms of the GNU |
52 |
|
|
* General Public License, version 2 or any later version published by the |
53 |
|
|
* Free Software Foundation, in which case the provisions of the GNU GPL are |
54 |
|
|
* required INSTEAD OF the above restrictions. |
55 |
|
|
* |
56 |
|
|
* Although not required under the terms of the GPL, it would still be nice if |
57 |
|
|
* you could make any changes available to the author to allow a consistent |
58 |
|
|
* code base to be maintained |
59 |
|
|
************************************************************************* |
60 |
|
|
* Heavily modified by Timo Schulz to fit into WinPT, 2001. |
61 |
|
|
*/ |
62 |
|
|
|
63 |
|
|
#include <stdio.h> |
64 |
|
|
#include <stdlib.h> |
65 |
|
|
#include <assert.h> |
66 |
|
|
#include <errno.h> |
67 |
|
|
#include <string.h> |
68 |
|
|
|
69 |
|
|
#include <windows.h> |
70 |
|
|
#include <tlhelp32.h> |
71 |
|
|
#include <winioctl.h> |
72 |
|
|
|
73 |
|
|
|
74 |
|
|
/* Type definitions for function pointers to call Toolhelp32 functions |
75 |
|
|
* used with the windows95 gatherer */ |
76 |
|
|
typedef BOOL (WINAPI * MODULEWALK) (HANDLE hSnapshot, MODULEENTRY32 *lpme); |
77 |
|
|
typedef BOOL (WINAPI * THREADWALK) (HANDLE hSnapshot, THREADENTRY32 *lpte); |
78 |
|
|
typedef BOOL (WINAPI * PROCESSWALK) (HANDLE hSnapshot, PROCESSENTRY32 *lppe); |
79 |
|
|
typedef BOOL (WINAPI * HEAPLISTWALK) (HANDLE hSnapshot, HEAPLIST32 *lphl); |
80 |
|
|
typedef BOOL (WINAPI * HEAPFIRST) (HEAPENTRY32 *lphe, DWORD th32ProcessID, |
81 |
|
|
DWORD th32HeapID); |
82 |
|
|
typedef BOOL (WINAPI * HEAPNEXT) (HEAPENTRY32 *lphe); |
83 |
|
|
typedef HANDLE (WINAPI * CREATESNAPSHOT) (DWORD dwFlags, DWORD th32ProcessID); |
84 |
|
|
|
85 |
|
|
/* Type definitions for function pointers to call NetAPI32 functions */ |
86 |
|
|
typedef DWORD (WINAPI * NETSTATISTICSGET) (LPWSTR szServer, LPWSTR szService, |
87 |
|
|
DWORD dwLevel, DWORD dwOptions, |
88 |
|
|
LPBYTE * lpBuffer); |
89 |
|
|
typedef DWORD (WINAPI * NETAPIBUFFERSIZE) (LPVOID lpBuffer, LPDWORD cbBuffer); |
90 |
|
|
typedef DWORD (WINAPI * NETAPIBUFFERFREE) (LPVOID lpBuffer); |
91 |
|
|
|
92 |
|
|
|
93 |
|
|
/* When we query the performance counters, we allocate an initial buffer and |
94 |
|
|
* then reallocate it as required until RegQueryValueEx() stops returning |
95 |
|
|
* ERROR_MORE_DATA. The following values define the initial buffer size and |
96 |
|
|
* step size by which the buffer is increased |
97 |
|
|
*/ |
98 |
|
|
#define PERFORMANCE_BUFFER_SIZE 65536 /* Start at 64K */ |
99 |
|
|
#define PERFORMANCE_BUFFER_STEP 16384 /* Step by 16K */ |
100 |
|
|
|
101 |
|
|
|
102 |
|
|
static void |
103 |
|
|
random_w32_err( const char *format, ... ) |
104 |
|
|
{ |
105 |
|
|
char log[8192]; |
106 |
|
|
va_list arg_ptr; |
107 |
|
|
|
108 |
|
|
va_start( arg_ptr, format ); |
109 |
|
|
_vsnprintf( log, sizeof log-1, format, arg_ptr ); |
110 |
|
|
MessageBox( NULL, log, "Crypto RNG", MB_ICONERROR|MB_OK ); |
111 |
|
|
va_end( arg_ptr ); |
112 |
|
|
} /* log_box */ |
113 |
|
|
|
114 |
|
|
|
115 |
|
|
static void |
116 |
|
|
slow_gatherer_windows95( void (*add)(const void*, size_t, int), int requester ) |
117 |
|
|
{ |
118 |
|
|
static CREATESNAPSHOT pCreateToolhelp32Snapshot = NULL; |
119 |
|
|
static MODULEWALK pModule32First = NULL; |
120 |
|
|
static MODULEWALK pModule32Next = NULL; |
121 |
|
|
static PROCESSWALK pProcess32First = NULL; |
122 |
|
|
static PROCESSWALK pProcess32Next = NULL; |
123 |
|
|
static THREADWALK pThread32First = NULL; |
124 |
|
|
static THREADWALK pThread32Next = NULL; |
125 |
|
|
static HEAPLISTWALK pHeap32ListFirst = NULL; |
126 |
|
|
static HEAPLISTWALK pHeap32ListNext = NULL; |
127 |
|
|
static HEAPFIRST pHeap32First = NULL; |
128 |
|
|
static HEAPNEXT pHeap32Next = NULL; |
129 |
|
|
HANDLE hSnapshot; |
130 |
|
|
|
131 |
|
|
|
132 |
|
|
/* initialize the Toolhelp32 function pointers */ |
133 |
|
|
if ( !pCreateToolhelp32Snapshot ) { |
134 |
|
|
HANDLE hKernel; |
135 |
|
|
|
136 |
|
|
/* Obtain the module handle of the kernel to retrieve the addresses |
137 |
|
|
* of the Toolhelp32 functions */ |
138 |
|
|
if ( ( !(hKernel = GetModuleHandle ("KERNEL32.DLL"))) ) { |
139 |
|
|
random_w32_err( "rndw32: can't get module handle" ); |
140 |
|
|
return; |
141 |
|
|
} |
142 |
|
|
|
143 |
|
|
/* Now get pointers to the functions */ |
144 |
|
|
pCreateToolhelp32Snapshot = (CREATESNAPSHOT) GetProcAddress (hKernel, |
145 |
|
|
"CreateToolhelp32Snapshot"); |
146 |
|
|
pModule32First = (MODULEWALK) GetProcAddress (hKernel, "Module32First"); |
147 |
|
|
pModule32Next = (MODULEWALK) GetProcAddress (hKernel, "Module32Next"); |
148 |
|
|
pProcess32First = (PROCESSWALK) GetProcAddress (hKernel, |
149 |
|
|
"Process32First"); |
150 |
|
|
pProcess32Next = (PROCESSWALK) GetProcAddress (hKernel, |
151 |
|
|
"Process32Next"); |
152 |
|
|
pThread32First = (THREADWALK) GetProcAddress (hKernel, "Thread32First"); |
153 |
|
|
pThread32Next = (THREADWALK) GetProcAddress (hKernel, "Thread32Next"); |
154 |
|
|
pHeap32ListFirst = (HEAPLISTWALK) GetProcAddress (hKernel, |
155 |
|
|
"Heap32ListFirst"); |
156 |
|
|
pHeap32ListNext = (HEAPLISTWALK) GetProcAddress (hKernel, |
157 |
|
|
"Heap32ListNext"); |
158 |
|
|
pHeap32First = (HEAPFIRST) GetProcAddress (hKernel, "Heap32First"); |
159 |
|
|
pHeap32Next = (HEAPNEXT) GetProcAddress (hKernel, "Heap32Next"); |
160 |
|
|
|
161 |
|
|
if ( !pCreateToolhelp32Snapshot |
162 |
|
|
|| !pModule32First || !pModule32Next |
163 |
|
|
|| !pProcess32First || !pProcess32Next |
164 |
|
|
|| !pThread32First || !pThread32Next |
165 |
|
|
|| !pHeap32ListFirst || !pHeap32ListNext |
166 |
|
|
|| !pHeap32First || !pHeap32Next ) { |
167 |
|
|
random_w32_err( "rndw32: failed to get a toolhep function" ); |
168 |
|
|
return; |
169 |
|
|
} |
170 |
|
|
} |
171 |
|
|
|
172 |
|
|
/* Take a snapshot of everything we can get to which is currently |
173 |
|
|
* in the system */ |
174 |
|
|
if ( !(hSnapshot = pCreateToolhelp32Snapshot (TH32CS_SNAPALL, 0)) ) { |
175 |
|
|
random_w32_err( "rndw32: failed to take a toolhelp snapshot" ); |
176 |
|
|
return; |
177 |
|
|
} |
178 |
|
|
|
179 |
|
|
/* Walk through the local heap */ |
180 |
|
|
{ HEAPLIST32 hl32; |
181 |
|
|
hl32.dwSize = sizeof (HEAPLIST32); |
182 |
|
|
if (pHeap32ListFirst (hSnapshot, &hl32)) { |
183 |
|
|
do { |
184 |
|
|
HEAPENTRY32 he32; |
185 |
|
|
|
186 |
|
|
/* First add the information from the basic Heaplist32 struct */ |
187 |
|
|
(*add) ( &hl32, sizeof (hl32), requester ); |
188 |
|
|
|
189 |
|
|
/* Now walk through the heap blocks getting information |
190 |
|
|
* on each of them */ |
191 |
|
|
he32.dwSize = sizeof (HEAPENTRY32); |
192 |
|
|
if (pHeap32First (&he32, hl32.th32ProcessID, hl32.th32HeapID)){ |
193 |
|
|
do { |
194 |
|
|
(*add) ( &he32, sizeof (he32), requester ); |
195 |
|
|
} while (pHeap32Next (&he32)); |
196 |
|
|
} |
197 |
|
|
} while (pHeap32ListNext (hSnapshot, &hl32)); |
198 |
|
|
} |
199 |
|
|
} |
200 |
|
|
|
201 |
|
|
|
202 |
|
|
/* Walk through all processes */ |
203 |
|
|
{ PROCESSENTRY32 pe32; |
204 |
|
|
pe32.dwSize = sizeof (PROCESSENTRY32); |
205 |
|
|
if (pProcess32First (hSnapshot, &pe32)) { |
206 |
|
|
do { |
207 |
|
|
(*add) ( &pe32, sizeof (pe32), requester ); |
208 |
|
|
} while (pProcess32Next (hSnapshot, &pe32)); |
209 |
|
|
} |
210 |
|
|
} |
211 |
|
|
|
212 |
|
|
/* Walk through all threads */ |
213 |
|
|
{ THREADENTRY32 te32; |
214 |
|
|
te32.dwSize = sizeof (THREADENTRY32); |
215 |
|
|
if (pThread32First (hSnapshot, &te32)) { |
216 |
|
|
do { |
217 |
|
|
(*add) ( &te32, sizeof (te32), requester ); |
218 |
|
|
} while (pThread32Next (hSnapshot, &te32)); |
219 |
|
|
} |
220 |
|
|
} |
221 |
|
|
|
222 |
|
|
/* Walk through all modules associated with the process */ |
223 |
|
|
{ MODULEENTRY32 me32; |
224 |
|
|
me32.dwSize = sizeof (MODULEENTRY32); |
225 |
|
|
if (pModule32First (hSnapshot, &me32)) { |
226 |
|
|
do { |
227 |
|
|
(*add) ( &me32, sizeof (me32), requester ); |
228 |
|
|
} while (pModule32Next (hSnapshot, &me32)); |
229 |
|
|
} |
230 |
|
|
} |
231 |
|
|
|
232 |
|
|
CloseHandle (hSnapshot); |
233 |
|
|
} |
234 |
|
|
|
235 |
|
|
|
236 |
|
|
|
237 |
|
|
|
238 |
|
|
|
239 |
|
|
static void |
240 |
|
|
slow_gatherer_windowsNT( void (*add)(const void*, size_t, int), int requester ) |
241 |
|
|
{ |
242 |
|
|
static int is_initialized = 0; |
243 |
|
|
static NETSTATISTICSGET pNetStatisticsGet = NULL; |
244 |
|
|
static NETAPIBUFFERSIZE pNetApiBufferSize = NULL; |
245 |
|
|
static NETAPIBUFFERFREE pNetApiBufferFree = NULL; |
246 |
|
|
static int is_workstation = 1; |
247 |
|
|
static int diskperf_warning = 0; |
248 |
|
|
|
249 |
|
|
static int cbPerfData = PERFORMANCE_BUFFER_SIZE; |
250 |
|
|
PERF_DATA_BLOCK *pPerfData; |
251 |
|
|
HANDLE hDevice, hNetAPI32 = NULL; |
252 |
|
|
DWORD dwSize, status; |
253 |
|
|
int nDrive; |
254 |
|
|
|
255 |
|
|
if ( !is_initialized ) { |
256 |
|
|
HKEY hKey; |
257 |
|
|
|
258 |
|
|
/* Find out whether this is an NT server or workstation if necessary */ |
259 |
|
|
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, |
260 |
|
|
"SYSTEM\\CurrentControlSet\\Control\\ProductOptions", |
261 |
|
|
0, KEY_READ, &hKey) == ERROR_SUCCESS) { |
262 |
|
|
BYTE szValue[32]; |
263 |
|
|
dwSize = sizeof (szValue); |
264 |
|
|
|
265 |
|
|
status = RegQueryValueEx (hKey, "ProductType", 0, NULL, |
266 |
|
|
szValue, &dwSize); |
267 |
|
|
if (status == ERROR_SUCCESS && stricmp (szValue, "WinNT")) { |
268 |
|
|
/* Note: There are (at least) three cases for ProductType: |
269 |
|
|
* WinNT = NT Workstation, ServerNT = NT Server, LanmanNT = |
270 |
|
|
* NT Server acting as a Domain Controller */ |
271 |
|
|
is_workstation = 0; |
272 |
|
|
} |
273 |
|
|
RegCloseKey (hKey); |
274 |
|
|
} |
275 |
|
|
|
276 |
|
|
/* Initialize the NetAPI32 function pointers if necessary */ |
277 |
|
|
if ( (hNetAPI32 = LoadLibrary ("NETAPI32.DLL")) ) { |
278 |
|
|
pNetStatisticsGet = (NETSTATISTICSGET) GetProcAddress (hNetAPI32, |
279 |
|
|
"NetStatisticsGet"); |
280 |
|
|
pNetApiBufferSize = (NETAPIBUFFERSIZE) GetProcAddress (hNetAPI32, |
281 |
|
|
"NetApiBufferSize"); |
282 |
|
|
pNetApiBufferFree = (NETAPIBUFFERFREE) GetProcAddress (hNetAPI32, |
283 |
|
|
"NetApiBufferFree"); |
284 |
|
|
|
285 |
|
|
if ( !pNetStatisticsGet |
286 |
|
|
|| !pNetApiBufferSize || !pNetApiBufferFree ) { |
287 |
|
|
FreeLibrary (hNetAPI32); |
288 |
|
|
hNetAPI32 = NULL; |
289 |
|
|
} |
290 |
|
|
} |
291 |
|
|
|
292 |
|
|
is_initialized = 1; |
293 |
|
|
} |
294 |
|
|
|
295 |
|
|
/* Get network statistics. Note: Both NT Workstation and NT Server by |
296 |
|
|
* default will be running both the workstation and server services. The |
297 |
|
|
* heuristic below is probably useful though on the assumption that the |
298 |
|
|
* majority of the network traffic will be via the appropriate service. |
299 |
|
|
* In any case the network statistics return almost no randomness */ |
300 |
|
|
{ LPBYTE lpBuffer; |
301 |
|
|
if (hNetAPI32 && !pNetStatisticsGet (NULL, |
302 |
|
|
is_workstation ? L"LanmanWorkstation" : |
303 |
|
|
L"LanmanServer", 0, 0, &lpBuffer) ) { |
304 |
|
|
pNetApiBufferSize (lpBuffer, &dwSize); |
305 |
|
|
(*add) ( lpBuffer, dwSize,requester ); |
306 |
|
|
pNetApiBufferFree (lpBuffer); |
307 |
|
|
} |
308 |
|
|
} |
309 |
|
|
|
310 |
|
|
/* Get disk I/O statistics for all the hard drives */ |
311 |
|
|
for (nDrive = 0;; nDrive++) { |
312 |
|
|
DISK_PERFORMANCE diskPerformance; |
313 |
|
|
char szDevice[50]; |
314 |
|
|
|
315 |
|
|
/* Check whether we can access this device */ |
316 |
|
|
sprintf (szDevice, "\\\\.\\PhysicalDrive%d", nDrive); |
317 |
|
|
hDevice = CreateFile (szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, |
318 |
|
|
NULL, OPEN_EXISTING, 0, NULL); |
319 |
|
|
if (hDevice == INVALID_HANDLE_VALUE) |
320 |
|
|
break; |
321 |
|
|
|
322 |
|
|
/* Note: This only works if you have turned on the disk performance |
323 |
|
|
* counters with 'diskperf -y'. These counters are off by default */ |
324 |
|
|
if (DeviceIoControl (hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0, |
325 |
|
|
&diskPerformance, sizeof (DISK_PERFORMANCE), |
326 |
|
|
&dwSize, NULL)) |
327 |
|
|
{ |
328 |
|
|
(*add) ( &diskPerformance, dwSize, requester ); |
329 |
|
|
} |
330 |
|
|
CloseHandle (hDevice); |
331 |
|
|
} |
332 |
|
|
|
333 |
|
|
/* Get information from the system performance counters. This can take |
334 |
|
|
* a few seconds to do. In some environments the call to |
335 |
|
|
* RegQueryValueEx() can produce an access violation at some random time |
336 |
|
|
* in the future, adding a short delay after the following code block |
337 |
|
|
* makes the problem go away. This problem is extremely difficult to |
338 |
|
|
* reproduce, I haven't been able to get it to occur despite running it |
339 |
|
|
* on a number of machines. The best explanation for the problem is that |
340 |
|
|
* on the machine where it did occur, it was caused by an external driver |
341 |
|
|
* or other program which adds its own values under the |
342 |
|
|
* HKEY_PERFORMANCE_DATA key. The NT kernel calls the required external |
343 |
|
|
* modules to map in the data, if there's a synchronisation problem the |
344 |
|
|
* external module would write its data at an inappropriate moment, |
345 |
|
|
* causing the access violation. A low-level memory checker indicated |
346 |
|
|
* that ExpandEnvironmentStrings() in KERNEL32.DLL, called an |
347 |
|
|
* interminable number of calls down inside RegQueryValueEx(), was |
348 |
|
|
* overwriting memory (it wrote twice the allocated size of a buffer to a |
349 |
|
|
* buffer allocated by the NT kernel). This may be what's causing the |
350 |
|
|
* problem, but since it's in the kernel there isn't much which can be |
351 |
|
|
* done. |
352 |
|
|
* |
353 |
|
|
* In addition to these problems the code in RegQueryValueEx() which |
354 |
|
|
* estimates the amount of memory required to return the performance |
355 |
|
|
* counter information isn't very accurate, since it always returns a |
356 |
|
|
* worst-case estimate which is usually nowhere near the actual amount |
357 |
|
|
* required. For example it may report that 128K of memory is required, |
358 |
|
|
* but only return 64K of data */ |
359 |
|
|
{ pPerfData = malloc (cbPerfData); |
360 |
|
|
for (;;) { |
361 |
|
|
dwSize = cbPerfData; |
362 |
|
|
status = RegQueryValueEx (HKEY_PERFORMANCE_DATA, "Global", NULL, |
363 |
|
|
NULL, (LPBYTE) pPerfData, &dwSize); |
364 |
|
|
if (status == ERROR_SUCCESS) { |
365 |
|
|
if (!memcmp (pPerfData->Signature, L"PERF", 8)) { |
366 |
|
|
(*add) ( pPerfData, dwSize, requester ); |
367 |
|
|
} |
368 |
|
|
break; |
369 |
|
|
} |
370 |
|
|
else if (status == ERROR_MORE_DATA) { |
371 |
|
|
cbPerfData += PERFORMANCE_BUFFER_STEP; |
372 |
|
|
pPerfData = realloc (pPerfData, cbPerfData); |
373 |
|
|
} |
374 |
|
|
else { |
375 |
|
|
random_w32_err ( "rndw32: get performance data problem"); |
376 |
|
|
break; |
377 |
|
|
} |
378 |
|
|
} |
379 |
|
|
free (pPerfData); |
380 |
|
|
} |
381 |
|
|
/* Although this isn't documented in the Win32 API docs, it's necessary |
382 |
|
|
to explicitly close the HKEY_PERFORMANCE_DATA key after use (it's |
383 |
|
|
implicitly opened on the first call to RegQueryValueEx()). If this |
384 |
|
|
isn't done then any system components which provide performance data |
385 |
|
|
can't be removed or changed while the handle remains active */ |
386 |
|
|
RegCloseKey (HKEY_PERFORMANCE_DATA); |
387 |
|
|
} |
388 |
|
|
|
389 |
|
|
|
390 |
|
|
int |
391 |
|
|
gather_random( void (*add)(const void*, size_t, int), int requester, |
392 |
|
|
size_t length, int level ) |
393 |
|
|
{ |
394 |
|
|
static int is_initialized; |
395 |
|
|
static int is_windows95; |
396 |
|
|
|
397 |
|
|
|
398 |
|
|
if( !level ) |
399 |
|
|
return 0; |
400 |
|
|
/* We don't differentiate between level 1 and 2 here because |
401 |
|
|
* there is no nternal entropy pool as a scary resource. It may |
402 |
|
|
* all work slower, but because our entropy source will never |
403 |
|
|
* block but deliver some not easy to measure entropy, we assume level 2 |
404 |
|
|
*/ |
405 |
|
|
|
406 |
|
|
|
407 |
|
|
if ( !is_initialized ) { |
408 |
|
|
OSVERSIONINFO osvi = { sizeof( osvi ) }; |
409 |
|
|
DWORD platform; |
410 |
|
|
|
411 |
|
|
GetVersionEx( &osvi ); |
412 |
|
|
platform = osvi.dwPlatformId; |
413 |
|
|
is_windows95 = platform == VER_PLATFORM_WIN32_WINDOWS; |
414 |
|
|
|
415 |
|
|
if ( platform == VER_PLATFORM_WIN32s ) { |
416 |
|
|
random_w32_err("can't run on a W32s platform" ); |
417 |
|
|
return 0; |
418 |
|
|
} |
419 |
|
|
is_initialized = 1; |
420 |
|
|
} |
421 |
|
|
|
422 |
|
|
if (is_windows95 ) { |
423 |
|
|
slow_gatherer_windows95( add, requester ); |
424 |
|
|
} |
425 |
|
|
else { |
426 |
|
|
slow_gatherer_windowsNT( add, requester ); |
427 |
|
|
} |
428 |
|
|
|
429 |
|
|
return 0; |
430 |
|
|
} |
431 |
|
|
|
432 |
|
|
|
433 |
|
|
|
434 |
|
|
int |
435 |
|
|
gather_random_fast( void (*add)(const void*, size_t, int), int requester ) |
436 |
|
|
{ |
437 |
|
|
static int addedFixedItems = 0; |
438 |
|
|
|
439 |
|
|
/* Get various basic pieces of system information: Handle of active |
440 |
|
|
* window, handle of window with mouse capture, handle of clipboard owner |
441 |
|
|
* handle of start of clpboard viewer list, pseudohandle of current |
442 |
|
|
* process, current process ID, pseudohandle of current thread, current |
443 |
|
|
* thread ID, handle of desktop window, handle of window with keyboard |
444 |
|
|
* focus, whether system queue has any events, cursor position for last |
445 |
|
|
* message, 1 ms time for last message, handle of window with clipboard |
446 |
|
|
* open, handle of process heap, handle of procs window station, types of |
447 |
|
|
* events in input queue, and milliseconds since Windows was started */ |
448 |
|
|
{ BYTE buffer[20*sizeof(DWORD)], *bufptr; |
449 |
|
|
bufptr = buffer; |
450 |
|
|
#define ADD(f) do { DWORD along = (DWORD)(f); \ |
451 |
|
|
memcpy (bufptr, &along, sizeof (along) ); \ |
452 |
|
|
bufptr += sizeof (along); } while (0) |
453 |
|
|
ADD ( GetActiveWindow ()); |
454 |
|
|
ADD ( GetCapture ()); |
455 |
|
|
ADD ( GetClipboardOwner ()); |
456 |
|
|
ADD ( GetClipboardViewer ()); |
457 |
|
|
ADD ( GetCurrentProcess ()); |
458 |
|
|
ADD ( GetCurrentProcessId ()); |
459 |
|
|
ADD ( GetCurrentThread ()); |
460 |
|
|
ADD ( GetCurrentThreadId ()); |
461 |
|
|
ADD ( GetDesktopWindow ()); |
462 |
|
|
ADD ( GetFocus ()); |
463 |
|
|
ADD ( GetInputState ()); |
464 |
|
|
ADD ( GetMessagePos ()); |
465 |
|
|
ADD ( GetMessageTime ()); |
466 |
|
|
ADD ( GetOpenClipboardWindow ()); |
467 |
|
|
ADD ( GetProcessHeap ()); |
468 |
|
|
ADD ( GetProcessWindowStation ()); |
469 |
|
|
ADD ( GetQueueStatus (QS_ALLEVENTS)); |
470 |
|
|
ADD ( GetTickCount ()); |
471 |
|
|
|
472 |
|
|
assert ( bufptr-buffer < sizeof (buffer) ); |
473 |
|
|
(*add) ( buffer, bufptr-buffer, requester ); |
474 |
|
|
#undef ADD |
475 |
|
|
} |
476 |
|
|
|
477 |
|
|
/* Get multiword system information: Current caret position, current |
478 |
|
|
* mouse cursor position */ |
479 |
|
|
{ POINT point; |
480 |
|
|
GetCaretPos (&point); |
481 |
|
|
(*add) ( &point, sizeof (point), requester ); |
482 |
|
|
GetCursorPos (&point); |
483 |
|
|
(*add) ( &point, sizeof (point), requester ); |
484 |
|
|
} |
485 |
|
|
|
486 |
|
|
/* Get percent of memory in use, bytes of physical memory, bytes of free |
487 |
|
|
* physical memory, bytes in paging file, free bytes in paging file, user |
488 |
|
|
* bytes of address space, and free user bytes */ |
489 |
|
|
{ MEMORYSTATUS memoryStatus; |
490 |
|
|
memoryStatus.dwLength = sizeof (MEMORYSTATUS); |
491 |
|
|
GlobalMemoryStatus (&memoryStatus); |
492 |
|
|
(*add) ( &memoryStatus, sizeof (memoryStatus), requester ); |
493 |
|
|
} |
494 |
|
|
|
495 |
|
|
/* Get thread and process creation time, exit time, time in kernel mode, |
496 |
|
|
and time in user mode in 100ns intervals */ |
497 |
|
|
{ HANDLE handle; |
498 |
|
|
FILETIME creationTime, exitTime, kernelTime, userTime; |
499 |
|
|
DWORD minimumWorkingSetSize, maximumWorkingSetSize; |
500 |
|
|
|
501 |
|
|
handle = GetCurrentThread (); |
502 |
|
|
GetThreadTimes (handle, &creationTime, &exitTime, |
503 |
|
|
&kernelTime, &userTime); |
504 |
|
|
(*add) ( &creationTime, sizeof (creationTime), requester ); |
505 |
|
|
(*add) ( &exitTime, sizeof (exitTime), requester ); |
506 |
|
|
(*add) ( &kernelTime, sizeof (kernelTime), requester ); |
507 |
|
|
(*add) ( &userTime, sizeof (userTime), requester ); |
508 |
|
|
|
509 |
|
|
handle = GetCurrentProcess (); |
510 |
|
|
GetProcessTimes (handle, &creationTime, &exitTime, |
511 |
|
|
&kernelTime, &userTime); |
512 |
|
|
(*add) ( &creationTime, sizeof (creationTime), requester ); |
513 |
|
|
(*add) ( &exitTime, sizeof (exitTime), requester ); |
514 |
|
|
(*add) ( &kernelTime, sizeof (kernelTime), requester ); |
515 |
|
|
(*add) ( &userTime, sizeof (userTime), requester ); |
516 |
|
|
|
517 |
|
|
/* Get the minimum and maximum working set size for the current process */ |
518 |
|
|
GetProcessWorkingSetSize (handle, &minimumWorkingSetSize, |
519 |
|
|
&maximumWorkingSetSize); |
520 |
|
|
(*add) ( &minimumWorkingSetSize, |
521 |
|
|
sizeof (&minimumWorkingSetSize), requester ); |
522 |
|
|
(*add) ( &maximumWorkingSetSize, |
523 |
|
|
sizeof (&maximumWorkingSetSize), requester ); |
524 |
|
|
} |
525 |
|
|
|
526 |
|
|
|
527 |
|
|
/* The following are fixed for the lifetime of the process so we only |
528 |
|
|
* add them once */ |
529 |
|
|
if (!addedFixedItems) { |
530 |
|
|
STARTUPINFO startupInfo; |
531 |
|
|
|
532 |
|
|
/* Get name of desktop, console window title, new window position and |
533 |
|
|
* size, window flags, and handles for stdin, stdout, and stderr */ |
534 |
|
|
startupInfo.cb = sizeof (STARTUPINFO); |
535 |
|
|
GetStartupInfo (&startupInfo); |
536 |
|
|
(*add) ( &startupInfo, sizeof (STARTUPINFO), requester ); |
537 |
|
|
addedFixedItems = 1; |
538 |
|
|
} |
539 |
|
|
|
540 |
|
|
/* The performance of QPC varies depending on the architecture it's |
541 |
|
|
* running on and on the OS. Under NT it reads the CPU's 64-bit timestamp |
542 |
|
|
* counter (at least on a Pentium and newer '486's, it hasn't been tested |
543 |
|
|
* on anything without a TSC), under Win95 it reads the 1.193180 MHz PIC |
544 |
|
|
* timer. There are vague mumblings in the docs that it may fail if the |
545 |
|
|
* appropriate hardware isn't available (possibly '386's or MIPS machines |
546 |
|
|
* running NT), but who's going to run NT on a '386? */ |
547 |
|
|
{ LARGE_INTEGER performanceCount; |
548 |
|
|
if (QueryPerformanceCounter (&performanceCount)) { |
549 |
|
|
(*add) (&performanceCount, sizeof (&performanceCount), requester); |
550 |
|
|
} |
551 |
|
|
else { /* Millisecond accuracy at best... */ |
552 |
|
|
DWORD aword = GetTickCount (); |
553 |
|
|
(*add) (&aword, sizeof (aword), requester ); |
554 |
|
|
} |
555 |
|
|
} |
556 |
|
|
|
557 |
|
|
return 0; |
558 |
|
|
} |