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

📄 cryptctx.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 3 页
字号:
/****************************************************************************
*																			*
*					  cryptlib Encryption Context Routines					*
*						Copyright Peter Gutmann 1992-2008					*
*																			*
****************************************************************************/

/* "Modern cryptography is nothing more than a mathematical framework for
	debating the implications of various paranoid delusions"
												- Don Alvarez */

#define PKC_CONTEXT		/* Indicate that we're working with PKC contexts */
#include "crypt.h"
#ifdef INC_ALL
  #include "context.h"
  #include "asn1.h"
#else
  #include "context/context.h"
  #include "misc/asn1.h"
#endif /* Compiler-specific includes */

/* The number of bytes of data that we check to make sure that the 
   encryption operation succeeded.  See the comment in encryptData() before 
   changing this */

#define ENCRYPT_CHECKSIZE	16

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

/* Initialise pointers to context-specific storage areas */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int initContextStorage( INOUT CONTEXT_INFO *contextInfoPtr, 
							   IN_LENGTH_SHORT_Z const int storageSize )
	{
	assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );

	REQUIRES( ( contextInfoPtr->type == CONTEXT_PKC && \
				storageSize == sizeof( PKC_INFO ) ) || \
			  ( contextInfoPtr->type != CONTEXT_PKC && \
				storageSize >= 16 && storageSize < MAX_INTLENGTH_SHORT ) );

	switch( contextInfoPtr->type )
		{
		case CONTEXT_CONV:
			contextInfoPtr->ctxConv = ( CONV_INFO * ) contextInfoPtr->storage;
			contextInfoPtr->ctxConv->key = contextInfoPtr->storage + storageSize;
			break;

		case CONTEXT_HASH:
			contextInfoPtr->ctxHash = ( HASH_INFO * ) contextInfoPtr->storage;
			contextInfoPtr->ctxHash->hashInfo = contextInfoPtr->storage + storageSize;
			break;

		case CONTEXT_MAC:
			contextInfoPtr->ctxMAC = ( MAC_INFO * ) contextInfoPtr->storage;
			contextInfoPtr->ctxMAC->macInfo = contextInfoPtr->storage + storageSize;
			break;

		case CONTEXT_PKC:
			contextInfoPtr->ctxPKC = ( PKC_INFO * ) contextInfoPtr->storage;
			break;
		}

	return( CRYPT_OK );
	}

/* Perform any context-specific checks that a context meets the given 
   requirements (general checks have already been performed by the kernel).  
   Although these checks are automatically performed by the kernel when we 
   try and use the context, they're duplicated here to allow for better 
   error reporting by catching problems when the context is first passed to 
   a cryptlib function rather than much later and at a lower level when the 
   kernel disallows the action */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int checkContext( INOUT CONTEXT_INFO *contextInfoPtr,
						 IN_ENUM( MESSAGE_CHECK ) \
							const MESSAGE_CHECK_TYPE checkType )
	{
	const CAPABILITY_INFO *capabilityInfoPtr = contextInfoPtr->capabilityInfo;

	assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );

	REQUIRES( checkType > MESSAGE_CHECK_NONE && \
			  checkType < MESSAGE_CHECK_LAST );

	/* If it's a check that an object's ready for key generation we can 
	   perform the check without requiring any algorithm-specific 
	   gyrations */
	if( checkType == MESSAGE_CHECK_KEYGEN_READY )
		{
		/* Make sure that there isn't already a key loaded */
		if( !needsKey( contextInfoPtr ) )
			return( CRYPT_ERROR_INITED );

		/* Make sure that we can actually generate a key.  This should be
		   enforced by the kernel anyway but we use a backup check here */
		if( capabilityInfoPtr->generateKeyFunction == NULL )
			return( CRYPT_ERROR_NOTAVAIL );

		return( CRYPT_OK );
		}

	/* If it's a check for the (potential) ability to perform conventional 
	   encryption or MACing at some point in the future, without necessarily 
	   currently having a key loaded for the task, we're done */
	if( checkType == MESSAGE_CHECK_CRYPT_READY || \
		checkType == MESSAGE_CHECK_MAC_READY )
		return( CRYPT_OK );

	/* Perform general checks */
	if( contextInfoPtr->type != CONTEXT_HASH && needsKey( contextInfoPtr ) )
		return( CRYPT_ERROR_NOTINITED );

	/* If it's a hash, MAC, conventional encryption, or basic PKC check, 
	   we're done */
	if( checkType == MESSAGE_CHECK_CRYPT || \
		checkType == MESSAGE_CHECK_HASH || \
		checkType == MESSAGE_CHECK_MAC || \
		checkType == MESSAGE_CHECK_PKC )
		return( CRYPT_OK );

	/* Check for key-agreement algorithms */
	if( isKeyxAlgo( capabilityInfoPtr->cryptAlgo ) )
		{
		/* DH can never be used for encryption or signatures (if it is then
		   we call it Elgamal) and KEA is explicitly for key agreement only.
		   Note that the status of DH is a bit ambiguous in that every DH key
		   is both a public and private key, in order to avoid confusion in 
		   situations where we're checking for real private keys we always 
		   denote a DH context as key-agreement only without taking a side 
		   about whether it's a public or private key */
		return( ( checkType == MESSAGE_CHECK_PKC_KA_EXPORT || \
				  checkType == MESSAGE_CHECK_PKC_KA_IMPORT ) ? \
				CRYPT_OK : CRYPT_ARGERROR_OBJECT );
		}
	if( checkType == MESSAGE_CHECK_PKC_KA_EXPORT || \
		checkType == MESSAGE_CHECK_PKC_KA_IMPORT )
		{
		/* A key agreement check requires a key agreement algorithm */
		return( CRYPT_ARGERROR_OBJECT );
		}

	/* We're down to various public-key checks */
	REQUIRES( checkType == MESSAGE_CHECK_PKC_PRIVATE || \
			  checkType == MESSAGE_CHECK_PKC_ENCRYPT || \
			  checkType == MESSAGE_CHECK_PKC_DECRYPT || \
			  checkType == MESSAGE_CHECK_PKC_SIGCHECK || \
			  checkType == MESSAGE_CHECK_PKC_SIGN || \
			  checkType == MESSAGE_CHECK_CA );

	/* Check that it's a private key if this is required */
	if( ( checkType == MESSAGE_CHECK_PKC_PRIVATE || \
		  checkType == MESSAGE_CHECK_PKC_DECRYPT || \
		  checkType == MESSAGE_CHECK_PKC_SIGN ) && \
		( contextInfoPtr->flags & CONTEXT_FLAG_ISPUBLICKEY ) )
		return( CRYPT_ARGERROR_OBJECT );

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*							Data Encryption Functions						*
*																			*
****************************************************************************/

/* Encrypt a block of data */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int encryptDataConv( INOUT CONTEXT_INFO *contextInfoPtr, 
							IN_BUFFER( dataLength ) void *data, 
							IN_LENGTH_Z const int dataLength )
	{
	BYTE savedData[ ENCRYPT_CHECKSIZE + 8 ];
	const CAPABILITY_INFO *capabilityInfoPtr = contextInfoPtr->capabilityInfo;
	const int savedDataLength = min( dataLength, ENCRYPT_CHECKSIZE );
	int status;

	assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
	assert( isWritePtr( data, dataLength ) );

	REQUIRES( contextInfoPtr->type == CONTEXT_CONV );
	REQUIRES( !needsKey( contextInfoPtr ) );
	REQUIRES( dataLength >= 0 && dataLength < MAX_INTLENGTH );
	REQUIRES( isStreamCipher( capabilityInfoPtr->cryptAlgo ) || \
			  !needsIV( contextInfoPtr->ctxConv->mode ) ||
			  ( contextInfoPtr->flags & CONTEXT_FLAG_IV_SET ) );
	REQUIRES( contextInfoPtr->ctxConv->key == \
			  contextInfoPtr->storage + sizeof( CONV_INFO ) );

	memcpy( savedData, data, savedDataLength );
	status = contextInfoPtr->encryptFunction( contextInfoPtr, data, 
											  dataLength );
	if( cryptStatusError( status ) || savedDataLength <= 8 )
		{
		zeroise( savedData, savedDataLength );
		return( status );
		}

	/* Check for a catastrophic failure of the encryption.  A check of
	   a single block unfortunately isn't completely foolproof for 64-bit
	   blocksize ciphers in CBC mode because of the way the IV is applied to 
	   the input.  For the CBC encryption operation:
					
		out = enc( in ^ IV )
						
	   if out == IV the operation turns into a no-op.  Consider the simple 
	   case where IV == in, so IV ^ in == 0.  Then out = enc( 0 ) == IV, 
	   with the input appearing again at the output.  In fact for a 64-bit 
	   block cipher this can occur during normal operation once every 2^32 
	   blocks.  Although the chances of this happening are fairly low (the 
	   collision would have to occur on the first encrypted block in a 
	   message since that's the one that we check), we check the first two 
	   blocks if we're using a 64-bit block cipher in CBC mode in order to 
	   reduce false positives */
	if( !memcmp( savedData, data, savedDataLength ) )
		{
		zeroise( data, dataLength );
		status = CRYPT_ERROR_FAILED;
		}
	zeroise( savedData, savedDataLength );
	return( status );
	}

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int encryptDataPKC( INOUT CONTEXT_INFO *contextInfoPtr, 
						   IN_BUFFER( dataLength ) void *data, 
						   IN_LENGTH_PKC const int dataLength )
	{
	BYTE savedData[ ENCRYPT_CHECKSIZE + 8 ];
	const CAPABILITY_INFO *capabilityInfoPtr = contextInfoPtr->capabilityInfo;
	const BOOLEAN isDLP = isDlpAlgo( capabilityInfoPtr->cryptAlgo );
	const BOOLEAN isECC = isEccAlgo( capabilityInfoPtr->cryptAlgo );
	int status;

	assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
	assert( isWritePtr( data, dataLength ) );

	REQUIRES( contextInfoPtr->type == CONTEXT_PKC );
	REQUIRES( !needsKey( contextInfoPtr ) );

	/* Key agreement algorithms are treated as a special case since they 
	   don't actually encrypt the data */
	if( isKeyxAlgo( capabilityInfoPtr->cryptAlgo ) )
		{
		REQUIRES( dataLength == sizeof( KEYAGREE_PARAMS ) );

		status = contextInfoPtr->encryptFunction( contextInfoPtr, data, 
												  dataLength );
		if( !( contextInfoPtr->flags & CONTEXT_FLAG_DUMMY ) )
			clearTempBignums( contextInfoPtr->ctxPKC );
		return( status );
		}

	REQUIRES( ( ( isDLP || isECC ) && \
				dataLength == sizeof( DLP_PARAMS ) ) || \
			  ( ( !isDLP && !isECC ) && \
			    dataLength >= MIN_PKCSIZE && \
				dataLength <= CRYPT_MAX_PKCSIZE ) );

	memcpy( savedData, ( isDLP || isECC ) ? \
						   ( ( DLP_PARAMS * ) data )->inParam1 : data, 
						   ENCRYPT_CHECKSIZE );
	status = contextInfoPtr->encryptFunction( contextInfoPtr, data, 
											  dataLength );
	if( !( contextInfoPtr->flags & CONTEXT_FLAG_DUMMY ) )
		clearTempBignums( contextInfoPtr->ctxPKC );
	if( cryptStatusError( status ) )
		{
		zeroise( savedData, ENCRYPT_CHECKSIZE );
		return( status );
		}

	/* Check for a catastrophic failure of the encryption */
	if( isDLP || isECC )
		{
		DLP_PARAMS *dlpParams = ( DLP_PARAMS * ) data;

		if( !memcmp( savedData, dlpParams->outParam, 
					 ENCRYPT_CHECKSIZE ) )
			{
			zeroise( dlpParams->outParam, dlpParams->outLen );
			status = CRYPT_ERROR_FAILED;
			}
		}
	else
		{
		if( !memcmp( savedData, data, ENCRYPT_CHECKSIZE ) )
			{
			zeroise( data, dataLength );
			status = CRYPT_ERROR_FAILED;
			}
		}
	zeroise( savedData, ENCRYPT_CHECKSIZE );

	return( status );
	}

/****************************************************************************
*																			*
*								Context Message Handler						*
*																			*
****************************************************************************/

/* Handle a message sent to an encryption context */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int contextMessageFunction( INOUT TYPECAST( CONTEXT_INFO * ) \
									void *objectInfoPtr,
								   IN_MESSAGE const MESSAGE_TYPE message,
								   void *messageDataPtr,
								   IN_INT_Z const int messageValue )
	{
	CONTEXT_INFO *contextInfoPtr = ( CONTEXT_INFO * ) objectInfoPtr;
	const CAPABILITY_INFO *capabilityInfo = contextInfoPtr->capabilityInfo;
	int status;

	assert( isWritePtr( objectInfoPtr, sizeof( CONTEXT_INFO ) ) );
	

⌨️ 快捷键说明

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