/[winpt]/trunk/Gnupg/rndw32.c
ViewVC logotype

Contents of /trunk/Gnupg/rndw32.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (show annotations)
Mon Jan 31 11:02:21 2005 UTC (20 years, 1 month ago) by twoaday
File MIME type: text/plain
File size: 22297 byte(s)
WinPT initial checkin.


1 /* 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 }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26