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

📄 keyex.c

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

#if defined( INC_ALL )
  #include "crypt.h"
  #include "mech.h"
  #include "asn1.h"
  #include "asn1_ext.h"
  #include "misc_rw.h"
  #include "pgp_rw.h"
#else
  #include "crypt.h"
  #include "mechs/mech.h"
  #include "misc/asn1.h"
  #include "misc/asn1_ext.h"
  #include "misc/misc_rw.h"
  #include "misc/pgp_rw.h"
#endif /* Compiler-specific includes */

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

/* Try and determine the format of the encrypted data */

CHECK_RETVAL_ENUM( CRYPT_FORMAT ) STDC_NONNULL_ARG( ( 1 ) ) \
static CRYPT_FORMAT_TYPE getFormatType( IN_BUFFER( dataLength ) const void *data, 
										IN_LENGTH const int dataLength )
	{
	STREAM stream;
	long value;
	int status;

	assert( isReadPtr( data, dataLength ) );

	REQUIRES( dataLength > MIN_CRYPT_OBJECTSIZE && \
			  dataLength < MAX_INTLENGTH );

	sMemConnect( &stream, data, min( 16, dataLength ) );

	/* Figure out what we've got.  PKCS #7/CMS/SMIME keyTrans begins:

		keyTransRecipientInfo ::= SEQUENCE {
			version		INTEGER (0|2),

	   while a kek begins:

		kekRecipientInfo ::= [3] IMPLICIT SEQUENCE {
			version		INTEGER (0),

	   which allows us to determine which type of object we have.  Note that 
	   we use sPeek() rather than peekTag() because we want to continue
	   processing (or at least checking for) PGP data if it's no ASN.1 */
	if( sPeek( &stream ) == BER_SEQUENCE )
		{
		CRYPT_FORMAT_TYPE formatType;

		readSequence( &stream, NULL );
		status = readShortInteger( &stream, &value );
		if( cryptStatusError( status ) )
			{
			sMemDisconnect( &stream );
			return( CRYPT_FORMAT_NONE );
			}
		switch( value )
			{
			case KEYTRANS_VERSION:
				formatType = CRYPT_FORMAT_CMS;
				break;

			case KEYTRANS_EX_VERSION:
				formatType = CRYPT_FORMAT_CRYPTLIB;
				break;

			default:
				formatType = CRYPT_FORMAT_NONE;
			}
		sMemDisconnect( &stream );

		return( formatType );
		}
	if( sPeek( &stream ) == MAKE_CTAG( CTAG_RI_PWRI ) )
		{
		readConstructed( &stream, NULL, CTAG_RI_PWRI );
		status = readShortInteger( &stream, &value );
		if( cryptStatusError( status ) )
			{
			sMemDisconnect( &stream );
			return( CRYPT_FORMAT_NONE );
			}
		sMemDisconnect( &stream );

		return( ( value == PWRI_VERSION ) ? \
				CRYPT_FORMAT_CRYPTLIB : CRYPT_FORMAT_NONE );
		}

#ifdef USE_PGP
	/* It's not ASN.1 data, check for PGP data */
	status = pgpReadPacketHeader( &stream, NULL, &value, 30 );
	if( cryptStatusOK( status ) && value > 30 && value < 8192 )
		{
		sMemDisconnect( &stream );
		return( CRYPT_FORMAT_PGP );
		}
#endif /* USE_PGP */

	sMemDisconnect( &stream );

	return( CRYPT_FORMAT_NONE );
	}

/* Check the key wrap key being used to import/export a session key */

CHECK_RETVAL STDC_NONNULL_ARG( ( 2 ) ) \
static int checkWrapKey( IN_HANDLE int importKey, 
						 OUT_ALGO_Z CRYPT_ALGO_TYPE *cryptAlgo,
						 const BOOLEAN isImport )
	{
	CRYPT_ALGO_TYPE localCryptAlgo;
	int status;

	assert( isWritePtr( cryptAlgo, sizeof( CRYPT_ALGO_TYPE ) ) );

	REQUIRES( isHandleRangeValid( importKey ) );

	/* Clear return value */
	*cryptAlgo = CRYPT_ALGO_NONE;

	/* Make sure that the context is valid and get the algorithm being 
	   used */
	status = krnlSendMessage( importKey, MESSAGE_GETATTRIBUTE,
							  &localCryptAlgo, CRYPT_CTXINFO_ALGO );
	if( cryptStatusError( status ) )
		return( status );
	if( localCryptAlgo >= CRYPT_ALGO_FIRST_PKC && \
		localCryptAlgo <= CRYPT_ALGO_LAST_PKC )
		{
		/* The DLP algorithms have specialised data-formatting requirements
		   and can't normally be directly accessed via external messages,
		   and PKC operations in general may be restricted to internal access
		   only if they have certificates that restrict their use associated
		   with them.  However if we're performing a high-level key import 
		   (rather than a low-level raw context operation) this is OK since 
		   the low-level operation is being performed via these higher-level
		   routines which handle the formatting requirements.  Doing the 
		   check via an internal message is safe at this point since we've 
		   already checked the context's external accessibility when we got 
		   the algorithm info */
		status = krnlSendMessage( importKey, IMESSAGE_CHECK, NULL,
								  isImport ? MESSAGE_CHECK_PKC_DECRYPT : \
											 MESSAGE_CHECK_PKC_ENCRYPT );
		}
	else
		{
		status = krnlSendMessage( importKey, MESSAGE_CHECK, NULL,
								  MESSAGE_CHECK_CRYPT );
		}
	if( cryptStatusError( status ) )
		return( status );

	*cryptAlgo = localCryptAlgo;
	return( CRYPT_OK );
	}

