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

📄 random.c

📁 cryptlib是功能强大的安全工具集。允许开发人员快速在自己的软件中集成加密和认证服务。
💻 C
📖 第 1 页 / 共 5 页
字号:
/****************************************************************************
*																			*
*					cryptlib Randomness Management Routines					*
*						Copyright Peter Gutmann 1995-2005					*
*																			*
****************************************************************************/

/* The random pool handling code in this module and the other modules in the
   /random subdirectory 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-2004
   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 BSD-style license 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>
#if defined( INC_ALL )
  #include "crypt.h"
  #include "des.h"
  #ifdef CONFIG_RANDSEED
	#include "stream.h"
  #endif /* CONFIG_RANDSEED */
#elif defined( INC_CHILD )
  #include "../crypt.h"
  #include "../crypt/des.h"
  #ifdef CONFIG_RANDSEED
	#include "../misc/stream.h"
  #endif /* CONFIG_RANDSEED */
#else
  #include "crypt.h"
  #include "crypt/des.h"
  #ifdef CONFIG_RANDSEED
	#include "misc/stream.h"
  #endif /* CONFIG_RANDSEED */
#endif /* Compiler-specific includes */

/* The maximum amount of random data needed by any cryptlib operation, 
   equivalent to the size of a maximum-length PKC key.  However this isn't 
   the absolute length because when generating the k value for DLP 
   operations we get n + m bits and then reduce via one of the DLP 
   parameters to get the value within range.  If we just got n bits, this 
   would introduce a bias into the top bit, see the DLP code for more 
   details.  Because of this we allow a length slightly larger than the 
   maximum PKC key size */

#define MAX_RANDOM_BYTES	( CRYPT_MAX_PKCSIZE + 8 )

/* If we don't have a defined randomness interface, complain */

#if !( defined( __BEOS__ ) || defined( __IBM4758__ ) || \
	   defined( __MAC__ ) || defined( __MSDOS__ ) || defined( __MVS__ ) || \
	   defined( __OS2__ ) || defined( __PALMOS__ ) || \
	   defined( __TANDEM_NSK__ ) || defined( __TANDEM_OSS__ ) || \
	   defined( __UNIX__ ) || defined( __VMCMS__ ) || \
	   defined( __WIN16__ ) || defined( __WIN32__ ) || \
	   defined( __WINCE__ ) )
  #error You need to create OS-specific randomness-gathering functions in random/<os-name>.c
#endif /* Various OS-specific defines */

/* If we're using stored seed data, make sure that the seed quality setting 
   is in order */

#ifdef CONFIG_RANDSEED
  #ifndef CONFIG_RANDSEED_QUALITY
	/* If the user hasn't provided a quality estimate, default to 80 */
	#define CONFIG_RANDSEED_QUALITY		80
  #endif /* !CONFIG_RANDSEED_QUALITY */
  #if ( CONFIG_RANDSEED_QUALITY < 10 ) || ( CONFIG_RANDSEED_QUALITY > 100 )
	#error CONFIG_RANDSEED_QUALITY must be between 10 and 100
  #endif /* CONFIG_RANDSEED_QUALITY check */
#endif /* CONFIG_RANDSEED */

/* Some systems systems require special-case initialisation to allow
   background randomness gathering, where this doesn't apply the routines to
   do this are nop'd out */

#if defined( __WIN32__ ) || defined( __WINCE__ )
  void initRandomPolling( void );
  void endRandomPolling( void );
  void waitforRandomCompletion( const BOOLEAN force );
#elif defined( __UNIX__ ) && \
	  !( defined( __MVS__ ) || defined( __TANDEM_NSK__ ) || \
		 defined( __TANDEM_OSS__ ) )
  void initRandomPolling( void );
  void endRandomPolling( void );
  void waitforRandomCompletion( const BOOLEAN force );
#else
  #define initRandomPolling()
  #define endRandomPolling()
  #define waitforRandomCompletion( dummy )
#endif /* !( __WIN32__ || __UNIX__ ) */

/* On Unix systems the randomness pool may be duplicated at any point if
   the process forks (qualis pater, talis filius), so we need to perform a
   complex check to make sure that 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 */

#if defined( __UNIX__ ) && \
	!( defined( __MVS__ ) || defined( __TANDEM_NSK__ ) || \
	   defined( __TANDEM_OSS__ ) )
  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 );

/****************************************************************************
*																			*
*						Randomness Interface Definitions					*
*																			*
****************************************************************************/

/* The size in bytes of the randomness pool and the size of the X9.17
   post-processor generator pool */

#define RANDOMPOOL_SIZE			256
#define X917_POOLSIZE			8

/* The allocated size of 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 that we keep for the FIPS 140
   continuous tests, and the number of retries that we perform if we detect 
   a repeat of a previous output */

#define RANDOMPOOL_SAMPLES		16
#define RANDOMPOOL_RETRIES		5

/* The number of times that we cycle the X9.17 generator before we load new
   key and state variables.  This means that we re-seed for every
   X917_MAX_BYTES of output produced */

#define X917_MAX_BYTES			4096
#define X917_MAX_CYCLES			( X917_MAX_BYTES / X917_POOLSIZE )

