f58d45866324212e3adc06cbb411eba641b02c23
[gnupg.git] / cipher / rndw32.c
1 /* rndw32.c  -  W32 entropy gatherer
2  *      Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
3  *      Copyright Peter Gutmann, Matt Thomlinson and Blake Coverett 1996-1999
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG 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  * GnuPG 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, <pgut001@cs.auckland.ac.nz> 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  */
61
62 #include <config.h>
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 #ifdef __CYGWIN32__
71 # include <winioctl.h>
72 #endif
73
74
75 #include "types.h"
76 #include "util.h"
77 #include "dynload.h"
78
79 /* We do not use the netropy DLL anymore because a standalone program is
80  * easier to maintain and */
81 /*#define USE_ENTROPY_DLL*/
82
83
84
85 #ifdef IS_MODULE
86   #define _(a) (a)
87 #else
88   #include "i18n.h"
89 #endif
90
91
92 static int debug_me;
93
94 #ifdef USE_ENTROPY_DLL
95
96 #define WIN32_SLOW_SEEDER       0
97 #define WIN32_FAST_SEEDER       1
98
99 #define PCP_SUCCESS             0
100 #define PCP_NULL_POINTER        1
101 #define PCP_SEEDER_FAILED       2
102 #define PCP_SEEDER_NO_MEM       3
103 #define PCP_SEEDER_TOO_SMALL    4
104 #define PCP_DLL_LOAD_FAILED     5
105 #define PCP_UNKNOWN_PLATFORM    6
106 #define PCP_ERROR_VERSION       7
107 #define PCP_DLL_FUNC            8
108 #define PCP_UNKNOWN_SEEDER_TYPE 9
109
110
111 /****************
112  * We sometimes get a SEEDER_TOO_SMALL error, in which case we increment
113  * the internal buffer by SEEDER_INC_CHUNK until we reach MAX_SEEDER_SIZE
114  * MAX_SEEDER_SIZE is used as an arbitrary limit to protect against
115  * bugs in Winseed.
116  */
117 #define MAX_SEEDER_SIZE  500000
118 #define SEEDER_INC_CHUNK  50000
119
120
121 typedef void *WIN32_SEEDER;
122
123 static WIN32_SEEDER (WINAPI *create_instance)( byte type, unsigned int *reason);
124 static void         (WINAPI *delete_instance)( WIN32_SEEDER that );
125 static unsigned int (WINAPI *get_internal_seed_size)( WIN32_SEEDER that );
126 static void         (WINAPI *set_internal_seed_size)( WIN32_SEEDER that,
127                                                       unsigned int new_size);
128 static unsigned int (WINAPI *get_expected_seed_size)( WIN32_SEEDER that);
129 static unsigned int (WINAPI *get_seed)( WIN32_SEEDER that, byte *buffer,
130                                         unsigned int *desired_length);
131
132 static WIN32_SEEDER slow_seeder, fast_seeder;
133 static byte *entropy_buffer;
134 static size_t entropy_buffer_size;
135
136 /****************
137  * Load and initialize the winseed DLL
138  * NOTE: winseed is not part of the GnuPG distribution.  It should be available
139  * at the GNU crypto FTP server site.
140  * We do not load the DLL on demand to have a better control over the
141  * location of the library.
142  */
143 static void
144 load_and_init_winseed( void )
145 {
146     HANDLE hInstance;
147     void *addr;
148     unsigned int reason = 0;
149     unsigned int n1, n2;
150     const char *dllname;
151
152     dllname = read_w32_registry_string( "HKEY_LOCAL_MACHINE",
153                                         "Software\\GNU\\GnuPG",
154                                         "EntropyDLL" );
155     if( !dllname )
156         dllname = "c:/gnupg/entropy.dll";
157
158     hInstance = LoadLibrary( dllname );
159     if( !hInstance )
160         goto failure;
161     if( !(addr = GetProcAddress( hInstance, "WS_create_instance" )) )
162         goto failure;
163     create_instance = addr;
164     if( !(addr = GetProcAddress( hInstance, "WS_delete_instance" )) )
165         goto failure;
166     delete_instance = addr;
167     if( !(addr = GetProcAddress( hInstance, "WS_get_internal_seed_size" )) )
168         goto failure;
169     get_internal_seed_size = addr;
170     if( !(addr = GetProcAddress( hInstance, "WS_set_internal_seed_size" )) )
171         goto failure;
172     set_internal_seed_size = addr;
173     if( !(addr = GetProcAddress( hInstance, "WS_get_expected_seed_size" )) )
174         goto failure;
175     get_expected_seed_size = addr;
176     if( !(addr = GetProcAddress( hInstance, "WS_get_seed" )) )
177         goto failure;
178     get_seed = addr;
179
180     /* we have all the functions - init the system */
181     slow_seeder = create_instance( WIN32_SLOW_SEEDER, &reason);
182     if( !slow_seeder ) {
183         g10_log_fatal("error creating winseed slow seeder: rc=%u\n", reason );
184         goto failure;
185     }
186     fast_seeder = create_instance( WIN32_FAST_SEEDER, &reason);
187     if( !fast_seeder ) {
188         g10_log_fatal("error creating winseed fast seeder: rc=%u\n", reason );
189         goto failure;
190     }
191     n1 = get_internal_seed_size( slow_seeder );
192     /*g10_log_info("slow buffer size=%u\n", n1);*/
193     n2 = get_internal_seed_size( fast_seeder );
194     /*g10_log_info("fast buffer size=%u\n", n2);*/
195
196     entropy_buffer_size =  n1 > n2? n1: n2;
197     entropy_buffer = m_alloc( entropy_buffer_size );
198     /*g10_log_info("using a buffer of size=%u\n", entropy_buffer_size );*/
199
200     return;
201
202   failure:
203     g10_log_fatal("error loading winseed DLL `%s'\n", dllname );
204 }
205
206
207
208
209
210 /* Note: we always use the highest level.
211  * TO boost the performance we may want to add some
212  * additional code for level 1
213  */
214 static int
215 gather_random( void (*add)(const void*, size_t, int), int requester,
216                                           size_t length, int level )
217 {
218     unsigned int result;
219     unsigned int nbytes;
220
221     if( !level )
222         return 0;
223
224     if( !slow_seeder )
225         load_and_init_winseed();
226
227     /* Our estimation on how much entropy we should use is very vague.
228      * Winseed delivers some amount of entropy on each slow poll and
229      * we add it to our random pool.  Depending on the required quality
230      * level we adjust the requested length so that for higher quality
231      * we make sure to add more entropy to our pool.  However, as we don't
232      * like to waste any entropy collected by winseed, we always add
233      * at least everything we got from winseed.
234      */
235     if( level > 1 )
236         length *= 100;
237     else if( level > 0 )
238         length *= 10;
239
240     for(;;) {
241         nbytes = entropy_buffer_size;
242         result = get_seed( slow_seeder, entropy_buffer, &nbytes);
243         if( result == PCP_SEEDER_TOO_SMALL ) {
244             unsigned int n1 = get_internal_seed_size( slow_seeder );
245
246             if( n1 > MAX_SEEDER_SIZE ) {
247                 g10_log_fatal("rndw32: internal seeder problem (size=%u)\n",
248                                                                           n1);
249                 return -1; /* actually never reached */
250             }
251             n1 += SEEDER_INC_CHUNK;
252             set_internal_seed_size( slow_seeder, n1 );
253             if( n1 > entropy_buffer_size ) {
254                 entropy_buffer_size =  n1;
255                 entropy_buffer = m_realloc( entropy_buffer,
256                                             entropy_buffer_size );
257             }
258             continue;
259         }
260
261
262         if( result ) {
263             g10_log_fatal("rndw32: get_seed(slow) failed: rc=%u\n", result);
264             return -1; /* actually never reached */
265         }
266         /*g10_log_info("rndw32: slow poll level %d, need %u, got %u\n",
267                       level, (unsigned int)length, (unsigned int)nbytes );*/
268         (*add)( entropy_buffer, nbytes, requester );
269         if( length <= nbytes )
270             return 0; /* okay */
271         length -= nbytes;
272     }
273 }
274
275 static int
276 gather_random_fast( void (*add)(const void*, size_t, int), int requester )
277 {
278     unsigned int result;
279     unsigned int nbytes;
280
281     if( !fast_seeder )
282         load_and_init_winseed();
283
284     /* winseed delivers a constant ammount of entropy for a fast
285      * poll.  We can simply use this and add it to the pool; no need
286      * a loop like it is used in the slow poll */
287     nbytes = entropy_buffer_size;
288     result = get_seed( fast_seeder, entropy_buffer, &nbytes);
289     if( result ) {
290         g10_log_fatal("rndw32: get_seed(fast) failed: rc=%u\n", result);
291         return -1; /* actually never reached */
292     }
293     /*g10_log_info("rndw32: fast poll got %u\n", (unsigned int)nbytes );*/
294     (*add)( entropy_buffer, nbytes, requester );
295     return 0;
296 }
297
298 #else /* !USE_ENTROPY_DLL */
299 /* This is the new code which does not require the entropy.dll */
300
301 /*
302  * Definitions which are missing from the current GNU Windows32Api
303  */
304
305 #ifndef TH32CS_SNAPHEAPLIST
306 #define TH32CS_SNAPHEAPLIST 1
307 #define TH32CS_SNAPPROCESS  2
308 #define TH32CS_SNAPTHREAD   4
309 #define TH32CS_SNAPMODULE   8
310 #define TH32CS_SNAPALL      (1|2|4|8)
311 #define TH32CS_INHERIT      0x80000000
312 #endif /*TH32CS_SNAPHEAPLIST*/
313
314 #ifndef IOCTL_DISK_PERFORMANCE
315 #define IOCTL_DISK_PERFORMANCE  0x00070020
316 #endif
317 #ifndef VER_PLATFORM_WIN32_WINDOWS
318 #define VER_PLATFORM_WIN32_WINDOWS 1
319 #endif
320
321 #define SIZEOF_DISK_PERFORMANCE_STRUCT (6*8+5*4+8*2)
322
323
324 typedef struct {
325     DWORD dwSize;
326     DWORD th32ProcessID;
327     DWORD th32HeapID;
328     DWORD dwFlags;
329 } HEAPLIST32;
330
331 typedef struct {
332     DWORD dwSize;
333     HANDLE hHandle;
334     DWORD dwAddress;
335     DWORD dwBlockSize;
336     DWORD dwFlags;
337     DWORD dwLockCount;
338     DWORD dwResvd;
339     DWORD th32ProcessID;
340     DWORD th32HeapID;
341 } HEAPENTRY32;
342
343 typedef struct {
344     DWORD dwSize;
345     DWORD cntUsage;
346     DWORD th32ProcessID;
347     DWORD th32DefaultHeapID;
348     DWORD th32ModuleID;
349     DWORD cntThreads;
350     DWORD th32ParentProcessID;
351     LONG  pcPriClassBase;
352     DWORD dwFlags;
353     char  szExeFile[260];
354 } PROCESSENTRY32;
355
356 typedef struct {
357     DWORD dwSize;
358     DWORD cntUsage;
359     DWORD th32ThreadID;
360     DWORD th32OwnerProcessID;
361     LONG  tpBasePri;
362     LONG  tpDeltaPri;
363     DWORD dwFlags;
364 } THREADENTRY32;
365
366 typedef struct {
367     DWORD dwSize;
368     DWORD th32ModuleID;
369     DWORD th32ProcessID;
370     DWORD GlblcntUsage;
371     DWORD ProccntUsage;
372     BYTE  *modBaseAddr;
373     DWORD modBaseSize;
374     HMODULE hModule;
375     char  szModule[256];
376     char  szExePath[260];
377 } MODULEENTRY32;
378
379
380
381 /* Type definitions for function pointers to call Toolhelp32 functions
382  * used with the windows95 gatherer */
383 typedef BOOL (WINAPI * MODULEWALK) (HANDLE hSnapshot, MODULEENTRY32 *lpme);
384 typedef BOOL (WINAPI * THREADWALK) (HANDLE hSnapshot, THREADENTRY32 *lpte);
385 typedef BOOL (WINAPI * PROCESSWALK) (HANDLE hSnapshot, PROCESSENTRY32 *lppe);
386 typedef BOOL (WINAPI * HEAPLISTWALK) (HANDLE hSnapshot, HEAPLIST32 *lphl);
387 typedef BOOL (WINAPI * HEAPFIRST) (HEAPENTRY32 *lphe, DWORD th32ProcessID,
388                                    DWORD th32HeapID);
389 typedef BOOL (WINAPI * HEAPNEXT) (HEAPENTRY32 *lphe);
390 typedef HANDLE (WINAPI * CREATESNAPSHOT) (DWORD dwFlags, DWORD th32ProcessID);
391
392 /* Type definitions for function pointers to call NetAPI32 functions */
393 typedef DWORD (WINAPI * NETSTATISTICSGET) (LPWSTR szServer, LPWSTR szService,
394                                            DWORD dwLevel, DWORD dwOptions,
395                                            LPBYTE * lpBuffer);
396 typedef DWORD (WINAPI * NETAPIBUFFERSIZE) (LPVOID lpBuffer, LPDWORD cbBuffer);
397 typedef DWORD (WINAPI * NETAPIBUFFERFREE) (LPVOID lpBuffer);
398
399
400 /* When we query the performance counters, we allocate an initial buffer and
401  * then reallocate it as required until RegQueryValueEx() stops returning
402  * ERROR_MORE_DATA.  The following values define the initial buffer size and
403  * step size by which the buffer is increased
404  */
405 #define PERFORMANCE_BUFFER_SIZE         65536   /* Start at 64K */
406 #define PERFORMANCE_BUFFER_STEP         16384   /* Step by 16K */
407
408
409 static void
410 slow_gatherer_windows95( void (*add)(const void*, size_t, int), int requester )
411 {
412     static CREATESNAPSHOT pCreateToolhelp32Snapshot = NULL;
413     static MODULEWALK pModule32First = NULL;
414     static MODULEWALK pModule32Next = NULL;
415     static PROCESSWALK pProcess32First = NULL;
416     static PROCESSWALK pProcess32Next = NULL;
417     static THREADWALK pThread32First = NULL;
418     static THREADWALK pThread32Next = NULL;
419     static HEAPLISTWALK pHeap32ListFirst = NULL;
420     static HEAPLISTWALK pHeap32ListNext = NULL;
421     static HEAPFIRST pHeap32First = NULL;
422     static HEAPNEXT pHeap32Next = NULL;
423     HANDLE hSnapshot;
424
425
426     /* initialize the Toolhelp32 function pointers */
427     if ( !pCreateToolhelp32Snapshot ) {
428         HANDLE hKernel;
429
430         if ( debug_me )
431             log_debug ("rndw32#slow_gatherer_95: init toolkit\n" );
432
433         /* Obtain the module handle of the kernel to retrieve the addresses
434          * of the Toolhelp32 functions */
435         if ( ( !(hKernel = GetModuleHandle ("KERNEL32.DLL"))) ) {
436             g10_log_fatal ( "rndw32: can't get module handle\n" );
437         }
438
439         /* Now get pointers to the functions */
440         pCreateToolhelp32Snapshot = (CREATESNAPSHOT) GetProcAddress (hKernel,
441                                                   "CreateToolhelp32Snapshot");
442         pModule32First = (MODULEWALK) GetProcAddress (hKernel, "Module32First");
443         pModule32Next = (MODULEWALK) GetProcAddress (hKernel, "Module32Next");
444         pProcess32First = (PROCESSWALK) GetProcAddress (hKernel,
445                                                         "Process32First");
446         pProcess32Next = (PROCESSWALK) GetProcAddress (hKernel,
447                                                        "Process32Next");
448         pThread32First = (THREADWALK) GetProcAddress (hKernel, "Thread32First");
449         pThread32Next = (THREADWALK) GetProcAddress (hKernel, "Thread32Next");
450         pHeap32ListFirst = (HEAPLISTWALK) GetProcAddress (hKernel,
451                                                           "Heap32ListFirst");
452         pHeap32ListNext = (HEAPLISTWALK) GetProcAddress (hKernel,
453                                                          "Heap32ListNext");
454         pHeap32First = (HEAPFIRST) GetProcAddress (hKernel, "Heap32First");
455         pHeap32Next = (HEAPNEXT) GetProcAddress (hKernel, "Heap32Next");
456
457         if (    !pCreateToolhelp32Snapshot
458              || !pModule32First || !pModule32Next
459              || !pProcess32First || !pProcess32Next
460              || !pThread32First  || !pThread32Next
461              || !pHeap32ListFirst || !pHeap32ListNext
462              || !pHeap32First     || !pHeap32Next  ) {
463             g10_log_fatal ( "rndw32: failed to get a toolhep function\n" );
464         }
465     }
466
467     /* Take a snapshot of everything we can get to which is currently
468      *  in the system */
469     if ( !(hSnapshot = pCreateToolhelp32Snapshot (TH32CS_SNAPALL, 0)) ) {
470         g10_log_fatal ( "rndw32: failed to take a toolhelp snapshot\n" );
471     }
472
473     /* Walk through the local heap */
474     {   HEAPLIST32 hl32;
475         hl32.dwSize = sizeof (HEAPLIST32);
476         if (pHeap32ListFirst (hSnapshot, &hl32)) {
477             if ( debug_me )
478                 log_debug ("rndw32#slow_gatherer_95: walk heap\n" );
479             do {
480                 HEAPENTRY32 he32;
481
482                 /* First add the information from the basic Heaplist32 struct */
483                 (*add) ( &hl32, sizeof (hl32), requester );
484
485                 /* Now walk through the heap blocks getting information
486                  * on each of them */
487                 he32.dwSize = sizeof (HEAPENTRY32);
488                 if (pHeap32First (&he32, hl32.th32ProcessID, hl32.th32HeapID)){
489                     do {
490                         (*add) ( &he32, sizeof (he32), requester );
491                     } while (pHeap32Next (&he32));
492                 }
493             } while (pHeap32ListNext (hSnapshot, &hl32));
494         }
495     }
496
497
498     /* Walk through all processes */
499     {   PROCESSENTRY32 pe32;
500         pe32.dwSize = sizeof (PROCESSENTRY32);
501         if (pProcess32First (hSnapshot, &pe32)) {
502             if ( debug_me )
503                 log_debug ("rndw32#slow_gatherer_95: walk processes\n" );
504             do {
505                 (*add) ( &pe32, sizeof (pe32), requester );
506             } while (pProcess32Next (hSnapshot, &pe32));
507         }
508     }
509
510     /* Walk through all threads */
511     {   THREADENTRY32 te32;
512         te32.dwSize = sizeof (THREADENTRY32);
513         if (pThread32First (hSnapshot, &te32)) {
514             if ( debug_me )
515                 log_debug ("rndw32#slow_gatherer_95: walk threads\n" );
516             do {
517                 (*add) ( &te32, sizeof (te32), requester );
518             } while (pThread32Next (hSnapshot, &te32));
519         }
520     }
521
522     /* Walk through all modules associated with the process */
523     {   MODULEENTRY32 me32;
524         me32.dwSize = sizeof (MODULEENTRY32);
525         if (pModule32First (hSnapshot, &me32)) {
526             if ( debug_me )
527                 log_debug ("rndw32#slow_gatherer_95: walk modules\n" );
528             do {
529                 (*add) ( &me32, sizeof (me32), requester );
530             } while (pModule32Next (hSnapshot, &me32));
531         }
532     }
533
534     CloseHandle (hSnapshot);
535 }
536
537
538
539 static void
540 slow_gatherer_windowsNT( void (*add)(const void*, size_t, int), int requester )
541 {
542     static int is_initialized = 0;
543     static NETSTATISTICSGET pNetStatisticsGet = NULL;
544     static NETAPIBUFFERSIZE pNetApiBufferSize = NULL;
545     static NETAPIBUFFERFREE pNetApiBufferFree = NULL;
546     static int is_workstation = 1;
547
548     static int cbPerfData = PERFORMANCE_BUFFER_SIZE;
549     PERF_DATA_BLOCK *pPerfData;
550     HANDLE hDevice, hNetAPI32 = NULL;
551     DWORD dwSize, status;
552     int nDrive;
553
554     if ( !is_initialized ) {
555         HKEY hKey;
556
557         if ( debug_me )
558             log_debug ("rndw32#slow_gatherer_nt: init toolkit\n" );
559         /* Find out whether this is an NT server or workstation if necessary */
560         if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,
561                           "SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
562                           0, KEY_READ, &hKey) == ERROR_SUCCESS) {
563             BYTE szValue[32];
564             dwSize = sizeof (szValue);
565
566             if ( debug_me )
567                 log_debug ("rndw32#slow_gatherer_nt: check product options\n" );
568             status = RegQueryValueEx (hKey, "ProductType", 0, NULL,
569                                       szValue, &dwSize);
570             if (status == ERROR_SUCCESS
571                 && ascii_strcasecmp (szValue, "WinNT")) {
572                 /* Note: There are (at least) three cases for ProductType:
573                  * WinNT = NT Workstation, ServerNT = NT Server, LanmanNT =
574                  * NT Server acting as a Domain Controller */
575                 is_workstation = 0;
576                 if ( debug_me )
577                     log_debug ("rndw32: this is a NT server\n");
578             }
579             RegCloseKey (hKey);
580         }
581
582         /* Initialize the NetAPI32 function pointers if necessary */
583         if ( (hNetAPI32 = LoadLibrary ("NETAPI32.DLL")) ) {
584             if ( debug_me )
585                 log_debug ("rndw32#slow_gatherer_nt: netapi32 loaded\n" );
586             pNetStatisticsGet = (NETSTATISTICSGET) GetProcAddress (hNetAPI32,
587                                                        "NetStatisticsGet");
588             pNetApiBufferSize = (NETAPIBUFFERSIZE) GetProcAddress (hNetAPI32,
589                                                        "NetApiBufferSize");
590             pNetApiBufferFree = (NETAPIBUFFERFREE) GetProcAddress (hNetAPI32,
591                                                        "NetApiBufferFree");
592
593             if ( !pNetStatisticsGet
594                  || !pNetApiBufferSize || !pNetApiBufferFree ) {
595                 FreeLibrary (hNetAPI32);
596                 hNetAPI32 = NULL;
597                 g10_log_debug ("rndw32: No NETAPI found\n" );
598             }
599         }
600
601         is_initialized = 1;
602     }
603
604     /* Get network statistics.  Note: Both NT Workstation and NT Server by
605      * default will be running both the workstation and server services.  The
606      * heuristic below is probably useful though on the assumption that the
607      * majority of the network traffic will be via the appropriate service.
608      * In any case the network statistics return almost no randomness */
609     {   LPBYTE lpBuffer;
610         if (hNetAPI32 && !pNetStatisticsGet (NULL,
611                            is_workstation ? L"LanmanWorkstation" :
612                            L"LanmanServer", 0, 0, &lpBuffer) ) {
613             if ( debug_me )
614                 log_debug ("rndw32#slow_gatherer_nt: get netstats\n" );
615             pNetApiBufferSize (lpBuffer, &dwSize);
616             (*add) ( lpBuffer, dwSize,requester );
617             pNetApiBufferFree (lpBuffer);
618         }
619     }
620
621     /* Get disk I/O statistics for all the hard drives */
622     for (nDrive = 0;; nDrive++) {
623         char diskPerformance[SIZEOF_DISK_PERFORMANCE_STRUCT];
624         char szDevice[50];
625
626         /* Check whether we can access this device */
627         sprintf (szDevice, "\\\\.\\PhysicalDrive%d", nDrive);
628         hDevice = CreateFile (szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
629                               NULL, OPEN_EXISTING, 0, NULL);
630         if (hDevice == INVALID_HANDLE_VALUE)
631             break;
632
633         /* Note: This only works if you have turned on the disk performance
634          * counters with 'diskperf -y'.  These counters are off by default */
635         if (DeviceIoControl (hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0,
636                              diskPerformance, SIZEOF_DISK_PERFORMANCE_STRUCT,
637                              &dwSize, NULL))
638         {
639             if ( debug_me )
640                 log_debug ("rndw32#slow_gatherer_nt: iostats drive %d\n",
641                                                                   nDrive );
642             (*add) (diskPerformance, dwSize, requester );
643         }
644         else {
645             log_info ("NOTE: you should run 'diskperf -y' "
646                       "to enable the disk statistics\n");
647         }
648         CloseHandle (hDevice);
649     }
650
651   #if 0 /* we don't need this in GnuPG  */
652     /* Wait for any async keyset driver binding to complete.  You may be
653      * wondering what this call is doing here... the reason it's necessary is
654      * because RegQueryValueEx() will hang indefinitely if the async driver
655      * bind is in progress.  The problem occurs in the dynamic loading and
656      * linking of driver DLL's, which work as follows:
657      *
658      * hDriver = LoadLibrary( DRIVERNAME );
659      * pFunction1 = ( TYPE_FUNC1 ) GetProcAddress( hDriver, NAME_FUNC1 );
660      * pFunction2 = ( TYPE_FUNC1 ) GetProcAddress( hDriver, NAME_FUNC2 );
661      *
662      * If RegQueryValueEx() is called while the GetProcAddress()'s are in
663      * progress, it will hang indefinitely.  This is probably due to some
664      * synchronisation problem in the NT kernel where the GetProcAddress()
665      * calls affect something like a module reference count or function
666      * reference count while RegQueryValueEx() is trying to take a snapshot
667      * of the statistics, which include the reference counts.  Because of
668      * this, we have to wait until any async driver bind has completed
669      * before we can call RegQueryValueEx() */
670     waitSemaphore (SEMAPHORE_DRIVERBIND);
671   #endif
672
673     /* Get information from the system performance counters.  This can take
674      * a few seconds to do.  In some environments the call to
675      * RegQueryValueEx() can produce an access violation at some random time
676      * in the future, adding a short delay after the following code block
677      * makes the problem go away.  This problem is extremely difficult to
678      * reproduce, I haven't been able to get it to occur despite running it
679      * on a number of machines.  The best explanation for the problem is that
680      * on the machine where it did occur, it was caused by an external driver
681      * or other program which adds its own values under the
682      * HKEY_PERFORMANCE_DATA key.  The NT kernel calls the required external
683      * modules to map in the data, if there's a synchronisation problem the
684      * external module would write its data at an inappropriate moment,
685      * causing the access violation.  A low-level memory checker indicated
686      * that ExpandEnvironmentStrings() in KERNEL32.DLL, called an
687      * interminable number of calls down inside RegQueryValueEx(), was
688      * overwriting memory (it wrote twice the allocated size of a buffer to a
689      * buffer allocated by the NT kernel).  This may be what's causing the
690      * problem, but since it's in the kernel there isn't much which can be
691      * done.
692      *
693      * In addition to these problems the code in RegQueryValueEx() which
694      * estimates the amount of memory required to return the performance
695      * counter information isn't very accurate, since it always returns a
696      * worst-case estimate which is usually nowhere near the actual amount
697      * required.  For example it may report that 128K of memory is required,
698      * but only return 64K of data */
699     {   pPerfData =  m_alloc (cbPerfData);
700         for (;;) {
701             dwSize = cbPerfData;
702             if ( debug_me )
703                 log_debug ("rndw32#slow_gatherer_nt: get perf data\n" );
704             status = RegQueryValueEx (HKEY_PERFORMANCE_DATA, "Global", NULL,
705                                       NULL, (LPBYTE) pPerfData, &dwSize);
706             if (status == ERROR_SUCCESS) {
707                 if (!memcmp (pPerfData->Signature, L"PERF", 8)) {
708                     (*add) ( pPerfData, dwSize, requester );
709                 }
710                 else
711                     g10_log_debug ( "rndw32: no PERF signature\n");
712                 break;
713             }
714             else if (status == ERROR_MORE_DATA) {
715                 cbPerfData += PERFORMANCE_BUFFER_STEP;
716                 pPerfData = m_realloc (pPerfData, cbPerfData);
717             }
718             else {
719                 g10_log_debug ( "rndw32: get performance data problem\n");
720                 break;
721             }
722         }
723         m_free (pPerfData);
724     }
725     /* Although this isn't documented in the Win32 API docs, it's necessary
726        to explicitly close the HKEY_PERFORMANCE_DATA key after use (it's
727        implicitly opened on the first call to RegQueryValueEx()).  If this
728        isn't done then any system components which provide performance data
729        can't be removed or changed while the handle remains active */
730     RegCloseKey (HKEY_PERFORMANCE_DATA);
731 }
732
733
734 static int
735 gather_random( void (*add)(const void*, size_t, int), int requester,
736                                           size_t length, int level )
737 {
738     static int is_initialized;
739     static int is_windowsNT, has_toolhelp;
740
741
742     if( !level )
743         return 0;
744     /* We don't differentiate between level 1 and 2 here because
745      * there is no nternal entropy pool as a scary resource.  It may
746      * all work slower, but because our entropy source will never
747      * block but deliver some not easy to measure entropy, we assume level 2
748      */
749
750
751     if ( !is_initialized ) {
752         OSVERSIONINFO osvi = { sizeof( osvi ) };
753         DWORD platform;
754
755         GetVersionEx( &osvi );
756         platform = osvi.dwPlatformId;
757         is_windowsNT = platform == VER_PLATFORM_WIN32_NT;
758         has_toolhelp = (platform == VER_PLATFORM_WIN32_WINDOWS
759                         || (is_windowsNT && osvi.dwMajorVersion >= 5));
760
761         if ( platform == VER_PLATFORM_WIN32s ) {
762             g10_log_fatal("can't run on a W32s platform\n" );
763         }
764         is_initialized = 1;
765         if ( debug_me )
766             log_debug ("rndw32#gather_random: platform=%d\n", (int)platform );
767     }
768
769
770     if ( debug_me )
771         log_debug ("rndw32#gather_random: req=%d len=%u lvl=%d\n",
772                            requester, (unsigned int)length, level );
773
774     if ( has_toolhelp ) {
775         slow_gatherer_windows95 ( add, requester );
776     }
777     if ( is_windowsNT ) {
778         slow_gatherer_windowsNT ( add, requester );
779     }
780
781     return 0;
782 }
783
784
785
786 static int
787 gather_random_fast( void (*add)(const void*, size_t, int), int requester )
788 {
789     static int addedFixedItems = 0;
790
791     if ( debug_me )
792         log_debug ("rndw32#gather_random_fast: req=%d\n", requester );
793
794     /* Get various basic pieces of system information: Handle of active
795      * window, handle of window with mouse capture, handle of clipboard owner
796      * handle of start of clpboard viewer list, pseudohandle of current
797      * process, current process ID, pseudohandle of current thread, current
798      * thread ID, handle of desktop window, handle  of window with keyboard
799      * focus, whether system queue has any events, cursor position for last
800      * message, 1 ms time for last message, handle of window with clipboard
801      * open, handle of process heap, handle of procs window station, types of
802      * events in input queue, and milliseconds since Windows was started */
803     {   byte buffer[20*sizeof(ulong)], *bufptr;
804         bufptr = buffer;
805       #define ADD(f)  do { ulong along = (ulong)(f);                  \
806                            memcpy (bufptr, &along, sizeof (along) );  \
807                            bufptr += sizeof (along); } while (0)
808         ADD ( GetActiveWindow ());
809         ADD ( GetCapture ());
810         ADD ( GetClipboardOwner ());
811         ADD ( GetClipboardViewer ());
812         ADD ( GetCurrentProcess ());
813         ADD ( GetCurrentProcessId ());
814         ADD ( GetCurrentThread ());
815         ADD ( GetCurrentThreadId ());
816         ADD ( GetDesktopWindow ());
817         ADD ( GetFocus ());
818         ADD ( GetInputState ());
819         ADD ( GetMessagePos ());
820         ADD ( GetMessageTime ());
821         ADD ( GetOpenClipboardWindow ());
822         ADD ( GetProcessHeap ());
823         ADD ( GetProcessWindowStation ());
824         ADD ( GetQueueStatus (QS_ALLEVENTS));
825         ADD ( GetTickCount ());
826
827         assert ( bufptr-buffer < sizeof (buffer) );
828         (*add) ( buffer, bufptr-buffer, requester );
829       #undef ADD
830     }
831
832     /* Get multiword system information: Current caret position, current
833      * mouse cursor position */
834     {   POINT point;
835         GetCaretPos (&point);
836         (*add) ( &point, sizeof (point), requester );
837         GetCursorPos (&point);
838         (*add) ( &point, sizeof (point), requester );
839     }
840
841     /* Get percent of memory in use, bytes of physical memory, bytes of free
842      * physical memory, bytes in paging file, free bytes in paging file, user
843      * bytes of address space, and free user bytes */
844     {   MEMORYSTATUS memoryStatus;
845         memoryStatus.dwLength = sizeof (MEMORYSTATUS);
846         GlobalMemoryStatus (&memoryStatus);
847         (*add) ( &memoryStatus, sizeof (memoryStatus), requester );
848     }
849
850     /* Get thread and process creation time, exit time, time in kernel mode,
851        and time in user mode in 100ns intervals */
852     {   HANDLE handle;
853         FILETIME creationTime, exitTime, kernelTime, userTime;
854         DWORD minimumWorkingSetSize, maximumWorkingSetSize;
855
856         handle = GetCurrentThread ();
857         GetThreadTimes (handle, &creationTime, &exitTime,
858                                                &kernelTime, &userTime);
859         (*add) ( &creationTime, sizeof (creationTime), requester );
860         (*add) ( &exitTime, sizeof (exitTime), requester );
861         (*add) ( &kernelTime, sizeof (kernelTime), requester );
862         (*add) ( &userTime, sizeof (userTime), requester );
863
864         handle = GetCurrentProcess ();
865         GetProcessTimes (handle, &creationTime, &exitTime,
866                                                 &kernelTime, &userTime);
867         (*add) ( &creationTime, sizeof (creationTime), requester );
868         (*add) ( &exitTime, sizeof (exitTime), requester );
869         (*add) ( &kernelTime, sizeof (kernelTime), requester );
870         (*add) ( &userTime, sizeof (userTime), requester );
871
872         /* Get the minimum and maximum working set size for the current process */
873         GetProcessWorkingSetSize (handle, &minimumWorkingSetSize,
874                                           &maximumWorkingSetSize);
875         (*add) ( &minimumWorkingSetSize,
876                                    sizeof (&minimumWorkingSetSize), requester );
877         (*add) ( &maximumWorkingSetSize,
878                                    sizeof (&maximumWorkingSetSize), requester );
879     }
880
881
882     /* The following are fixed for the lifetime of the process so we only
883      * add them once */
884     if (!addedFixedItems) {
885         STARTUPINFO startupInfo;
886
887         /* Get name of desktop, console window title, new window position and
888          * size, window flags, and handles for stdin, stdout, and stderr */
889         startupInfo.cb = sizeof (STARTUPINFO);
890         GetStartupInfo (&startupInfo);
891         (*add) ( &startupInfo, sizeof (STARTUPINFO), requester );
892         addedFixedItems = 1;
893     }
894
895     /* The performance of QPC varies depending on the architecture it's
896      * running on and on the OS.  Under NT it reads the CPU's 64-bit timestamp
897      * counter (at least on a Pentium and newer '486's, it hasn't been tested
898      * on anything without a TSC), under Win95 it reads the 1.193180 MHz PIC
899      * timer.  There are vague mumblings in the docs that it may fail if the
900      * appropriate hardware isn't available (possibly '386's or MIPS machines
901      * running NT), but who's going to run NT on a '386? */
902     {   LARGE_INTEGER performanceCount;
903         if (QueryPerformanceCounter (&performanceCount)) {
904             if ( debug_me )
905                 log_debug ("rndw32#gather_random_fast: perf data\n");
906             (*add) (&performanceCount, sizeof (&performanceCount), requester);
907         }
908         else { /* Millisecond accuracy at best... */
909             DWORD aword = GetTickCount ();
910             (*add) (&aword, sizeof (aword), requester );
911         }
912     }
913
914     return 0;
915 }
916
917
918
919
920
921 #endif /* !USE_ENTROPY_DLL */
922
923
924 #ifndef IS_MODULE
925 static
926 #endif
927 const char * const gnupgext_version = "RNDW32 ($Revision$)";
928
929 static struct {
930     int class;
931     int version;
932     void *func;
933 } func_table[] = {
934     { 40, 1, gather_random },
935     { 41, 1, gather_random_fast },
936 };
937
938
939 #ifndef IS_MODULE
940 static
941 #endif
942 void *
943 gnupgext_enum_func( int what, int *sequence, int *class, int *vers )
944 {
945     void *ret;
946     int i = *sequence;
947
948     debug_me = !!getenv("DEBUG_RNDW32");
949
950     do {
951         if ( i >= DIM(func_table) || i < 0 ) {
952             return NULL;
953         }
954         *class = func_table[i].class;
955         *vers  = func_table[i].version;
956         ret = func_table[i].func;
957         i++;
958     } while ( what && what != *class );
959
960     *sequence = i;
961     return ret;
962 }
963
964 #ifndef IS_MODULE
965 void
966 rndw32_constructor(void)
967 {
968     register_internal_cipher_extension( gnupgext_version,
969                                         gnupgext_enum_func );
970 }
971 #endif
972