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

📄 mech_pkwrap.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 3 页
字号:
		hashFunction( hashInfo, NULL, 0, seed, seedLen, HASH_STATE_START );
		hashFunction( hashInfo, maskBuffer, hashSize, countBuffer, 4, 
					  HASH_STATE_END );
		memcpy( maskOutPtr, maskBuffer, noMaskBytes );
		}
	ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
	zeroise( hashInfo, sizeof( HASHINFO ) );
	zeroise( maskBuffer, OAEP_MAX_HASHSIZE );

	return( CRYPT_OK );
	}

/* Generate/recover an OAEP data block:

							 +----------+---------+-------+
						DB = |  lHash   |    PS   |   M   |
							 +----------+---------+-------+
											|
				  +----------+				V
				  |   seed   |--> MGF ---> xor
				  +----------+				|
						|					|
			   +--+		V					|
			   |00|	   xor <----- MGF <-----|
			   +--+		|					|
				 |		|					|
				 V		V					V
			   +--+----------+----------------------------+
		 EM =  |00|maskedSeed|          maskedDB          |
			   +--+----------+----------------------------+ 
						|					|
						V					V
					   xor <----- MGF <-----|
						|					|
						V					|
				  +----------+				V
				  |   seed   |--> MGF ---> xor
				  +----------+				|
											V
							 +----------+---------+-------+
						DB = |  lHash   |    PS   |   M   |
							 +----------+---------+-------+ */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 5 ) ) \
static int generateOaepDataBlock( OUT_BUFFER_FIXED( dataMaxLen ) BYTE *data, 
								  IN_LENGTH_PKC const int dataMaxLen, 
								  IN_BUFFER( messageLen ) const void *message, 
								  IN_RANGE( MIN_KEYSIZE, CRYPT_MAX_KEYSIZE ) \
									const int messageLen,
								  IN_BUFFER( seedLen ) const void *seed, 
								  IN_LENGTH_PKC const int seedLen,
								  IN_ALGO const CRYPT_ALGO_TYPE hashAlgo )
	{
	BYTE dbMask[ CRYPT_MAX_PKCSIZE + 8 ], seedMask[ OAEP_MAX_HASHSIZE + 8 ];
	BYTE *maskedSeed, *db;
	int dbLen, i, length, status;

	assert( isWritePtr( data, dataMaxLen ) );
	assert( isReadPtr( message, messageLen ) );
	assert( isReadPtr( seed, seedLen ) );

	REQUIRES( dataMaxLen >= MIN_PKCSIZE && dataMaxLen <= CRYPT_MAX_PKCSIZE );
	REQUIRES( messageLen >= MIN_KEYSIZE && messageLen <= dataMaxLen && \
			  messageLen <= CRYPT_MAX_KEYSIZE );
	REQUIRES( seedLen >= 16 && seedLen <= dataMaxLen && \
			  seedLen <= CRYPT_MAX_PKCSIZE );
	REQUIRES( cryptStatusOK( \
				getOaepHashSize( &i, hashAlgo ) ) && seedLen == i );
	REQUIRES( hashAlgo >= CRYPT_ALGO_FIRST_HASH && 
			  hashAlgo <= CRYPT_ALGO_LAST_HASH );

	/* Make sure that the payload fits:

		<------------ dataMaxLen ----------->
		+--+------+-------+----+--+---------+
		|00| seed | lhash | PS |01| message |
		+--+------+-------+----+--+---------+
		  1	 hLen	 hLen	 1	 1	 msgLen

	   Although PS may have a length of zero bytes we require at least one
	   padding byte.  In general the only case where we can ever run into 
	   problems is if we try and use SHA2-512 with a 1024-bit key */
	if( 1 + seedLen + seedLen + 1 + 1 + messageLen > dataMaxLen )
		return( CRYPT_ERROR_OVERFLOW );

	/* Calculate the size and position of the various data quantities */
	maskedSeed = data + 1;
	db = maskedSeed + seedLen;
	dbLen = dataMaxLen - ( 1 + seedLen );

	ENSURES( dbLen >= 16 && dbLen >= messageLen + 1 && \
			 1 + seedLen + dbLen <= dataMaxLen );

	/* db = lHash || zeroes || 0x01 || message */
	memset( db, 0, dbLen );
	status = getOaepHash( db, CRYPT_MAX_PKCSIZE, &length, hashAlgo );
	if( cryptStatusError( status ) )
		return( status );
	db[ dbLen - messageLen - 1 ] = 0x01;
	memcpy( db + dbLen - messageLen, message, messageLen );

	ENSURES( length == seedLen );
	
	/* dbMask = MGF1( seed, dbLen ) */
	status = mgf1( dbMask, dbLen, seed, seedLen, hashAlgo );
	if( cryptStatusError( status ) )
		return( status );

	/* maskedDB = db ^ dbMask */
	for( i = 0; i < dbLen; i++ )
		db[ i ] ^= dbMask[ i ];

	/* seedMask = MGF1( maskedDB, seedLen ) */
	status = mgf1( seedMask, seedLen, db, dbLen, hashAlgo );
	if( cryptStatusError( status ) )
		return( status );

	/* maskedSeed = seed ^ seedMask */
	for( i = 0; i < seedLen; i++ )
		maskedSeed[ i ] = ( ( const BYTE * ) seed )[ i ] ^ seedMask[ i ];

	/* data = 0x00 || maskedSeed || maskedDB */
	data[ 0 ] = 0x00;

	zeroise( dbMask, CRYPT_MAX_PKCSIZE );
	zeroise( seedMask, OAEP_MAX_HASHSIZE );

	return( CRYPT_OK );
	}

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
static int recoverOaepDataBlock( OUT_BUFFER( messageMaxLen, *messageLen ) \
									BYTE *message, 
								 IN_LENGTH_PKC const int messageMaxLen, 
								 OUT_LENGTH_PKC_Z int *messageLen, 
								 IN_BUFFER( dataLen ) const void *data, 
								 IN_LENGTH_PKC const int dataLen, 
								 IN_ALGO const CRYPT_ALGO_TYPE hashAlgo )
	{
	BYTE dbMask[ CRYPT_MAX_PKCSIZE + 8 ], seedMask[ OAEP_MAX_HASHSIZE + 8 ];
	BYTE dataBuffer[ CRYPT_MAX_PKCSIZE + 8 ];
	BYTE *seed, *db;
	int seedLen, dbLen, length, i, m1status, m2status, dummy, status;

	assert( isWritePtr( message, messageMaxLen ) );
	assert( isWritePtr( messageLen, sizeof( int ) ) );
	assert( isReadPtr( data, dataLen ) );

	REQUIRES( messageMaxLen >= MIN_PKCSIZE && \
			  messageMaxLen <= CRYPT_MAX_PKCSIZE );
	REQUIRES( dataLen >= MIN_PKCSIZE && dataLen <= CRYPT_MAX_PKCSIZE );
	REQUIRES( hashAlgo >= CRYPT_ALGO_FIRST_HASH && \
			  hashAlgo <= CRYPT_ALGO_LAST_HASH );

	/* Clear return value */
	memset( message, 0, min( 16, messageMaxLen ) );
	*messageLen = 0;

	/* Make sure that the MGF requirements are met.  Note that this check 
	   has already been performed by the caller to avoid this being used as 
	   a timing oracle, this is merely here to make the fact that the check 
	   has been done explicit */
	status = getOaepHashSize( &seedLen, hashAlgo );
	if( cryptStatusError( status ) )
		return( status );

	/* Take a local copy of the input data, since we're about to operate on 
	   it */
	memcpy( dataBuffer, data, dataLen );

	/* Calculate the size and position of the various data quantities */
	seed = dataBuffer + 1;
	db = seed + seedLen;
	dbLen = dataLen - ( 1 + seedLen );

	ENSURES( dbLen >= 16 && 1 + seedLen + dbLen <= dataLen );

	/* seedMask = MGF1( maskedDB, seedLen ) */
	m1status = mgf1( seedMask, seedLen, db, dbLen, hashAlgo );
	if( m1status == CRYPT_ERROR_INTERNAL )
		return( m1status );	/* Standard status values checked below */

	/* seed = maskedSeed ^ seedMask */
	for( i = 0; i < seedLen; i++ )
		seed[ i ] ^= seedMask[ i ];

	/* dbMask = MGF1( seed, dbLen ) */
	m2status = mgf1( dbMask, dbLen, seed, seedLen, hashAlgo );
	if( m2status == CRYPT_ERROR_INTERNAL )
		return( m2status );	/* Standard status values checked below */

	/* db = maskedDB ^ dbMask */
	for( i = 0; i < dbLen; i++ )
		db[ i ] ^= dbMask[ i ];

	/* Verify that:

		data = 0x00 || [seed] || db 
			 = 0x00 || [seed] || lHash || zeroes || 0x01 || message

	   As before to be careful with the order of the checks, for example we 
	   could check for the leading 0x00 before performing the OAEP 
	   processing but this might allow an attacker to mount a timing attack,
	   see "A chosen ciphertext attack on RSA optimal asymmetric encryption 
	   padding (OAEP)" by James Manger, Proceedings of Crypto'01, LNCS 
	   No.2139, p.230.  To make this as hard as possible we cluster all of 
	   the format checks as close together as we can to try and produce a 
	   near-constant-time accept/reject decision */
	status = getOaepHash( dbMask, CRYPT_MAX_PKCSIZE, &dummy, hashAlgo );
	if( cryptStatusError( status ) )
		return( status );	/* See earlier comment about oracle attacks */
	if( cryptStatusError( m1status ) || cryptStatusError( m2status ) )
		return( cryptStatusError( m1status ) ? m1status : m2status );
	if( 1 + seedLen + seedLen + 1 + 1 + MIN_KEYSIZE > dataLen )
		{
		/* Make sure that at least a minimum-length payload fits:

			<------------ dataMaxLen ----------->
			+--+------+-------+----+--+---------+
			|00| seed | lhash | PS |01| message |
			+--+------+-------+----+--+---------+
			  1	 hLen	 hLen	 1	 1	 msgLen
		
		   Again, we perform this check after all formatting operations have
		   completed to try and avoid a timing attack */
		return( CRYPT_ERROR_BADDATA );
		}
	if( dataBuffer[ 0 ] != 0x00 || memcmp( db, dbMask, seedLen ) )
		return( CRYPT_ERROR_BADDATA );
	for( i = seedLen; i < dbLen && db[ i ] == 0x00; i++ );
	if( i <= seedLen || i >= dbLen || db[ i++ ] != 0x01 )
		return( CRYPT_ERROR_BADDATA );
	length = dbLen - i;
	if( length < MIN_KEYSIZE )
		return( CRYPT_ERROR_UNDERFLOW );
	if( length > messageMaxLen )
		return( CRYPT_ERROR_OVERFLOW );

	/* Return the recovered message to the caller */
	memcpy( message, db + i, length );
	*messageLen = length;

	zeroise( dbMask, CRYPT_MAX_PKCSIZE );
	zeroise( seedMask, OAEP_MAX_HASHSIZE );
	zeroise( dataBuffer, CRYPT_MAX_PKCSIZE );

	return( CRYPT_OK );
	}

/* Perform OAEP wrapping/unwrapping */

CHECK_RETVAL STDC_NONNULL_ARG( ( 2 ) ) \
int exportOAEP( STDC_UNUSED void *dummy, 
				INOUT MECHANISM_WRAP_INFO *mechanismInfo )
	{
	CRYPT_ALGO_TYPE cryptAlgo;
	BYTE payload[ CRYPT_MAX_KEYSIZE + 8 ], seed[ OAEP_MAX_HASHSIZE + 8 ];
	int seedLen, payloadSize, length, status;

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

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

	/* Make sure that the OAEP auxiliary algorithm requirements are met */
	status = getOaepHashSize( &seedLen, mechanismInfo->auxInfo );
	if( cryptStatusError( status ) )
		return( status );

	/* 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 );
		}

	/* Get the payload details from the key context and generate the OAEP 
	   random seed value */
	status = krnlSendMessage( mechanismInfo->keyContext, 
							  IMESSAGE_GETATTRIBUTE, &payloadSize,
							  CRYPT_CTXINFO_KEYSIZE );
	if( cryptStatusOK( status ) )
		{
		MESSAGE_DATA msgData;

		setMessageData( &msgData, seed, seedLen );
		status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
								  IMESSAGE_GETATTRIBUTE_S, &msgData,
								  CRYPT_IATTRIBUTE_RANDOM );
		}
	if( cryptStatusError( status ) )
		return( status );

	/* Extract the key data and process it into an OAEP data block */
	status = extractKeyData( mechanismInfo->keyContext, payload, payloadSize,
							 "keydata", 7 );
	if( cryptStatusOK( status ) )
		{
		status = generateOaepDataBlock( mechanismInfo->wrappedData, length, 
										payload, payloadSize, seed, seedLen,
										mechanismInfo->auxInfo );
		}
	zeroise( payload, bitsToBytes( CRYPT_MAX_KEYSIZE ) );
	zeroise( seed, OAEP_MAX_HASHSIZE );
	if( cryptStatusError( status ) )
		return( status );

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

CHECK_RETVAL STDC_NONNULL_ARG( ( 2 ) ) \
int importOAEP( STDC_UNUSED void *dummy, 
				INOUT MECHANISM_WRAP_INFO *mechanismInfo )
	{
	CRYPT_ALGO_TYPE cryptAlgo;
	MESSAGE_DATA msgData;
	BYTE decryptedData[ CRYPT_MAX_PKCSIZE + 8 ];
	BYTE message[ CRYPT_MAX_PKCSIZE + 8 ];
	int length, messageLen, status;

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

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

	/* Make sure that the MGF requirements are met.  This check isn't 
	   actually needed until the recoverOaepDataBlock() call but we perform 
	   it here before the decrypt to avoid being used as a timing oracle 
	   since feeding in a non-usable hash function that causes the 
	   processing to bail out right after the decrypt provides a reasonably 
	   precise timer for the decryption */
	status = getOaepHashSize( &length, mechanismInfo->auxInfo );
	if( cryptStatusError( status ) )
		return( status );

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

	/* Recover the payload from the OAEP data block */
	status = recoverOaepDataBlock( message, CRYPT_MAX_PKCSIZE, &messageLen, 
								   decryptedData, length, 
								   mechanismInfo->auxInfo );
	zeroise( decryptedData, CRYPT_MAX_PKCSIZE );
	if( cryptStatusError( status ) )
		{
		zeroise( message, CRYPT_MAX_PKCSIZE );
		return( status );
		}

	/* Load the decrypted keying information into the session key context */
	setMessageData( &msgData, message, messageLen );
	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;
		}
	zeroise( message, CRYPT_MAX_PKCSIZE );

	return( status );
	}

#if 0

void testOAEP( void )
	{
	const BYTE seed[] = { 0xaa, 0xfd, 0x12, 0xf6, 0x59, 0xca, 0xe6, 0x34, 
						  0x89, 0xb4, 0x79, 0xe5, 0x07, 0x6d, 0xde, 0xc2,
						  0xf0, 0x6c, 0xb5, 0x8f };
	const BYTE message[] = { 0xd4, 0x36, 0xe9, 0x95, 0x69, 0xfd, 0x32, 0xa7,
							 0xc8, 0xa0, 0x5b, 0xbc, 0x90, 0xd3, 0x2c, 0x49 };
	BYTE buffer[ 1024 ], outMessage[ 128 ];
	int seedLen, outLen, status;

	status = getOaepHashSize( &seedLen, CRYPT_ALGO_SHA1 );

	memset( buffer, '*', 1024 );

	status = generateOaepDataBlock( buffer, 128, message, 16, seed, seedLen, 
									CRYPT_ALGO_SHA1 );
	status = recoverOaepDataBlock( outMessage, 128, &outLen, buffer, 128, 
								   CRYPT_ALGO_SHA1 );
	if( outLen != 16 || memcmp( message, outMessage, outLen ) )
		puts( "Bang." );
	puts( "Done." );
	}
#endif /* 0 */

⌨️ 快捷键说明

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