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

📄 int_api.c

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

/* A generic module that implements a rug under which all problems not
   solved elsewhere are swept */

#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL )
  #include "crypt.h"
  #include "md2.h"
  #include "md5.h"
  #include "ripemd.h"
  #include "sha.h"
  #ifdef USE_SHA2
	#include "sha2.h"
  #endif /* USE_SHA2 */
  #include "stream.h"
#elif defined( INC_CHILD )
  #include "../crypt.h"
  #include "../crypt/md2.h"
  #include "../crypt/md5.h"
  #include "../crypt/ripemd.h"
  #include "../crypt/sha.h"
  #ifdef USE_SHA2
	#include "../crypt/sha2.h"
  #endif /* USE_SHA2 */
  #include "../io/stream.h"
#else
  #include "crypt.h"
  #include "crypt/md2.h"
  #include "crypt/md5.h"
  #include "crypt/ripemd.h"
  #include "crypt/sha.h"
  #ifdef USE_SHA2
	#include "crypt/sha2.h"
  #endif /* USE_SHA2 */
  #include "io/stream.h"
#endif /* Compiler-specific includes */

/****************************************************************************
*																			*
*								Internal API Functions						*
*																			*
****************************************************************************/

/* Get the system time safely.  The first function implements hard failures,
   converting invalid time values to zero, which yield a warning date of
   1/1/1970 rather than an out-of-bounds value or garbage value.  The second
   function implements soft failures, returning an estimate of the
   approximate current date.  The third function is used for operations such
   as signing certs and timestamping and tries to get the time from a
   hardware time source if one is available */

time_t getTime( void )
	{
	const time_t theTime = time( NULL );

	return( ( theTime < MIN_TIME_VALUE ) ? 0 : theTime );
	}

time_t getApproxTime( void )
	{
	const time_t theTime = time( NULL );

	return( ( theTime < MIN_TIME_VALUE ) ? CURRENT_TIME_VALUE : theTime );
	}

time_t getReliableTime( const CRYPT_HANDLE cryptHandle )
	{
	CRYPT_DEVICE cryptDevice;
	RESOURCE_DATA msgData;
	time_t theTime;
	int status;

	/* Get the dependent device for the object that needs the time */
	status = krnlSendMessage( cryptHandle, IMESSAGE_GETDEPENDENT,
							  &cryptDevice, OBJECT_TYPE_DEVICE );
	if( cryptStatusError( status ) )
		cryptDevice = SYSTEM_OBJECT_HANDLE;

	/* Try and get the time from the device */
	setMessageData( &msgData, &theTime, sizeof( time_t ) );
	status = krnlSendMessage( cryptDevice, IMESSAGE_GETATTRIBUTE_S,
							  &msgData, CRYPT_IATTRIBUTE_TIME );
	if( cryptStatusError( status ) && cryptDevice != SYSTEM_OBJECT_HANDLE )
		/* We couldn't get the time from a crypto token, fall back to the
		   system device */
		status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
								  IMESSAGE_GETATTRIBUTE_S, &msgData,
								  CRYPT_IATTRIBUTE_TIME );
	if( cryptStatusError( status ) )
		return( 0 );
	return( ( theTime < MIN_TIME_VALUE ) ? 0 : theTime );
	}

/* Calculate a 16-bit Fletcher-like checksum of a block of data.  This isn't
   quite a pure Fletcher checksum because we don't bother keeping the
   accumulators at 8 bits, and also don't need to set the initial value to
   nonzero since we'll never see a sequence of zero bytes.  This isn't a big
   deal since all we need is a consistent result.  In addition we don't
   bother with masking to 16 bits during the calculation since it's not
   being used as a true checksum */

int checksumData( const void *data, const int dataLength )
	{
	const BYTE *dataPtr = data;
	int sum1 = 0, sum2 = 0, i;

	assert( isReadPtr( data, dataLength ) );

	for( i = 0; i < dataLength; i++ )
		{
		sum1 += dataPtr[ i ];
		sum2 += sum1;
		}

	return( sum2 & 0xFFFF );
	}

/* Determine the parameters for a particular hash algorithm */

void md2HashBuffer( HASHINFO hashInfo, BYTE *outBuffer,
					const BYTE *inBuffer, const int length,
					const HASH_STATE hashState );
void md5HashBuffer( HASHINFO hashInfo, BYTE *outBuffer,
					const BYTE *inBuffer, const int length,
					const HASH_STATE hashState );
void ripemd160HashBuffer( HASHINFO hashInfo, BYTE *outBuffer,
						  const BYTE *inBuffer, const int length,
						  const HASH_STATE hashState );
