📄 dev_sys.c
字号:
/****************************************************************************
* *
* cryptlib System Device Routines *
* Copyright Peter Gutmann 1995-2002 *
* *
****************************************************************************/
/* The random pool handling code in 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 practically strong random numbers".
The CSPRNG code is copyright Peter Gutmann (and various others) 1995-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
General Public License, version 2 or any later version published by the
Free Software Foundation, in which case the provisions of the GNU GPL are
required INSTEAD OF the above restrictions.
Although not required under the terms of the GPL, it would still be nice
if you could make any changes available to the author to allow a
consistent code base to be maintained */
#include <stdlib.h>
#include <string.h>
#include <time.h>
#if defined( INC_ALL )
#include "crypt.h"
#include "cryptctx.h"
#include "des.h"
#include "sha.h"
#include "device.h"
#elif defined( INC_CHILD )
#include "../crypt.h"
#include "../cryptctx.h"
#include "../crypt/des.h"
#include "../hash/sha.h"
#include "device.h"
#else
#include "crypt.h"
#include "cryptctx.h"
#include "crypt/des.h"
#include "hash/sha.h"
#include "misc/device.h"
#endif /* Compiler-specific includes */
/* The EAY SHA code doesn't make the SHA compression function externally
accessible, so we use RIPEMD-160 for now */
#define SHA1Transform( hash, data ) RIPEMD160Transform( hash, data )
#ifdef __WIN32__
void __cdecl RIPEMD160Transform( LONG *H, const LONG *X );
#else
void RIPEMD160Transform( LONG *H, const LONG *X );
#endif /* __WIN32__ */
/* If we don't have a defined randomness interface, complain */
#if !( defined( __MSDOS__ ) || defined( __WIN16__ ) || defined( __WIN32__ ) || \
defined( __OS2__ ) || defined( __BEOS__ ) || defined( __UNIX__ ) || \
defined( __MAC__ ) || defined( __TANDEM__ ) || defined( __IBM4758__ ) || \
defined( __VMCMS__ ) )
#error You need to create OS-specific randomness-gathering functions in misc/rnd<os_name>.c
#endif /* Various OS-specific defines */
/* Some systems systems which require special-case initialisation for
threading support and allow background randomness gathering, where this
doesn't apply the routines to do this are nop'd out */
#if defined( __WIN32__ )
void initRandomPolling( void );
void endRandomPolling( void );
void waitforRandomCompletion( void );
#elif defined( __UNIX__ )
void initRandomPolling( void );
#define endRandomPolling()
void waitforRandomCompletion( void );
#else
#define initRandomPolling()
#define endRandomPolling()
#define waitforRandomCompletion()
#endif /* !( __WIN32__ || __UNIX__ ) */
/* On Unix systems the randomness pool may be duplicated at any point if
the process forks, so we need to perform a complex check to make sure
we're running with a unique copy of the pool contents rather than a
clone of data held in another process. The following function checks
whether we've forked or not, which is used as a signal to adjust the
pool contents */
#ifdef __UNIX__
BOOLEAN checkForked( void );
#else
#define checkForked() FALSE
#endif /* __UNIX__ */
/* Prototypes for functions in the OS-specific randomness polling routines */
void slowPoll( void );
void fastPoll( void );
/* The size of the randomness pool and the size of the optional X9.17
generator pool */
#define RANDOMPOOL_SIZE 256
#define X917_POOLSIZE 8
/* The allocated size if the randomness pool, which allows for the overflow
created by the fact that the hash function blocksize isn't any useful
multiple of a power of 2 */
#define RANDOMPOOL_ALLOCSIZE ( ( ( RANDOMPOOL_SIZE + 20 - 1 ) / 20 ) * 20 )
/* In order to avoid the pool startup problem (where initial pool data may
consist of minimally-mixed entropy samples) we require that the pool be
mixed at least the following number of times before we can draw data from
it. This usually happens automatically because a slow poll adds enough
data to cause many mixing iterations, however if this doesn't happen we
manually mix it the appropriate number of times to get it up to the
correct level */
#define RANDOMPOOL_MIXES 10
/* The number of samples of previous output we keep for the FIPS 140
continuous tests, and the number of retries we perform if we detect a
repeat of a previous output */
#define RANDOMPOOL_SAMPLES 16
#define RANDOMPOOL_RETRIES 5
/* The number of times we cycle the X9.17 generator before we load new key
and state variables */
#define X917_MAX_CYCLES 8192
/* Random pool information, pagelocked in memory to ensure it never gets
swapped to disk. We keep track of the write position in the pool, which
tracks where new data is added. Whenever we add new data the write
position is updated, once we reach the end of the pool we mix the pool
and start again at the beginning. In addition we track the pool status
by recording the quality of the pool contents (1-100) and the number of
times the pool has been mixed, we can't draw data from the pool unless
both of these values have reached an acceptable level.
In addition to the pool state information we keep track of the previous
RANDOMPOOL_SAMPLES output samples to check for stuck-at faults or (short)
cyles */
typedef struct {
/* Pool state information */
BYTE randomPool[ RANDOMPOOL_ALLOCSIZE ]; /* Random byte pool */
int randomPoolPos; /* Current write position in the pool */
/* Pool status information */
int randomQuality; /* Whether there's any randomness in the pool */
int randomPoolMixes; /* Number of times pool has been mixed */
/* X9.17 generator state information */
BYTE x917Pool[ X917_POOLSIZE ]; /* Generator state */
BOOLEAN x917Inited; /* Whether generator has been inited */
int x917Count; /* No of times generator has been cycled */
void *x917Key; /* Scheduled 3DES key */
/* Information for FIPS 140 continuous tests */
LONG prevOutput[ RANDOMPOOL_SAMPLES ];
LONG x917PrevOutput[ RANDOMPOOL_SAMPLES ];
int prevOutputIndex;
} RANDOM_INFO;
/****************************************************************************
* *
* Utility Functions *
* *
****************************************************************************/
/* Convenience functions used by the system-specific randomness-polling
routines to send data to the randomness device. These just accumulate as
close to bufSize bytes of data as possible in a user-provided buffer and
then forward them to the device object. Note that addRandomString()
assumes the quantity of data being added is small (a fixed-size struct or
something similar), it shouldn't be used to add large buffers full of
data since information at the end of the buffer will be lost (in the
debug build this will trigger an exception telling the caller to use a
direct krnlSendMessage() instead) */
void addRandomString( BYTE *buffer, int *bufIndex, const int bufSize,
const void *value, const int valueLength )
{
assert( buffer != NULL );
assert( *bufIndex >= 0 && *bufIndex <= bufSize );
assert( ( value != NULL && \
valueLength > 0 && valueLength <= bufSize ) || \
( value == NULL && valueLength == 0 ) );
/* If the new data would overflow the accumulator or it's a flush, send
the data through to the device */
if( ( *bufIndex + valueLength > bufSize ) || value == NULL )
{
RESOURCE_DATA msgData;
setResourceData( &msgData, buffer, *bufIndex );
krnlSendMessage( SYSTEM_OBJECT_HANDLE, RESOURCE_IMESSAGE_SETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_RANDOM );
*bufIndex = 0;
/* If this is the flush call, clear the accumulator and exit */
if( value == NULL )
{
zeroise( buffer, bufSize );
return;
}
}
/* Add the data to the accumulator */
memcpy( buffer + *bufIndex, value, min( valueLength, bufSize ) );
*bufIndex += valueLength;
}
void addRandomLong( BYTE *buffer, int *bufIndex, const int bufSize,
const long value )
{
assert( buffer != NULL );
assert( *bufIndex >= 0 && *bufIndex <= bufSize );
addRandomString( buffer, bufIndex, bufSize, &value, sizeof( long ) );
}
/****************************************************************************
* *
* Random Pool Management Routines *
* *
****************************************************************************/
/* Initialise a random pool */
static void initRandomPool( RANDOM_INFO *randomInfo )
{
memset( randomInfo, 0, sizeof( RANDOM_INFO ) );
}
/* Stir up the data in the random buffer. Given a circular buffer of length
n bytes, we hash the 20 bytes at n with the 64 bytes at n - 20...n - 1 (to
provide chaining across previous hashes) and n + 20...n + 64 (to have as
much surrounding data as possible affect the current data) as the input
data block. Then we move on to the next 20 bytes until the entire buffer
has been mixed. We don't bother with data endianess-adjustment since
we're not really interested in the final output values, as long as they're
well-mixed */
static void mixRandomPool( RANDOM_INFO *randomInfo )
{
#ifdef _BIG_WORDS
LONG dataBuffer[ SHA_CBLOCK / 4 ];
#else
BYTE dataBuffer[ SHA_CBLOCK ];
#endif /* BIG_WORDS */
int hashIndex;
/* Stir up the entire pool */
#ifdef _BIG_WORDS
for( hashIndex = 0; hashIndex < RANDOMPOOL_SIZE; hashIndex += SHA_DIGEST_LENGTH )
{
LONG digestLong[ SHA_DIGEST_LENGTH / 4 ];
BYTE *digestPtr;
int dataBufIndex, poolIndex, i;
/* If we're at the start of the pool then the first block we hash is
at the end of the pool, otherwise it's the block immediately
preceding the current one */
poolIndex = hashIndex ? hashIndex - SHA_DIGEST_LENGTH : \
RANDOMPOOL_SIZE - SHA_DIGEST_LENGTH;
/* Copy SHA_DIGEST_LENGTH bytes from position n - 19...n - 1 in the
circular pool into the hash data buffer */
for( dataBufIndex = 0; dataBufIndex < SHA_DIGEST_LENGTH; dataBufIndex += 4 )
dataBuffer[ dataBufIndex / 4 ] = \
( ( LONG ) randomInfo->randomPool[ poolIndex++ % RANDOMPOOL_SIZE ] << 24 ) | \
( ( LONG ) randomInfo->randomPool[ poolIndex++ % RANDOMPOOL_SIZE ] << 16 ) | \
( ( LONG ) randomInfo->randomPool[ poolIndex++ % RANDOMPOOL_SIZE ] << 8 ) | \
( ( LONG ) randomInfo->randomPool[ poolIndex++ % RANDOMPOOL_SIZE ] );
/* Postconditions for chaining data copy */
POST( dataBufIndex == SHA_DIGEST_LENGTH ); /* Got 20 bytes... */
POST( poolIndex >= SHA_DIGEST_LENGTH && \
poolIndex <= RANDOMPOOL_SIZE ); /* ...from within pool... */
POST( !hashIndex || \
hashIndex == poolIndex ); /* ...before current pos.*/
/* Copy SHA_CBLOCK - SHA_DIGEST_LENGTH bytes from position n + 20...
n + 64 from the circular pool into the hash data buffer */
poolIndex = hashIndex + SHA_DIGEST_LENGTH;
while( dataBufIndex < SHA_CBLOCK )
{
dataBuffer[ dataBufIndex / 4 ] = \
( ( LONG ) randomInfo->randomPool[ poolIndex++ % RANDOMPOOL_SIZE ] << 24 ) | \
( ( LONG ) randomInfo->randomPool[ poolIndex++ % RANDOMPOOL_SIZE ] << 16 ) | \
( ( LONG ) randomInfo->randomPool[ poolIndex++ % RANDOMPOOL_SIZE ] << 8 ) | \
( ( LONG ) randomInfo->randomPool[ poolIndex++ % RANDOMPOOL_SIZE ] );
dataBufIndex += 4;
}
/* Postconditions for state data copy */
POST( dataBufIndex == SHA_CBLOCK ); /* Got remain.44 bytes... */
POST( poolIndex == hashIndex + SHA_CBLOCK );/* ...after current pos.*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -