summaryrefslogtreecommitdiff
path: root/plugins/MirOTR/Libgcrypt/cipher/rndw32.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/MirOTR/Libgcrypt/cipher/rndw32.c')
-rw-r--r--plugins/MirOTR/Libgcrypt/cipher/rndw32.c982
1 files changed, 0 insertions, 982 deletions
diff --git a/plugins/MirOTR/Libgcrypt/cipher/rndw32.c b/plugins/MirOTR/Libgcrypt/cipher/rndw32.c
deleted file mode 100644
index b31b6382f4..0000000000
--- a/plugins/MirOTR/Libgcrypt/cipher/rndw32.c
+++ /dev/null
@@ -1,982 +0,0 @@
-/* rndw32.c - W32 entropy gatherer
- * Copyright (C) 1999, 2000, 2002, 2003, 2007 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
-
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#include <winperf.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 amout 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 intialized 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. */
-
-static int debug_me; /* Debug flag. */
-
-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 nonexistant 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 */
- pPerfData = gcry_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 = gcry_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;
- }
- }
- gcry_free (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 (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,
- 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 = gcry_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);
- }
- gcry_free (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;
-
- 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 ) };
-
- 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);
-
- 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. */
-
- {
- byte buffer[20*sizeof(ulong)], *bufptr;
-
- bufptr = buffer;
-#define ADD(f) do { ulong along = (ulong)(f); \
- memcpy (bufptr, &along, sizeof (along) ); \
- bufptr += sizeof (along); \
- } while (0)
-
- ADD ( GetActiveWindow ());
- ADD ( GetCapture ());
- ADD ( GetClipboardOwner ());
- ADD ( GetClipboardViewer ());
- ADD ( GetCurrentProcess ());
- ADD ( GetCurrentProcessId ());
- ADD ( GetCurrentThread ());
- ADD ( GetCurrentThreadId ());
- ADD ( GetDesktopWindow ());
- ADD ( GetFocus ());
- ADD ( GetInputState ());
- ADD ( GetMessagePos ());
- ADD ( GetMessageTime ());
- ADD ( GetOpenClipboardWindow ());
- ADD ( GetProcessHeap ());
- ADD ( GetProcessWindowStation ());
- ADD ( GetQueueStatus (QS_ALLEVENTS));
- ADD ( GetTickCount ());
-
- gcry_assert ( bufptr-buffer < sizeof (buffer) );
- (*add) ( buffer, bufptr-buffer, origin );
-#undef ADD
- }
-
- /* 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;
- DWORD 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);
- (*add) ( &minimumWorkingSetSize,
- sizeof (minimumWorkingSetSize), origin );
- (*add) ( &maximumWorkingSetSize,
- sizeof (maximumWorkingSetSize), 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-
- dependant, 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. */
-#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 );
- }
- }
-
-
-}