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

📄 ctx_misc.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 2 页
字号:
/****************************************************************************
*																			*
*						cryptlib Context Support Routines					*
*						Copyright Peter Gutmann 1995-2007					*
*																			*
****************************************************************************/

#define PKC_CONTEXT		/* Indicate that we're working with PKC contexts */
#if defined( INC_ALL )
  #include "crypt.h"
  #include "context.h"
  #ifdef USE_MD5
	#include "md5.h"
  #endif /* USE_MD5 */
  #ifdef USE_RIPEMD160
	#include "ripemd.h"
  #endif /* USE_RIPEMD160 */
  #include "sha.h"
  #ifdef USE_SHA2
	#include "sha2.h"
  #endif /* USE_SHA2 */
#else
  #include "crypt.h"
  #include "context/context.h"
  #ifdef USE_MD5
	#include "crypt/md5.h"
  #endif /* USE_MD5 */
  #ifdef USE_RIPEMD160
	#include "crypt/ripemd.h"
  #endif /* USE_RIPEMD160 */
  #include "crypt/sha.h"
  #ifdef USE_SHA2
	#include "crypt/sha2.h"
  #endif /* USE_SHA2 */
#endif /* Compiler-specific includes */

/****************************************************************************
*																			*
*						Capability Management Functions						*
*																			*
****************************************************************************/

/* Check that a capability info record is consistent */

CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
BOOLEAN sanityCheckCapability( const CAPABILITY_INFO *capabilityInfoPtr,
							   const BOOLEAN asymmetricOK )
	{
	CRYPT_ALGO_TYPE cryptAlgo = capabilityInfoPtr->cryptAlgo;

	assert( isReadPtr( capabilityInfoPtr, sizeof( CAPABILITY_INFO ) ) );

	/* Check the algorithm and mode parameters.  We check for an algorithm
	   name one shorter than the maximum because as returned to an external
	   caller it's an ASCIZ string so we need to allow room for the
	   terminator */
	if( cryptAlgo <= CRYPT_ALGO_NONE || cryptAlgo >= CRYPT_ALGO_LAST_MAC || \
		capabilityInfoPtr->algoName == NULL || \
		capabilityInfoPtr->algoNameLen < 3 || \
		capabilityInfoPtr->algoNameLen > CRYPT_MAX_TEXTSIZE - 1 )
		return( FALSE );

	/* Make sure that the minimum functions are present.  We don't check for
	   the presence of the keygen function since the symmetric capabilities
	   use the generic keygen and the hash capabilities don't do keygen at 
	   all */
	if( capabilityInfoPtr->selfTestFunction == NULL || \
		capabilityInfoPtr->getInfoFunction == NULL )
		return( FALSE );
	if( isStreamCipher( cryptAlgo ) )
		{
		if( capabilityInfoPtr->encryptOFBFunction == NULL || \
			capabilityInfoPtr->decryptOFBFunction == NULL )
			return( FALSE );
		}
	else
		{
		if( asymmetricOK )
			{
			/* If asymmetric capabilities (e.g. decrypt but not encrypt,
			   present in some tinkertoy tokens) are permitted then we only 
			   check that there's at least one useful capability available */
			if( capabilityInfoPtr->decryptFunction == NULL && \
				capabilityInfoPtr->signFunction == NULL )
				return( FALSE );
			}
		else
			{
			/* We need at least one mechanism pair to be able to do anything
			   useful with the capability */
			if( ( capabilityInfoPtr->encryptFunction == NULL || \
				  capabilityInfoPtr->decryptFunction == NULL ) && \
				( capabilityInfoPtr->encryptCBCFunction == NULL || \
				  capabilityInfoPtr->decryptCBCFunction == NULL ) && \
				( capabilityInfoPtr->encryptCFBFunction == NULL || \
				  capabilityInfoPtr->decryptCFBFunction == NULL ) && \
				( capabilityInfoPtr->encryptOFBFunction == NULL || \
				  capabilityInfoPtr->decryptOFBFunction == NULL ) && \
				( capabilityInfoPtr->signFunction == NULL || \
				  capabilityInfoPtr->sigCheckFunction == NULL ) )
				return( FALSE );
			}
		}

	/* Make sure that the algorithm/mode-specific parameters are
	   consistent */
	if( capabilityInfoPtr->minKeySize > capabilityInfoPtr->keySize || \
		capabilityInfoPtr->maxKeySize < capabilityInfoPtr->keySize )
		return( FALSE );
	if( cryptAlgo >= CRYPT_ALGO_FIRST_CONVENTIONAL && \
		cryptAlgo <= CRYPT_ALGO_LAST_CONVENTIONAL )
		{
		if( ( capabilityInfoPtr->blockSize < bitsToBytes( 8 ) || \
        	  capabilityInfoPtr->blockSize > CRYPT_MAX_IVSIZE ) || \
			( capabilityInfoPtr->minKeySize < MIN_KEYSIZE || \
			  capabilityInfoPtr->maxKeySize > CRYPT_MAX_KEYSIZE ) )
			return( FALSE );
		if( capabilityInfoPtr->initKeyParamsFunction == NULL || \
			capabilityInfoPtr->initKeyFunction == NULL )
			return( FALSE );
		if( !isStreamCipher( cryptAlgo ) && \
			 capabilityInfoPtr->blockSize < bitsToBytes( 64 ) )
			return( FALSE );
		if( ( capabilityInfoPtr->encryptCBCFunction != NULL && \
			  capabilityInfoPtr->decryptCBCFunction == NULL ) || \
			( capabilityInfoPtr->encryptCBCFunction == NULL && \
			  capabilityInfoPtr->decryptCBCFunction != NULL ) )
			return( FALSE );
		if( ( capabilityInfoPtr->encryptCFBFunction != NULL && \
			  capabilityInfoPtr->decryptCFBFunction == NULL ) || \
			( capabilityInfoPtr->encryptCFBFunction == NULL && \
			  capabilityInfoPtr->decryptCFBFunction != NULL ) )
			return( FALSE );
		if( ( capabilityInfoPtr->encryptOFBFunction != NULL && \
			  capabilityInfoPtr->decryptOFBFunction == NULL ) || \
			( capabilityInfoPtr->encryptOFBFunction == NULL && \
			  capabilityInfoPtr->decryptOFBFunction != NULL ) )
			return( FALSE );
		}
	if( cryptAlgo >= CRYPT_ALGO_FIRST_PKC && \
		cryptAlgo <= CRYPT_ALGO_LAST_PKC )
		{
		const int minKeySize = isEccAlgo( cryptAlgo ) ? \
							   MIN_PKCSIZE_ECC : MIN_PKCSIZE;

		if( capabilityInfoPtr->blockSize != 0 || \
			( capabilityInfoPtr->minKeySize < minKeySize || \
			  capabilityInfoPtr->maxKeySize > CRYPT_MAX_PKCSIZE ) )
			return( FALSE );
		if( capabilityInfoPtr->initKeyFunction == NULL || \
			capabilityInfoPtr->generateKeyFunction == NULL )
			return( FALSE );
		}
	if( cryptAlgo >= CRYPT_ALGO_FIRST_HASH && \
		cryptAlgo <= CRYPT_ALGO_LAST_HASH )
		{
		if( ( capabilityInfoPtr->blockSize < bitsToBytes( 128 ) || \
			  capabilityInfoPtr->blockSize > CRYPT_MAX_HASHSIZE ) || \
			( capabilityInfoPtr->minKeySize != 0 || \
			  capabilityInfoPtr->keySize != 0 || \
			  capabilityInfoPtr->maxKeySize != 0 ) )
			return( FALSE );
		}
	if( cryptAlgo >= CRYPT_ALGO_FIRST_MAC && \
		cryptAlgo <= CRYPT_ALGO_LAST_MAC )
		{
		if( ( capabilityInfoPtr->blockSize < bitsToBytes( 128 ) || \
			  capabilityInfoPtr->blockSize > CRYPT_MAX_HASHSIZE ) || \
			( capabilityInfoPtr->minKeySize < MIN_KEYSIZE || \
			  capabilityInfoPtr->maxKeySize > CRYPT_MAX_KEYSIZE ) )
			return( FALSE );
		if( capabilityInfoPtr->initKeyFunction == NULL )
			return( FALSE );
		}

	return( TRUE );
	}

/* Get information from a capability record */

STDC_NONNULL_ARG( ( 1, 2 ) ) \
void getCapabilityInfo( OUT CRYPT_QUERY_INFO *cryptQueryInfo,
						const CAPABILITY_INFO FAR_BSS *capabilityInfoPtr )
	{
	assert( isWritePtr( cryptQueryInfo, sizeof( CRYPT_QUERY_INFO ) ) );
	assert( isReadPtr( capabilityInfoPtr, sizeof( CAPABILITY_INFO ) ) );

	memset( cryptQueryInfo, 0, sizeof( CRYPT_QUERY_INFO ) );
	memcpy( cryptQueryInfo->algoName, capabilityInfoPtr->algoName,
			capabilityInfoPtr->algoNameLen );
	cryptQueryInfo->algoName[ capabilityInfoPtr->algoNameLen ] = '\0';
	cryptQueryInfo->blockSize = capabilityInfoPtr->blockSize;
	cryptQueryInfo->minKeySize = capabilityInfoPtr->minKeySize;
	cryptQueryInfo->keySize = capabilityInfoPtr->keySize;
	cryptQueryInfo->maxKeySize = capabilityInfoPtr->maxKeySize;
	}