void shaHashBuffer( HASHINFO hashInfo, BYTE *outBuffer,
					const BYTE *inBuffer, const int length,
					const HASH_STATE hashState );
void sha2HashBuffer( HASHINFO hashInfo, BYTE *outBuffer,
					 const BYTE *inBuffer, const int length,
					 const HASH_STATE hashState );

void getHashParameters( const CRYPT_ALGO_TYPE hashAlgorithm,
						HASHFUNCTION *hashFunction, int *hashSize )
	{
	assert( isWritePtr( hashFunction, sizeof( HASHFUNCTION ) ) );
	assert( ( hashSize == NULL ) || isWritePtr( hashSize, sizeof( int ) ) );

	switch( hashAlgorithm )
		{
#ifdef USE_MD2
		case CRYPT_ALGO_MD2:
			*hashFunction = md2HashBuffer;
			if( hashSize != NULL )
				*hashSize = MD2_DIGEST_LENGTH;
			return;
#endif /* USE_MD2 */

		case CRYPT_ALGO_MD5:
			*hashFunction = md5HashBuffer;
			if( hashSize != NULL )
				*hashSize = MD5_DIGEST_LENGTH;
			return;

#ifdef USE_RIPEMD160
		case CRYPT_ALGO_RIPEMD160:
			*hashFunction = ripemd160HashBuffer;
			if( hashSize != NULL )
				*hashSize = RIPEMD160_DIGEST_LENGTH;
			return;
#endif /* USE_RIPEMD160 */

		case CRYPT_ALGO_SHA:
			*hashFunction = shaHashBuffer;
			if( hashSize != NULL )
				*hashSize = SHA_DIGEST_LENGTH;
			return;

#ifdef USE_SHA2
		case CRYPT_ALGO_SHA2:
			*hashFunction = sha2HashBuffer;
			if( hashSize != NULL )
				*hashSize = SHA256_DIGEST_SIZE;
			return;
#endif /* USE_SHA2 */
		}

	/* Make sure that we always get some sort of hash function rather than
	   just dying.  This code always works because the internal self-test
	   has confirmed the availability and functioning of SHA-1 on startup */
	*hashFunction = shaHashBuffer;
	if( hashSize != NULL )
		*hashSize = SHA_DIGEST_LENGTH;
	assert( NOTREACHED );
	}

/* Perform the FIPS-140 statistical checks that are feasible on a byte
   string.  The full suite of tests assumes that an infinite source of
   values (and time) is available, the following is a scaled-down version
   used to sanity-check keys and other short random data blocks.  Note that
   this check requires at least 64 bits of data in order to produce useful
   results */

BOOLEAN checkEntropy( const BYTE *data, const int dataLength )
	{
	const int delta = ( dataLength < 16 ) ? 1 : 0;
	int bitCount[ 4 ] = { 0 }, noOnes, i;

	assert( isReadPtr( data, dataLength ) );
	assert( dataLength >= 8 );

	for( i = 0; i < dataLength; i++ )
		{
		const int value = data[ i ];

		bitCount[ value & 3 ]++;
		bitCount[ ( value >> 2 ) & 3 ]++;
		bitCount[ ( value >> 4 ) & 3 ]++;
		bitCount[ value >> 6 ]++;
		}

	/* Monobit test: Make sure that at least 1/4 of the bits are ones and 1/4
	   are zeroes */
	noOnes = bitCount[ 1 ] + bitCount[ 2 ] + ( 2 * bitCount[ 3 ] );
	if( noOnes < dataLength * 2 || noOnes > dataLength * 6 )
		return( FALSE );

	/* Poker test (almost): Make sure that each bit pair is present at least
	   1/16 of the time.  The FIPS 140 version uses 4-bit values, but the
	   numer of samples available from the keys is far too small for this.

	   This isn't precisely 1/16, for short samples (< 128 bits) we adjust
	   the count by one because of the small sample size, and for odd-length
	   data we're getting four more samples so the actual figure is slightly
	   less than 1/16 */
	if( ( bitCount[ 0 ] + delta < dataLength / 2 ) || \
		( bitCount[ 1 ] + delta < dataLength / 2 ) || \
		( bitCount[ 2 ] + delta < dataLength / 2 ) || \
		( bitCount[ 3 ] + delta < dataLength / 2 ) )
		return( FALSE );

	return( TRUE );
	}

/* Copy a string attribute to external storage, with various range checks
   to follow the cryptlib semantics (these will already have been done by
   the caller, this is just a backup check) */

int attributeCopy( RESOURCE_DATA *msgData, const void *attribute,
				   const int attributeLength )
	{
	assert( isWritePtr( msgData, sizeof( RESOURCE_DATA ) ) );

	if( attributeLength <= 0 )
		{
		msgData->length = 0;
		return( CRYPT_ERROR_NOTFOUND );
		}
	if( msgData->data != NULL )
		{
		assert( isReadPtr( attribute, attributeLength ) );

		if( attributeLength > msgData->length || \
			!isWritePtr( msgData->data, attributeLength ) )
			return( CRYPT_ARGERROR_STR1 );
		memcpy( msgData->data, attribute, attributeLength );
		}
	msgData->length = attributeLength;

	return( CRYPT_OK );
	}

/* Check whether a given algorithm is available */

BOOLEAN algoAvailable( const CRYPT_ALGO_TYPE cryptAlgo )
	{
	CRYPT_QUERY_INFO queryInfo;

	return( cryptStatusOK( krnlSendMessage( SYSTEM_OBJECT_HANDLE,
									IMESSAGE_DEV_QUERYCAPABILITY, &queryInfo,
									cryptAlgo ) ) ? TRUE : FALSE );
	}

/* For a given algorithm pair, check whether the first is stronger than the
   second.  For hashes the order is:

	SHA2 > RIPEMD160 > SHA-1 > all others */

BOOLEAN isStrongerHash( const CRYPT_ALGO_TYPE algorithm1,
						const CRYPT_ALGO_TYPE algorithm2 )
	{
	static const CRYPT_ALGO_TYPE algoPrecedence[] = {
		CRYPT_ALGO_SHA2, CRYPT_ALGO_RIPEMD160, CRYPT_ALGO_SHA,
		CRYPT_ALGO_NONE };
	int algo1index, algo2index;

	/* Find the relative positions on the scale of the two algorithms */
	for( algo1index = 0; algoPrecedence[ algo1index ] != algorithm1;
		 algo1index++ )
		if( algoPrecedence[ algo1index ] == CRYPT_ALGO_NONE )
			/* We've reached an unrated algorithm, it can't be stronger
			   than the other one */
			return( FALSE );
	for( algo2index = 0; algoPrecedence[ algo2index ] != algorithm2;
		 algo2index++ )
		if( algoPrecedence[ algo2index ] == CRYPT_ALGO_NONE )
			/* We've reached an unrated algorithm, it's weaker than the
			   other one */
			return( TRUE );

	/* If the first algorithm has a smaller index than the second, it's a
	   stronger algorithm */
	return( ( algo1index < algo2index ) ? TRUE : FALSE );
	}

/* Sanitise a string before passing it back to the user.  This is used to
   clear potential problem characters (for example control characters)
   from strings passed back from untrusted sources */

char *sanitiseString( char *string )
	{
	int i;

	assert( isWritePtr( string, strlen( string ) ) );

	/* Remove any potentially unsafe characters from the string */
	for( i = 0; string[ i ] != '\0'; i++ )
		if( !isPrint( string[ i ] ) )
			string[ i ] = '.';

	return( string );
	}

/****************************************************************************
*																			*
*						Dynamic Buffer Management Routines					*
*																			*
****************************************************************************/

/* Dynamic buffer management functions.  When reading variable-length
   attribute data we can usually fit the data in a small, fixed-length
   buffer, but occasionally we have to cope with larger data amounts that
   require a dynamically-allocated buffer.  The following routines manage
   this process, dynamically allocating and freeing a larger buffer if
   required */

int dynCreate( DYNBUF *dynBuf, const CRYPT_HANDLE cryptHandle,
			   const CRYPT_ATTRIBUTE_TYPE attributeType )
	{
	RESOURCE_DATA msgData;
	const MESSAGE_TYPE message = \
						( attributeType == CRYPT_CERTFORMAT_CERTIFICATE ) ? \
						IMESSAGE_CRT_EXPORT : IMESSAGE_GETATTRIBUTE_S;
	void *dataPtr = NULL;
	int status;

	assert( isWritePtr( dynBuf, sizeof( DYNBUF ) ) );
	assert( ( cryptHandle == CRYPT_UNUSED && \
			  attributeType == CRYPT_UNUSED ) || \
			( isHandleRangeValid( cryptHandle ) && \
			  ( isAttribute( attributeType ) || \
				isInternalAttribute( attributeType ) ) ) );

	/* Clear return value */
	dynBuf->data = dynBuf->dataBuffer;

⌨️ 快捷键说明

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