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

📄 keyex_rw.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 3 页
字号:
		const long position = stell( stream );

		/* Because of the last-minute change in the PWRI format before the 
		   RFC was published, older versions of cryptlib generate a slightly
		   different KEK algorithm info format.  To handle this, we read
		   part of the AlgorithmIdentifier and, if it's the newer format,
		   skip the extra level of wrapping */
		readSequence( stream, NULL );
		status = readOID( stream, OID_PWRIKEK );
		if( cryptStatusError( status ) )
			{
			/* It's the original format, clear the stream error state caused 
			   by the failed PWRI KEK OID read and try again */
			sClearError( stream );
			sseek( stream, position );
			}
		status = readContextAlgoID( stream, NULL, queryInfo, DEFAULT_TAG );
		}
	if( cryptStatusError( status ) )
		return( status );

	/* Finally, read the start of the encrypted key.  We never read the data
	   itself since it's passed directly to the decrypt function */
	status = readOctetStringHole( stream, &queryInfo->dataLength, 
								  DEFAULT_TAG );
	if( cryptStatusOK( status ) )
		{
		queryInfo->dataStart = sMemBufPtr( stream );
		if( queryInfo->dataLength < bitsToBytes( MIN_KEYSIZE_BITS ) )
			/* We shouldn't be using a key this short, we can't actually 
			   load it anyway but a CRYPT_ERROR_BADDATA at this point 
			   provides more meaningful information to the caller */
			status = CRYPT_ERROR_BADDATA;
		}

	return( status );
	}

static int writeCryptlibKek( STREAM *stream, const CRYPT_CONTEXT iCryptContext,
							 const BYTE *encryptedKey, const int encryptedKeyLength )
	{
	STREAM localStream;
	BYTE derivationInfo[ CRYPT_MAX_HASHSIZE + 32 ], kekInfo[ 128 ];
	BOOLEAN hasKeyDerivationInfo = TRUE;
	int derivationInfoSize = 0, kekInfoSize, value, status;

	/* If it's a non-password-derived key and there's a label attached, 
	   write it as a KEKRI with a PWRI algorithm identifier as the key
	   encryption algorithm */
	status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
							  &value, CRYPT_CTXINFO_KEYING_ITERATIONS );
	if( status == CRYPT_ERROR_NOTINITED )
		{
		RESOURCE_DATA msgData;

		/* There's no password-derivation information present, see if there's
		   a label present */
		hasKeyDerivationInfo = FALSE;
		setMessageData( &msgData, NULL, 0 );
		status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
								  &msgData, CRYPT_CTXINFO_LABEL );
		if( cryptStatusOK( status ) )
			/* There's a label present, write it as a PWRI within a KEKRI */
			return( writeCmsKek( stream, iCryptContext, encryptedKey, 
								 encryptedKeyLength ) );
		}

	/* Determine the size of the derivation info and KEK info.  To save
	   evaluating it twice in a row and because it's short, we just write
	   it to local buffers */
	if( hasKeyDerivationInfo )
		{
		sMemOpen( &localStream, derivationInfo, CRYPT_MAX_HASHSIZE + 32 );
		status = writeKeyDerivationInfo( &localStream, iCryptContext );
		derivationInfoSize = stell( &localStream );
		sMemDisconnect( &localStream );
		if( cryptStatusError( status ) )
			return( status );
		}
	sMemOpen( &localStream, kekInfo, 128 );
	writeSequence( &localStream, 
				   sizeofOID( OID_PWRIKEK ) + \
				   sizeofContextAlgoID( iCryptContext, CRYPT_ALGO_NONE,
										ALGOID_FLAG_NONE ) );
	writeOID( &localStream, OID_PWRIKEK );
	status = writeContextAlgoID( &localStream, iCryptContext, CRYPT_ALGO_NONE,
								 ALGOID_FLAG_NONE );
	kekInfoSize = stell( &localStream );
	sMemDisconnect( &localStream );
	if( cryptStatusError( status ) )
		return( status );

	/* Write the algorithm identifiers and encrypted key */
	writeConstructed( stream, sizeofShortInteger( PWRI_VERSION ) +
					  derivationInfoSize + kekInfoSize + 
					  ( int ) sizeofObject( encryptedKeyLength ), 
					  CTAG_RI_PWRI );
	writeShortInteger( stream, PWRI_VERSION, DEFAULT_TAG );
	if( derivationInfoSize )
		swrite( stream, derivationInfo, derivationInfoSize );
	swrite( stream, kekInfo, kekInfoSize );
	return( writeOctetString( stream, encryptedKey, encryptedKeyLength, 
							  DEFAULT_TAG ) );
	}

#ifdef USE_PGP

/* Read/write PGP KEK data.

	SKE:
		byte	ctb = PGP_PACKET_SKE
		byte[]	length
		byte	version = 4
		byte	cryptAlgo
		byte	stringToKey specifier:
		byte[]	stringToKey data
				0x00: byte		hashAlgo
				0x01: byte[8]	salt
				0x02: byte		iterations */

static int readPgpKek( STREAM *stream, QUERY_INFO *queryInfo )
	{
	int value, status;

	/* Make sure that the packet header is in order and check the packet 
	   version.  This is an OpenPGP-only packet */
	status = getPacketInfo( stream, queryInfo );
	if( cryptStatusError( status ) )
		return( status );
	if( sgetc( stream ) != PGP_VERSION_OPENPGP )
		return( CRYPT_ERROR_BADDATA );
	queryInfo->version = PGP_VERSION_OPENPGP;

	/* Get the password hash algorithm */
	if( ( queryInfo->cryptAlgo = \
			pgpToCryptlibAlgo( sgetc( stream ),
							   PGP_ALGOCLASS_PWCRYPT ) ) == CRYPT_ALGO_NONE )
		return( CRYPT_ERROR_NOTAVAIL );

	/* Read the S2K specifier */
	value = sgetc( stream );
	if( value != 0 && value != 1 && value != 3 )
		return( cryptStatusError( value ) ? value : CRYPT_ERROR_BADDATA );
	if( ( queryInfo->keySetupAlgo = \
			pgpToCryptlibAlgo( sgetc( stream ), 
							   PGP_ALGOCLASS_HASH ) ) == CRYPT_ALGO_NONE )
		return( CRYPT_ERROR_NOTAVAIL );
	if( value == 0 )
		/* It's a straight hash, we're done */
		return( CRYPT_OK );
	status = sread( stream, queryInfo->salt, PGP_SALTSIZE );
	if( cryptStatusError( status ) )
		return( status );
	queryInfo->saltLength = PGP_SALTSIZE;
	if( value == 3 )
		{
		/* Salted iterated hash, get the iteration count, limited to a sane
		   value.  The "iteration count" is actually a count of how many
		   bytes are hashed, this is because the "iterated hashing" treats
		   the salt + password as an infinitely-repeated sequence of values
		   and hashes the resulting string for PGP-iteration-count bytes
		   worth.  The value we calculate here (to prevent overflow on 16-bit
		   machines) is the count without the base * 64 scaling, this also
		   puts the range within the value of the standard sanity check */
		value = sgetc( stream );
		if( cryptStatusError( value ) )
			return( value );
		queryInfo->keySetupIterations = \
				( 16 + ( ( long ) value & 0x0F ) ) << ( value >> 4 );
		if( queryInfo->keySetupIterations <= 0 || \
			queryInfo->keySetupIterations > MAX_KEYSETUP_ITERATIONS )
			return( CRYPT_ERROR_BADDATA );
		}

	return( CRYPT_OK );
	}

static int writePgpKek( STREAM *stream, const CRYPT_CONTEXT iCryptContext,
						const BYTE *encryptedKey, const int encryptedKeyLength )
	{
	CRYPT_ALGO_TYPE hashAlgo, cryptAlgo;
	BYTE salt[ CRYPT_MAX_HASHSIZE ];
	int keySetupIterations, count = 0, status;

	assert( encryptedKey == NULL );
	assert( encryptedKeyLength == 0 );

	/* Get the key derivation information */
	status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE, 
						&keySetupIterations, CRYPT_CTXINFO_KEYING_ITERATIONS );
	if( cryptStatusOK( status ) )
		status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE, 
						&hashAlgo, CRYPT_CTXINFO_KEYING_ALGO );
	if( cryptStatusOK( status ) )
		status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE, 
						&cryptAlgo, CRYPT_CTXINFO_ALGO );
	if( cryptStatusOK( status ) )
		{
		RESOURCE_DATA msgData;

		setMessageData( &msgData, salt, CRYPT_MAX_HASHSIZE );
		status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S, 
						&msgData, CRYPT_CTXINFO_KEYING_SALT );
		}
	if( cryptStatusError( status ) )
		return( status );

	/* Calculate the PGP "iteration count" from the value used to derive
	   the key.  The "iteration count" is actually a count of how many bytes 
	   are hashed, this is because the "iterated hashing" treats the salt + 
	   password as an infinitely-repeated sequence of values and hashes the 
	   resulting string for PGP-iteration-count bytes worth.  Instead of 
	   being written directly the count is encoded in a complex manner which
	   saves a whole byte, so before we can write it we have to encode it 
	   into the base + exponent form expected by PGP.  This has a default 
	   base of 16 + the user-supplied base value, we can set this to zero
	   since the iteration count used by cryptlib is always a multiple of
	   16, the remainder is just log2 of what's left of the iteration 
	   count */
	assert( keySetupIterations % 16 == 0 );
	keySetupIterations /= 32;	/* Remove fixed offset before log2 op.*/
	while( keySetupIterations )
		{
		count++;
		keySetupIterations >>= 1;
		}
	count <<= 4;				/* Exponent comes first */

	/* Write the SKE packet */
	pgpWritePacketHeader( stream, PGP_PACKET_SKE, 4 + PGP_SALTSIZE + 1 );
	sputc( stream, PGP_VERSION_OPENPGP );
	sputc( stream, cryptlibToPgpAlgo( cryptAlgo ) );
	sputc( stream, 3 );		/* S2K = salted, iterated hash */
	sputc( stream, cryptlibToPgpAlgo( hashAlgo ) );
	swrite( stream, salt, PGP_SALTSIZE );
	return( sputc( stream, count ) );
	}
#endif /* USE_PGP */

/****************************************************************************
*																			*
*						Public-key Encrypted Key Routines					*
*																			*
****************************************************************************/

/* Read/write CMS key transport data */

static int readCmsKeytrans( STREAM *stream, QUERY_INFO *queryInfo )
	{
	long value;
	int status;

	/* Read the header and version number */
	readSequence( stream, NULL );
	status = readShortInteger( stream, &value );
	if( cryptStatusError( status ) )
		return( status );
	if( value != KEYTRANS_VERSION )
		return( CRYPT_ERROR_BADDATA );

	/* Read the key ID and PKC algorithm information */
	value = getStreamObjectLength( stream );
	if( cryptStatusError( value ) )
		return( value );
	queryInfo->iAndSStart = sMemBufPtr( stream );
	queryInfo->iAndSLength = value;
	readUniversal( stream );
	status = readAlgoID( stream, &queryInfo->cryptAlgo );
	if( cryptStatusError( status ) )
		return( status );

	/* Finally, read the start of the encrypted key.  We never read the data
	   itself since it's passed directly to the PKC decrypt function */
	status = readOctetStringHole( stream, &queryInfo->dataLength, 
								  DEFAULT_TAG );
	if( cryptStatusOK( status ) )
		queryInfo->dataStart = sMemBufPtr( stream );

	return( status );
	}

static int writeCmsKeytrans( STREAM *stream, 
							 const CRYPT_CONTEXT iCryptContext,
							 const BYTE *buffer, const int length,
							 const void *auxInfo, const int auxInfoLength )
	{
	const int dataLength = \
				sizeofContextAlgoID( iCryptContext, CRYPT_ALGO_NONE,
									 ALGOID_FLAG_ALGOID_ONLY ) + \
				( int ) sizeofObject( length );

	writeSequence( stream, sizeofShortInteger( KEYTRANS_VERSION ) +
				   auxInfoLength + dataLength );
	writeShortInteger( stream, KEYTRANS_VERSION, DEFAULT_TAG );
	swrite( stream, auxInfo, auxInfoLength );
	writeContextAlgoID( stream, iCryptContext, CRYPT_ALGO_NONE,
						ALGOID_FLAG_ALGOID_ONLY );
	return( writeOctetString( stream, buffer, length, DEFAULT_TAG ) );
	}

/* Read/write cryptlib key transport data */

static int writeCryptlibKeytrans( STREAM *stream, 
								  const CRYPT_CONTEXT iCryptContext,
								  const BYTE *buffer, const int length,
								  const void *auxInfo, 
								  const int auxInfoLength )
	{
	RESOURCE_DATA msgData;
	BYTE keyID[ CRYPT_MAX_HASHSIZE ];
	const int dataLength = \
				sizeofContextAlgoID( iCryptContext, CRYPT_ALGO_NONE,
									 ALGOID_FLAG_ALGOID_ONLY ) + \
				( int ) sizeofObject( length );

	setMessageData( &msgData, keyID, CRYPT_MAX_HASHSIZE );
	krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S, &msgData, 
					 CRYPT_IATTRIBUTE_KEYID );
	writeSequence( stream, sizeofShortInteger( KEYTRANS_EX_VERSION ) +
				   ( int ) sizeofObject( msgData.length ) + dataLength );
	writeShortInteger( stream, KEYTRANS_EX_VERSION, DEFAULT_TAG );
	writeOctetString( stream, msgData.data, msgData.length, CTAG_KT_SKI );
	writeContextAlgoID( stream, iCryptContext, CRYPT_ALGO_NONE,
						ALGOID_FLAG_ALGOID_ONLY );
	return( writeOctetString( stream, buffer, length, DEFAULT_TAG ) );
	}

static int readCryptlibKeytrans( STREAM *stream, QUERY_INFO *queryInfo )
	{
	long value;
	int status;

	/* Read the header and version number */
	readSequence( stream, NULL );
	status = readShortInteger( stream, &value );
	if( cryptStatusError( status ) )
		return( status );
	if( value != KEYTRANS_EX_VERSION )
		return( CRYPT_ERROR_BADDATA );

	/* Read the key ID and PKC algorithm information */
	readOctetStringTag( stream, queryInfo->keyID, &queryInfo->keyIDlength, 
						CRYPT_MAX_HASHSIZE, CTAG_KT_SKI );
	status = readAlgoID( stream, &queryInfo->cryptAlgo );
	if( cryptStatusError( status ) )
		return( status );

	/* Finally, read the start of the encrypted key.  We never read the data
	   itself since it's passed directly to the PKC decrypt function */
	status = readOctetStringHole( stream, &queryInfo->dataLength, 
								  DEFAULT_TAG );
	if( cryptStatusOK( status ) )
		queryInfo->dataStart = sMemBufPtr( stream );

	return( status );
	}

#ifdef USE_PGP

/* Read/write PGP key transport data:

	PKE:
		byte	ctb = PGP_PACKET_PKE
		byte[]	length
		byte	version = 2 or 3
		byte[8]	keyID
		byte	PKC algo

⌨️ 快捷键说明

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