/* Find the capability record for a given encryption algorithm */

CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 1 ) ) \
const CAPABILITY_INFO FAR_BSS *findCapabilityInfo(
						const CAPABILITY_INFO_LIST *capabilityInfoList,
						IN_ALGO const CRYPT_ALGO_TYPE cryptAlgo )
	{
	const CAPABILITY_INFO_LIST *capabilityInfoListPtr;
	int iterationCount;

	assert( isReadPtr( capabilityInfoList, sizeof( CAPABILITY_INFO ) ) );

	/* Find the capability corresponding to the requested algorithm/mode */
	for( capabilityInfoListPtr = capabilityInfoList, iterationCount = 0;
		 capabilityInfoListPtr != NULL && iterationCount < FAILSAFE_ITERATIONS_MED;
		 capabilityInfoListPtr = capabilityInfoListPtr->next, iterationCount++ )
		{
		if( capabilityInfoListPtr->info->cryptAlgo == cryptAlgo )
			return( capabilityInfoListPtr->info );
		}
	ENSURES_N( iterationCount < FAILSAFE_ITERATIONS_MED );

	return( NULL );
	}

/****************************************************************************
*																			*
*							Shared Context Functions						*
*																			*
****************************************************************************/

/* Default handler to get object subtype-specific information.  This 
   fallback function is called if the object-specific primary get-info 
   handler doesn't want to handle the query */

CHECK_RETVAL STDC_NONNULL_ARG( ( 4 ) )  \
int getDefaultInfo( IN_ENUM( CAPABILITY_INFO ) \
						const CAPABILITY_INFO_TYPE type, 
					IN_OPT const void *ptrParam, 
					const int intParam,
					OUT_INT_Z int *result )
	{
	assert( isWritePtr( result, sizeof( int ) ) );

	REQUIRES( type > CAPABILITY_INFO_NONE && type < CAPABILITY_INFO_LAST );

	/* Clear return value */
	*result = 0;

	switch( type )
		{
		case CAPABILITY_INFO_STATESIZE:
			REQUIRES( ptrParam == NULL && intParam == 0 );

			/* Result is already set to zero from earlier code */
			return( CRYPT_OK );
		}

	retIntError();
	}

/****************************************************************************
*																			*
*							Bignum Support Routines 						*
*																			*
****************************************************************************/

#ifdef USE_PKC

/* Clear temporary bignum values used during PKC operations */

STDC_NONNULL_ARG( ( 1 ) ) \
void clearTempBignums( INOUT PKC_INFO *pkcInfo )
	{
	assert( isWritePtr( pkcInfo, sizeof( PKC_INFO ) ) );

	BN_clear( &pkcInfo->tmp1 );
	BN_clear( &pkcInfo->tmp2 );
	BN_clear( &pkcInfo->tmp3 );
	BN_CTX_clear( pkcInfo->bnCTX );
	}

/* Initialse and free the bignum information in a context */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int initContextBignums( INOUT PKC_INFO *pkcInfo, 
						IN_RANGE( 0, 3 ) const int sideChannelProtectionLevel )
	{
	BN_CTX *bnCTX;

	assert( isWritePtr( pkcInfo, sizeof( PKC_INFO ) ) );

	REQUIRES( sideChannelProtectionLevel >= 0 && \
			  sideChannelProtectionLevel <= 3 );

	/* Perform any required memory allocations */
	bnCTX = BN_CTX_new();
	if( bnCTX == NULL )
		return( CRYPT_ERROR_MEMORY );

	/* Initialise the bignum information */
	BN_init( &pkcInfo->param1 );
	BN_init( &pkcInfo->param2 );
	BN_init( &pkcInfo->param3 );
	BN_init( &pkcInfo->param4 );
	BN_init( &pkcInfo->param5 );
	BN_init( &pkcInfo->param6 );
	BN_init( &pkcInfo->param7 );
	BN_init( &pkcInfo->param8 );
	if( sideChannelProtectionLevel > 0 )
		{
		BN_init( &pkcInfo->blind1 );
		BN_init( &pkcInfo->blind2 );
		}
	BN_init( &pkcInfo->tmp1 );
	BN_init( &pkcInfo->tmp2 );
	BN_init( &pkcInfo->tmp3 );
	pkcInfo->bnCTX = bnCTX;
	BN_MONT_CTX_init( &pkcInfo->montCTX1 );
	BN_MONT_CTX_init( &pkcInfo->montCTX2 );
	BN_MONT_CTX_init( &pkcInfo->montCTX3 );

	return( CRYPT_OK );
	}