/* Check that the context data is encodable using the chosen format */

CHECK_RETVAL \
static int checkContextsEncodable( IN_HANDLE const CRYPT_HANDLE exportKey,
								   IN_ALGO const CRYPT_ALGO_TYPE exportAlgo,
								   IN_HANDLE const CRYPT_CONTEXT sessionKeyContext,
								   IN_ENUM( CRYPT_FORMAT ) \
									const CRYPT_FORMAT_TYPE formatType )
	{
	CRYPT_ALGO_TYPE sessionKeyAlgo;
	CRYPT_MODE_TYPE sessionKeyMode = DUMMY_INIT, exportMode;
	const BOOLEAN exportIsPKC = ( exportAlgo >= CRYPT_ALGO_FIRST_PKC && \
								  exportAlgo <= CRYPT_ALGO_LAST_PKC ) ? \
								TRUE : FALSE;
	BOOLEAN sessionIsMAC = FALSE;
	int status;

	REQUIRES( isHandleRangeValid( exportKey ) );
	REQUIRES( exportAlgo > CRYPT_ALGO_NONE && exportAlgo < CRYPT_ALGO_LAST );
	REQUIRES( isHandleRangeValid( sessionKeyContext ) );
	REQUIRES( formatType > CRYPT_FORMAT_NONE && \
			  formatType < CRYPT_FORMAT_LAST_EXTERNAL );

	/* Get any required context information */
	status = krnlSendMessage( sessionKeyContext, MESSAGE_GETATTRIBUTE,
							  &sessionKeyAlgo, CRYPT_CTXINFO_ALGO );
	if( cryptStatusError( status ) )
		return( CRYPT_ERROR_PARAM3 );
	if( sessionKeyAlgo >= CRYPT_ALGO_FIRST_MAC && \
		sessionKeyAlgo <= CRYPT_ALGO_LAST_MAC )
		sessionIsMAC = TRUE;
	else
		{
		status = krnlSendMessage( sessionKeyContext, MESSAGE_GETATTRIBUTE,
								  &sessionKeyMode, CRYPT_CTXINFO_MODE );
		if( cryptStatusError( status ) )
			return( CRYPT_ERROR_PARAM3 );
		}

	switch( formatType )
		{
		case CRYPT_FORMAT_CRYPTLIB:
		case CRYPT_FORMAT_CMS:
		case CRYPT_FORMAT_SMIME:
			/* Check that the export algorithm is encodable */
			if( exportIsPKC )
				{
				if( cryptStatusError( sizeofAlgoID( exportAlgo ) ) )
					return( CRYPT_ERROR_PARAM1 );
				}
			else
				{
				/* If it's a conventional key export, the key wrap mechanism 
				   requires the use of CBC mode for the wrapping */
				status = krnlSendMessage( exportKey, MESSAGE_GETATTRIBUTE, 
										  &exportMode, CRYPT_CTXINFO_MODE );
				if( cryptStatusError( status ) )
					return( CRYPT_ERROR_PARAM1 );
				if( exportMode != CRYPT_MODE_CBC || \
					cryptStatusError( \
						sizeofAlgoIDex( exportAlgo, exportMode, 0 ) ) )
					return( CRYPT_ERROR_PARAM1 );
				}

			/* Check that the session-key algorithm is encodable */
			if( sessionIsMAC )
				status = sizeofAlgoID( sessionKeyAlgo );
			else
				status = checkAlgoID( sessionKeyAlgo, sessionKeyMode );
			if( cryptStatusError( status ) )
				return( CRYPT_ERROR_PARAM3 );

			return( CRYPT_OK );

#ifdef USE_PGP
		case CRYPT_FORMAT_PGP:
			{
			int dummy;

			/* Check that the export algorithm is encodable */
			if( cryptStatusError( \
					cryptlibToPgpAlgo( exportAlgo, &dummy ) ) )
				return( CRYPT_ERROR_PARAM1 );

			/* Check that the session-key algorithm is encodable */
			if( exportIsPKC )
				{
				if( cryptStatusError( \
						cryptlibToPgpAlgo( sessionKeyAlgo, &dummy ) ) )
					return( CRYPT_ERROR_PARAM3 );
				if( sessionKeyMode != CRYPT_MODE_CFB )
					return( CRYPT_ERROR_PARAM3 );
				}
			else
				{
				/* If it's a conventional key export there's no key wrap as 
				   in CMS (the session-key context isn't used), so the 
				   "export context" mode must be CFB */
				status = krnlSendMessage( exportKey, MESSAGE_GETATTRIBUTE, 
										  &exportMode, CRYPT_CTXINFO_MODE );
				if( cryptStatusError( status ) || \
					exportMode != CRYPT_MODE_CFB )
					return( CRYPT_ERROR_PARAM1 );
				}

			return( CRYPT_OK );
			}
#endif /* USE_PGP */
		}
	
	/* It's an invalid/unknown format, we can't check the encodability of 
	   the context data */
	return( CRYPT_ERROR_PARAM4 );
	}

