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

📄 mech_pkwrap.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 3 页
字号:

	return( CRYPT_OK );
	}

/* Perform PKCS #1 wrapping/unwrapping.  There are several variations of
   this that are handled through common PKCS #1 mechanism functions */

typedef enum { PKCS1_WRAP_NONE, PKCS1_WRAP_NORMAL, PKCS1_WRAP_RAW, 
			   PKCS1_WRAP_PGP, PKCS1_WRAP_LAST } PKCS1_WRAP_TYPE;

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int pkcs1Wrap( INOUT MECHANISM_WRAP_INFO *mechanismInfo,
					  IN_ENUM( PKCS1_WRAP ) const PKCS1_WRAP_TYPE type )
	{
	CRYPT_ALGO_TYPE cryptAlgo;
	BYTE *wrappedData = mechanismInfo->wrappedData, *dataPtr;
	int payloadSize, length, dataBlockSize, status;
#ifdef USE_PGP
	int pgpAlgoID = DUMMY_INIT;
#endif /* USE_PGP */

	assert( isWritePtr( mechanismInfo, sizeof( MECHANISM_WRAP_INFO ) ) );

	REQUIRES( type > PKCS1_WRAP_NONE && type < PKCS1_WRAP_LAST );

	/* Clear return value */
	if( mechanismInfo->wrappedData != NULL )
		{
		memset( mechanismInfo->wrappedData, 0,
				mechanismInfo->wrappedDataLength );
		}

	/* Get various algorithm parameters */
	status = getPkcAlgoParams( mechanismInfo->wrapContext, &cryptAlgo, 
							   &length );
	if( cryptStatusError( status ) )
		return( status );

	/* If this is just a length check, we're done */
	if( mechanismInfo->wrappedData == NULL )
		{
		/* Determine how long the encrypted value will be.  In the case of
		   Elgamal it's just an estimate since it can change by up to two
		   bytes depending on whether the values have the high bit set or
		   not, which requires zero-padding of the ASN.1-encoded integers.
		   This is rather nasty because it means that we can't tell how 
		   large an encrypted value will be without actually creating it.  
		   The 10-byte length at the start is for the ASN.1 SEQUENCE (= 4) 
		   and 2 * INTEGER (= 2*3) encoding */
		mechanismInfo->wrappedDataLength = \
							( cryptAlgo == CRYPT_ALGO_ELGAMAL ) ? \
							10 + ( 2 * ( length + 1 ) ) : length;
		return( CRYPT_OK );
		}

	/* Make sure that there's enough room for the wrapped key data */
	if( length > mechanismInfo->wrappedDataLength )
		return( CRYPT_ERROR_OVERFLOW );

	/* Get the payload details, either as data passed in by the caller or
	   from the key context */
	if( type == PKCS1_WRAP_RAW )
		payloadSize = mechanismInfo->keyDataLength;
	else
		{
		status = krnlSendMessage( mechanismInfo->keyContext,
								  IMESSAGE_GETATTRIBUTE, &payloadSize,
								  CRYPT_CTXINFO_KEYSIZE );
		if( cryptStatusError( status ) )
			return( status );
		}
#ifdef USE_PGP
	if( type == PKCS1_WRAP_PGP )
		{
		CRYPT_ALGO_TYPE sessionKeyAlgo;

		/* PGP includes an additional algorithm specifier and checksum with
		   the wrapped key so we adjust the length to take this into
		   account */
		status = krnlSendMessage( mechanismInfo->keyContext,
								  IMESSAGE_GETATTRIBUTE, &sessionKeyAlgo,
								  CRYPT_CTXINFO_ALGO );
		if( cryptStatusOK( status ) )
			status = cryptlibToPgpAlgo( sessionKeyAlgo, &pgpAlgoID );
		if( cryptStatusError( status ) )
			return( status );
		payloadSize += 3;	/* 1-byte algo ID + 2-byte checksum */
		}
#endif /* USE_PGP */

	/* Perform a preliminary check for an excessively long payload to make
	   it explicit, however generatePkcs1DataBlock() will also perform a 
	   more precise check when it performs the data formatting */
	if( payloadSize >= length )
		return( CRYPT_ERROR_OVERFLOW );

	/* Generate the PKCS #1 data block with room for the payload at the end */
	status = generatePkcs1DataBlock( wrappedData, length, &dataBlockSize, 
									 payloadSize );
	if( cryptStatusError( status ) )
		{
		zeroise( wrappedData, length );
		return( status );
		}
	ENSURES( dataBlockSize + payloadSize == length );

	/* Copy the payload in at the last possible moment, then encrypt it */
	dataPtr = wrappedData + dataBlockSize;
	switch( type )
		{
		case PKCS1_WRAP_NORMAL:
			status = extractKeyData( mechanismInfo->keyContext, dataPtr,
									 payloadSize, "keydata", 7 );
			break;

		case PKCS1_WRAP_RAW:
			memcpy( dataPtr, mechanismInfo->keyData, payloadSize );
			break;

#ifdef USE_PGP
		case PKCS1_WRAP_PGP:
			*dataPtr++ = pgpAlgoID;
			status = extractKeyData( mechanismInfo->keyContext, dataPtr,
									 payloadSize - 3, "keydata", 7 );
			if( cryptStatusOK( status ) )
				{
				status = pgpGenerateChecksum( dataPtr, payloadSize - 1,
									payloadSize - ( 1 + UINT16_SIZE ) );
				}
			break;
#endif /* USE_PGP */

		default:
			retIntError();
		}
	if( cryptStatusError( status ) )
		{
		zeroise( wrappedData, length );
		return( status );
		}

	/* Wrap the encoded data using the public key */
	return( pkcWrapData( mechanismInfo, wrappedData, length,
						 ( type == PKCS1_WRAP_PGP ) ? TRUE : FALSE,
						 ( cryptAlgo == CRYPT_ALGO_ELGAMAL ) ? TRUE : FALSE ) );
	}

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int pkcs1Unwrap( INOUT MECHANISM_WRAP_INFO *mechanismInfo,
						IN_ENUM( PKCS1_WRAP ) const PKCS1_WRAP_TYPE type )
	{
	CRYPT_ALGO_TYPE cryptAlgo;
	MESSAGE_DATA msgData;
	BYTE decryptedData[ CRYPT_MAX_PKCSIZE + 8 ];
	const BYTE *payloadPtr;
	int length, dataBlockSize, status;

	assert( isWritePtr( mechanismInfo, sizeof( MECHANISM_WRAP_INFO ) ) );

	REQUIRES( type > PKCS1_WRAP_NONE && type < PKCS1_WRAP_LAST );

	/* Clear the return value if we're returning raw data */
	if( type == PKCS1_WRAP_RAW )
		memset( mechanismInfo->keyData, 0, mechanismInfo->keyDataLength );

	/* Get various algorithm parameters */
	status = getPkcAlgoParams( mechanismInfo->wrapContext, &cryptAlgo, 
							   &length );
	if( cryptStatusError( status ) )
		return( status );

	/* Decrypt the data */
	status = pkcUnwrapData( mechanismInfo, decryptedData, CRYPT_MAX_PKCSIZE,
							&length, length, 
							( type == PKCS1_WRAP_PGP ) ? TRUE : FALSE,
							( cryptAlgo == CRYPT_ALGO_ELGAMAL ) ? TRUE : FALSE );
	if( cryptStatusError( status ) )
		return( status );

	/* Recover the PKCS #1 data block, with the payload at the end */
	status = recoverPkcs1DataBlock( decryptedData, length, &dataBlockSize );
	if( cryptStatusError( status ) )
		{
		zeroise( decryptedData, CRYPT_MAX_PKCSIZE );
		return( status );
		}
	payloadPtr = decryptedData + dataBlockSize;
	length -= dataBlockSize;

	/* Return the result to the caller or load it into a context as a key */
	switch( type )
		{
#ifdef USE_PGP
		case PKCS1_WRAP_PGP:
			/* PGP includes extra wrapping around the key so we have to
			   process that before we can load it */
			status = pgpExtractKey( &mechanismInfo->keyContext, payloadPtr, 
									length );
			if( cryptStatusError( status ) )
				break;
			payloadPtr++;		/* Skip algorithm ID */
			length -= 3;		/* Subtract extra wrapping length */
			if( length < MIN_KEYSIZE )
				return( CRYPT_ERROR_BADDATA );
			/* Fall through */
#endif /* USE_PGP */

		case PKCS1_WRAP_NORMAL:
			/* Load the decrypted keying information into the session key
			   context */
			setMessageData( &msgData, ( void * ) payloadPtr, length );
			status = krnlSendMessage( mechanismInfo->keyContext,
									  IMESSAGE_SETATTRIBUTE_S, &msgData,
									  CRYPT_CTXINFO_KEY );
			if( cryptArgError( status ) )
				{
				/* If there was an error with the key value or size convert 
				   the return value into something more appropriate */
				status = CRYPT_ERROR_BADDATA;
				}
			break;

		case PKCS1_WRAP_RAW:
			/* Return the result to the caller */
			if( length > mechanismInfo->keyDataLength )
				status = CRYPT_ERROR_OVERFLOW;
			else
				{
				memcpy( mechanismInfo->keyData, payloadPtr, length );
				mechanismInfo->keyDataLength = length;
				}
			break;

		default:
			retIntError();
		}
	zeroise( decryptedData, CRYPT_MAX_PKCSIZE );

	return( status );
	}

