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

📄 cryptctx.c

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

/* "Modern cryptography is nothing more than a mathematical framework for
	debating the implications of various paranoid delusions"
												- Don Alvarez */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PKC_CONTEXT		/* Indicate that we're working with PKC context */
#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 default size of the salt for PKCS #5v2 key derivation, needed when we
   set the CRYPT_CTXINFO_KEYING_VALUE */

#define PKCS5_SALT_SIZE		8	/* 64 bits */

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

#define ENCRYPT_CHECKSIZE	16

/* Prototypes for functions in ctx_misc.c */

const CAPABILITY_INFO FAR_BSS *findCapabilityInfo(
					const CAPABILITY_INFO_LIST *capabilityInfoList,
					const CRYPT_ALGO_TYPE cryptAlgo );

/* Prototypes for functions in keyload.c */

void initKeyHandling( CONTEXT_INFO *contextInfoPtr );
int initKeyParams( CONTEXT_INFO *contextInfoPtr, const void *iv,
				   const int ivLength, const CRYPT_MODE_TYPE mode );

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

/* Exit after setting extended error information */

static int exitError( CONTEXT_INFO *contextInfoPtr,
					  const CRYPT_ATTRIBUTE_TYPE errorLocus,
					  const CRYPT_ERRTYPE_TYPE errorType, const int status )
	{
	setErrorInfo( contextInfoPtr, errorLocus, errorType );
	return( status );
	}

static int exitErrorInited( CONTEXT_INFO *contextInfoPtr,
							const CRYPT_ATTRIBUTE_TYPE errorLocus )
	{
	return( exitError( contextInfoPtr, errorLocus, 
					   CRYPT_ERRTYPE_ATTR_PRESENT, CRYPT_ERROR_INITED ) );
	}

static int exitErrorNotInited( CONTEXT_INFO *contextInfoPtr,
							   const CRYPT_ATTRIBUTE_TYPE errorLocus )
	{
	return( exitError( contextInfoPtr, errorLocus, 
					   CRYPT_ERRTYPE_ATTR_ABSENT, CRYPT_ERROR_NOTINITED ) );
	}

static int exitErrorNotFound( CONTEXT_INFO *contextInfoPtr,
							  const CRYPT_ATTRIBUTE_TYPE errorLocus )
	{
	return( exitError( contextInfoPtr, errorLocus, 
					   CRYPT_ERRTYPE_ATTR_ABSENT, CRYPT_ERROR_NOTFOUND ) );
	}

/* Convert a key attribute type into a key format type */

static int attributeToFormatType( const CRYPT_ATTRIBUTE_TYPE attribute )
	{
	switch( attribute )
		{
		case CRYPT_IATTRIBUTE_KEY_SSH1:
			return( KEYFORMAT_SSH1 );

		case CRYPT_IATTRIBUTE_KEY_SSH2:
			return( KEYFORMAT_SSH2 );

		case CRYPT_IATTRIBUTE_KEY_SSL:
			return( KEYFORMAT_SSL );

		case CRYPT_IATTRIBUTE_KEY_PGP:
		case CRYPT_IATTRIBUTE_KEY_PGP_PARTIAL:
			return( KEYFORMAT_PGP );
		
		case CRYPT_IATTRIBUTE_KEY_SPKI:
		case CRYPT_IATTRIBUTE_KEY_SPKI_PARTIAL:
			return( KEYFORMAT_CERT );
		}

	assert( NOTREACHED );
	return( CRYPT_ERROR );	/* Get rid of compiler warning */
	}

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

void clearTempBignums( PKC_INFO *pkcInfo )
	{
	BN_clear( &pkcInfo->tmp1 );
	BN_clear( &pkcInfo->tmp2 );
	BN_clear( &pkcInfo->tmp3 );
	BN_CTX_clear( pkcInfo->bnCTX );
	}

/****************************************************************************
*																			*
*								Misc. Context Functions						*
*																			*
****************************************************************************/

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

static void initContextStorage( CONTEXT_INFO *contextInfoPtr, 
								const int storageSize )
	{
	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;
		}
	}

/* 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 */

static int checkContext( CONTEXT_INFO *contextInfoPtr,
						 const MESSAGE_CHECK_TYPE checkType )
	{
	const CAPABILITY_INFO *capabilityInfoPtr = contextInfoPtr->capabilityInfo;

	/* If it's a check that an object's ready for key generation (which is 
	   algorithm-type independent), we check it before performing any 
	   algorithm-specific checks */
	if( checkType == MESSAGE_CHECK_KEYGEN_READY )
		{
		if( !needsKey( contextInfoPtr ) )
			return( exitErrorInited( contextInfoPtr, CRYPT_CTXINFO_KEY ) );
		return( CRYPT_OK );
		}

	/* If it's a check for the (potential) ability to perform conventional 
	   encryption or MAC'ing at some point in the future, without 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( exitErrorNotInited( contextInfoPtr, CRYPT_CTXINFO_KEY ) );

	/* 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 )
		return( CRYPT_ARGERROR_OBJECT );	/* Must be a key agreement algorithm */

	/* We're down to various public-key checks */
	assert( 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_ISPUBLICKEY ) )
		return( CRYPT_ARGERROR_OBJECT );

	return( CRYPT_OK );
	}

/* Derive a key into a context from a user-supplied keying value */

static int deriveKey( CONTEXT_INFO *contextInfoPtr, void *keyValue, 
					  const int keyValueLen )
	{
	MECHANISM_DERIVE_INFO mechanismInfo;
	const CAPABILITY_INFO *capabilityInfoPtr = contextInfoPtr->capabilityInfo;
	int status;

	assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
	assert( contextInfoPtr->type == CONTEXT_CONV || \
			contextInfoPtr->type == CONTEXT_MAC );
	assert( needsKey( contextInfoPtr ) );
	assert( isReadPtr( keyValue, keyValueLen ) );

	/* Set up various derivation parameters if they're not already set.  
	   Since there's only one MUST MAC algorithm for PKCS #5v2, we always 
	   force the key derivation algorithm to this value to avoid interop 
	   problems */
	if( contextInfoPtr->type == CONTEXT_CONV )
		{
		CONV_INFO *convInfo = contextInfoPtr->ctxConv;

		if( convInfo->saltLength <= 0 )
			{
			RESOURCE_DATA nonceMsgData;

			setMessageData( &nonceMsgData, convInfo->salt, PKCS5_SALT_SIZE );
			status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
									  IMESSAGE_GETATTRIBUTE_S, &nonceMsgData,
									  CRYPT_IATTRIBUTE_RANDOM_NONCE );
			if( cryptStatusError( status ) )
				return( status );
			convInfo->saltLength = PKCS5_SALT_SIZE;
			}
		convInfo->keySetupAlgorithm = CRYPT_ALGO_HMAC_SHA;
		setMechanismDeriveInfo( &mechanismInfo, convInfo->userKey,
				capabilityInfoPtr->getInfoFunction( CAPABILITY_INFO_KEYSIZE, 
									contextInfoPtr, convInfo->userKeyLength ),
				keyValue, keyValueLen, convInfo->keySetupAlgorithm,
				convInfo->salt, convInfo->saltLength, 
				convInfo->keySetupIterations );
		if( mechanismInfo.iterations <= 0 )
			{
			krnlSendMessage( contextInfoPtr->ownerHandle, IMESSAGE_GETATTRIBUTE, 
							 &mechanismInfo.iterations, 
							 CRYPT_OPTION_KEYING_ITERATIONS );
			convInfo->keySetupIterations = mechanismInfo.iterations;
			}
		}
	else
		{
		MAC_INFO *macInfo = contextInfoPtr->ctxMAC;

		if( macInfo->saltLength <= 0 )
			{
			RESOURCE_DATA nonceMsgData;

			setMessageData( &nonceMsgData, macInfo->salt, PKCS5_SALT_SIZE );
			status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
									  IMESSAGE_GETATTRIBUTE_S, &nonceMsgData,
									  CRYPT_IATTRIBUTE_RANDOM_NONCE );
			if( cryptStatusError( status ) )
				return( status );
			macInfo->saltLength = PKCS5_SALT_SIZE;
			}
		contextInfoPtr->ctxConv->keySetupAlgorithm = CRYPT_ALGO_HMAC_SHA;
		setMechanismDeriveInfo( &mechanismInfo, macInfo->userKey,
				capabilityInfoPtr->getInfoFunction( CAPABILITY_INFO_KEYSIZE, 
									contextInfoPtr, macInfo->userKeyLength ),
				keyValue, keyValueLen, macInfo->keySetupAlgorithm,
				macInfo->salt, macInfo->saltLength,
				macInfo->keySetupIterations );
		if( mechanismInfo.iterations <= 0 )
			{
			krnlSendMessage( contextInfoPtr->ownerHandle, IMESSAGE_GETATTRIBUTE, 
							 &mechanismInfo.iterations, 
							 CRYPT_OPTION_KEYING_ITERATIONS );
			macInfo->keySetupIterations = mechanismInfo.iterations;
			}
		}

	/* Turn the user key into an encryption context key and load the key 
	   into the context */
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_DERIVE, 
							  &mechanismInfo, MECHANISM_DERIVE_PKCS5 );
	if( cryptStatusOK( status ) )
		status = contextInfoPtr->loadKeyFunction( contextInfoPtr,
												  mechanismInfo.dataOut,
												  mechanismInfo.dataOutLength );
	if( cryptStatusOK( status ) )
		{
		contextInfoPtr->flags |= CONTEXT_KEY_SET | CONTEXT_EPHEMERAL;
		if( contextInfoPtr->type == CONTEXT_MAC )
			contextInfoPtr->flags |= CONTEXT_HASH_INITED;
		}
	return( status );
	}

/* Load an encoded composite key into a context.  This is used for two 
   purposes, to load public key components into native contexts and to save 
   encoded public-key values for use in certs associated with non-native 
   contexts held in a device.  The latter is necessary because there's no 
   key data stored with the context itself, however it's necessary to have 
   SubjectPublicKeyInfo available for certificate requests/certificates.  
   Normally this is sufficient because cryptlib always generates native 
   contexts for public keys/certs, and for private keys the data is generated 
   in the device with the encoded public components attached to the context 
   as described above.
			   
   For DH keys this gets a bit more complex, since although the private key 
   is generated in the device, in the case of the DH responder this is only 
   the DH x value, with the parameters (p and g) being supplied externally 
   by the initiator.  This means that it's necessary to decode at least some 
   of the public key data in order to create the y value after the x value 
   has been generated in the device.

   The only situation where this functionality is currently needed is for the 
   SSHv2 code, which at the moment always uses native DH contexts.  For this 
   reason we leave off resolving this issue until it's actually required */

static int setKey( CONTEXT_INFO *contextInfoPtr, 
				   const CRYPT_ATTRIBUTE_TYPE keyType, const void *keyData, 
				   const int keyDataLen )
	{
	static const int actionFlags = \
		MK_ACTION_PERM( MESSAGE_CTX_SIGCHECK, ACTION_PERM_NONE_EXTERNAL ) | \

⌨️ 快捷键说明

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