📄 rndwin32.c
字号:
/****************************************************************************
* *
* Win32 Randomness-Gathering Code *
* Copyright Peter Gutmann, Matt Thomlinson and Blake Coverett 1996-2001 *
* *
****************************************************************************/
/* This module is part of the cryptlib continuously seeded pseudorandom number
generator. For usage conditions, see dev_sys.c.
From the "Peter giveth and Microsoft taketh away" department: The default
NT setup has Everyone:Read permissions for the
\\HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\PerfLib
key, which is the key for the performance counters. This means that
everyone on the network can read your machine's performance counters,
significantly reducing their usefulness (although, since they contain a
snapshot only, network users will never see exactly what you're seeing). To
fix this problem, delete the Everyone:Read ACL and replace it with
Interactive:Read, which only allows access to locally logged on users. This
means an attacker will have to go to the effort of planting a trojan to get
your crypto keys rather than getting them over the net.
"Windows NT is a thing of genuine beauty, if you're seriously into genuine
ugliness. It's like a woman with a history of insanity in the family,
only worse" -- Hans Chloride, "Why I Love Windows NT" */
/* General includes */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef INC_CHILD
#include "../crypt.h"
#else
#include "crypt.h"
#endif /* Compiler-specific includes */
/* OS-specific includes */
#include <tlhelp32.h>
#include <winperf.h>
#include <winioctl.h>
#include <process.h>
/* The size of the intermediate buffer used to accumulate polled data */
#define RANDOM_BUFSIZE 4096
/* The number of bytes to read from the PIII RNG and serial-port RNG on each
slow poll */
#define PIIIRNG_BYTES 64
#define SERIALRNG_BYTES 64
/* A mapping from CryptoAPI to standard data types */
#define HCRYPTPROV HANDLE
/* 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 HANDLE hComm; /* Handle to serial RNG */
static HCRYPTPROV hProv; /* Handle to Intel RNG CSP */
/* 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 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 );
/* 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;
/* Initialise a serial-based RNG if there's one present */
static int initSerialRNG( void )
{
RESOURCE_DATA msgData;
COMMPROP commProp;
DWORD bytesRead;
DCB dcb;
char serialPortString[ CRYPT_MAX_TEXTSIZE + 1 ];
char serialParamString[ CRYPT_MAX_TEXTSIZE + 1 ];
char buffer[ 10 ];
int status;
/* Get the serial-port RNG parameters if there's one being used. Since
this is a general systemwide config option, we always query the built-
in default user object */
setResourceData( &msgData, serialPortString, CRYPT_MAX_TEXTSIZE );
status = krnlSendMessage( DEFAULTUSER_OBJECT_HANDLE,
RESOURCE_IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_OPTION_DEVICE_SERIALRNG );
if( cryptStatusOK( status ) )
{
serialPortString[ msgData.length ] = '\0';
setResourceData( &msgData, serialParamString, CRYPT_MAX_TEXTSIZE );
status = krnlSendMessage( DEFAULTUSER_OBJECT_HANDLE,
RESOURCE_IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_OPTION_DEVICE_SERIALRNG_PARAMS );
serialParamString[ msgData.length ] = '\0';
}
if( cryptStatusError( status ) )
return( CRYPT_ERROR );
/* Open the serial port device and set the port parameters. We need to
call GetCommState() before we call BuildCommDCB() because
BuildCommDCB() doesn't touch the DCB fields not affected by the config
string, so that they're left with garbage values which causes
SetCommState() to fail */
hComm = CreateFile( serialPortString, GENERIC_READ, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
if( hComm == ( HANDLE ) -1 )
{
hComm = NULL;
return( CRYPT_ERROR ) ;
}
GetCommState( hComm, &dcb );
BuildCommDCB( serialParamString, &dcb );
dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
if( !SetCommState( hComm, &dcb ) )
{
CloseHandle( hComm );
hComm = NULL;
return( CRYPT_ERROR );
}
/* Set the timeout to return immediately in case there's nothing
plugged in */
commProp.wPacketLength = sizeof( COMMPROP );
GetCommProperties( hComm, &commProp );
if( commProp.dwProvCapabilities & PCF_INTTIMEOUTS )
{
COMMTIMEOUTS timeouts;
/* Wait 10ms between chars and per char (which will work even with
a 1200bps generator), and 100ms overall (we need to make this
fairly short since we don't want to have a long delay every
time the library is started up if the RNG is unplugged) */
GetCommTimeouts( hComm, &timeouts );
timeouts.ReadIntervalTimeout = 10;
timeouts.ReadTotalTimeoutMultiplier = 10;
timeouts.ReadTotalTimeoutConstant = 100;
SetCommTimeouts( hComm, &timeouts );
}
/* The RNG can take awhile to get started so we wait 1/4s before trying
to read anything */
PurgeComm( hComm, PURGE_RXABORT | PURGE_RXCLEAR );
Sleep( 250 );
/* Try and read a few bytes to make sure there's something there */
PurgeComm( hComm, PURGE_RXABORT | PURGE_RXCLEAR );
if( !ReadFile( hComm, buffer, 10, &bytesRead, NULL ) || bytesRead != 10 )
{
CloseHandle( hComm );
hComm = NULL;
return( CRYPT_ERROR );
}
return( CRYPT_OK );
}
/* The shared Win32 fast poll routine */
void fastPoll( void )
{
static BOOLEAN addedFixedItems = FALSE;
BYTE buffer[ RANDOM_BUFSIZE ];
FILETIME creationTime, exitTime, kernelTime, userTime;
DWORD minimumWorkingSetSize, maximumWorkingSetSize;
LARGE_INTEGER performanceCount;
MEMORYSTATUS memoryStatus;
HANDLE handle;
POINT point;
int quality = 34, bufIndex = 0; /* Quality = int( 33 1/3 % ) */
/* 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 */
addRandom( buffer, &bufIndex, RANDOM_BUFSIZE, GetActiveWindow() );
addRandom( buffer, &bufIndex, RANDOM_BUFSIZE, GetCapture() );
addRandom( buffer, &bufIndex, RANDOM_BUFSIZE, GetClipboardOwner() );
addRandom( buffer, &bufIndex, RANDOM_BUFSIZE, GetClipboardViewer() );
addRandom( buffer, &bufIndex, RANDOM_BUFSIZE, GetCurrentProcess() );
addRandom( buffer, &bufIndex, RANDOM_BUFSIZE, GetCurrentProcessId() );
addRandom( buffer, &bufIndex, RANDOM_BUFSIZE, GetCurrentThread() );
addRandom( buffer, &bufIndex, RANDOM_BUFSIZE, GetCurrentThreadId() );
addRandom( buffer, &bufIndex, RANDOM_BUFSIZE, GetDesktopWindow() );
addRandom( buffer, &bufIndex, RANDOM_BUFSIZE, GetFocus() );
addRandom( buffer, &bufIndex, RANDOM_BUFSIZE, GetInputState() );
addRandom( buffer, &bufIndex, RANDOM_BUFSIZE, GetMessagePos() );
addRandom( buffer, &bufIndex, RANDOM_BUFSIZE, GetMessageTime() );
addRandom( buffer, &bufIndex, RANDOM_BUFSIZE, GetOpenClipboardWindow() );
addRandom( buffer, &bufIndex, RANDOM_BUFSIZE, GetProcessHeap() );
addRandom( buffer, &bufIndex, RANDOM_BUFSIZE, GetProcessWindowStation() );
addRandom( buffer, &bufIndex, RANDOM_BUFSIZE, GetTickCount() );
/* Calling the following function can cause problems in some cases in
that a calling application eventually stops getting events from its
event loop, so we can't (safely) use it as an entropy source */
/* addRandom( buffer, &bufIndex, RANDOM_BUFSIZE,
GetQueueStatus( QS_ALLEVENTS ) ); */
/* Get multiword system information: Current caret position, current
mouse cursor position */
GetCaretPos( &point );
addRandomString( buffer, &bufIndex, RANDOM_BUFSIZE, &point,
sizeof( POINT ) );
GetCursorPos( &point );
addRandomString( buffer, &bufIndex, RANDOM_BUFSIZE, &point,
sizeof( POINT ) );
/* 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.dwLength = sizeof( MEMORYSTATUS );
GlobalMemoryStatus( &memoryStatus );
addRandomString( buffer, &bufIndex, RANDOM_BUFSIZE, &memoryStatus,
sizeof( MEMORYSTATUS ) );
/* Get thread and process creation time, exit time, time in kernel mode,
and time in user mode in 100ns intervals */
handle = GetCurrentThread();
GetThreadTimes( handle, &creationTime, &exitTime, &kernelTime, &userTime );
addRandomString( buffer, &bufIndex, RANDOM_BUFSIZE,
&creationTime, sizeof( FILETIME ) );
addRandomString( buffer, &bufIndex, RANDOM_BUFSIZE,
&exitTime, sizeof( FILETIME ) );
addRandomString( buffer, &bufIndex, RANDOM_BUFSIZE,
&kernelTime, sizeof( FILETIME ) );
addRandomString( buffer, &bufIndex, RANDOM_BUFSIZE,
&userTime, sizeof( FILETIME ) );
handle = GetCurrentProcess();
GetProcessTimes( handle, &creationTime, &exitTime, &kernelTime, &userTime );
addRandomString( buffer, &bufIndex, RANDOM_BUFSIZE,
&creationTime, sizeof( FILETIME ) );
addRandomString( buffer, &bufIndex, RANDOM_BUFSIZE,
&exitTime, sizeof( FILETIME ) );
addRandomString( buffer, &bufIndex, RANDOM_BUFSIZE,
&kernelTime, sizeof( FILETIME ) );
addRandomString( buffer, &bufIndex, RANDOM_BUFSIZE,
&userTime, sizeof( FILETIME ) );
/* Get the minimum and maximum working set size for the current process */
GetProcessWorkingSetSize( handle, &minimumWorkingSetSize,
&maximumWorkingSetSize );
addRandom( buffer, &bufIndex, RANDOM_BUFSIZE, minimumWorkingSetSize );
addRandom( buffer, &bufIndex, RANDOM_BUFSIZE, maximumWorkingSetSize );
/* 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 );
addRandomString( buffer, &bufIndex, RANDOM_BUFSIZE, &startupInfo,
sizeof( STARTUPINFO ) );
addedFixedItems = TRUE;
}
/* The performance of QPC varies depending on the architecture it's
running on and on the OS. Under NT it reads the CPU's 64-bit timstamp
counter (at least on a Pentium and newer '486's, it hasn't been tested
on anything without a TSC), under Win95 it reads the 1.193180 MHz PIC
timer. There are vague mumblings in the docs that it may fail if the
appropriate hardware isn't available (possibly '386's or MIPS machines
running NT), but who's going to run NT on a '386? */
if( QueryPerformanceCounter( &performanceCount ) )
addRandomString( buffer, &bufIndex, RANDOM_BUFSIZE,
&performanceCount, sizeof( LARGE_INTEGER ) );
else
/* Millisecond accuracy at best... */
addRandom( buffer, &bufIndex, RANDOM_BUFSIZE, GetTickCount() );
/* Flush any remaining data through */
addRandomString( buffer, &bufIndex, RANDOM_BUFSIZE, NULL, 0 );
krnlSendMessage( SYSTEM_OBJECT_HANDLE, RESOURCE_IMESSAGE_SETATTRIBUTE,
&quality, CRYPT_IATTRIBUTE_RANDOM_QUALITY );
}
/* Type definitions for function pointers to call Toolhelp32 functions */
typedef BOOL ( WINAPI *MODULEWALK )( HANDLE hSnapshot, LPMODULEENTRY32 lpme );
typedef BOOL ( WINAPI *THREADWALK )( HANDLE hSnapshot, LPTHREADENTRY32 lpte );
typedef BOOL ( WINAPI *PROCESSWALK )( HANDLE hSnapshot, LPPROCESSENTRY32 lppe );
typedef BOOL ( WINAPI *HEAPLISTWALK )( HANDLE hSnapshot, LPHEAPLIST32 lphl );
typedef BOOL ( WINAPI *HEAPFIRST )( LPHEAPENTRY32 lphe, DWORD th32ProcessID, DWORD th32HeapID );
typedef BOOL ( WINAPI *HEAPNEXT )( LPHEAPENTRY32 lphe );
typedef HANDLE ( WINAPI *CREATESNAPSHOT )( DWORD dwFlags, DWORD th32ProcessID );
/* Global function pointers. These are necessary because the functions need to
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -