📄 win32.c
字号:
/****************************************************************************
* *
* Win32 Randomness-Gathering Code *
* Copyright Peter Gutmann, Matt Thomlinson and Blake Coverett 1996-2007 *
* *
****************************************************************************/
/* This module is part of the cryptlib continuously seeded pseudorandom number
generator. For usage conditions, see random.c */
/* General includes */
#include "crypt.h"
#include "random/random.h"
/* OS-specific includes */
#include <tlhelp32.h>
#include <winperf.h>
#include <winioctl.h>
#include <process.h>
/* Some new CPU opcodes aren't supported by all compiler versions, if
they're not available we define them here. BC++ can only handle the
emit directive outside an asm block, so we have to terminate the current
block, emit the opcode, and then restart the asm block. In addition
while the 16-bit versions of BC++ had built-in asm support, the 32-bit
versions removed it and generate a temporary asm file which is passed
to Tasm32. This is only included with some high-end versions of BC++,
and it's not possible to order it separately, so if you're building with
BC++ and get error messages about a missing tasm32.exe, add NO_ASM to
Project Options | Compiler | Defines */
#if defined( _MSC_VER )
#if _MSC_VER <= 1100
#define cpuid __asm _emit 0x0F __asm _emit 0xA2
#define rdtsc __asm _emit 0x0F __asm _emit 0x31
#endif /* VC++ 5.0 or earlier */
#define xstore_rng __asm _emit 0x0F __asm _emit 0xA7 __asm _emit 0xC0
#endif /* VC++ */
#if defined __BORLANDC__
#define cpuid } __emit__( 0x0F, 0xA2 ); __asm {
#define rdtsc } __emit__( 0x0F, 0x31 ); __asm {
#define xstore_rng } __emit__( 0x0F, 0xA7, 0xC0 ); __asm {
#endif /* BC++ */
/* Map a value that may be 32 or 64 bits depending on the platform to a
long */
#if defined( _MSC_VER ) && ( _MSC_VER >= 1400 )
#define addRandomHandle( randomState, handle ) \
addRandomLong( randomState, PtrToUlong( handle ) )
#else
#define addRandomHandle addRandomValue
#endif /* 32- vs. 64-bit VC++ */
/* The size of the intermediate buffer used to accumulate polled data */
#define RANDOM_BUFSIZE 4096
#if RANDOM_BUFSIZE > MAX_INTLENGTH_SHORT
#error RANDOM_BUFSIZE exceeds randomness accumulator size
#endif /* RANDOM_BUFSIZE > MAX_INTLENGTH_SHORT */
/* Handles to various randomness objects */
static HANDLE hAdvAPI32; /* Handle to misc.library */
static HANDLE hNetAPI32; /* Handle to networking library */
static HANDLE hNTAPI; /* Handle to NT kernel library */
static HANDLE hThread; /* Background polling thread handle */
static DWORD threadID; /* Background polling thread ID */
/****************************************************************************
* *
* System RNG Interface *
* *
****************************************************************************/
/* 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"
/* A mapping from CryptoAPI to standard data types */
#define HCRYPTPROV HANDLE
/* 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 and newer, 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 );
/* Global function pointers. These are necessary because the functions need
to be dynamically linked since older versions of Win95 and NT don't contain
them */
static CRYPTACQUIRECONTEXT pCryptAcquireContext = NULL;
static CRYPTGENRANDOM pCryptGenRandom = NULL;
static CRYPTRELEASECONTEXT pCryptReleaseContext = NULL;
static RTLGENRANDOM pRtlGenRandom = NULL;
/* Handle to the RNG CSP */
static BOOLEAN systemRngAvailable; /* Whether system RNG is available */
static HCRYPTPROV hProv; /* Handle to Intel RNG CSP */
/* Try and connect to the system RNG if there's one present */
static void initSystemRNG( void )
{
systemRngAvailable = FALSE;
hProv = NULL;
if( ( hAdvAPI32 = GetModuleHandle( "AdvAPI32.dll" ) ) == NULL )
return;
/* Get pointers to the CSP functions. Although the acquire context
function looks like a standard function, it's actually a macro which
is mapped to (depending on the build type) CryptAcquireContextA or
CryptAcquireContextW, so we access it under the straight-ASCII-
function name */
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 == NULL || \
pCryptGenRandom == NULL || pCryptReleaseContext == NULL || \
pCryptAcquireContext( &hProv, NULL, INTEL_DEF_PROV,
PROV_INTEL_SEC, 0 ) == FALSE ) && \
( pRtlGenRandom == NULL ) )
{
hAdvAPI32 = NULL;
hProv = NULL;
}
else
{
/* Remember that we have a system RNG available for use */
systemRngAvailable = TRUE;
}
}
/* Read data from the system RNG, in theory the PIII hardware RNG but in
practice more likely the CryptoAPI software RNG */
static void readSystemRNG( void )
{
BYTE buffer[ SYSTEMRNG_BYTES + 8 ];
int quality = 0;
if( !systemRngAvailable )
return;
/* Read SYSTEMRNG_BYTES bytes from the system RNG. Rather presciently,
the code up until late 2007 stated that "We don't rely on this for
all our randomness requirements (particularly the software RNG) in
case it's broken in some way", and in November 2007 an analysis paper
by Leo Dorrendorf, Zvi Gutterman, and Benny Pinkas showed that the
CryptoAPI RNG is indeed broken, being neither forwards- nor
backwards-secure, being reseeded far too infrequently, and (as far as
their reverse-engineering was able to tell) using far less entropy
sources than cryptlib's built-in mechanisms even though the CryptoAPI
one is deeply embedded in the OS.
The way the CryptoAPI RNG works is that a system RNG is used to key
a set of eight RC4 ciphers, each of which is used in turn in a round-
robin fashion to output 20 bytes of randomness which are then hashed
with SHA1, with the operation being approximately:
output[ 0...19 ] = SHA1( RC4[ i++ % 8 ] );
output[ 20...39 ] = SHA1( RC4[ i++ % 8 ] );
[...]
Each RC4 cipher is re-keyed every 16KB of output, so for 8 ciphers
the rekey interval is every 128KB of output. Furthermore, although
the kernel RNG used to key the RC4 ciphers stores its state in-
kernel, the RC4 cipher state is stored in user-space and per-process.
This means that in most cases the RNG is never re-keyed. Finally,
the way the RNG works means that it's possible to recover earlier
state in O( 2^23 ). See "Cryptanalysis of the Random Number
Generator of the Windows Operating System" for details */
if( hProv != NULL )
{
if( pCryptGenRandom( hProv, SYSTEMRNG_BYTES, buffer ) )
quality = 70;
}
else
{
if( pRtlGenRandom( buffer, SYSTEMRNG_BYTES ) )
quality = 30;
}
if( quality > 0 )
{
MESSAGE_DATA msgData;
int status;
setMessageData( &msgData, buffer, SYSTEMRNG_BYTES );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_SETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_ENTROPY );
if( cryptStatusOK( status ) )
{
( void ) krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_SETATTRIBUTE,
( void * ) &quality,
CRYPT_IATTRIBUTE_ENTROPY_QUALITY );
}
zeroise( buffer, SYSTEMRNG_BYTES );
}
}
/* Clean up the system RNG access */
static void endSystemRNG( void )
{
if( hProv != NULL )
{
pCryptReleaseContext( hProv, 0 );
hProv = NULL;
}
}
/****************************************************************************
* *
* Hardware Monitoring Interface *
* *
****************************************************************************/
/* These interfaces currently support data supplied by MBM, Everest,
SysTool, RivaTuner, HMonitor, and ATI Tray Tools. Two notable omissions
are SVPro and HWMonitor, unfortunately the authors haven't responded to
any requests for interfacing information */
/* MBM data structures, originally by Alexander van Kaam, converted to C by
Anders@Majland.org, finally updated by Chris Zahrt <techn0@iastate.edu>.
The __int64 values below are actually (64-bit) doubles, but we overlay
them with __int64s since we don't care about the values */
#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 */
__int64 /*double*/ ssCurrent;/* Current value */
__int64 /*double*/ ssLow; /* Lowest readout */
__int64 /*double*/ ssHigh; /* Highest readout */
long ssCount; /* Total number of readout */
char sspadding2[ 4 ]; /* Padding of 4 bytes */
BYTE /*long double*/ ssTotal[ 8 ]; /* Total amout of all readouts */
char sspadding3[ 6 ]; /* Padding of 6 bytes */
__int64 /*double*/ ssAlarm1;/* Temp & fan: high alarm; voltage: % off */
__int64 /*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 {
__int64 /*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) */
/* unsigned char sdCurrent[ 41 ]; /* Current time */
/* unsigned char sdPath[ 256 ]; /* MBM path */
} SharedData;
/* Read data from MBM via the shared-memory interface */
static void readMBMData( void )
{
HANDLE hMBMData;
const SharedData *mbmDataPtr;
if( ( hMBMData = OpenFileMapping( FILE_MAP_READ, FALSE,
"$M$B$M$5$S$D$" ) ) == NULL )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -