summaryrefslogtreecommitdiffstats
path: root/comm/third_party/libgcrypt/random/rndw32.c
diff options
context:
space:
mode:
Diffstat (limited to 'comm/third_party/libgcrypt/random/rndw32.c')
-rw-r--r--comm/third_party/libgcrypt/random/rndw32.c1030
1 files changed, 1030 insertions, 0 deletions
diff --git a/comm/third_party/libgcrypt/random/rndw32.c b/comm/third_party/libgcrypt/random/rndw32.c
new file mode 100644
index 0000000000..b3f63d2072
--- /dev/null
+++ b/comm/third_party/libgcrypt/random/rndw32.c
@@ -0,0 +1,1030 @@
+/* rndw32.c - W32 entropy gatherer
+ * Copyright (C) 1999, 2000, 2002, 2003, 2007,
+ * 2010 Free Software Foundation, Inc.
+ * Copyright Peter Gutmann, Matt Thomlinson and Blake Coverett 1996-2006
+ *
+ * This file is part of Libgcrypt.
+ *
+ *************************************************************************
+ * The code here is based on code from Cryptlib 3.0 beta by Peter Gutmann.
+ * Source file misc/rndwin32.c "Win32 Randomness-Gathering Code" with this
+ * copyright notice:
+ *
+ * This module is part of the cryptlib continuously seeded pseudorandom
+ * number generator. For usage conditions, see lib_rand.c
+ *
+ * [Here is the notice from lib_rand.c, which is now called dev_sys.c]
+ *
+ * This module and the misc/rnd*.c modules represent the cryptlib
+ * continuously seeded pseudorandom number generator (CSPRNG) as described in
+ * my 1998 Usenix Security Symposium paper "The generation of random numbers
+ * for cryptographic purposes".
+ *
+ * The CSPRNG code is copyright Peter Gutmann (and various others) 1996,
+ * 1997, 1998, 1999, all rights reserved. Redistribution of the CSPRNG
+ * modules and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice
+ * and this permission notice in its entirety.
+ *
+ * 2. Redistributions in binary form must reproduce the copyright notice in
+ * the documentation and/or other materials provided with the distribution.
+ *
+ * 3. A copy of any bugfixes or enhancements made must be provided to the
+ * author, <pgut001@cs.auckland.ac.nz> to allow them to be added to the
+ * baseline version of the code.
+ *
+ * ALTERNATIVELY, the code may be distributed under the terms of the
+ * GNU Lesser General Public License, version 2.1 or any later version
+ * published by the Free Software Foundation, in which case the
+ * provisions of the GNU LGPL are required INSTEAD OF the above
+ * restrictions.
+ *
+ * Although not required under the terms of the LGPL, it would still
+ * be nice if you could make any changes available to the author to
+ * allow a consistent code base to be maintained.
+ *************************************************************************
+ * The above alternative was changed from GPL to LGPL on 2007-08-22 with
+ * permission from Peter Gutmann:
+ *==========
+ From: pgut001 <pgut001@cs.auckland.ac.nz>
+ Subject: Re: LGPL for the windows entropy gatherer
+ To: wk@gnupg.org
+ Date: Wed, 22 Aug 2007 03:05:42 +1200
+
+ Hi,
+
+ >As of now libgcrypt is GPL under Windows due to that module and some people
+ >would really like to see it under LGPL too. Can you do such a license change
+ >to LGPL version 2? Note that LGPL give the user the option to relicense it
+ >under GPL, so the change would be pretty easy and backwar compatible.
+
+ Sure. I assumed that since GPG was GPLd, you'd prefer the GPL for the entropy
+ code as well, but Ian asked for LGPL as an option so as of the next release
+ I'll have LGPL in there. You can consider it to be retroactive, so your
+ current version will be LGPLd as well.
+
+ Peter.
+ *==========
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#ifdef __GNUC__
+#include <stdint.h>
+#endif
+
+#include <winsock2.h>
+#include <windows.h>
+
+
+#include "types.h"
+#include "g10lib.h"
+#include "rand-internal.h"
+
+
+/* Definitions which are missing from the current GNU Windows32Api. */
+#ifndef IOCTL_DISK_PERFORMANCE
+#define IOCTL_DISK_PERFORMANCE 0x00070020
+#endif
+
+/* This used to be (6*8+5*4+8*2), but Peter Gutmann figured a larger
+ value in a newer release. So we use a far larger value. */
+#define SIZEOF_DISK_PERFORMANCE_STRUCT 256
+
+/* We don't include wincrypt.h so define it here. */
+#define HCRYPTPROV HANDLE
+
+
+/* When we query the performance counters, we allocate an initial buffer and
+ * then reallocate it as required until RegQueryValueEx() stops returning
+ * ERROR_MORE_DATA. The following values define the initial buffer size and
+ * step size by which the buffer is increased
+ */
+#define PERFORMANCE_BUFFER_SIZE 65536 /* Start at 64K */
+#define PERFORMANCE_BUFFER_STEP 16384 /* Step by 16K */
+
+
+/* The number of bytes to read from the system RNG on each slow poll. */
+#define SYSTEMRNG_BYTES 64
+
+/* Intel Chipset CSP type and name */
+#define PROV_INTEL_SEC 22
+#define INTEL_DEF_PROV "Intel Hardware Cryptographic Service Provider"
+
+
+
+
+/* Type definitions for function pointers to call NetAPI32 functions. */
+typedef DWORD (WINAPI *NETSTATISTICSGET)(LPWSTR szServer, LPWSTR szService,
+ DWORD dwLevel, DWORD dwOptions,
+ LPBYTE *lpBuffer);
+typedef DWORD (WINAPI *NETAPIBUFFERSIZE)(LPVOID lpBuffer, LPDWORD cbBuffer);
+typedef DWORD (WINAPI *NETAPIBUFFERFREE)(LPVOID lpBuffer);
+
+/* Type definitions for function pointers to call native NT functions. */
+typedef DWORD (WINAPI *NTQUERYSYSTEMINFORMATION)(DWORD systemInformationClass,
+ PVOID systemInformation,
+ ULONG systemInformationLength,
+ PULONG returnLength);
+typedef DWORD (WINAPI *NTQUERYINFORMATIONPROCESS)
+ (HANDLE processHandle, DWORD processInformationClass,
+ PVOID processInformation, ULONG processInformationLength,
+ PULONG returnLength);
+typedef DWORD (WINAPI *NTPOWERINFORMATION)
+ (DWORD powerInformationClass, PVOID inputBuffer,
+ ULONG inputBufferLength, PVOID outputBuffer, ULONG outputBufferLength );
+
+/* Type definitions for function pointers to call CryptoAPI functions. */
+typedef BOOL (WINAPI *CRYPTACQUIRECONTEXT)(HCRYPTPROV *phProv,
+ LPCTSTR pszContainer,
+ LPCTSTR pszProvider,
+ DWORD dwProvType,
+ DWORD dwFlags);
+typedef BOOL (WINAPI *CRYPTGENRANDOM)(HCRYPTPROV hProv, DWORD dwLen,
+ BYTE *pbBuffer);
+typedef BOOL (WINAPI *CRYPTRELEASECONTEXT)(HCRYPTPROV hProv, DWORD dwFlags);
+
+/* Somewhat alternative functionality available as a direct call, for
+ Windows XP and newer. This is the CryptoAPI RNG, which isn't anywhere
+ near as good as the HW RNG, but we use it if it's present on the basis
+ that at least it can't make things any worse. This direct access version
+ is only available under Windows XP, we don't go out of our way to access
+ the more general CryptoAPI one since the main purpose of using it is to
+ take advantage of any possible future hardware RNGs that may be added,
+ for example via TCPA devices. */
+typedef BOOL (WINAPI *RTLGENRANDOM)(PVOID RandomBuffer,
+ ULONG RandomBufferLength);
+
+
+
+/* MBM data structures, originally by Alexander van Kaam, converted to C by
+ Anders@Majland.org, finally updated by Chris Zahrt <techn0@iastate.edu> */
+#define BusType char
+#define SMBType char
+#define SensorType char
+
+typedef struct
+{
+ SensorType iType; /* Type of sensor. */
+ int Count; /* Number of sensor for that type. */
+} SharedIndex;
+
+typedef struct
+{
+ SensorType ssType; /* Type of sensor */
+ unsigned char ssName[12]; /* Name of sensor */
+ char sspadding1[3]; /* Padding of 3 bytes */
+ double ssCurrent; /* Current value */
+ double ssLow; /* Lowest readout */
+ double ssHigh; /* Highest readout */
+ long ssCount; /* Total number of readout */
+ char sspadding2[4]; /* Padding of 4 bytes */
+ long double ssTotal; /* Total amount of all readouts */
+ char sspadding3[6]; /* Padding of 6 bytes */
+ double ssAlarm1; /* Temp & fan: high alarm; voltage: % off */
+ double ssAlarm2; /* Temp: low alarm */
+} SharedSensor;
+
+typedef struct
+{
+ short siSMB_Base; /* SMBus base address */
+ BusType siSMB_Type; /* SMBus/Isa bus used to access chip */
+ SMBType siSMB_Code; /* SMBus sub type, Intel, AMD or ALi */
+ char siSMB_Addr; /* Address of sensor chip on SMBus */
+ unsigned char siSMB_Name[41]; /* Nice name for SMBus */
+ short siISA_Base; /* ISA base address of sensor chip on ISA */
+ int siChipType; /* Chip nr, connects with Chipinfo.ini */
+ char siVoltageSubType; /* Subvoltage option selected */
+} SharedInfo;
+
+typedef struct
+{
+ double sdVersion; /* Version number (example: 51090) */
+ SharedIndex sdIndex[10]; /* Sensor index */
+ SharedSensor sdSensor[100]; /* Sensor info */
+ SharedInfo sdInfo; /* Misc.info */
+ unsigned char sdStart[41]; /* Start time */
+
+ /* We don't use the next two fields both because they're not random
+ and because it provides a nice safety margin in case of data size
+ mis- estimates (we always under-estimate the buffer size). */
+#if 0
+ unsigned char sdCurrent[41]; /* Current time */
+ unsigned char sdPath[256]; /* MBM path */
+#endif /*0*/
+} SharedData;
+
+
+
+/* One time initialized handles and function pointers. We use dynamic
+ loading of the DLLs to do without them in case libgcrypt does not
+ need any random. */
+static HANDLE hNetAPI32;
+static NETSTATISTICSGET pNetStatisticsGet;
+static NETAPIBUFFERSIZE pNetApiBufferSize;
+static NETAPIBUFFERFREE pNetApiBufferFree;
+
+static HANDLE hNTAPI;
+static NTQUERYSYSTEMINFORMATION pNtQuerySystemInformation;
+static NTQUERYINFORMATIONPROCESS pNtQueryInformationProcess;
+static NTPOWERINFORMATION pNtPowerInformation;
+
+static HANDLE hAdvAPI32;
+static CRYPTACQUIRECONTEXT pCryptAcquireContext;
+static CRYPTGENRANDOM pCryptGenRandom;
+static CRYPTRELEASECONTEXT pCryptReleaseContext;
+static RTLGENRANDOM pRtlGenRandom;
+
+
+/* Other module global variables. */
+static int system_rng_available; /* Whether a system RNG is available. */
+static HCRYPTPROV hRNGProv; /* Handle to Intel RNG CSP. */
+
+/* The debug flag. Debugging is enabled if the value of the envvar
+ * GCRY_RNDW32_DBG is a positive number.*/
+static int debug_me;
+
+static int system_is_w2000; /* True if running on W2000. */
+
+
+
+/* Try and connect to the system RNG if there's one present. */
+static void
+init_system_rng (void)
+{
+ system_rng_available = 0;
+ hRNGProv = NULL;
+
+ hAdvAPI32 = GetModuleHandle ("AdvAPI32.dll");
+ if (!hAdvAPI32)
+ return;
+
+ pCryptAcquireContext = (CRYPTACQUIRECONTEXT)
+ GetProcAddress (hAdvAPI32, "CryptAcquireContextA");
+ pCryptGenRandom = (CRYPTGENRANDOM)
+ GetProcAddress (hAdvAPI32, "CryptGenRandom");
+ pCryptReleaseContext = (CRYPTRELEASECONTEXT)
+ GetProcAddress (hAdvAPI32, "CryptReleaseContext");
+
+ /* Get a pointer to the native randomness function if it's available.
+ This isn't exported by name, so we have to get it by ordinal. */
+ pRtlGenRandom = (RTLGENRANDOM)
+ GetProcAddress (hAdvAPI32, "SystemFunction036");
+
+ /* Try and connect to the PIII RNG CSP. The AMD 768 southbridge (from
+ the 760 MP chipset) also has a hardware RNG, but there doesn't appear
+ to be any driver support for this as there is for the Intel RNG so we
+ can't do much with it. OTOH the Intel RNG is also effectively dead
+ as well, mostly due to virtually nonexistent support/marketing by
+ Intel, it's included here mostly for form's sake. */
+ if ( (!pCryptAcquireContext || !pCryptGenRandom || !pCryptReleaseContext
+ || !pCryptAcquireContext (&hRNGProv, NULL, INTEL_DEF_PROV,
+ PROV_INTEL_SEC, 0) )
+ && !pRtlGenRandom)
+ {
+ hAdvAPI32 = NULL;
+ }
+ else
+ system_rng_available = 1;
+}
+
+
+/* Read data from the system RNG if availavle. */
+static void
+read_system_rng (void (*add)(const void*, size_t, enum random_origins),
+ enum random_origins requester)
+{
+ BYTE buffer[ SYSTEMRNG_BYTES + 8 ];
+ int quality = 0;
+
+ if (!system_rng_available)
+ return;
+
+ /* Read SYSTEMRNG_BYTES bytes from the system RNG. We don't rely on
+ this for all our randomness requirements (particularly the
+ software RNG) in case it's broken in some way. */
+ if (hRNGProv)
+ {
+ if (pCryptGenRandom (hRNGProv, SYSTEMRNG_BYTES, buffer))
+ quality = 80;
+ }
+ else if (pRtlGenRandom)
+ {
+ if ( pRtlGenRandom (buffer, SYSTEMRNG_BYTES))
+ quality = 50;
+ }
+ if (quality > 0)
+ {
+ if (debug_me)
+ log_debug ("rndw32#read_system_rng: got %d bytes of quality %d\n",
+ SYSTEMRNG_BYTES, quality);
+ (*add) (buffer, SYSTEMRNG_BYTES, requester);
+ wipememory (buffer, SYSTEMRNG_BYTES);
+ }
+}
+
+
+/* Read data from MBM. This communicates via shared memory, so all we
+ need to do is map a file and read the data out. */
+static void
+read_mbm_data (void (*add)(const void*, size_t, enum random_origins),
+ enum random_origins requester)
+{
+ HANDLE hMBMData;
+ SharedData *mbmDataPtr;
+
+ hMBMData = OpenFileMapping (FILE_MAP_READ, FALSE, "$M$B$M$5$S$D$" );
+ if (hMBMData)
+ {
+ mbmDataPtr = (SharedData*)MapViewOfFile (hMBMData, FILE_MAP_READ,0,0,0);
+ if (mbmDataPtr)
+ {
+ if (debug_me)
+ log_debug ("rndw32#read_mbm_data: got %d bytes\n",
+ (int)sizeof (SharedData));
+ (*add) (mbmDataPtr, sizeof (SharedData), requester);
+ UnmapViewOfFile (mbmDataPtr);
+ }
+ CloseHandle (hMBMData);
+ }
+}
+
+
+/* Fallback method using the registry to poll the statistics. */
+static void
+registry_poll (void (*add)(const void*, size_t, enum random_origins),
+ enum random_origins requester)
+{
+ static int cbPerfData = PERFORMANCE_BUFFER_SIZE;
+ int iterations;
+ DWORD dwSize, status;
+ PERF_DATA_BLOCK *pPerfData;
+
+ /* Get information from the system performance counters. This can take a
+ few seconds to do. In some environments the call to RegQueryValueEx()
+ can produce an access violation at some random time in the future, in
+ some cases adding a short delay after the following code block makes
+ the problem go away. This problem is extremely difficult to
+ reproduce, I haven't been able to get it to occur despite running it
+ on a number of machines. MS knowledge base article Q178887 covers
+ this type of problem, it's typically caused by an external driver or
+ other program that adds its own values under the
+ HKEY_PERFORMANCE_DATA key. The NT kernel, via Advapi32.dll, calls the
+ required external module to map in the data inside an SEH try/except
+ block, so problems in the module's collect function don't pop up until
+ after it has finished, so the fault appears to occur in Advapi32.dll.
+ There may be problems in the NT kernel as well though, a low-level
+ memory checker indicated that ExpandEnvironmentStrings() in
+ Kernel32.dll, called an interminable number of calls down inside
+ RegQueryValueEx(), was overwriting memory (it wrote twice the
+ allocated size of a buffer to a buffer allocated by the NT kernel).
+ OTOH this could be coming from the external module calling back into
+ the kernel, which eventually causes the problem described above.
+
+ Possibly as an extension of the problem that the krnlWaitSemaphore()
+ call above works around, running two instances of cryptlib (e.g. two
+ applications that use it) under NT4 can result in one of them hanging
+ in the RegQueryValueEx() call. This happens only under NT4 and is
+ hard to reproduce in any consistent manner.
+
+ One workaround that helps a bit is to read the registry as a remote
+ (rather than local) registry, it's possible that the use of a network
+ RPC call isolates the calling app from the problem in that whatever
+ service handles the RPC is taking the hit and not affecting the
+ calling app. Since this would require another round of extensive
+ testing to verify and the NT native API call is working fine, we'll
+ stick with the native API call for now.
+
+ Some versions of NT4 had a problem where the amount of data returned
+ was mis-reported and would never settle down, because of this the code
+ below includes a safety-catch that bails out after 10 attempts have
+ been made, this results in no data being returned but at does ensure
+ that the thread will terminate.
+
+ In addition to these problems the code in RegQueryValueEx() that
+ estimates the amount of memory required to return the performance
+ counter information isn't very accurate (it's much worse than the
+ "slightly-inaccurate" level that the MS docs warn about, it's usually
+ wildly off) since it always returns a worst-case estimate which is
+ usually nowhere near the actual amount required. For example it may
+ report that 128K of memory is required, but only return 64K of data.
+
+ Even worse than the registry-based performance counters is the
+ performance data helper (PDH) shim that tries to make the counters
+ look like the old Win16 API (which is also used by Win95). Under NT
+ this can consume tens of MB of memory and huge amounts of CPU time
+ while it gathers its data, and even running once can still consume
+ about 1/2MB of memory */
+ if (getenv ("GCRYPT_RNDW32_NOPERF"))
+ {
+ static int shown;
+
+ if (!shown)
+ {
+ shown = 1;
+ log_info ("note: get performance data has been disabled\n");
+ }
+ }
+ else
+ {
+ pPerfData = xmalloc (cbPerfData);
+ for (iterations=0; iterations < 10; iterations++)
+ {
+ dwSize = cbPerfData;
+ if ( debug_me )
+ log_debug ("rndw32#slow_gatherer_nt: get perf data\n" );
+
+ status = RegQueryValueEx (HKEY_PERFORMANCE_DATA, "Global", NULL,
+ NULL, (LPBYTE) pPerfData, &dwSize);
+ if (status == ERROR_SUCCESS)
+ {
+ if (!memcmp (pPerfData->Signature, L"PERF", 8))
+ (*add) ( pPerfData, dwSize, requester );
+ else
+ log_debug ("rndw32: no PERF signature\n");
+ break;
+ }
+ else if (status == ERROR_MORE_DATA)
+ {
+ cbPerfData += PERFORMANCE_BUFFER_STEP;
+ pPerfData = xrealloc (pPerfData, cbPerfData);
+ }
+ else
+ {
+ static int been_here;
+
+ /* Silence the error message. In particular under Wine (as
+ of 2008) we would get swamped with such diagnotiscs. One
+ such diagnotiscs should be enough. */
+ if (been_here != status)
+ {
+ been_here = status;
+ log_debug ("rndw32: get performance data problem: ec=%ld\n",
+ status);
+ }
+ break;
+ }
+ }
+ xfree (pPerfData);
+ }
+
+ /* Although this isn't documented in the Win32 API docs, it's necessary
+ to explicitly close the HKEY_PERFORMANCE_DATA key after use (it's
+ implicitly opened on the first call to RegQueryValueEx()). If this
+ isn't done then any system components which provide performance data
+ can't be removed or changed while the handle remains active. */
+ RegCloseKey (HKEY_PERFORMANCE_DATA);
+}
+
+
+static void
+slow_gatherer ( void (*add)(const void*, size_t, enum random_origins),
+ enum random_origins requester )
+{
+ static int is_initialized = 0;
+ static int is_workstation = 1;
+ HANDLE hDevice;
+ DWORD dwType, dwSize, dwResult;
+ ULONG ulSize;
+ int drive_no, status;
+ int no_results = 0;
+ void *buffer;
+
+ if ( !is_initialized )
+ {
+ HKEY hKey;
+
+ if ( debug_me )
+ log_debug ("rndw32#slow_gatherer: init toolkit\n" );
+ /* Find out whether this is an NT server or workstation if necessary */
+ if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,
+ "SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
+ 0, KEY_READ, &hKey) == ERROR_SUCCESS)
+ {
+ BYTE szValue[32 + 8];
+ dwSize = 32;
+
+ if ( debug_me )
+ log_debug ("rndw32#slow_gatherer: check product options\n" );
+
+ status = RegQueryValueEx (hKey, "ProductType", 0, NULL,
+ szValue, &dwSize);
+ if (status == ERROR_SUCCESS && stricmp ((char*)szValue, "WinNT"))
+ {
+ /* Note: There are (at least) three cases for ProductType:
+ WinNT = NT Workstation, ServerNT = NT Server, LanmanNT =
+ NT Server acting as a Domain Controller. */
+ is_workstation = 0;
+ if ( debug_me )
+ log_debug ("rndw32: this is a NT server\n");
+ }
+ RegCloseKey (hKey);
+ }
+
+ /* The following are fixed for the lifetime of the process so we
+ only add them once */
+ /* readPnPData (); - we have not implemented that. */
+
+ /* Initialize the NetAPI32 function pointers if necessary */
+ hNetAPI32 = LoadLibrary ("NETAPI32.DLL");
+ if (hNetAPI32)
+ {
+ if (debug_me)
+ log_debug ("rndw32#slow_gatherer: netapi32 loaded\n" );
+ pNetStatisticsGet = (NETSTATISTICSGET)
+ GetProcAddress (hNetAPI32, "NetStatisticsGet");
+ pNetApiBufferSize = (NETAPIBUFFERSIZE)
+ GetProcAddress (hNetAPI32, "NetApiBufferSize");
+ pNetApiBufferFree = (NETAPIBUFFERFREE)
+ GetProcAddress (hNetAPI32, "NetApiBufferFree");
+
+ if (!pNetStatisticsGet || !pNetApiBufferSize || !pNetApiBufferFree)
+ {
+ FreeLibrary (hNetAPI32);
+ hNetAPI32 = NULL;
+ log_debug ("rndw32: No NETAPI found\n" );
+ }
+ }
+
+ /* Initialize the NT kernel native API function pointers if necessary */
+ hNTAPI = GetModuleHandle ("NTDll.dll");
+ if (hNTAPI)
+ {
+ /* Get a pointer to the NT native information query functions */
+ pNtQuerySystemInformation = (NTQUERYSYSTEMINFORMATION)
+ GetProcAddress (hNTAPI, "NtQuerySystemInformation");
+ pNtQueryInformationProcess = (NTQUERYINFORMATIONPROCESS)
+ GetProcAddress (hNTAPI, "NtQueryInformationProcess");
+ pNtPowerInformation = (NTPOWERINFORMATION)
+ GetProcAddress(hNTAPI, "NtPowerInformation");
+
+ if (!pNtQuerySystemInformation || !pNtQueryInformationProcess)
+ hNTAPI = NULL;
+ }
+
+
+ is_initialized = 1;
+ }
+
+ read_system_rng ( add, requester );
+ read_mbm_data ( add, requester );
+
+ /* Get network statistics. Note: Both NT Workstation and NT Server by
+ default will be running both the workstation and server services. The
+ heuristic below is probably useful though on the assumption that the
+ majority of the network traffic will be via the appropriate service.
+ In any case the network statistics return almost no randomness. */
+ {
+ LPBYTE lpBuffer;
+
+ if (hNetAPI32
+ && !pNetStatisticsGet (NULL,
+ (LPWSTR)(is_workstation ? L"LanmanWorkstation" :
+ L"LanmanServer"), 0, 0, &lpBuffer))
+ {
+ if ( debug_me )
+ log_debug ("rndw32#slow_gatherer: get netstats\n" );
+ pNetApiBufferSize (lpBuffer, &dwSize);
+ (*add) ( lpBuffer, dwSize, requester );
+ pNetApiBufferFree (lpBuffer);
+ }
+ }
+
+ /* Get disk I/O statistics for all the hard drives. 100 is an
+ arbitrary failsafe limit. */
+ for (drive_no = 0; drive_no < 100 ; drive_no++)
+ {
+ char diskPerformance[SIZEOF_DISK_PERFORMANCE_STRUCT + 8];
+ char szDevice[50];
+
+ /* Check whether we can access this device. */
+ snprintf (szDevice, sizeof szDevice, "\\\\.\\PhysicalDrive%d",
+ drive_no);
+ hDevice = CreateFile (szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, 0, NULL);
+ if (hDevice == INVALID_HANDLE_VALUE)
+ break; /* No more drives. */
+
+ /* Note: This only works if you have turned on the disk performance
+ counters with 'diskperf -y'. These counters are off by default. */
+ dwSize = sizeof diskPerformance;
+ if (DeviceIoControl (hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0,
+ diskPerformance, SIZEOF_DISK_PERFORMANCE_STRUCT,
+ &dwSize, NULL))
+ {
+ if ( debug_me )
+ log_debug ("rndw32#slow_gatherer: iostat drive %d\n",
+ drive_no);
+ (*add) (diskPerformance, dwSize, requester);
+ }
+ else
+ {
+ log_info ("NOTE: you should run 'diskperf -y' "
+ "to enable the disk statistics\n");
+ }
+ CloseHandle (hDevice);
+ }
+
+ /* In theory we should be using the Win32 performance query API to obtain
+ unpredictable data from the system, however this is so unreliable (see
+ the multiple sets of comments in registryPoll()) that it's too risky
+ to rely on it except as a fallback in emergencies. Instead, we rely
+ mostly on the NT native API function NtQuerySystemInformation(), which
+ has the dual advantages that it doesn't have as many (known) problems
+ as the Win32 equivalent and that it doesn't access the data indirectly
+ via pseudo-registry keys, which means that it's much faster. Note
+ that the Win32 equivalent actually works almost all of the time, the
+ problem is that on one or two systems it can fail in strange ways that
+ are never the same and can't be reproduced on any other system, which
+ is why we use the native API here. Microsoft officially documented
+ this function in early 2003, so it'll be fairly safe to use. */
+ if ( !hNTAPI )
+ {
+ registry_poll (add, requester);
+ return;
+ }
+
+
+ /* Scan the first 64 possible information types (we don't bother with
+ increasing the buffer size as we do with the Win32 version of the
+ performance data read, we may miss a few classes but it's no big deal).
+ This scan typically yields around 20 pieces of data, there's nothing
+ in the range 65...128 so chances are there won't be anything above
+ there either. */
+ buffer = xmalloc (PERFORMANCE_BUFFER_SIZE);
+ for (dwType = 0; dwType < 64; dwType++)
+ {
+ switch (dwType)
+ {
+ /* ID 17 = SystemObjectInformation hangs on some win2k systems. */
+ case 17:
+ if (system_is_w2000)
+ continue;
+ break;
+
+ /* Some information types are write-only (the IDs are shared with
+ a set-information call), we skip these. */
+ case 26: case 27: case 38: case 46: case 47: case 48: case 52:
+ continue;
+
+ /* ID 53 = SystemSessionProcessInformation reads input from the
+ output buffer, which has to contain a session ID and pointer
+ to the actual buffer in which to store the session information.
+ Because this isn't a standard query, we skip this. */
+ case 53:
+ continue;
+ }
+
+ /* Query the info for this ID. Some results (for example for
+ ID = 6, SystemCallCounts) are only available in checked builds
+ of the kernel. A smaller subcless of results require that
+ certain system config flags be set, for example
+ SystemObjectInformation requires that the
+ FLG_MAINTAIN_OBJECT_TYPELIST be set in NtGlobalFlags. To avoid
+ having to special-case all of these, we try reading each one and
+ only use those for which we get a success status. */
+ dwResult = pNtQuerySystemInformation (dwType, buffer,
+ PERFORMANCE_BUFFER_SIZE - 2048,
+ &ulSize);
+ if (dwResult != ERROR_SUCCESS)
+ continue;
+
+ /* Some calls (e.g. ID = 23, SystemProcessorStatistics, and ID = 24,
+ SystemDpcInformation) incorrectly return a length of zero, so we
+ manually adjust the length to the correct value. */
+ if ( !ulSize )
+ {
+ if (dwType == 23)
+ ulSize = 6 * sizeof (ULONG);
+ else if (dwType == 24)
+ ulSize = 5 * sizeof (ULONG);
+ }
+
+ /* If we got some data back, add it to the entropy pool. */
+ if (ulSize > 0 && ulSize <= PERFORMANCE_BUFFER_SIZE - 2048)
+ {
+ if (debug_me)
+ log_debug ("rndw32#slow_gatherer: %lu bytes from sysinfo %ld\n",
+ ulSize, dwType);
+ (*add) (buffer, ulSize, requester);
+ no_results++;
+ }
+ }
+
+ /* Now we would do the same for the process information. This
+ call would rather ugly in that it requires an exact length
+ match for the data returned, failing with a
+ STATUS_INFO_LENGTH_MISMATCH error code (0xC0000004) if the
+ length isn't an exact match. It requires a compiler to handle
+ complex nested structs, alignment issues, and so on, and
+ without the headers in which the entries are declared it's
+ almost impossible to do. Thus we don't. */
+
+
+ /* Finally, do the same for the system power status information. There
+ are only a limited number of useful information types available so we
+ restrict ourselves to the useful types. In addition since this
+ function doesn't return length information, we have to hardcode in
+ length data. */
+ if (pNtPowerInformation)
+ {
+ static const struct { int type; int size; } powerInfo[] = {
+ { 0, 128 }, /* SystemPowerPolicyAc */
+ { 1, 128 }, /* SystemPowerPolicyDc */
+ { 4, 64 }, /* SystemPowerCapabilities */
+ { 5, 48 }, /* SystemBatteryState */
+ { 11, 48 }, /* ProcessorInformation */
+ { 12, 24 }, /* SystemPowerInformation */
+ { -1, -1 }
+ };
+ int i;
+
+ /* The 100 is a failsafe limit. */
+ for (i = 0; powerInfo[i].type != -1 && i < 100; i++ )
+ {
+ /* Query the info for this ID */
+ dwResult = pNtPowerInformation (powerInfo[i].type, NULL, 0, buffer,
+ PERFORMANCE_BUFFER_SIZE - 2048);
+ if (dwResult != ERROR_SUCCESS)
+ continue;
+ if (debug_me)
+ log_debug ("rndw32#slow_gatherer: %u bytes from powerinfo %d\n",
+ powerInfo[i].size, i);
+ (*add) (buffer, powerInfo[i].size, requester);
+ no_results++;
+ }
+ gcry_assert (i < 100);
+ }
+ xfree (buffer);
+
+ /* We couldn't get enough results from the kernel, fall back to the
+ somewhat troublesome registry poll. */
+ if (no_results < 15)
+ registry_poll (add, requester);
+}
+
+
+int
+_gcry_rndw32_gather_random (void (*add)(const void*, size_t,
+ enum random_origins),
+ enum random_origins origin,
+ size_t length, int level )
+{
+ static int is_initialized;
+ size_t n;
+
+ if (!level)
+ return 0;
+
+ /* We don't differentiate between level 1 and 2 here because there
+ is no internal entropy pool as a scary resource. It may all work
+ slower, but because our entropy source will never block but
+ deliver some not easy to measure entropy, we assume level 2. */
+
+ if (!is_initialized)
+ {
+ OSVERSIONINFO osvi = { sizeof( osvi ) };
+ const char *s;
+
+ if ((s = getenv ("GCRYPT_RNDW32_DBG")) && atoi (s) > 0)
+ debug_me = 1;
+
+ GetVersionEx( &osvi );
+ if (osvi.dwPlatformId != VER_PLATFORM_WIN32_NT)
+ log_fatal ("can only run on a Windows NT platform\n" );
+ system_is_w2000 = (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0);
+
+ init_system_rng ();
+ is_initialized = 1;
+ }
+
+ if (debug_me)
+ log_debug ("rndw32#gather_random: ori=%d len=%u lvl=%d\n",
+ origin, (unsigned int)length, level );
+
+ slow_gatherer (add, origin);
+
+ /* Round requested LENGTH up to full 32 bytes. */
+ n = _gcry_rndjent_poll (add, origin, ((length + 31) / 32) * 32);
+
+ if (debug_me)
+ log_debug ("rndw32#gather_random: jent contributed extra %u bytes\n",
+ (unsigned int)n);
+
+ return 0;
+}
+
+
+
+void
+_gcry_rndw32_gather_random_fast (void (*add)(const void*, size_t,
+ enum random_origins),
+ enum random_origins origin)
+{
+ static int addedFixedItems = 0;
+
+ if ( debug_me )
+ log_debug ("rndw32#gather_random_fast: ori=%d\n", origin );
+
+ /* Get various basic pieces of system information: Handle of active
+ window, handle of window with mouse capture, handle of clipboard
+ owner handle of start of clpboard viewer list, pseudohandle of
+ current process, current process ID, pseudohandle of current
+ thread, current thread ID, handle of desktop window, handle of
+ window with keyboard focus, whether system queue has any events,
+ cursor position for last message, 1 ms time for last message,
+ handle of window with clipboard open, handle of process heap,
+ handle of procs window station, types of events in input queue,
+ and milliseconds since Windows was started. On 64-bit platform
+ some of these return values are pointers and thus 64-bit wide.
+ We discard the upper 32-bit of those values. */
+
+ {
+ byte buffer[20*sizeof(unsigned long)], *bufptr;
+
+ bufptr = buffer;
+#define ADDINT(f) do { unsigned long along = (unsigned long)(f); \
+ memcpy (bufptr, &along, sizeof (along) ); \
+ bufptr += sizeof (along); \
+ } while (0)
+#define ADDPTR(f) do { void *aptr = (f); \
+ ADDINT((SIZE_T)aptr); \
+ } while (0)
+
+ ADDPTR ( GetActiveWindow ());
+ ADDPTR ( GetCapture ());
+ ADDPTR ( GetClipboardOwner ());
+ ADDPTR ( GetClipboardViewer ());
+ ADDPTR ( GetCurrentProcess ());
+ ADDINT ( GetCurrentProcessId ());
+ ADDPTR ( GetCurrentThread ());
+ ADDINT ( GetCurrentThreadId ());
+ ADDPTR ( GetDesktopWindow ());
+ ADDPTR ( GetFocus ());
+ ADDINT ( GetInputState ());
+ ADDINT ( GetMessagePos ());
+ ADDINT ( GetMessageTime ());
+ ADDPTR ( GetOpenClipboardWindow ());
+ ADDPTR ( GetProcessHeap ());
+ ADDPTR ( GetProcessWindowStation ());
+ /* Following function in some cases stops returning events, and cannot
+ be used as an entropy source. */
+ /*ADDINT ( GetQueueStatus (QS_ALLEVENTS));*/
+ ADDINT ( GetTickCount ());
+
+ gcry_assert ( bufptr-buffer < sizeof (buffer) );
+ (*add) ( buffer, bufptr-buffer, origin );
+#undef ADDINT
+#undef ADDPTR
+ }
+
+ /* Get multiword system information: Current caret position, current
+ mouse cursor position. */
+ {
+ POINT point;
+
+ GetCaretPos (&point);
+ (*add) ( &point, sizeof (point), origin );
+ GetCursorPos (&point);
+ (*add) ( &point, sizeof (point), origin );
+ }
+
+ /* Get percent of memory in use, bytes of physical memory, bytes of
+ free physical memory, bytes in paging file, free bytes in paging
+ file, user bytes of address space, and free user bytes. */
+ {
+ MEMORYSTATUS memoryStatus;
+
+ memoryStatus.dwLength = sizeof (MEMORYSTATUS);
+ GlobalMemoryStatus (&memoryStatus);
+ (*add) ( &memoryStatus, sizeof (memoryStatus), origin );
+ }
+
+ /* Get thread and process creation time, exit time, time in kernel
+ mode, and time in user mode in 100ns intervals. */
+ {
+ HANDLE handle;
+ FILETIME creationTime, exitTime, kernelTime, userTime;
+ SIZE_T minimumWorkingSetSize, maximumWorkingSetSize;
+
+ handle = GetCurrentThread ();
+ GetThreadTimes (handle, &creationTime, &exitTime,
+ &kernelTime, &userTime);
+ (*add) ( &creationTime, sizeof (creationTime), origin );
+ (*add) ( &exitTime, sizeof (exitTime), origin );
+ (*add) ( &kernelTime, sizeof (kernelTime), origin );
+ (*add) ( &userTime, sizeof (userTime), origin );
+
+ handle = GetCurrentProcess ();
+ GetProcessTimes (handle, &creationTime, &exitTime,
+ &kernelTime, &userTime);
+ (*add) ( &creationTime, sizeof (creationTime), origin );
+ (*add) ( &exitTime, sizeof (exitTime), origin );
+ (*add) ( &kernelTime, sizeof (kernelTime), origin );
+ (*add) ( &userTime, sizeof (userTime), origin );
+
+ /* Get the minimum and maximum working set size for the current
+ process. */
+ GetProcessWorkingSetSize (handle, &minimumWorkingSetSize,
+ &maximumWorkingSetSize);
+ /* On 64-bit system, discard the high 32-bits. */
+ (*add) ( &minimumWorkingSetSize, sizeof (int), origin );
+ (*add) ( &maximumWorkingSetSize, sizeof (int), origin );
+ }
+
+
+ /* The following are fixed for the lifetime of the process so we only
+ * add them once */
+ if (!addedFixedItems)
+ {
+ STARTUPINFO startupInfo;
+
+ /* Get name of desktop, console window title, new window
+ position and size, window flags, and handles for stdin,
+ stdout, and stderr. */
+ startupInfo.cb = sizeof (STARTUPINFO);
+ GetStartupInfo (&startupInfo);
+ (*add) ( &startupInfo, sizeof (STARTUPINFO), origin );
+ addedFixedItems = 1;
+ }
+
+ /* The performance of QPC varies depending on the architecture it's
+ running on and on the OS, the MS documentation is vague about the
+ details because it varies so much. Under Win9x/ME it reads the
+ 1.193180 MHz PIC timer. Under NT/Win2K/XP it may or may not read the
+ 64-bit TSC depending on the HAL and assorted other circumstances,
+ generally on machines with a uniprocessor HAL
+ KeQueryPerformanceCounter() uses a 3.579545MHz timer and on machines
+ with a multiprocessor or APIC HAL it uses the TSC (the exact time
+ source is controlled by the HalpUse8254 flag in the kernel). That
+ choice of time sources is somewhat peculiar because on a
+ multiprocessor machine it's theoretically possible to get completely
+ different TSC readings depending on which CPU you're currently
+ running on, while for uniprocessor machines it's not a problem.
+ However, the kernel appears to synchronise the TSCs across CPUs at
+ boot time (it resets the TSC as part of its system init), so this
+ shouldn't really be a problem. Under WinCE it's completely platform-
+ dependent, if there's no hardware performance counter available, it
+ uses the 1ms system timer.
+
+ Another feature of the TSC (although it doesn't really affect us here)
+ is that mobile CPUs will turn off the TSC when they idle, Pentiums
+ will change the rate of the counter when they clock-throttle (to
+ match the current CPU speed), and hyperthreading Pentiums will turn
+ it off when both threads are idle (this more or less makes sense,
+ since the CPU will be in the halted state and not executing any
+ instructions to count).
+
+ To make things unambiguous, we detect a CPU new enough to call RDTSC
+ directly by checking for CPUID capabilities, and fall back to QPC if
+ this isn't present.
+
+ On AMD64, TSC is always available and intrinsic is provided for accessing
+ it. */
+#ifdef __x86_64__
+ {
+ unsigned __int64 aint64;
+
+ /* Note: cryptlib does not discard upper 32 bits of TSC on WIN64, but does
+ * on WIN32. Is this correct? */
+ aint64 = __rdtsc();
+ (*add) (&aint64, sizeof(aint64), origin);
+ }
+#else
+#ifdef __GNUC__
+/* FIXME: We would need to implement the CPU feature tests first. */
+/* if (cpu_has_feature_rdtsc) */
+/* { */
+/* uint32_t lo, hi; */
+ /* We cannot use "=A", since this would use %rax on x86_64. */
+/* __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); */
+ /* Ignore high 32 bits, hwich are >1s res. */
+/* (*add) (&lo, 4, origin ); */
+/* } */
+/* else */
+#endif /*!__GNUC__*/
+ {
+ LARGE_INTEGER performanceCount;
+
+ if (QueryPerformanceCounter (&performanceCount))
+ {
+ if ( debug_me )
+ log_debug ("rndw32#gather_random_fast: perf data\n");
+ (*add) (&performanceCount, sizeof (performanceCount), origin);
+ }
+ else
+ {
+ /* Millisecond accuracy at best... */
+ DWORD aword = GetTickCount ();
+ (*add) (&aword, sizeof (aword), origin );
+ }
+ }
+#endif /*__x86_64__*/
+
+
+}