📄 randlib.c
字号:
/*++
Copyright (c) 1993, 1998 Microsoft Corporation
Module Name:
randlib.c
Abstract:
This module implements the core cryptographic random number generator
for use by system components.
The #define KMODE_RNG affects whether the file is built in a way
suitable for kernel mode usage. if KMODE_RNG is not defined, the file
is built in a way suitable for user mode usage.
Author:
Scott Field (sfield) 27-Nov-96
Jeff Spelman (jeffspel) 14-Oct-96
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <zwapi.h>
#ifdef KMODE_RNG
#include <ntos.h>
#ifdef USE_HW_RNG
#ifdef _M_IX86
#include <io.h>
#include "deftypes.h" //ISD typedefs and constants
#include "ioctldef.h" //ISD ioctl definitions
#endif // _M_IX86
#endif // USE_HW_RNG
#endif // KMODE_RNG
#include <windows.h>
#include <winioctl.h>
#include <lmcons.h>
#include <rc4.h>
#include <sha.h>
#include <md4.h>
#include <ntddksec.h> // IOCTL_
#include <randlib.h>
#include "vlhash.h"
#include "circhash.h"
#include "cpu.h"
#include "seed.h"
#ifdef KMODE_RNG
#include <ntos.h>
#ifdef USE_HW_RNG
#ifdef _M_IX86
static DWORD g_dwHWDriver = 0;
static PFILE_OBJECT g_pFileObject = NULL;
static PDEVICE_OBJECT g_pDeviceObject = NULL;
#endif // _M_IX86
#endif // USE_HW_RNG
#endif // KMODE_RNG
#include "umkm.h"
//
// note: RAND_CTXT_LEN dictates the maximum input quantity for re-seed entropy
// is. We make this fairly large, so that we can take all the entropy generated
// during the GatherRandomBits(). Since the lifetime of the RandContext structure
// is very short, and it lives on the stack, this larger than necessary size
// is ok. The last few items processed during GatherRandomBits() are of
// variable size, up to a maximum of of UNLEN for the username.
//
#define RAND_CTXT_LEN (256)
#define RC4_REKEY_PARAM_NT (16384) // rekey less often on NT
#ifndef KMODE_RNG
#define RC4_REKEY_PARAM_DEFAULT (512) // rekey every 512 bytes by default
#else
#define RC4_REKEY_PARAM_DEFAULT RC4_REKEY_PARAM_NT
#endif
static unsigned int g_dwRC4RekeyParam = RC4_REKEY_PARAM_DEFAULT;
static CircularHash g_CircularHashCtx;
static BYTE g_VeryLargeHash[A_SHA_DIGEST_LEN*4];
static void * g_RC4SafeCtx;
#ifndef KMODE_RNG
typedef NTSYSAPI NTSTATUS (NTAPI *NTQUERYSYSTEMINFORMATION) (
IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
OUT PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength OPTIONAL
);
typedef NTSYSAPI NTSTATUS (NTAPI *NTOPENFILE) (
OUT PHANDLE FileHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN ULONG ShareAccess,
IN ULONG OpenOptions
);
typedef NTSYSAPI VOID (NTAPI *RTLINITUNICODESTRING) (
PUNICODE_STRING DestinationString,
PCWSTR SourceString
);
typedef BOOL (WINAPI *GETCURSORPOS)(
LPPOINT lpPoint
);
typedef LONG (WINAPI *GETMESSAGETIME)(
VOID
);
NTQUERYSYSTEMINFORMATION ___NtQuerySystemInformationRNG = NULL;
NTOPENFILE ___NtOpenFileRNG = NULL;
RTLINITUNICODESTRING ___RtlInitUnicodeStringRNG = NULL;
GETCURSORPOS ___GetCursorPosRNG = NULL;
GETMESSAGETIME ___GetMessageTimeRNG = NULL;
HANDLE g_hKsecDD = NULL;
#define _NtQuerySystemInformation ___NtQuerySystemInformationRNG
#define _NtOpenFile ___NtOpenFileRNG
#define _RtlInitUnicodeString ___RtlInitUnicodeStringRNG
#define _GetCursorPos ___GetCursorPosRNG
#define _GetMessageTime ___GetMessageTimeRNG
#else
#define _NtQuerySystemInformation ZwQuerySystemInformation
#endif // !KMODE_RNG
/// TODO: cache hKeySeed later.
///extern HKEY g_hKeySeed;
//
// private function prototypes.
//
BOOL
GenRandom (
IN PVOID hUID,
OUT BYTE *pbBuffer,
IN size_t dwLength
);
BOOL
RandomFillBuffer(
OUT BYTE *pbBuffer,
IN DWORD *pdwLength
);
BOOL
GatherRandomKey(
IN BYTE *pbUserSeed,
IN DWORD cbUserSeed,
IN OUT BYTE *pbRandomKey,
IN OUT DWORD *pcbRandomKey
);
BOOL
GatherRandomKeyFastUserMode(
IN BYTE *pbUserSeed,
IN DWORD cbUserSeed,
IN OUT BYTE *pbRandomKey,
IN OUT DWORD *pcbRandomKey
);
BOOL
IsRNGWinNT(
VOID
);
#ifdef _M_IX86
unsigned int
QueryForHWRandomBits(
IN DWORD *pdwRandom,
IN OUT DWORD cdwRandom
);
#endif //_M_IX86
#ifdef KMODE_RNG
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, NewGenRandom)
#pragma alloc_text(PAGE, NewGenRandomEx)
#pragma alloc_text(PAGE, GenRandom)
#pragma alloc_text(PAGE, RandomFillBuffer)
#pragma alloc_text(PAGE, InitializeRNG)
#pragma alloc_text(PAGE, ShutdownRNG)
#ifdef _M_IX86
#pragma alloc_text(PAGE, QueryForHWRandomBits)
#endif //_M_IX86
#pragma alloc_text(PAGE, GatherRandomKey)
#endif // ALLOC_PRAGMA
#endif // KMODE_RNG
/************************************************************************/
/* NewGenRandom generates a specified number of random bytes and places */
/* them into the specified buffer. */
/************************************************************************/
/* */
/* Pseudocode logic flow: */
/* */
/* if (bits streamed >= threshold) */
/* { */
/* Gather_Bits() */
/* SHAMix_Bits(User, Gathered, Static -> Static) */
/* RC4Key(Static -> newRC4Key) */
/* SaveToRegistry(Static) */
/* } */
/* else */
/* { */
/* Mix_Bits(User, Static -> Static) */
/* } */
/* */
/* RC4(newRC4Key -> outbuf) */
/* bits streamed += sizeof(outbuf) */
/* */
/************************************************************************/
unsigned int
RSA32API
NewGenRandomEx(
IN RNG_CONTEXT *pRNGContext,
IN OUT unsigned char *pbRandBuffer,
IN unsigned long cbRandBuffer
)
{
unsigned char **ppbRandSeed;
unsigned long *pcbRandSeed;
unsigned int fRet;
#ifdef KMODE_RNG
PAGED_CODE();
#endif // KMODE_RNG
fRet = TRUE;
if( pRNGContext->cbSize != sizeof( RNG_CONTEXT ) )
return FALSE;
if( pRNGContext->pbRandSeed && pRNGContext->cbRandSeed ) {
ppbRandSeed = &pRNGContext->pbRandSeed;
pcbRandSeed = &pRNGContext->cbRandSeed;
} else {
ppbRandSeed = NULL;
pcbRandSeed = NULL;
}
InitRand( ppbRandSeed, pcbRandSeed );
InitializeRNG( NULL );
if( pRNGContext->Flags & RNG_FLAG_REKEY_ONLY ) {
//
// caller wants REKEY only.
//
fRet = GatherRandomKey( NULL, 0, pbRandBuffer, &cbRandBuffer );
} else {
//
// standard RNG request.
//
fRet = GenRandom(0, pbRandBuffer, cbRandBuffer);
}
if( ppbRandSeed && pcbRandSeed ) {
DeInitRand( *ppbRandSeed, *pcbRandSeed);
}
return fRet;
}
unsigned int
RSA32API
NewGenRandom (
IN OUT unsigned char **ppbRandSeed,
IN unsigned long *pcbRandSeed,
IN OUT unsigned char *pbBuffer,
IN unsigned long dwLength
)
{
RNG_CONTEXT RNGContext;
#ifdef KMODE_RNG
PAGED_CODE();
#endif // KMODE_RNG
ZeroMemory( &RNGContext, sizeof(RNGContext) );
RNGContext.cbSize = sizeof(RNGContext);
if( ppbRandSeed && pcbRandSeed ) {
BOOL fRet;
RNGContext.pbRandSeed = *ppbRandSeed;
RNGContext.cbRandSeed = *pcbRandSeed;
fRet = NewGenRandomEx( &RNGContext, pbBuffer, dwLength );
*pcbRandSeed = RNGContext.cbRandSeed;
return fRet;
}
return NewGenRandomEx( &RNGContext, pbBuffer, dwLength );
}
unsigned int
RSA32API
InitRand(
IN OUT unsigned char **ppbRandSeed,
IN unsigned long *pcbRandSeed
)
{
static BOOL fInitialized = FALSE;
#ifdef KMODE_RNG
PAGED_CODE();
#endif // KMODE_RNG
if( !fInitialized ) {
InitCircularHash(
&g_CircularHashCtx,
7,
CH_ALG_MD4,
0 // CH_MODE_FEEDBACK
);
//
// get prior seed.
//
ReadSeed( g_VeryLargeHash, sizeof( g_VeryLargeHash ) );
fInitialized = TRUE;
}
if( ppbRandSeed != NULL && pcbRandSeed != NULL && *pcbRandSeed != 0 )
UpdateCircularHash( &g_CircularHashCtx, *ppbRandSeed, *pcbRandSeed );
return TRUE;
}
unsigned int
RSA32API
DeInitRand(
IN OUT unsigned char *pbRandSeed,
IN unsigned long cbRandSeed
)
{
PBYTE pbCircularHash;
DWORD cbCircularHash;
#ifdef KMODE_RNG
PAGED_CODE();
#endif // KMODE_RNG
if( pbRandSeed == NULL || cbRandSeed == 0 )
return TRUE;
if(GetCircularHashValue( &g_CircularHashCtx, &pbCircularHash, &cbCircularHash )) {
unsigned long cbToCopy;
if( cbRandSeed > cbCircularHash ) {
cbToCopy = cbCircularHash;
} else {
cbToCopy = cbRandSeed;
}
memcpy(pbRandSeed, pbCircularHash, cbToCopy);
}
return TRUE;
}
unsigned int
RSA32API
InitializeRNG(
VOID *pvReserved
)
{
void *pvCtx;
void *pvOldCtx;
#ifdef KMODE_RNG
PAGED_CODE();
#endif // KMODE_RNG
if( g_RC4SafeCtx ) {
return TRUE;
}
if(!rc4_safe_startup( &pvCtx )) {
return FALSE;
}
pvOldCtx = INTERLOCKEDCOMPAREEXCHANGEPOINTER( &g_RC4SafeCtx, pvCtx, NULL );
if( pvOldCtx ) {
//
// race condition occured during init.
//
rc4_safe_shutdown( pvCtx );
}
return TRUE;
}
void
RSA32API
ShutdownRNG(
VOID *pvReserved
)
{
void *pvCtx;
HKEY hKey;
#ifdef KMODE_RNG
PAGED_CODE();
#endif // KMODE_RNG
pvCtx = InterlockedExchangePointer( &g_RC4SafeCtx, NULL );
if( pvCtx ) {
rc4_safe_shutdown( pvCtx );
}
#ifndef KMODE_RNG
{
HANDLE hFile;
hFile = InterlockedExchangePointer( &g_hKsecDD, NULL );
if( hFile ) {
CloseHandle( hFile );
}
}
#endif
#if 0
// TODO later: finish logic for caching registry key.
hKey = InterlockedExchangePointer( &g_hKeySeed, NULL );
if( hKey ) {
REGCLOSEKEY( hKey );
}
#endif
}
BOOL
GenRandom (
IN PVOID hUID,
OUT BYTE *pbBuffer,
IN size_t dwLength
)
{
DWORD dwBytesThisPass;
DWORD dwFilledBytes;
#ifdef KMODE_RNG
PAGED_CODE();
#endif // KMODE_RNG
dwFilledBytes = 0;
// break request into chunks that we rekey between
while(dwFilledBytes < dwLength)
{
dwBytesThisPass = dwLength - dwFilledBytes;
if(!RandomFillBuffer(
pbBuffer + dwFilledBytes,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -