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

📄 keyex.c

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

#include <string.h>
#include <stdlib.h>
#if defined( INC_ALL )
  #include "crypt.h"
  #include "pgp.h"
  #include "mechanism.h"
  #include "asn1.h"
  #include "asn1_ext.h"
  #include "misc_rw.h"
#elif defined( INC_CHILD )
  #include "../crypt.h"
  #include "../envelope/pgp.h"
  #include "mechanism.h"
  #include "../misc/asn1.h"
  #include "../misc/asn1_ext.h"
  #include "../misc/misc_rw.h"
#else
  #include "crypt.h"
  #include "envelope/pgp.h"
  #include "mechs/mechanism.h"
  #include "misc/asn1.h"
  #include "misc/asn1_ext.h"
  #include "misc/misc_rw.h"
#endif /* Compiler-specific includes */

/****************************************************************************
*																			*
*							Low-level Key Export Functions					*
*																			*
****************************************************************************/

/* Export a conventionally encrypted session key */

static int exportConventionalKey( void *encryptedKey, int *encryptedKeyLength,
								  const int encryptedKeyMaxLength,
								  const CRYPT_CONTEXT iSessionKeyContext,
								  const CRYPT_CONTEXT iExportContext,
								  const KEYEX_TYPE keyexType )
	{
	MECHANISM_WRAP_INFO mechanismInfo;
	const WRITEKEK_FUNCTION writeKeyexFunction = \
										kekWriteTable[ keyexType ];
	BYTE buffer[ CRYPT_MAX_KEYSIZE + 16 ];
	int keySize, ivSize, status;

	/* Make sure the requested key exchange format is available */
	if( writeKeyexFunction == NULL )
		return( CRYPT_ERROR_NOTAVAIL );

	/* PGP doesn't actually wrap up a key but derives the session key 
	   directly from the password.  Because of this there isn't any key
	   wrapping to be done, so we just write the key derivation parameters
	   and exit */
	if( keyexType == KEYEX_PGP )
		{
		STREAM stream;

		sMemOpen( &stream, encryptedKey, encryptedKeyMaxLength );
		status = writeKeyexFunction( &stream, iExportContext, NULL, 0 );
		*encryptedKeyLength = stell( &stream );
		sMemDisconnect( &stream );

		return( status );
		}

	status = krnlSendMessage( iSessionKeyContext, IMESSAGE_GETATTRIBUTE, 
							  &keySize, CRYPT_CTXINFO_KEYSIZE );
	if( cryptStatusError( status ) )
		return( ( status == CRYPT_ARGERROR_OBJECT ) ? \
				CRYPT_ARGERROR_NUM1 : status );
	if( cryptStatusError( krnlSendMessage( iExportContext, 
										   IMESSAGE_GETATTRIBUTE, &ivSize, 
										   CRYPT_CTXINFO_IVSIZE ) ) )
		ivSize = 0;

	/* If we're just doing a length check, write the data to a null stream
	   and return its length */
	if( encryptedKey == NULL )
		{
		STREAM nullStream;
		int dummyDataSize;

		/* Calculate the eventual encrypted key size */
		setMechanismWrapInfo( &mechanismInfo, NULL, 0,
							  NULL, 0, iSessionKeyContext, iExportContext,
							  CRYPT_UNUSED );
		status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_EXPORT, 
								  &mechanismInfo, MECHANISM_ENC_CMS );
		dummyDataSize = mechanismInfo.wrappedDataLength;
		clearMechanismInfo( &mechanismInfo );
		if( cryptStatusError( status ) )
			return( status );

		/* Generate an IV to allow the KEK write to succeed - see the comment
		   below about this */
		if( ivSize )
			krnlSendNotifier( iExportContext, IMESSAGE_CTX_GENIV );

		/* Write the data to a null stream to determine its size.  The 
		   buffer doesn't contain anything useful since it's only used for a 
		   size check */
		sMemOpen( &nullStream, NULL, 0 );
		status = writeKeyexFunction( &nullStream, iExportContext, buffer,
									 dummyDataSize );
		*encryptedKeyLength = stell( &nullStream );
		sMemClose( &nullStream );

		return( status );
		}

	/* Load an IV into the exporting context.  This is somewhat nasty in that
	   a side-effect of exporting a key is to load an IV into the exporting
	   context which isn't really part of the function's job description.  
	   The alternative is to require the user to explicitly load an IV before
	   exporting the key, which is equally nasty (they'll never remember).  
	   The lesser of the two evils is to load the IV here and assume that 
	   anyone loading the IV themselves will read the docs which warn about 
	   the side-effects of exporting a key.

	   Note that we always load a new IV when we export a key because the
	   caller may be using the context to exchange multiple keys.  Since each
	   exported key requires its own IV, we perform an unconditional reload.
	   In addition because we don't want another thread coming along and
	   changing the IV while we're in the process of encrypting with it, we
	   lock the exporting key object until the encryption has completed and 
	   the IV is written to the output */
	status = krnlSendMessage( iExportContext, IMESSAGE_SETATTRIBUTE,
							  MESSAGE_VALUE_TRUE, CRYPT_IATTRIBUTE_LOCKED );
	if( cryptStatusError( status ) )
		return( status );
	if( ivSize )
		krnlSendNotifier( iExportContext, IMESSAGE_CTX_GENIV );

	/* Encrypt the session key and write the result to the output stream */
	setMechanismWrapInfo( &mechanismInfo, buffer, CRYPT_MAX_KEYSIZE + 16,
						  NULL, 0, iSessionKeyContext, iExportContext,
						  CRYPT_UNUSED );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_EXPORT, 
							  &mechanismInfo, MECHANISM_ENC_CMS );
	if( cryptStatusOK( status ) )
		{
		STREAM stream;

		sMemOpen( &stream, encryptedKey, encryptedKeyMaxLength );
		status = writeKeyexFunction( &stream, iExportContext, 
									 mechanismInfo.wrappedData, 
									 mechanismInfo.wrappedDataLength );
		*encryptedKeyLength = stell( &stream );
		sMemDisconnect( &stream );
		}
	krnlSendMessage( iExportContext, IMESSAGE_SETATTRIBUTE, 
					 MESSAGE_VALUE_FALSE, CRYPT_IATTRIBUTE_LOCKED );
	clearMechanismInfo( &mechanismInfo );
	zeroise( buffer, CRYPT_MAX_KEYSIZE + 16 );
	return( status );
	}

