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

📄 ssl_cry.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 3 页
字号:
/****************************************************************************
*																			*
*					cryptlib SSL v3/TLS Crypto Routines						*
*					 Copyright Peter Gutmann 1998-2008						*
*																			*
****************************************************************************/

#if defined( INC_ALL )
  #include "crypt.h"
  #include "misc_rw.h"
  #include "session.h"
  #include "ssl.h"
#else
  #include "crypt.h"
  #include "misc/misc_rw.h"
  #include "session/session.h"
  #include "session/ssl.h"
#endif /* Compiler-specific includes */

/* Proto-HMAC padding data */

#define PROTOHMAC_PAD1_VALUE	0x36
#define PROTOHMAC_PAD2_VALUE	0x5C
#define PROTOHMAC_PAD1			"\x36\x36\x36\x36\x36\x36\x36\x36" \
								"\x36\x36\x36\x36\x36\x36\x36\x36" \
								"\x36\x36\x36\x36\x36\x36\x36\x36" \
								"\x36\x36\x36\x36\x36\x36\x36\x36" \
								"\x36\x36\x36\x36\x36\x36\x36\x36" \
								"\x36\x36\x36\x36\x36\x36\x36\x36"
#define PROTOHMAC_PAD2			"\x5C\x5C\x5C\x5C\x5C\x5C\x5C\x5C" \
								"\x5C\x5C\x5C\x5C\x5C\x5C\x5C\x5C" \
								"\x5C\x5C\x5C\x5C\x5C\x5C\x5C\x5C" \
								"\x5C\x5C\x5C\x5C\x5C\x5C\x5C\x5C" \
								"\x5C\x5C\x5C\x5C\x5C\x5C\x5C\x5C" \
								"\x5C\x5C\x5C\x5C\x5C\x5C\x5C\x5C"

#ifdef USE_SSL

/****************************************************************************
*																			*
*							Encrypt/Decrypt Functions						*
*																			*
****************************************************************************/

/* Encrypt/decrypt a data block */

int encryptData( const SESSION_INFO *sessionInfoPtr, BYTE *data,
				 const int dataMaxLength, int *dataLength,
				 const int payloadLength )
	{
	int length = payloadLength, status;

	assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
	assert( payloadLength > 0 && \
			payloadLength <= MAX_PACKET_SIZE + 20 && \
			payloadLength < sessionInfoPtr->sendBufSize && \
			payloadLength < dataMaxLength );
	assert( isWritePtr( data, dataMaxLength ) );
	assert( isWritePtr( dataLength, sizeof( int ) ) );

	/* Sanity-check the state */
	if( payloadLength <= 0 || \
		payloadLength > MAX_PACKET_SIZE + 20 || \
		payloadLength >= sessionInfoPtr->sendBufSize || \
		payloadLength >= dataMaxLength )
		retIntError();

	/* Clear return value */
	*dataLength = 0;

	/* If it's a block cipher, we need to add end-of-block padding */
	if( sessionInfoPtr->cryptBlocksize > 1 )
		{
		BYTE *dataPadPtr = data + payloadLength;
		const int padSize = ( sessionInfoPtr->cryptBlocksize - 1 ) - \
						    ( payloadLength & ( sessionInfoPtr->cryptBlocksize - 1 ) );
		int i;

		/* Make sure that there's room to add the padding */
		if( padSize < 0 || length + padSize + 1 > dataMaxLength ) 
			retIntError();

		/* Add the PKCS #5-style padding (PKCS #5 uses n, TLS uses n-1) */
		for( i = 0; i < padSize + 1; i++ )
			*dataPadPtr++ = padSize;
		length += padSize + 1;
		}

	/* Encrypt the data and optional padding */
	status = krnlSendMessage( sessionInfoPtr->iCryptOutContext,
							  IMESSAGE_CTX_ENCRYPT, data, length );
	if( cryptStatusError( status ) )
		return( status );
	*dataLength = length;

	return( CRYPT_OK );
	}

int decryptData( SESSION_INFO *sessionInfoPtr, BYTE *data,
				 const int dataLength, int *processedDataLength )
	{
	int length = dataLength, padSize, status;

	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
	assert( dataLength > 0 && dataLength <= sessionInfoPtr->receiveBufEnd );
	assert( isWritePtr( data, dataLength ) );
	assert( isWritePtr( processedDataLength, sizeof( int ) ) );

	/* Sanity-check the state */
	if( dataLength <= 0 || dataLength > sessionInfoPtr->receiveBufEnd )
		retIntError();

	/* Clear return value */
	*processedDataLength = 0;

	/* Decrypt the data */
	status = krnlSendMessage( sessionInfoPtr->iCryptInContext,
							  IMESSAGE_CTX_DECRYPT, data, length );
	if( cryptStatusError( status ) )
		{
		retExt( status,
				( status, SESSION_ERRINFO, 
				  "Packet decryption failed" ) );
		}

	/* If it's a stream cipher there's no padding present */
	if( sessionInfoPtr->cryptBlocksize <= 1 )
		{
		*processedDataLength = length;

		return( CRYPT_OK );
		}

	/* If it's a block cipher, we need to remove end-of-block padding.  Up
	   until TLS 1.1 the spec was silent about any requirement to check the
	   padding (and for SSLv3 it didn't specify the padding format at all)
	   so it's not really safe to reject an SSL message if we don't find the
	   correct padding because many SSL implementations didn't process the
	   padded space in any way, leaving it containing whatever was there
	   before (which can include old plaintext (!!)).  Almost all TLS
	   implementations get it right (even though in TLS 1.0 there was only a
	   requirement to generate, but not to check, the PKCS #5-style padding).
	   Because of this we only check the padding bytes if we're talking
	   TLS.

	   First we make sure that the padding info looks OK.  TLS allows up to 
	   256 bytes of padding (only GnuTLS actually seems to use this 
	   capability though) so we can't check for a sensible (small) padding 
	   length, however we can check this for SSL, which is good because for 
	   that we can't check the padding itself */
	padSize = data[ dataLength - 1 ];
	if( padSize < 0 || \
		( sessionInfoPtr->version == SSL_MINOR_VERSION_SSL && \
		  padSize > sessionInfoPtr->cryptBlocksize - 1 ) )
		{
		retExt( CRYPT_ERROR_BADDATA,
				( CRYPT_ERROR_BADDATA, SESSION_ERRINFO, 
				  "Invalid encryption padding value 0x%02X", padSize ) );
		}
	length -= padSize + 1;
	if( length < 0 )
		{
		retExt( CRYPT_ERROR_BADDATA,
				( CRYPT_ERROR_BADDATA, SESSION_ERRINFO, 
				  "Encryption padding adjustment value %d is greater "
				  "than packet length %d", padSize, dataLength ) );
		}

	/* Check for PKCS #5-type padding (PKCS #5 uses n, TLS uses n-1) if 
	   necessary */
	if( sessionInfoPtr->version >= SSL_MINOR_VERSION_TLS )
		{
		int i;

		for( i = 0; i < padSize; i++ )
			{
			if( data[ length + i ] != padSize )
				{
				retExt( CRYPT_ERROR_BADDATA,
						( CRYPT_ERROR_BADDATA, SESSION_ERRINFO, 
						  "Invalid encryption padding byte 0x%02X at "
						  "position %d, should be 0x%02X",
						  data[ length + i ], length + i, padSize ) );
				}
			}
		}
	*processedDataLength = length;

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*								SSL MAC Functions							*
*																			*
****************************************************************************/

/* Perform an SSL MAC of a data block.  We have to provide special-case 
   handling of zero-length blocks since some versions of OpenSSL send these 
   as a kludge in SSL/TLS 1.0 to work around chosen-IV attacks */

CHECK_RETVAL STDC_NONNULL_ARG( ( 3, 6 ) ) \
static int macDataSSL( const CRYPT_CONTEXT iHashContext, 
					   const CRYPT_ALGO_TYPE hashAlgo,
					   IN_BUFFER( macSecretLength ) \
					   const void *macSecret, const int macSecretLength,
					   const long seqNo, 
					   IN_BUFFER( dataLength ) \
					   const void *data, const int dataLength, 
					   const int type )
	{
	MESSAGE_DATA msgData;
	STREAM stream;
	BYTE buffer[ 128 + 8 ];
	const int padSize = ( hashAlgo == CRYPT_ALGO_MD5 ) ? 48 : 40;
	int length = DUMMY_INIT, status;

	assert( isHandleRangeValid( iHashContext ) );
	assert( isReadPtr( macSecret, macSecretLength ) );
	assert( seqNo >= 0 );
	assert( isReadPtr( data, dataLength ) );
	assert( dataLength >= 0 && dataLength <= MAX_PACKET_SIZE );

	/* Set up the sequence number and length data */
	memset( buffer, PROTOHMAC_PAD1_VALUE, padSize );
	sMemOpen( &stream, buffer + padSize, 128 - padSize );
	writeUint64( &stream, seqNo );
	sputc( &stream, type );
	status = writeUint16( &stream, dataLength );
	if( cryptStatusOK( status ) )
		length = stell( &stream );
	sMemDisconnect( &stream );
	if( cryptStatusError( status ) )
		return( status );

	/* Reset the hash context and generate the inner portion of the MAC:

		hash( MAC_secret || pad1 || seq_num || type || length || data ) */
	krnlSendMessage( iHashContext, IMESSAGE_DELETEATTRIBUTE, NULL,
					 CRYPT_CTXINFO_HASHVALUE );
	krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, ( void * ) macSecret,
					 macSecretLength );
	krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, buffer,
					 padSize + length );
	if( dataLength > 0 )
		krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, ( void * ) data,
						 dataLength );
	status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, "", 0 );
	if( cryptStatusError( status ) )
		return( status );

	/* Extract the inner hash value */
	memset( buffer, PROTOHMAC_PAD2_VALUE, padSize );
	setMessageData( &msgData, buffer + padSize, CRYPT_MAX_HASHSIZE );
	status = krnlSendMessage( iHashContext, IMESSAGE_GETATTRIBUTE_S,
							  &msgData, CRYPT_CTXINFO_HASHVALUE );
	if( cryptStatusError( status ) )
		return( status );

	/* Generate the outer portion of the handshake message's MAC:

		hash( MAC_secret || pad2 || inner_hash ) */
	krnlSendMessage( iHashContext, IMESSAGE_DELETEATTRIBUTE, NULL,
					 CRYPT_CTXINFO_HASHVALUE );
	krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, ( void * ) macSecret,
					 macSecretLength );
	krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, buffer,
					 padSize + msgData.length );
	return( krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, "", 0 ) );
	}

int createMacSSL( SESSION_INFO *sessionInfoPtr, void *data,
				  const int dataMaxLength, int *dataLength,
				  const int payloadLength, const int type )
	{
	SSL_INFO *sslInfo = sessionInfoPtr->sessionSSL;
	MESSAGE_DATA msgData;
	int status;

	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
	assert( isWritePtr( data, dataMaxLength ) );
	assert( isWritePtr( dataLength, sizeof( int ) ) );
	assert( payloadLength >= 0 && payloadLength <= MAX_PACKET_SIZE && \
			payloadLength + sessionInfoPtr->authBlocksize <= dataMaxLength );

	/* Sanity-check the state */
	if( payloadLength < 0 || payloadLength > MAX_PACKET_SIZE || \
		payloadLength + sessionInfoPtr->authBlocksize > dataMaxLength )
		retIntError();

	/* Clear return value */
	*dataLength = 0;

	/* MAC the payload */
	status = macDataSSL( sessionInfoPtr->iAuthOutContext, 
						 sessionInfoPtr->integrityAlgo,
						 sslInfo->macWriteSecret, 
						 sessionInfoPtr->authBlocksize, sslInfo->writeSeqNo,
						 data, payloadLength, type );
	if( cryptStatusError( status ) )
		return( status );
	sslInfo->writeSeqNo++;

	/* Set the MAC value at the end of the packet */
	setMessageData( &msgData, ( BYTE * ) data + payloadLength,
					sessionInfoPtr->authBlocksize );
	status = krnlSendMessage( sessionInfoPtr->iAuthOutContext, 
							  IMESSAGE_GETATTRIBUTE_S, &msgData, 
							  CRYPT_CTXINFO_HASHVALUE );
	if( cryptStatusError( status ) )
		return( status );
	*dataLength = payloadLength + msgData.length;

	return( CRYPT_OK );
	}

int checkMacSSL( SESSION_INFO *sessionInfoPtr, const void *data,
				 const int dataLength, const int payloadLength,
				 const int type, const BOOLEAN noReportError )
	{
	SSL_INFO *sslInfo = sessionInfoPtr->sessionSSL;
	MESSAGE_DATA msgData;
	int status;

	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
	assert( isReadPtr( data, dataLength ) );
	assert( payloadLength >= 0 && payloadLength <= MAX_PACKET_SIZE && \
			payloadLength + sessionInfoPtr->authBlocksize <= dataLength );

	/* Sanity-check the state */
	if( payloadLength < 0 || payloadLength > MAX_PACKET_SIZE || \
		payloadLength + sessionInfoPtr->authBlocksize > dataLength )
		retIntError();

	/* MAC the payload */
	status = macDataSSL( sessionInfoPtr->iAuthInContext, 
						 sessionInfoPtr->integrityAlgo,
						 sslInfo->macReadSecret, 
						 sessionInfoPtr->authBlocksize, sslInfo->readSeqNo,
						 data, payloadLength, type );
	if( cryptStatusError( status ) )
		return( status );
	sslInfo->readSeqNo++;

⌨️ 快捷键说明

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