diff options
Diffstat (limited to 'plugins/MirOTR/Libgcrypt/cipher/rndw32.c')
-rw-r--r-- | plugins/MirOTR/Libgcrypt/cipher/rndw32.c | 982 |
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 ); - } - } - - -} |