/****************************************************************************
*																			*
*								Import a Session Key						*
*																			*
****************************************************************************/

/* Import an extended encrypted key, either a cryptlib key or a CMS key */

C_RET cryptImportKeyEx( C_IN void C_PTR encryptedKey,
						C_IN int encryptedKeyLength,
						C_IN CRYPT_CONTEXT importKey,
						C_IN CRYPT_CONTEXT sessionKeyContext,
						C_OUT CRYPT_CONTEXT C_PTR returnedContext )
	{
	CRYPT_CONTEXT iReturnedContext;
	CRYPT_FORMAT_TYPE formatType;
	CRYPT_ALGO_TYPE importAlgo;
	int owner, originalOwner, status;

	/* Perform basic error checking */
	if( encryptedKeyLength <= MIN_CRYPT_OBJECTSIZE || \
		encryptedKeyLength >= MAX_INTLENGTH_SHORT )
		return( CRYPT_ERROR_PARAM2 );
	if( !isReadPtr( encryptedKey, encryptedKeyLength ) )
		return( CRYPT_ERROR_PARAM1 );
	if( ( formatType = \
			getFormatType( encryptedKey, encryptedKeyLength ) ) == CRYPT_FORMAT_NONE )
		return( CRYPT_ERROR_BADDATA );
	if( !isHandleRangeValid( importKey ) )
		return( CRYPT_ERROR_PARAM3 );
	if( sessionKeyContext != CRYPT_UNUSED && \
		!isHandleRangeValid( sessionKeyContext ) )
		return( CRYPT_ERROR_PARAM4 );

	/* Check the importing key */
	status = checkWrapKey( importKey, &importAlgo, TRUE );
	if( cryptStatusError( status ) )
		return( cryptArgError( status ) ? CRYPT_ERROR_PARAM3 : status );

	/* Check the session key */
	if( formatType == CRYPT_FORMAT_PGP )
		{
		/* PGP stores the session key information with the encrypted key
		   data, so the user can't provide a context */
		if( sessionKeyContext != CRYPT_UNUSED )
			return( CRYPT_ERROR_PARAM4 );
		if( !isWritePtr( returnedContext, sizeof( CRYPT_CONTEXT ) ) )
			return( CRYPT_ERROR_PARAM5 );
		*returnedContext = CRYPT_ERROR;
		}
	else
		{
		CRYPT_ALGO_TYPE sessionKeyAlgo;

		status = krnlSendMessage( sessionKeyContext, MESSAGE_GETATTRIBUTE,
								  &sessionKeyAlgo, CRYPT_CTXINFO_ALGO );
		if( cryptStatusOK( status ) )
			{
			status = krnlSendMessage( sessionKeyContext, MESSAGE_CHECK, NULL,
							( sessionKeyAlgo >= CRYPT_ALGO_FIRST_MAC ) ? \
								MESSAGE_CHECK_MAC_READY : \
								MESSAGE_CHECK_CRYPT_READY );
			}
		if( cryptStatusError( status ) )
			return( cryptArgError( status ) ? CRYPT_ERROR_PARAM4 : status );
		if( returnedContext != NULL )
			return( CRYPT_ERROR_PARAM5 );
		}

	/* If the importing key is owned, bind the session key context to the same
	   owner before we load a key into it.  We also need to save the original
	   owner so that we can undo the binding later if things fail */
	status = krnlSendMessage( sessionKeyContext, MESSAGE_GETATTRIBUTE,
							  &originalOwner, CRYPT_PROPERTY_OWNER );
	if( cryptStatusError( status ) )
		originalOwner = CRYPT_ERROR;	/* Non-owned object */
	status = krnlSendMessage( importKey, MESSAGE_GETATTRIBUTE, &owner,
							  CRYPT_PROPERTY_OWNER );
	if( cryptStatusOK( status ) )
		{

⌨️ 快捷键说明

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