CHECK_RETVAL STDC_NONNULL_ARG( ( 2 ) ) \
int exportPKCS1( STDC_UNUSED void *dummy, 
				 INOUT MECHANISM_WRAP_INFO *mechanismInfo )
	{
	UNUSED_ARG( dummy );

	assert( isWritePtr( mechanismInfo, sizeof( MECHANISM_WRAP_INFO ) ) );

	return( pkcs1Wrap( mechanismInfo,
					   ( mechanismInfo->keyContext == CRYPT_UNUSED ) ? \
					   PKCS1_WRAP_RAW : PKCS1_WRAP_NORMAL ) );
	}

CHECK_RETVAL STDC_NONNULL_ARG( ( 2 ) ) \
int importPKCS1( STDC_UNUSED void *dummy, 
				 INOUT MECHANISM_WRAP_INFO *mechanismInfo )
	{
	UNUSED_ARG( dummy );

	assert( isWritePtr( mechanismInfo, sizeof( MECHANISM_WRAP_INFO ) ) );

	return( pkcs1Unwrap( mechanismInfo,
						 ( mechanismInfo->keyData != NULL ) ? \
						 PKCS1_WRAP_RAW : PKCS1_WRAP_NORMAL ) );
	}

#ifdef USE_PGP

CHECK_RETVAL STDC_NONNULL_ARG( ( 2 ) ) \
int exportPKCS1PGP( STDC_UNUSED void *dummy, 
					INOUT MECHANISM_WRAP_INFO *mechanismInfo )
	{
	UNUSED_ARG( dummy );

	assert( isWritePtr( mechanismInfo, sizeof( MECHANISM_WRAP_INFO ) ) );

	return( pkcs1Wrap( mechanismInfo, PKCS1_WRAP_PGP ) );
	}

CHECK_RETVAL STDC_NONNULL_ARG( ( 2 ) ) \
int importPKCS1PGP( STDC_UNUSED void *dummy, 
					INOUT MECHANISM_WRAP_INFO *mechanismInfo )
	{
	UNUSED_ARG( dummy );

	assert( isWritePtr( mechanismInfo, sizeof( MECHANISM_WRAP_INFO ) ) );

	return( pkcs1Unwrap( mechanismInfo, PKCS1_WRAP_PGP ) );
	}
#endif /* USE_PGP */

/****************************************************************************
*																			*
*							OAEP Key Wrap/Unwrap Mechanisms					*
*																			*
****************************************************************************/

/* If OAEP is used with SHA2-512 in the PRF then the standard 
   CRYPT_MAX_HASHSIZE value isn't sufficient to contain the hash data any 
   more so we have to define a special larger-than-normal maximum hash size 
   to contain it */

#define OAEP_MAX_HASHSIZE	64

/* Get the lHash value used for OAEP.  In theory this should be a hash of a 
   label applied to the OAEP operation but this is never used so what ends
   up being used is a fixed hash of an empty string.  Since this is 
   constant we can use a pre-calculated value for each hash algorithm */

typedef struct {
	const CRYPT_ALGO_TYPE hashAlgo;
	BUFFER_FIXED( lHashSize ) \
	const BYTE FAR_BSS *lHash;
	const int lHashSize;
	} LHASH_INFO;

static const LHASH_INFO FAR_BSS lHashInfo[] = {
	{ CRYPT_ALGO_SHA1, ( const BYTE * )		/* For pedantic compilers */
	  "\xDA\x39\xA3\xEE\x5E\x6B\x4B\x0D\x32\x55\xBF\xEF\x95\x60\x18\x90"
	  "\xAF\xD8\x07\x09", 20 },
	{ CRYPT_ALGO_SHA2, ( const BYTE * )		/* For pedantic compilers */
	  "\xE3\xB0\xC4\x42\x98\xFC\x1C\x14\x9A\xFB\xF4\xC8\x99\x6F\xB9\x24"
	  "\x27\xAE\x41\xE4\x64\x9B\x93\x4C\xA4\x95\x99\x1B\x78\x52\xB8\x55", 32 },
#ifdef USE_SHA2_512
	  /* SHA2-512 is only available on systems with 64-bit data type support, 
	     at the moment this is only used internally for some PRFs so we have 
		 to identify it via a kludge on the SHA2 algorithm ID */
	{ CRYPT_ALGO_SHA2 + 1, ( const BYTE * )	/* For pedantic compilers */
	  "\xCF\x83\xE1\x35\x7E\xEF\xB8\xBD\xF1\x54\x28\x50\xD6\x6D\x80\x07"
	  "\xD6\x20\xE4\x05\x0B\x57\x15\xDC\x83\xF4\xA9\x21\xD3\x6C\xE9\xCE"
	  "\x47\xD0\xD1\x3C\x5D\x85\xF2\xB0\xFF\x83\x18\xD2\x87\x7E\xEC\x2F"
	  "\x63\xB9\x31\xBD\x47\x41\x7A\x81\xA5\x38\x32\x7A\xF9\x27\xDA\x3E", 64 },
#endif /* USE_SHA2_512 */
	{ CRYPT_ALGO_NONE, NULL, 0 }, { CRYPT_ALGO_NONE, NULL, 0 }
	};

