⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dev_sys.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 5 页
字号:
/****************************************************************************
*																			*
*						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 + -