/* The scheduled DES keys for the X9.17 generator */

typedef struct {
	Key_schedule desKey1, desKey2, desKey3;
	} X917_3DES_KEY;

#define DES_KEYSIZE		sizeof( Key_schedule )

/* The size of the X9.17 generator key (112 bits for EDE 3DES) */

#define X917_KEYSIZE	16

/* Random pool information.  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.  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;		/* Level of randomness in the pool */
	int randomPoolMixes;	/* Number of times pool has been mixed */

	/* X9.17 generator state information */
	BYTE x917Pool[ X917_POOLSIZE ];	/* Generator state */
	BYTE x917DT[ X917_POOLSIZE ];	/* Date/time vector */
	X917_3DES_KEY x917Key;	/* Scheduled 3DES key */
	BOOLEAN x917Inited;		/* Whether generator has been inited */
	int x917Count;			/* No.of times generator has been cycled */
	BOOLEAN x917x931;		/* X9.17 vs. X9.31 operation (see code comments */

	/* Information for the FIPS 140 continuous tests */
	unsigned long prevOutput[ RANDOMPOOL_SAMPLES ];
	unsigned long x917PrevOutput[ RANDOMPOOL_SAMPLES ];
	int prevOutputIndex;

	/* Other status information used to check the pool's operation */
	int entropyByteCount;	/* Number of bytes entropy added */

	/* Random seed data information if seeding is done from a stored seed */
#ifdef CONFIG_RANDSEED
	BOOLEAN seedProcessed;	/* Whether stored seed has been processed */
	int seedSize;			/* Size of stored seed data */
	int seedUpdateCount;	/* When to update stored seed data */
#endif /* CONFIG_RANDSEED */
	} RANDOM_INFO;

/****************************************************************************
*																			*
*						Randomness Utility Functions						*
*																			*
****************************************************************************/

/* Convenience functions used by the system-specific randomness-polling
   routines to send data to the system 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 addRandomData()
   assumes that 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) */

typedef struct {
	void *buffer;			/* Entropy buffer */
	int bufPos, bufSize;	/* Current buffer pos.and total size */
	int updateStatus;		/* Error status if update failed */
	} RANDOM_STATE_INFO;

void initRandomData( void *statePtr, void *buffer, const int maxSize )
	{
	RANDOM_STATE_INFO *state = ( RANDOM_STATE_INFO * ) statePtr;

	assert( isWritePtr( state, sizeof( RANDOM_STATE_INFO ) ) );
	assert( sizeof( RANDOM_STATE_INFO ) <= sizeof( RANDOM_STATE ) );
	assert( isWritePtr( buffer, maxSize ) );
	assert( maxSize >= 16 );

	memset( state, 0, sizeof( RANDOM_STATE_INFO ) );
	state->buffer = buffer;
	state->bufSize = maxSize;
	}

int addRandomData( void *statePtr, const void *value,
				   const int valueLength )
	{
	RANDOM_STATE_INFO *state = ( RANDOM_STATE_INFO * ) statePtr;
	RESOURCE_DATA msgData;
	const BYTE *valuePtr = value;
	int length = min( valueLength, state->bufSize - state->bufPos );
	int totalLength = valueLength, status;

	assert( isWritePtr( state, sizeof( RANDOM_STATE_INFO ) ) );
	assert( isReadPtr( value, valueLength ) );
	assert( state->bufPos >= 0 && state->bufPos <= state->bufSize );
	assert( valueLength > 0 && valueLength <= state->bufSize );

	/* Sanity check on inputs (the length check checks both the input data
	   length and that bufSize > bufPos) */
	if( state->bufPos < 0 || length < 0 || state->bufSize < 16 )
		{
		/* Some type of fatal data corruption has occurred */
		state->updateStatus = CRYPT_ERROR_FAILED;
		assert( NOTREACHED );
		return( CRYPT_ERROR_FAILED );
		}

	/* Copy as much of the input as we can into the accumulator */
	if( length > 0 )
		{
		memcpy( ( BYTE * ) state->buffer + state->bufPos, valuePtr, length );
		state->bufPos += length;
		valuePtr += length;
		totalLength -= length;
		}
	assert( totalLength >= 0 );

	/* If everything went into the accumulator, we're done */
	if( state->bufPos < state->bufSize )
		return( CRYPT_OK );

	assert( state->bufPos == state->bufSize );

	/* The accumulator is full, send the data through to the system device */
	setMessageData( &msgData, state->buffer, state->bufPos );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_SETATTRIBUTE_S,
							  &msgData, CRYPT_IATTRIBUTE_ENTROPY );
	if( cryptStatusError( status ) )
		{
		/* There was a problem moving the data through, make the error status
		   persistent.  Normally this is a should-never-occur error, however 
		   if cryptlib has been shut down from another thread the kernel 
		   will fail all non shutdown-related calls with a permission error.  
		   To avoid false alarms, we mask out failures due to permission 
		   errors */
		state->updateStatus = status;
		assert( ( status == CRYPT_ERROR_PERMISSION ) || NOTREACHED );
		return( status );
		}
	state->bufPos = 0;

	/* If there's uncopied data left, copy it in now */
	if( totalLength > 0 )

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -