summary refs log tree commit diff stats
path: root/libotr/libgcrypt-1.8.7/random/rndw32.c
diff options
context:
space:
mode:
authorSoniEx2 <endermoneymod@gmail.com>2021-04-09 07:19:03 -0300
committerSoniEx2 <endermoneymod@gmail.com>2021-04-09 07:19:03 -0300
commit0e752a6e215aee21dc73da097c3225495d54a5b6 (patch)
treeb81be02cbf2f06aebf322ac4a5d014b44176bba5 /libotr/libgcrypt-1.8.7/random/rndw32.c
parent7754076c715285173311a1b6811ce377950e18a6 (diff)
Add libotr/etc sources
Diffstat (limited to 'libotr/libgcrypt-1.8.7/random/rndw32.c')
-rw-r--r--libotr/libgcrypt-1.8.7/random/rndw32.c1030
1 files changed, 1030 insertions, 0 deletions
diff --git a/libotr/libgcrypt-1.8.7/random/rndw32.c b/libotr/libgcrypt-1.8.7/random/rndw32.c
new file mode 100644
index 0000000..08a8867
--- /dev/null
+++ b/libotr/libgcrypt-1.8.7/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(ulong)], *bufptr;
+
+    bufptr = buffer;
+#define ADDINT(f)  do { ulong along = (ulong)(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__*/
+
+
+}