CHECK_RETVAL STDC_NONNULL_ARG( ( 3 ) ) \
static int getOaepHash( OUT_BUFFER_OPT( lHashMaxLen, *lHashLen ) void *lHash, 
						IN_LENGTH_SHORT_Z const int lHashMaxLen, 
						OUT_LENGTH_SHORT_Z int *lHashLen,
						IN_ALGO const CRYPT_ALGO_TYPE hashAlgo )
	{
	int i;

	assert( ( lHash == NULL && lHashMaxLen == 0 ) || \
			isWritePtr( lHash, lHashMaxLen ) );
	
	REQUIRES( ( lHash == NULL && lHashMaxLen == 0 ) || \
			  ( lHashMaxLen >= OAEP_MAX_HASHSIZE && \
				lHashMaxLen < MAX_INTLENGTH_SHORT ) );
	REQUIRES( hashAlgo >= CRYPT_ALGO_FIRST_HASH && \
			  hashAlgo <= CRYPT_ALGO_LAST_HASH );

	/* Clear return value */
	if( lHash != NULL )
		zeroise( lHash, lHashMaxLen );
	*lHashLen = 0;

	for( i = 0; lHashInfo[ i ].hashAlgo != CRYPT_ALGO_NONE && \
				i < FAILSAFE_ARRAYSIZE( lHashInfo, LHASH_INFO ); i++ )
		{
		if( lHashInfo[ i ].hashAlgo == hashAlgo )
			{
			if( lHash != NULL )
				{
				memcpy( lHash, lHashInfo[ i ].lHash, 
						lHashInfo[ i ].lHashSize );
				}
			*lHashLen = lHashInfo[ i ].lHashSize;

			return( CRYPT_OK );
			}
		}
	ENSURES( i < FAILSAFE_ARRAYSIZE( lHashInfo, LHASH_INFO ) );
	if( lHash != NULL )
		zeroise( lHash, lHashMaxLen );

	return( CRYPT_ERROR_NOTAVAIL );
	}

#define getOaepHashSize( hashLen, hashAlgo ) \
		getOaepHash( NULL, 0, hashLen, hashAlgo )

/* OAEP mask generation function MGF1 */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
static int mgf1( OUT_BUFFER_FIXED( maskLen ) void *mask, 
				 IN_LENGTH_PKC const int maskLen, 
				 IN_BUFFER( seedLen ) const void *seed, 
				 IN_LENGTH_PKC const int seedLen,
				 IN_ALGO const CRYPT_ALGO_TYPE hashAlgo )
	{
	HASHFUNCTION hashFunction;
	HASHINFO hashInfo;
	BYTE countBuffer[ 4 + 8 ], maskBuffer[ OAEP_MAX_HASHSIZE + 8 ];
	BYTE *maskOutPtr = mask;
	int hashSize, maskIndex, blockCount = 0, iterationCount;

	assert( isWritePtr( mask, maskLen ) );
	assert( isReadPtr( seed, seedLen ) );

	REQUIRES( maskLen >= 16 && maskLen <= CRYPT_MAX_PKCSIZE );
	REQUIRES( seedLen >= 16 && seedLen <= CRYPT_MAX_PKCSIZE );
	REQUIRES( hashAlgo >= CRYPT_ALGO_FIRST_HASH && \
			  hashAlgo <= CRYPT_ALGO_LAST_HASH );

	getHashParameters( hashAlgo, &hashFunction, &hashSize );

	/* Set up the block counter buffer.  This will never have more than the
	   last few bits set (8 bits = 5120 bytes of mask for the smallest hash,
	   SHA-1) so we only change the last byte */
	memset( countBuffer, 0, 4 );

	/* Produce enough blocks of output to fill the mask */
	for( maskIndex = 0, iterationCount = 0; 
		 maskIndex < maskLen && iterationCount < FAILSAFE_ITERATIONS_MED;
		 maskIndex += hashSize, maskOutPtr += hashSize, iterationCount++ )
		{
		const int noMaskBytes = ( maskLen - maskIndex > hashSize ) ? \
								hashSize : maskLen - maskIndex;

		/* Calculate hash( seed || counter ) */
		countBuffer[ 3 ] = ( BYTE ) blockCount++;

⌨️ 快捷键说明

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