/* Export a public-key encrypted session key */

static int exportPublicKey( void *encryptedKey, int *encryptedKeyLength,
							const int encryptedKeyMaxLength,
							const CRYPT_CONTEXT iSessionKeyContext,
							const CRYPT_CONTEXT iExportContext,
							const void *auxInfo, const int auxInfoLength,
							const KEYEX_TYPE keyexType )
	{
	MECHANISM_WRAP_INFO mechanismInfo;
	const WRITEKEYTRANS_FUNCTION writeKeyexFunction = \
										keytransWriteTable[ keyexType ];
	BYTE buffer[ MAX_PKCENCRYPTED_SIZE + 8 ];
	int keySize, status;

	/* Make sure the requested key exchange format is available */
	if( writeKeyexFunction == NULL )
		return( CRYPT_ERROR_NOTAVAIL );

	status = krnlSendMessage( iSessionKeyContext, IMESSAGE_GETATTRIBUTE, 
							  &keySize, CRYPT_CTXINFO_KEYSIZE );
	if( cryptStatusError( status ) )
		return( ( status == CRYPT_ARGERROR_OBJECT ) ? \
				CRYPT_ARGERROR_NUM1 : status );

	/* If we're just doing a length check, write the data to a null stream
	   and return its length */
	if( encryptedKey == NULL )
		{
		STREAM nullStream;
		int dummyDataSize;

		/* Calculate the eventual encrypted key size */
		setMechanismWrapInfo( &mechanismInfo, NULL, 0, NULL, 0, 
							  iSessionKeyContext, iExportContext,
							  CRYPT_UNUSED );
		status = krnlSendMessage( iExportContext, IMESSAGE_DEV_EXPORT, 
								  &mechanismInfo, 
								  ( keyexType == KEYEX_PGP ) ? \
									MECHANISM_ENC_PKCS1_PGP : \
									MECHANISM_ENC_PKCS1 );
		dummyDataSize = mechanismInfo.wrappedDataLength;
		clearMechanismInfo( &mechanismInfo );
		if( cryptStatusError( status ) )
			return( status );

		/* Write the data to a null stream to determine its size.  The 
		   buffer doesn't contain anything useful since it's only used for a 
		   size check */
		sMemOpen( &nullStream, NULL, 0 );
		status = writeKeyexFunction( &nullStream, iExportContext, buffer,
									 dummyDataSize, auxInfo, auxInfoLength );
		if( cryptStatusOK( status ) )
			*encryptedKeyLength = stell( &nullStream );
		sMemClose( &nullStream );

		return( status );
		}

	/* Encrypt the session key and write the result to the output stream */
	setMechanismWrapInfo( &mechanismInfo, buffer, MAX_PKCENCRYPTED_SIZE, 
						  NULL, 0, iSessionKeyContext, iExportContext, 
						  CRYPT_UNUSED );
	status = krnlSendMessage( iExportContext, IMESSAGE_DEV_EXPORT, 
							  &mechanismInfo, ( keyexType == KEYEX_PGP ) ? \
								MECHANISM_ENC_PKCS1_PGP : \
								MECHANISM_ENC_PKCS1 );
	if( cryptStatusOK( status ) )
		{
		STREAM stream;

		sMemOpen( &stream, encryptedKey, encryptedKeyMaxLength );
		status = writeKeyexFunction( &stream, iExportContext, 
									 mechanismInfo.wrappedData, 
									 mechanismInfo.wrappedDataLength, 
									 auxInfo, auxInfoLength );
		if( cryptStatusOK( status ) )
			*encryptedKeyLength = stell( &stream );
		sMemDisconnect( &stream );
		}
	clearMechanismInfo( &mechanismInfo );

	/* Clean up */
	zeroise( buffer, MAX_PKCENCRYPTED_SIZE );
	return( status );
	}

#if 0	/* 24/11/02 Removed since it was only used for Fortezza */

/* Export a key agreement key */

static int exportKeyAgreeKey( void *encryptedKey, int *encryptedKeyLength,
							  const int encryptedKeyMaxLength,
							  const CRYPT_CONTEXT iSessionKeyContext,
							  const CRYPT_CONTEXT iExportContext,
							  const CRYPT_CONTEXT iAuxContext,
							  const void *auxInfo, const int auxInfoLength )
	{
	CRYPT_ALGO_TYPE keyAgreeAlgo;
	MECHANISM_WRAP_INFO mechanismInfo;
	BYTE buffer[ CRYPT_MAX_PKCSIZE + 8 ];
	int wrappedKeyLen, ukmLen, status;

	/* Extract general information */
	status = krnlSendMessage( iExportContext, IMESSAGE_GETATTRIBUTE,
							  &keyAgreeAlgo, CRYPT_CTXINFO_ALGO );
	if( cryptStatusError( status ) )
		return( ( status == CRYPT_ARGERROR_OBJECT ) ? \
				CRYPT_ARGERROR_NUM2 : status );

	/* If we're just doing a length check, write the data to a null stream
	   and return its length */
	if( encryptedKey == NULL )
		{
		STREAM nullStream;

		/* Calculate the eventual encrypted key size */
		setMechanismWrapInfo( &mechanismInfo, NULL, 0,
							  NULL, 0, iSessionKeyContext, iExportContext,
							  iAuxContext );
		status = krnlSendMessage( iExportContext, IMESSAGE_DEV_EXPORT, 
								  &mechanismInfo, MECHANISM_KEA );
		wrappedKeyLen = mechanismInfo.wrappedDataLength >> 8;
		ukmLen = mechanismInfo.wrappedDataLength & 0xFF;
		clearMechanismInfo( &mechanismInfo );
		if( cryptStatusError( status ) )
			return( status );

		/* Write the data to a null stream to determine its size.  The 
		   buffer doesn't contain anything useful since it's only used for a 
		   size check */
		sMemOpen( &nullStream, NULL, 0 );
		status = writeKeyAgreeInfo( &nullStream, iExportContext, 
									buffer, wrappedKeyLen, buffer, 
									ukmLen, auxInfo, auxInfoLength );
		if( cryptStatusOK( status ) )
			*encryptedKeyLength = stell( &nullStream );
		sMemClose( &nullStream );

		return( status );
		}

	/* Export the session key and write the result to the output stream */
	setMechanismWrapInfo( &mechanismInfo, buffer, CRYPT_MAX_PKCSIZE,
						  NULL, 0, iSessionKeyContext, iExportContext,
						  iAuxContext );
	status = krnlSendMessage( iExportContext, IMESSAGE_DEV_EXPORT, 
							  &mechanismInfo, MECHANISM_KEA );
	if( cryptStatusOK( status ) )
		{
		STREAM stream;

		/* Extract the length information */
		wrappedKeyLen = mechanismInfo.wrappedDataLength >> 8;
		ukmLen = mechanismInfo.wrappedDataLength & 0xFF;

		sMemOpen( &stream, encryptedKey, encryptedKeyMaxLength );
		status = writeKeyAgreeInfo( &stream, iExportContext, buffer, 
									wrappedKeyLen, buffer, ukmLen, auxInfo, 
									auxInfoLength );
		if( cryptStatusOK( status ) )
			*encryptedKeyLength = stell( &stream );
		sMemDisconnect( &stream );
		}
	clearMechanismInfo( &mechanismInfo );

	/* Clean up */
	zeroise( buffer, CRYPT_MAX_PKCSIZE );
	return( status );
	}
#endif /* 0 */

/****************************************************************************
*																			*
*							Low-level Key Import Functions					*
*																			*
****************************************************************************/

/* Import a conventionally encrypted session key */

static int importConventionalKey( const void *encryptedKey,
								  const int encryptedKeyLength,
								  const CRYPT_CONTEXT iSessionKeyContext,
								  const CRYPT_CONTEXT iImportContext,
								  const KEYEX_TYPE keyexType )
	{
	CRYPT_ALGO_TYPE cryptAlgo;
	CRYPT_MODE_TYPE cryptMode;
	MECHANISM_WRAP_INFO mechanismInfo;
	const READKEK_FUNCTION readKeyexFunction = \
										kekReadTable[ keyexType ];
	QUERY_INFO queryInfo;
	RESOURCE_DATA msgData;
	STREAM stream;
	int status;

	/* Make sure the requested key exchange format is available */
	if( readKeyexFunction == NULL )
		return( CRYPT_ERROR_NOTAVAIL );

	/* Get information on the importing key */
	krnlSendMessage( iImportContext, IMESSAGE_GETATTRIBUTE, &cryptAlgo, 
					 CRYPT_CTXINFO_ALGO );
	status = krnlSendMessage( iImportContext, IMESSAGE_GETATTRIBUTE, 

⌨️ 快捷键说明

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