STDC_NONNULL_ARG( ( 1 ) ) \
void freeContextBignums( INOUT PKC_INFO *pkcInfo, 
						 IN_FLAGS( CONTEXT ) const int contextFlags )
	{
	assert( isWritePtr( pkcInfo, sizeof( PKC_INFO ) ) );

	REQUIRES_V( contextFlags >= CONTEXT_FLAG_NONE && \
				contextFlags <= CONTEXT_FLAG_MAX );

	if( !( contextFlags & CONTEXT_FLAG_DUMMY ) )
		{
		BN_clear_free( &pkcInfo->param1 );
		BN_clear_free( &pkcInfo->param2 );
		BN_clear_free( &pkcInfo->param3 );
		BN_clear_free( &pkcInfo->param4 );
		BN_clear_free( &pkcInfo->param5 );
		BN_clear_free( &pkcInfo->param6 );
		BN_clear_free( &pkcInfo->param7 );
		BN_clear_free( &pkcInfo->param8 );
		if( contextFlags & CONTEXT_FLAG_SIDECHANNELPROTECTION )
			{
			BN_clear_free( &pkcInfo->blind1 );
			BN_clear_free( &pkcInfo->blind2 );
			}
		BN_clear_free( &pkcInfo->tmp1 );
		BN_clear_free( &pkcInfo->tmp2 );
		BN_clear_free( &pkcInfo->tmp3 );
		BN_MONT_CTX_free( &pkcInfo->montCTX1 );
		BN_MONT_CTX_free( &pkcInfo->montCTX2 );
		BN_MONT_CTX_free( &pkcInfo->montCTX3 );
		BN_CTX_free( pkcInfo->bnCTX );
		}
	if( pkcInfo->publicKeyInfo != NULL )
		clFree( "contextMessageFunction", pkcInfo->publicKeyInfo );
	}

/* Convert a byte string into a BIGNUM value */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int extractBignum( INOUT TYPECAST( BIGNUM * ) void *bignumPtr, 
				   IN_BUFFER( length ) const void *buffer, 
				   IN_LENGTH_SHORT const int length,
				   IN_LENGTH_PKC const int minLength, 
				   IN_LENGTH_PKC const int maxLength, 
				   INOUT_OPT const void *maxRangePtr,
				   const BOOLEAN checkShortKey )
	{
	BIGNUM *bignum = ( BIGNUM * ) bignumPtr;
	BIGNUM *maxRange = ( BIGNUM * ) maxRangePtr;
	BN_ULONG bnWord;
	int bignumLength;

	assert( isWritePtr( bignum, sizeof( BIGNUM ) ) );
	assert( isReadPtr( buffer, length ) );
	assert( maxRange == NULL || isReadPtr( maxRange, sizeof( BIGNUM ) ) );

	REQUIRES( minLength > 0 && minLength <= maxLength && \
			  maxLength <= CRYPT_MAX_PKCSIZE );

	/* Make sure that we've been given valid input.  This should have been 
	   checked by the caller anyway using far more specific checks than the
	   very generic values that we use here, but we perform the check anyway
	   just to be sure */
	if( length < 1 || length > CRYPT_MAX_PKCSIZE )
		return( CRYPT_ERROR_BADDATA );

	/* Convert the byte string into a bignum */
	if( BN_bin2bn( buffer, length, bignum ) == NULL )
		return( CRYPT_ERROR_MEMORY );

	/* The following should never happen because BN_bin2bn() works with 
	   unsigned values but we perform the check anyway just in case someone 
	   messes with the underlying bignum code */
	ENSURES( !( BN_is_negative( bignum ) ) )

	/* A zero- or one-valued bignum on the other hand is an error because we 
	   should never find zero or one in a PKC-related value.  This check is 
	   somewhat redundant with the one that follows, we place it here to 
	   make it explicit and because the cost is near zero */
	bnWord = BN_get_word( bignum );
	if( bnWord < BN_MASK2 && bnWord <= 1 )
		return( CRYPT_ERROR_BADDATA );

	/* Check that the final bignum value falls within the allowed length 
	   range */
	bignumLength = BN_num_bytes( bignum );
	if( checkShortKey )
		{
		REQUIRES( minLength > bitsToBytes( 256 ) );

		/* If the length is below the minimum allowed but still looks at 
		   least vaguely valid, report it as a too-short key rather than a
		   bad data error */
		if( isShortPKCKey( bignumLength ) )
			return( CRYPT_ERROR_NOSECURE );
		}
	if( bignumLength < minLength || bignumLength > maxLength )
		return( CRYPT_ERROR_BADDATA );

⌨️ 快捷键说明

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