author | zautrix <zautrix> | 2004-10-19 20:16:14 (UTC) |
---|---|---|
committer | zautrix <zautrix> | 2004-10-19 20:16:14 (UTC) |
commit | eca49bb06a71980ef61d078904573f25890fc7f2 (patch) (unidiff) | |
tree | c5338e3b12430248979a9ac2c1c7e6646ea9ecdf /pwmanager/libcrypt/cipher/rndw32.c | |
parent | 53cc32b6e7b1f672bf91b2baf2df6c1e8baf3e0a (diff) | |
download | kdepimpi-eca49bb06a71980ef61d078904573f25890fc7f2.zip kdepimpi-eca49bb06a71980ef61d078904573f25890fc7f2.tar.gz kdepimpi-eca49bb06a71980ef61d078904573f25890fc7f2.tar.bz2 |
Initial revision
Diffstat (limited to 'pwmanager/libcrypt/cipher/rndw32.c') (more/less context) (ignore whitespace changes)
-rw-r--r-- | pwmanager/libcrypt/cipher/rndw32.c | 682 |
1 files changed, 682 insertions, 0 deletions
diff --git a/pwmanager/libcrypt/cipher/rndw32.c b/pwmanager/libcrypt/cipher/rndw32.c new file mode 100644 index 0000000..870eec6 --- a/dev/null +++ b/pwmanager/libcrypt/cipher/rndw32.c | |||
@@ -0,0 +1,682 @@ | |||
1 | /* rndw32.c -W32 entropy gatherer | ||
2 | *Copyright (C) 1999, 2000, 2002, 2003 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 | ************************************************************************* | ||
8 | * The code here is based on code from Cryptlib 3.0 beta by Peter Gutmann. | ||
9 | * Source file misc/rndwin32.c "Win32 Randomness-Gathering Code" with this | ||
10 | * copyright notice: | ||
11 | * | ||
12 | * This module is part of the cryptlib continuously seeded pseudorandom | ||
13 | * number generator. For usage conditions, see lib_rand.c | ||
14 | * | ||
15 | * [Here is the notice from lib_rand.c, which is now called dev_sys.c] | ||
16 | * | ||
17 | * This module and the misc/rnd*.c modules represent the cryptlib | ||
18 | * continuously seeded pseudorandom number generator (CSPRNG) as described in | ||
19 | * my 1998 Usenix Security Symposium paper "The generation of random numbers | ||
20 | * for cryptographic purposes". | ||
21 | * | ||
22 | * The CSPRNG code is copyright Peter Gutmann (and various others) 1996, | ||
23 | * 1997, 1998, 1999, all rights reserved. Redistribution of the CSPRNG | ||
24 | * modules and use in source and binary forms, with or without modification, | ||
25 | * are permitted provided that the following conditions are met: | ||
26 | * | ||
27 | * 1. Redistributions of source code must retain the above copyright notice | ||
28 | * and this permission notice in its entirety. | ||
29 | * | ||
30 | * 2. Redistributions in binary form must reproduce the copyright notice in | ||
31 | * the documentation and/or other materials provided with the distribution. | ||
32 | * | ||
33 | * 3. A copy of any bugfixes or enhancements made must be provided to the | ||
34 | * author, <pgut001@cs.auckland.ac.nz> to allow them to be added to the | ||
35 | * baseline version of the code. | ||
36 | * | ||
37 | * ALTERNATIVELY, the code may be distributed under the terms of the GNU | ||
38 | * General Public License, version 2 or any later version published by the | ||
39 | * Free Software Foundation, in which case the provisions of the GNU GPL are | ||
40 | * required INSTEAD OF the above restrictions. | ||
41 | * | ||
42 | * Although not required under the terms of the GPL, it would still be nice if | ||
43 | * you could make any changes available to the author to allow a consistent | ||
44 | * code base to be maintained | ||
45 | ************************************************************************* | ||
46 | */ | ||
47 | |||
48 | #include <config.h> | ||
49 | #include <stdio.h> | ||
50 | #include <stdlib.h> | ||
51 | #include <assert.h> | ||
52 | #include <errno.h> | ||
53 | #include <string.h> | ||
54 | |||
55 | #include <windows.h> | ||
56 | |||
57 | |||
58 | #include "types.h" | ||
59 | #include "g10lib.h" | ||
60 | #include "rand-internal.h" | ||
61 | |||
62 | |||
63 | static int debug_me; | ||
64 | |||
65 | /* | ||
66 | * Definitions which are missing from the current GNU Windows32Api | ||
67 | */ | ||
68 | |||
69 | #ifndef TH32CS_SNAPHEAPLIST | ||
70 | #define TH32CS_SNAPHEAPLIST 1 | ||
71 | #define TH32CS_SNAPPROCESS 2 | ||
72 | #define TH32CS_SNAPTHREAD 4 | ||
73 | #define TH32CS_SNAPMODULE 8 | ||
74 | #define TH32CS_SNAPALL (1|2|4|8) | ||
75 | #define TH32CS_INHERIT 0x80000000 | ||
76 | #endif /*TH32CS_SNAPHEAPLIST*/ | ||
77 | |||
78 | #ifndef IOCTL_DISK_PERFORMANCE | ||
79 | #define IOCTL_DISK_PERFORMANCE0x00070020 | ||
80 | #endif | ||
81 | #ifndef VER_PLATFORM_WIN32_WINDOWS | ||
82 | #define VER_PLATFORM_WIN32_WINDOWS 1 | ||
83 | #endif | ||
84 | |||
85 | /* This used to be (6*8+5*4+8*2), but Peter Gutmann figured a larger | ||
86 | value in a newer release. So we use a far larger value. */ | ||
87 | #define SIZEOF_DISK_PERFORMANCE_STRUCT 256 | ||
88 | |||
89 | |||
90 | typedef struct { | ||
91 | DWORD dwSize; | ||
92 | DWORD th32ProcessID; | ||
93 | DWORD th32HeapID; | ||
94 | DWORD dwFlags; | ||
95 | } HEAPLIST32; | ||
96 | |||
97 | typedef struct { | ||
98 | DWORD dwSize; | ||
99 | HANDLE hHandle; | ||
100 | DWORD dwAddress; | ||
101 | DWORD dwBlockSize; | ||
102 | DWORD dwFlags; | ||
103 | DWORD dwLockCount; | ||
104 | DWORD dwResvd; | ||
105 | DWORD th32ProcessID; | ||
106 | DWORD th32HeapID; | ||
107 | } HEAPENTRY32; | ||
108 | |||
109 | typedef struct { | ||
110 | DWORD dwSize; | ||
111 | DWORD cntUsage; | ||
112 | DWORD th32ProcessID; | ||
113 | DWORD th32DefaultHeapID; | ||
114 | DWORD th32ModuleID; | ||
115 | DWORD cntThreads; | ||
116 | DWORD th32ParentProcessID; | ||
117 | LONG pcPriClassBase; | ||
118 | DWORD dwFlags; | ||
119 | char szExeFile[260]; | ||
120 | } PROCESSENTRY32; | ||
121 | |||
122 | typedef struct { | ||
123 | DWORD dwSize; | ||
124 | DWORD cntUsage; | ||
125 | DWORD th32ThreadID; | ||
126 | DWORD th32OwnerProcessID; | ||
127 | LONG tpBasePri; | ||
128 | LONG tpDeltaPri; | ||
129 | DWORD dwFlags; | ||
130 | } THREADENTRY32; | ||
131 | |||
132 | typedef struct { | ||
133 | DWORD dwSize; | ||
134 | DWORD th32ModuleID; | ||
135 | DWORD th32ProcessID; | ||
136 | DWORD GlblcntUsage; | ||
137 | DWORD ProccntUsage; | ||
138 | BYTE *modBaseAddr; | ||
139 | DWORD modBaseSize; | ||
140 | HMODULE hModule; | ||
141 | char szModule[256]; | ||
142 | char szExePath[260]; | ||
143 | } MODULEENTRY32; | ||
144 | |||
145 | |||
146 | |||
147 | /* Type definitions for function pointers to call Toolhelp32 functions | ||
148 | * used with the windows95 gatherer */ | ||
149 | typedef BOOL (WINAPI * MODULEWALK) (HANDLE hSnapshot, MODULEENTRY32 *lpme); | ||
150 | typedef BOOL (WINAPI * THREADWALK) (HANDLE hSnapshot, THREADENTRY32 *lpte); | ||
151 | typedef BOOL (WINAPI * PROCESSWALK) (HANDLE hSnapshot, PROCESSENTRY32 *lppe); | ||
152 | typedef BOOL (WINAPI * HEAPLISTWALK) (HANDLE hSnapshot, HEAPLIST32 *lphl); | ||
153 | typedef BOOL (WINAPI * HEAPFIRST) (HEAPENTRY32 *lphe, DWORD th32ProcessID, | ||
154 | DWORD th32HeapID); | ||
155 | typedef BOOL (WINAPI * HEAPNEXT) (HEAPENTRY32 *lphe); | ||
156 | typedef HANDLE (WINAPI * CREATESNAPSHOT) (DWORD dwFlags, DWORD th32ProcessID); | ||
157 | |||
158 | /* Type definitions for function pointers to call NetAPI32 functions */ | ||
159 | typedef DWORD (WINAPI * NETSTATISTICSGET) (LPWSTR szServer, LPWSTR szService, | ||
160 | DWORD dwLevel, DWORD dwOptions, | ||
161 | LPBYTE * lpBuffer); | ||
162 | typedef DWORD (WINAPI * NETAPIBUFFERSIZE) (LPVOID lpBuffer, LPDWORD cbBuffer); | ||
163 | typedef DWORD (WINAPI * NETAPIBUFFERFREE) (LPVOID lpBuffer); | ||
164 | |||
165 | |||
166 | /* When we query the performance counters, we allocate an initial buffer and | ||
167 | * then reallocate it as required until RegQueryValueEx() stops returning | ||
168 | * ERROR_MORE_DATA. The following values define the initial buffer size and | ||
169 | * step size by which the buffer is increased | ||
170 | */ | ||
171 | #define PERFORMANCE_BUFFER_SIZE 65536/* Start at 64K */ | ||
172 | #define PERFORMANCE_BUFFER_STEP 16384/* Step by 16K */ | ||
173 | |||
174 | |||
175 | static void | ||
176 | slow_gatherer_windows95( void (*add)(const void*, size_t, int), int requester ) | ||
177 | { | ||
178 | static CREATESNAPSHOT pCreateToolhelp32Snapshot = NULL; | ||
179 | static MODULEWALK pModule32First = NULL; | ||
180 | static MODULEWALK pModule32Next = NULL; | ||
181 | static PROCESSWALK pProcess32First = NULL; | ||
182 | static PROCESSWALK pProcess32Next = NULL; | ||
183 | static THREADWALK pThread32First = NULL; | ||
184 | static THREADWALK pThread32Next = NULL; | ||
185 | static HEAPLISTWALK pHeap32ListFirst = NULL; | ||
186 | static HEAPLISTWALK pHeap32ListNext = NULL; | ||
187 | static HEAPFIRST pHeap32First = NULL; | ||
188 | static HEAPNEXT pHeap32Next = NULL; | ||
189 | HANDLE hSnapshot; | ||
190 | |||
191 | |||
192 | /* initialize the Toolhelp32 function pointers */ | ||
193 | if ( !pCreateToolhelp32Snapshot ) { | ||
194 | HANDLE hKernel; | ||
195 | |||
196 | if ( debug_me ) | ||
197 | log_debug ("rndw32#slow_gatherer_95: init toolkit\n" ); | ||
198 | |||
199 | /* Obtain the module handle of the kernel to retrieve the addresses | ||
200 | * of the Toolhelp32 functions */ | ||
201 | if ( ( !(hKernel = GetModuleHandle ("KERNEL32.DLL"))) ) { | ||
202 | log_fatal ( "rndw32: can't get module handle\n" ); | ||
203 | } | ||
204 | |||
205 | /* Now get pointers to the functions */ | ||
206 | pCreateToolhelp32Snapshot = (CREATESNAPSHOT) GetProcAddress (hKernel, | ||
207 | "CreateToolhelp32Snapshot"); | ||
208 | pModule32First = (MODULEWALK) GetProcAddress (hKernel, "Module32First"); | ||
209 | pModule32Next = (MODULEWALK) GetProcAddress (hKernel, "Module32Next"); | ||
210 | pProcess32First = (PROCESSWALK) GetProcAddress (hKernel, | ||
211 | "Process32First"); | ||
212 | pProcess32Next = (PROCESSWALK) GetProcAddress (hKernel, | ||
213 | "Process32Next"); | ||
214 | pThread32First = (THREADWALK) GetProcAddress (hKernel, "Thread32First"); | ||
215 | pThread32Next = (THREADWALK) GetProcAddress (hKernel, "Thread32Next"); | ||
216 | pHeap32ListFirst = (HEAPLISTWALK) GetProcAddress (hKernel, | ||
217 | "Heap32ListFirst"); | ||
218 | pHeap32ListNext = (HEAPLISTWALK) GetProcAddress (hKernel, | ||
219 | "Heap32ListNext"); | ||
220 | pHeap32First = (HEAPFIRST) GetProcAddress (hKernel, "Heap32First"); | ||
221 | pHeap32Next = (HEAPNEXT) GetProcAddress (hKernel, "Heap32Next"); | ||
222 | |||
223 | if (!pCreateToolhelp32Snapshot | ||
224 | || !pModule32First || !pModule32Next | ||
225 | || !pProcess32First || !pProcess32Next | ||
226 | || !pThread32First || !pThread32Next | ||
227 | || !pHeap32ListFirst || !pHeap32ListNext | ||
228 | || !pHeap32First || !pHeap32Next ) { | ||
229 | log_fatal ( "rndw32: failed to get a toolhelp function\n" ); | ||
230 | } | ||
231 | } | ||
232 | |||
233 | /* Take a snapshot of everything we can get to which is currently | ||
234 | *in the system */ | ||
235 | if ( !(hSnapshot = pCreateToolhelp32Snapshot (TH32CS_SNAPALL, 0)) ) { | ||
236 | log_fatal ( "rndw32: failed to take a toolhelp snapshot\n" ); | ||
237 | } | ||
238 | |||
239 | /* Walk through the local heap */ | ||
240 | {HEAPLIST32 hl32; | ||
241 | hl32.dwSize = sizeof (HEAPLIST32); | ||
242 | if (pHeap32ListFirst (hSnapshot, &hl32)) { | ||
243 | if ( debug_me ) | ||
244 | log_debug ("rndw32#slow_gatherer_95: walk heap\n" ); | ||
245 | do { | ||
246 | HEAPENTRY32 he32; | ||
247 | |||
248 | /* First add the information from the basic Heaplist32 struct */ | ||
249 | (*add) ( &hl32, sizeof (hl32), requester ); | ||
250 | |||
251 | /* Now walk through the heap blocks getting information | ||
252 | * on each of them */ | ||
253 | he32.dwSize = sizeof (HEAPENTRY32); | ||
254 | if (pHeap32First (&he32, hl32.th32ProcessID, hl32.th32HeapID)){ | ||
255 | do { | ||
256 | (*add) ( &he32, sizeof (he32), requester ); | ||
257 | } while (pHeap32Next (&he32)); | ||
258 | } | ||
259 | } while (pHeap32ListNext (hSnapshot, &hl32)); | ||
260 | } | ||
261 | } | ||
262 | |||
263 | |||
264 | /* Walk through all processes */ | ||
265 | {PROCESSENTRY32 pe32; | ||
266 | pe32.dwSize = sizeof (PROCESSENTRY32); | ||
267 | if (pProcess32First (hSnapshot, &pe32)) { | ||
268 | if ( debug_me ) | ||
269 | log_debug ("rndw32#slow_gatherer_95: walk processes\n" ); | ||
270 | do { | ||
271 | (*add) ( &pe32, sizeof (pe32), requester ); | ||
272 | } while (pProcess32Next (hSnapshot, &pe32)); | ||
273 | } | ||
274 | } | ||
275 | |||
276 | /* Walk through all threads */ | ||
277 | {THREADENTRY32 te32; | ||
278 | te32.dwSize = sizeof (THREADENTRY32); | ||
279 | if (pThread32First (hSnapshot, &te32)) { | ||
280 | if ( debug_me ) | ||
281 | log_debug ("rndw32#slow_gatherer_95: walk threads\n" ); | ||
282 | do { | ||
283 | (*add) ( &te32, sizeof (te32), requester ); | ||
284 | } while (pThread32Next (hSnapshot, &te32)); | ||
285 | } | ||
286 | } | ||
287 | |||
288 | /* Walk through all modules associated with the process */ | ||
289 | {MODULEENTRY32 me32; | ||
290 | me32.dwSize = sizeof (MODULEENTRY32); | ||
291 | if (pModule32First (hSnapshot, &me32)) { | ||
292 | if ( debug_me ) | ||
293 | log_debug ("rndw32#slow_gatherer_95: walk modules\n" ); | ||
294 | do { | ||
295 | (*add) ( &me32, sizeof (me32), requester ); | ||
296 | } while (pModule32Next (hSnapshot, &me32)); | ||
297 | } | ||
298 | } | ||
299 | |||
300 | CloseHandle (hSnapshot); | ||
301 | } | ||
302 | |||
303 | |||
304 | |||
305 | static void | ||
306 | slow_gatherer_windowsNT( void (*add)(const void*, size_t, int), int requester ) | ||
307 | { | ||
308 | static int is_initialized = 0; | ||
309 | static NETSTATISTICSGET pNetStatisticsGet = NULL; | ||
310 | static NETAPIBUFFERSIZE pNetApiBufferSize = NULL; | ||
311 | static NETAPIBUFFERFREE pNetApiBufferFree = NULL; | ||
312 | static int is_workstation = 1; | ||
313 | |||
314 | static int cbPerfData = PERFORMANCE_BUFFER_SIZE; | ||
315 | PERF_DATA_BLOCK *pPerfData; | ||
316 | HANDLE hDevice, hNetAPI32 = NULL; | ||
317 | DWORD dwSize, status; | ||
318 | int nDrive; | ||
319 | |||
320 | if ( !is_initialized ) { | ||
321 | HKEY hKey; | ||
322 | |||
323 | if ( debug_me ) | ||
324 | log_debug ("rndw32#slow_gatherer_nt: init toolkit\n" ); | ||
325 | /* Find out whether this is an NT server or workstation if necessary */ | ||
326 | if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, | ||
327 | "SYSTEM\\CurrentControlSet\\Control\\ProductOptions", | ||
328 | 0, KEY_READ, &hKey) == ERROR_SUCCESS) { | ||
329 | BYTE szValue[32]; | ||
330 | dwSize = sizeof (szValue); | ||
331 | |||
332 | if ( debug_me ) | ||
333 | log_debug ("rndw32#slow_gatherer_nt: check product options\n" ); | ||
334 | status = RegQueryValueEx (hKey, "ProductType", 0, NULL, | ||
335 | szValue, &dwSize); | ||
336 | if (status == ERROR_SUCCESS && stricmp (szValue, "WinNT")) { | ||
337 | /* Note: There are (at least) three cases for ProductType: | ||
338 | * WinNT = NT Workstation, ServerNT = NT Server, LanmanNT = | ||
339 | * NT Server acting as a Domain Controller */ | ||
340 | is_workstation = 0; | ||
341 | if ( debug_me ) | ||
342 | log_debug ("rndw32: this is a NT server\n"); | ||
343 | } | ||
344 | RegCloseKey (hKey); | ||
345 | } | ||
346 | |||
347 | /* Initialize the NetAPI32 function pointers if necessary */ | ||
348 | if ( (hNetAPI32 = LoadLibrary ("NETAPI32.DLL")) ) { | ||
349 | if ( debug_me ) | ||
350 | log_debug ("rndw32#slow_gatherer_nt: netapi32 loaded\n" ); | ||
351 | pNetStatisticsGet = (NETSTATISTICSGET) GetProcAddress (hNetAPI32, | ||
352 | "NetStatisticsGet"); | ||
353 | pNetApiBufferSize = (NETAPIBUFFERSIZE) GetProcAddress (hNetAPI32, | ||
354 | "NetApiBufferSize"); | ||
355 | pNetApiBufferFree = (NETAPIBUFFERFREE) GetProcAddress (hNetAPI32, | ||
356 | "NetApiBufferFree"); | ||
357 | |||
358 | if ( !pNetStatisticsGet | ||
359 | || !pNetApiBufferSize || !pNetApiBufferFree ) { | ||
360 | FreeLibrary (hNetAPI32); | ||
361 | hNetAPI32 = NULL; | ||
362 | log_debug ("rndw32: No NETAPI found\n" ); | ||
363 | } | ||
364 | } | ||
365 | |||
366 | is_initialized = 1; | ||
367 | } | ||
368 | |||
369 | /* Get network statistics.Note: Both NT Workstation and NT Server by | ||
370 | * default will be running both the workstation and server services. The | ||
371 | * heuristic below is probably useful though on the assumption that the | ||
372 | * majority of the network traffic will be via the appropriate service. | ||
373 | * In any case the network statistics return almost no randomness */ | ||
374 | {LPBYTE lpBuffer; | ||
375 | if (hNetAPI32 && !pNetStatisticsGet (NULL, | ||
376 | is_workstation ? L"LanmanWorkstation" : | ||
377 | L"LanmanServer", 0, 0, &lpBuffer) ) { | ||
378 | if ( debug_me ) | ||
379 | log_debug ("rndw32#slow_gatherer_nt: get netstats\n" ); | ||
380 | pNetApiBufferSize (lpBuffer, &dwSize); | ||
381 | (*add) ( lpBuffer, dwSize,requester ); | ||
382 | pNetApiBufferFree (lpBuffer); | ||
383 | } | ||
384 | } | ||
385 | |||
386 | /* Get disk I/O statistics for all the hard drives */ | ||
387 | for (nDrive = 0;; nDrive++) { | ||
388 | char diskPerformance[SIZEOF_DISK_PERFORMANCE_STRUCT]; | ||
389 | char szDevice[50]; | ||
390 | |||
391 | /* Check whether we can access this device */ | ||
392 | sprintf (szDevice, "\\\\.\\PhysicalDrive%d", nDrive); | ||
393 | hDevice = CreateFile (szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, | ||
394 | NULL, OPEN_EXISTING, 0, NULL); | ||
395 | if (hDevice == INVALID_HANDLE_VALUE) | ||
396 | break; | ||
397 | |||
398 | /* Note: This only works if you have turned on the disk performance | ||
399 | * counters with 'diskperf -y'. These counters are off by default */ | ||
400 | if (DeviceIoControl (hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0, | ||
401 | &diskPerformance, SIZEOF_DISK_PERFORMANCE_STRUCT, | ||
402 | &dwSize, NULL)) | ||
403 | { | ||
404 | if ( debug_me ) | ||
405 | log_debug ("rndw32#slow_gatherer_nt: iostats drive %d\n", | ||
406 | nDrive ); | ||
407 | (*add) (diskPerformance, dwSize, requester ); | ||
408 | } | ||
409 | else { | ||
410 | log_info ("NOTE: you should run 'diskperf -y' " | ||
411 | "to enable the disk statistics\n"); | ||
412 | } | ||
413 | CloseHandle (hDevice); | ||
414 | } | ||
415 | |||
416 | #if 0 /* we don't need this in GnuPG */ | ||
417 | /* Wait for any async keyset driver binding to complete. You may be | ||
418 | * wondering what this call is doing here... the reason it's necessary is | ||
419 | * because RegQueryValueEx() will hang indefinitely if the async driver | ||
420 | * bind is in progress. The problem occurs in the dynamic loading and | ||
421 | * linking of driver DLL's, which work as follows: | ||
422 | * | ||
423 | * hDriver = LoadLibrary( DRIVERNAME ); | ||
424 | * pFunction1 = ( TYPE_FUNC1 ) GetProcAddress( hDriver, NAME_FUNC1 ); | ||
425 | * pFunction2 = ( TYPE_FUNC1 ) GetProcAddress( hDriver, NAME_FUNC2 ); | ||
426 | * | ||
427 | * If RegQueryValueEx() is called while the GetProcAddress()'s are in | ||
428 | * progress, it will hang indefinitely. This is probably due to some | ||
429 | * synchronisation problem in the NT kernel where the GetProcAddress() | ||
430 | * calls affect something like a module reference count or function | ||
431 | * reference count while RegQueryValueEx() is trying to take a snapshot | ||
432 | * of the statistics, which include the reference counts. Because of | ||
433 | * this, we have to wait until any async driver bind has completed | ||
434 | * before we can call RegQueryValueEx() */ | ||
435 | waitSemaphore (SEMAPHORE_DRIVERBIND); | ||
436 | #endif | ||
437 | |||
438 | /* Get information from the system performance counters. This can take | ||
439 | * a few seconds to do. In some environments the call to | ||
440 | * RegQueryValueEx() can produce an access violation at some random time | ||
441 | * in the future, adding a short delay after the following code block | ||
442 | * makes the problem go away. This problem is extremely difficult to | ||
443 | * reproduce, I haven't been able to get it to occur despite running it | ||
444 | * on a number of machines. The best explanation for the problem is that | ||
445 | * on the machine where it did occur, it was caused by an external driver | ||
446 | * or other program which adds its own values under the | ||
447 | * HKEY_PERFORMANCE_DATA key. The NT kernel calls the required external | ||
448 | * modules to map in the data, if there's a synchronisation problem the | ||
449 | * external module would write its data at an inappropriate moment, | ||
450 | * causing the access violation. A low-level memory checker indicated | ||
451 | * that ExpandEnvironmentStrings() in KERNEL32.DLL, called an | ||
452 | * interminable number of calls down inside RegQueryValueEx(), was | ||
453 | * overwriting memory (it wrote twice the allocated size of a buffer to a | ||
454 | * buffer allocated by the NT kernel). This may be what's causing the | ||
455 | * problem, but since it's in the kernel there isn't much which can be | ||
456 | * done. | ||
457 | * | ||
458 | * In addition to these problems the code in RegQueryValueEx() which | ||
459 | * estimates the amount of memory required to return the performance | ||
460 | * counter information isn't very accurate, since it always returns a | ||
461 | * worst-case estimate which is usually nowhere near the actual amount | ||
462 | * required. For example it may report that 128K of memory is required, | ||
463 | * but only return 64K of data */ | ||
464 | {pPerfData = gcry_xmalloc (cbPerfData); | ||
465 | for (;;) { | ||
466 | dwSize = cbPerfData; | ||
467 | if ( debug_me ) | ||
468 | log_debug ("rndw32#slow_gatherer_nt: get perf data\n" ); | ||
469 | status = RegQueryValueEx (HKEY_PERFORMANCE_DATA, "Global", NULL, | ||
470 | NULL, (LPBYTE) pPerfData, &dwSize); | ||
471 | if (status == ERROR_SUCCESS) { | ||
472 | if (!memcmp (pPerfData->Signature, L"PERF", 8)) { | ||
473 | (*add) ( pPerfData, dwSize, requester ); | ||
474 | } | ||
475 | else | ||
476 | log_debug ( "rndw32: no PERF signature\n"); | ||
477 | break; | ||
478 | } | ||
479 | else if (status == ERROR_MORE_DATA) { | ||
480 | cbPerfData += PERFORMANCE_BUFFER_STEP; | ||
481 | pPerfData = gcry_realloc (pPerfData, cbPerfData); | ||
482 | } | ||
483 | else { | ||
484 | log_debug ( "rndw32: get performance data problem\n"); | ||
485 | break; | ||
486 | } | ||
487 | } | ||
488 | gcry_free (pPerfData); | ||
489 | } | ||
490 | /* Although this isn't documented in the Win32 API docs, it's necessary | ||
491 | to explicitly close the HKEY_PERFORMANCE_DATA key after use (it's | ||
492 | implicitly opened on the first call to RegQueryValueEx()). If this | ||
493 | isn't done then any system components which provide performance data | ||
494 | can't be removed or changed while the handle remains active */ | ||
495 | RegCloseKey (HKEY_PERFORMANCE_DATA); | ||
496 | } | ||
497 | |||
498 | |||
499 | int | ||
500 | _gcry_rndw32_gather_random( void (*add)(const void*, size_t, int), | ||
501 | int requester, | ||
502 | size_t length, int level ) | ||
503 | { | ||
504 | static int is_initialized; | ||
505 | static int is_windowsNT, has_toolhelp; | ||
506 | |||
507 | |||
508 | if( !level ) | ||
509 | return 0; | ||
510 | /* We don't differentiate between level 1 and 2 here because | ||
511 | * there is no internal entropy pool as a scary resource. It may | ||
512 | * all work slower, but because our entropy source will never | ||
513 | * block but deliver some not easy to measure entropy, we assume level 2 | ||
514 | */ | ||
515 | |||
516 | |||
517 | if ( !is_initialized ) { | ||
518 | OSVERSIONINFO osvi = { sizeof( osvi ) }; | ||
519 | DWORD platform; | ||
520 | |||
521 | GetVersionEx( &osvi ); | ||
522 | platform = osvi.dwPlatformId; | ||
523 | is_windowsNT = platform == VER_PLATFORM_WIN32_NT; | ||
524 | has_toolhelp = (platform == VER_PLATFORM_WIN32_WINDOWS | ||
525 | || (is_windowsNT && osvi.dwMajorVersion >= 5)); | ||
526 | |||
527 | if ( platform == VER_PLATFORM_WIN32s ) { | ||
528 | log_fatal("can't run on a W32s platform\n" ); | ||
529 | } | ||
530 | is_initialized = 1; | ||
531 | if ( debug_me ) | ||
532 | log_debug ("rndw32#gather_random: platform=%d\n", (int)platform ); | ||
533 | } | ||
534 | |||
535 | |||
536 | if ( debug_me ) | ||
537 | log_debug ("rndw32#gather_random: req=%d len=%u lvl=%d\n", | ||
538 | requester, (unsigned int)length, level ); | ||
539 | |||
540 | if ( has_toolhelp ) { | ||
541 | slow_gatherer_windows95 ( add, requester ); | ||
542 | } | ||
543 | if ( is_windowsNT ) { | ||
544 | slow_gatherer_windowsNT ( add, requester ); | ||
545 | } | ||
546 | |||
547 | return 0; | ||
548 | } | ||
549 | |||
550 | |||
551 | int | ||
552 | _gcry_rndw32_gather_random_fast (void (*add)(const void*, size_t, int), | ||
553 | int requester ) | ||
554 | { | ||
555 | static int addedFixedItems = 0; | ||
556 | |||
557 | if ( debug_me ) | ||
558 | log_debug ("rndw32#gather_random_fast: req=%d\n", requester ); | ||
559 | |||
560 | /* Get various basic pieces of system information: Handle of active | ||
561 | * window, handle of window with mouse capture, handle of clipboard owner | ||
562 | * handle of start of clpboard viewer list, pseudohandle of current | ||
563 | * process, current process ID, pseudohandle of current thread, current | ||
564 | * thread ID, handle of desktop window, handle of window with keyboard | ||
565 | * focus, whether system queue has any events, cursor position for last | ||
566 | * message, 1 ms time for last message, handle of window with clipboard | ||
567 | * open, handle of process heap, handle of procs window station, types of | ||
568 | * events in input queue, and milliseconds since Windows was started */ | ||
569 | {byte buffer[20*sizeof(ulong)], *bufptr; | ||
570 | bufptr = buffer; | ||
571 | #define ADD(f) do { ulong along = (ulong)(f); \ | ||
572 | memcpy (bufptr, &along, sizeof (along) ); \ | ||
573 | bufptr += sizeof (along); } while (0) | ||
574 | ADD ( GetActiveWindow ()); | ||
575 | ADD ( GetCapture ()); | ||
576 | ADD ( GetClipboardOwner ()); | ||
577 | ADD ( GetClipboardViewer ()); | ||
578 | ADD ( GetCurrentProcess ()); | ||
579 | ADD ( GetCurrentProcessId ()); | ||
580 | ADD ( GetCurrentThread ()); | ||
581 | ADD ( GetCurrentThreadId ()); | ||
582 | ADD ( GetDesktopWindow ()); | ||
583 | ADD ( GetFocus ()); | ||
584 | ADD ( GetInputState ()); | ||
585 | ADD ( GetMessagePos ()); | ||
586 | ADD ( GetMessageTime ()); | ||
587 | ADD ( GetOpenClipboardWindow ()); | ||
588 | ADD ( GetProcessHeap ()); | ||
589 | ADD ( GetProcessWindowStation ()); | ||
590 | ADD ( GetQueueStatus (QS_ALLEVENTS)); | ||
591 | ADD ( GetTickCount ()); | ||
592 | |||
593 | assert ( bufptr-buffer < sizeof (buffer) ); | ||
594 | (*add) ( buffer, bufptr-buffer, requester ); | ||
595 | #undef ADD | ||
596 | } | ||
597 | |||
598 | /* Get multiword system information: Current caret position, current | ||
599 | * mouse cursor position */ | ||
600 | {POINT point; | ||
601 | GetCaretPos (&point); | ||
602 | (*add) ( &point, sizeof (point), requester ); | ||
603 | GetCursorPos (&point); | ||
604 | (*add) ( &point, sizeof (point), requester ); | ||
605 | } | ||
606 | |||
607 | /* Get percent of memory in use, bytes of physical memory, bytes of free | ||
608 | * physical memory, bytes in paging file, free bytes in paging file, user | ||
609 | * bytes of address space, and free user bytes */ | ||
610 | {MEMORYSTATUS memoryStatus; | ||
611 | memoryStatus.dwLength = sizeof (MEMORYSTATUS); | ||
612 | GlobalMemoryStatus (&memoryStatus); | ||
613 | (*add) ( &memoryStatus, sizeof (memoryStatus), requester ); | ||
614 | } | ||
615 | |||
616 | /* Get thread and process creation time, exit time, time in kernel mode, | ||
617 | and time in user mode in 100ns intervals */ | ||
618 | {HANDLE handle; | ||
619 | FILETIME creationTime, exitTime, kernelTime, userTime; | ||
620 | DWORD minimumWorkingSetSize, maximumWorkingSetSize; | ||
621 | |||
622 | handle = GetCurrentThread (); | ||
623 | GetThreadTimes (handle, &creationTime, &exitTime, | ||
624 | &kernelTime, &userTime); | ||
625 | (*add) ( &creationTime, sizeof (creationTime), requester ); | ||
626 | (*add) ( &exitTime, sizeof (exitTime), requester ); | ||
627 | (*add) ( &kernelTime, sizeof (kernelTime), requester ); | ||
628 | (*add) ( &userTime, sizeof (userTime), requester ); | ||
629 | |||
630 | handle = GetCurrentProcess (); | ||
631 | GetProcessTimes (handle, &creationTime, &exitTime, | ||
632 | &kernelTime, &userTime); | ||
633 | (*add) ( &creationTime, sizeof (creationTime), requester ); | ||
634 | (*add) ( &exitTime, sizeof (exitTime), requester ); | ||
635 | (*add) ( &kernelTime, sizeof (kernelTime), requester ); | ||
636 | (*add) ( &userTime, sizeof (userTime), requester ); | ||
637 | |||
638 | /* Get the minimum and maximum working set size for the current process */ | ||
639 | GetProcessWorkingSetSize (handle, &minimumWorkingSetSize, | ||
640 | &maximumWorkingSetSize); | ||
641 | (*add) ( &minimumWorkingSetSize, | ||
642 | sizeof (&minimumWorkingSetSize), requester ); | ||
643 | (*add) ( &maximumWorkingSetSize, | ||
644 | sizeof (&maximumWorkingSetSize), requester ); | ||
645 | } | ||
646 | |||
647 | |||
648 | /* The following are fixed for the lifetime of the process so we only | ||
649 | * add them once */ | ||
650 | if (!addedFixedItems) { | ||
651 | STARTUPINFO startupInfo; | ||
652 | |||
653 | /* Get name of desktop, console window title, new window position and | ||
654 | * size, window flags, and handles for stdin, stdout, and stderr */ | ||
655 | startupInfo.cb = sizeof (STARTUPINFO); | ||
656 | GetStartupInfo (&startupInfo); | ||
657 | (*add) ( &startupInfo, sizeof (STARTUPINFO), requester ); | ||
658 | addedFixedItems = 1; | ||
659 | } | ||
660 | |||
661 | /* The performance of QPC varies depending on the architecture it's | ||
662 | * running on and on the OS. Under NT it reads the CPU's 64-bit timestamp | ||
663 | * counter (at least on a Pentium and newer '486's, it hasn't been tested | ||
664 | * on anything without a TSC), under Win95 it reads the 1.193180 MHz PIC | ||
665 | * timer. There are vague mumblings in the docs that it may fail if the | ||
666 | * appropriate hardware isn't available (possibly '386's or MIPS machines | ||
667 | * running NT), but who's going to run NT on a '386? */ | ||
668 | {LARGE_INTEGER performanceCount; | ||
669 | if (QueryPerformanceCounter (&performanceCount)) { | ||
670 | if ( debug_me ) | ||
671 | log_debug ("rndw32#gather_random_fast: perf data\n"); | ||
672 | (*add) (&performanceCount, sizeof (&performanceCount), requester); | ||
673 | } | ||
674 | else { /* Millisecond accuracy at best... */ | ||
675 | DWORD aword = GetTickCount (); | ||
676 | (*add) (&aword, sizeof (aword), requester ); | ||
677 | } | ||
678 | } | ||
679 | |||
680 | return 0; | ||
681 | } | ||
682 | |||