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

📄 ssl_cry.c

📁 cryptlib是功能强大的安全工具集。允许开发人员快速在自己的软件中集成加密和认证服务。
💻 C
📖 第 1 页 / 共 4 页
字号:

int loadExplicitIV( SESSION_INFO *sessionInfoPtr, STREAM *stream )
	{
	RESOURCE_DATA msgData;
	BYTE iv[ CRYPT_MAX_IVSIZE + 8 ];
	int status;

	/* Read and load the IV */
	status = sread( stream, iv, sessionInfoPtr->cryptBlocksize );
	if( cryptStatusOK( status ) )
		{
		setMessageData( &msgData, iv, sessionInfoPtr->cryptBlocksize );
		status = krnlSendMessage( sessionInfoPtr->iCryptInContext,
								  IMESSAGE_SETATTRIBUTE_S, &msgData, 
								  CRYPT_CTXINFO_IV );
		}
	if( cryptStatusError( status ) )
		retExt( sessionInfoPtr, status, "Packet IV read/load failed" );

	/* The following alternate code, which decrypts and discards the first
	   block, can be used when we can't reload an IV during decryption */
#if 0
	status = krnlSendMessage( sessionInfoPtr->iCryptInContext,
							  IMESSAGE_CTX_DECRYPT, iv, 
							  sessionInfoPtr->cryptBlocksize );
#endif /* 0 */

	return( CRYPT_OK );
	}

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

/* Encrypt/decrypt a data block */

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

	assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
	assert( dataLength > 0 && dataLength <= MAX_PACKET_SIZE + 20 );
	assert( isWritePtr( data, dataLength ) );

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

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

	status = krnlSendMessage( sessionInfoPtr->iCryptOutContext,
							  IMESSAGE_CTX_ENCRYPT, data, length );
	return( cryptStatusError( status ) ? status : length );
	}

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

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

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

	/* 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 */
	if( sessionInfoPtr->cryptBlocksize > 1 )
		{
		const int padSize = data[ dataLength - 1 ];

		/* 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 */
		if( padSize < 0 || \
			( sessionInfoPtr->version == SSL_MINOR_VERSION_SSL && \
			  padSize > sessionInfoPtr->cryptBlocksize - 1 ) )
			retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
					"Invalid encryption padding value 0x%02X", padSize );
		length -= padSize + 1;
		if( length < 0 )
			retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
					"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( sessionInfoPtr, CRYPT_ERROR_BADDATA,
							"Invalid encryption padding byte 0x%02X at "
							"position %d, should be 0x%02X", 
							data[ length + i ], length + i, padSize );
			}
		}

	return( length );
	}

/****************************************************************************
*																			*
*								MAC Data Functions							*
*																			*
****************************************************************************/

/* Perform a MAC or dual 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 */

int macDataSSL( SESSION_INFO *sessionInfoPtr, const void *data,
				const int dataLength, const int type, const BOOLEAN isRead, 
				const BOOLEAN noReportError )
	{
	SSL_INFO *sslInfo = sessionInfoPtr->sessionSSL;
	RESOURCE_DATA msgData;
	STREAM stream;
	BYTE buffer[ 128 ];
	const CRYPT_CONTEXT iHashContext = isRead ? \
			sessionInfoPtr->iAuthInContext : sessionInfoPtr->iAuthOutContext;
	const void *macSecret = isRead ? sslInfo->macReadSecret : \
									 sslInfo->macWriteSecret;
	const long seqNo = isRead ? sslInfo->readSeqNo++ : sslInfo->writeSeqNo++;
	const int padSize = \
			( sessionInfoPtr->integrityAlgo == CRYPT_ALGO_MD5 ) ? 48 : 40;
	int length, status;

	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
	assert( dataLength >= 0 && dataLength <= MAX_PACKET_SIZE );
	assert( dataLength == 0 || isReadPtr( data, dataLength ) );

	/* 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 );
	writeUint16( &stream, dataLength );
	length = stell( &stream );
	sMemDisconnect( &stream );

	/* 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, 
					 sessionInfoPtr->authBlocksize );
	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, 
					 sessionInfoPtr->authBlocksize );
	krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, buffer, 
					 padSize + msgData.length );
	status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, "", 0 );
	if( cryptStatusError( status ) )
		return( status );

	/* If it's a read, compare the calculated MAC to the MAC present at the
	   end of the data */
	if( isRead )
		{
		RESOURCE_DATA msgData;

		setMessageData( &msgData, ( BYTE * ) data + dataLength, 
						sessionInfoPtr->authBlocksize );
		status = krnlSendMessage( iHashContext, IMESSAGE_COMPARE, 
								  &msgData, MESSAGE_COMPARE_HASH );
		if( cryptStatusError( status ) )
			{
			/* If the error message has already been set at a higher level,
			   don't update the error info */
			if( noReportError )
				return( CRYPT_ERROR_SIGNATURE );

			retExt( sessionInfoPtr, CRYPT_ERROR_SIGNATURE,
					"Bad message MAC for packet type %d, length %d",
					type, dataLength );
			}
		return( CRYPT_OK );
		}

	/* Set the MAC value at the end of the packet */
	setMessageData( &msgData, ( BYTE * ) data + dataLength, 
					sessionInfoPtr->authBlocksize );
	status = krnlSendMessage( iHashContext, IMESSAGE_GETATTRIBUTE_S, 
							  &msgData, CRYPT_CTXINFO_HASHVALUE );
	return( cryptStatusOK( status ) ? dataLength + msgData.length : status );
	}

int macDataTLS( SESSION_INFO *sessionInfoPtr, const void *data,
				const int dataLength, const int type, const BOOLEAN isRead, 
				const BOOLEAN noReportError )
	{
	SSL_INFO *sslInfo = sessionInfoPtr->sessionSSL;
	RESOURCE_DATA msgData;
	STREAM stream;
	BYTE buffer[ 64 ];
	const CRYPT_CONTEXT iHashContext = isRead ? \
			sessionInfoPtr->iAuthInContext : sessionInfoPtr->iAuthOutContext;
	const long seqNo = isRead ? sslInfo->readSeqNo++ : sslInfo->writeSeqNo++;
	int length, status;

	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
	assert( dataLength >= 0 && dataLength <= MAX_PACKET_SIZE );
	assert( dataLength == 0 || isReadPtr( data, dataLength ) );

	/* Set up the sequence number, type, version, and length data */
	sMemOpen( &stream, buffer, 64 );
	writeUint64( &stream, seqNo );
	sputc( &stream, type );
	sputc( &stream, SSL_MAJOR_VERSION );
	sputc( &stream, sessionInfoPtr->version );
	writeUint16( &stream, dataLength );
	length = stell( &stream );
	sMemDisconnect( &stream );

	/* Reset the hash context and generate the MAC:

		HMAC( seq_num || type || version || length || data ) */
	krnlSendMessage( iHashContext, IMESSAGE_DELETEATTRIBUTE, NULL,
					 CRYPT_CTXINFO_HASHVALUE );
	krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, buffer, length );
	if( dataLength > 0 )
		krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, ( void * ) data, 
						 dataLength );
	status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, "", 0 );
	if( cryptStatusError( status ) )
		return( status );

	/* If it's a read, compare the calculated MAC to the MAC present at the
	   end of the data */
	if( isRead )
		{
		RESOURCE_DATA msgData;

		setMessageData( &msgData, ( BYTE * ) data + dataLength, 
						sessionInfoPtr->authBlocksize );
		status = krnlSendMessage( iHashContext, IMESSAGE_COMPARE, 
								  &msgData, MESSAGE_COMPARE_HASH );
		if( cryptStatusError( status ) )
			{
			/* If the error message has already been set at a higher level,
			   don't update the error info */
			if( noReportError )
				return( CRYPT_ERROR_SIGNATURE );

			retExt( sessionInfoPtr, CRYPT_ERROR_SIGNATURE,
					"Bad message MAC for packet type %d, length %d",
					type, dataLength );
			}
		return( CRYPT_OK );
		}

	/* Set the MAC value at the end of the packet */
	setMessageData( &msgData, ( BYTE * ) data + dataLength, 
					sessionInfoPtr->authBlocksize );
	status = krnlSendMessage( iHashContext, IMESSAGE_GETATTRIBUTE_S, 
							  &msgData, CRYPT_CTXINFO_HASHVALUE );
	return( cryptStatusOK( status ) ? dataLength + msgData.length : status );
	}

int dualMacData( const SSL_HANDSHAKE_INFO *handshakeInfo, 
				 const STREAM *stream, const BOOLEAN isRawData )
	{
	const int dataLength = isRawData ? sMemDataLeft( stream ) : \
									   stell( stream ) - SSL_HEADER_SIZE;
	const void *data = isRawData ? sMemBufPtr( stream ) : \
								   sMemBufPtr( stream ) - dataLength;
	int status;

	assert( dataLength > 0 );

	status = krnlSendMessage( handshakeInfo->clientMD5context,
							  IMESSAGE_CTX_HASH, ( void * ) data, 
							  dataLength );
	if( cryptStatusOK( status ) )
		status = krnlSendMessage( handshakeInfo->clientSHA1context,
								  IMESSAGE_CTX_HASH, ( void * ) data, 
								  dataLength );
	if( cryptStatusOK( status ) )
		status = krnlSendMessage( handshakeInfo->serverMD5context,
								  IMESSAGE_CTX_HASH, ( void * ) data, 
								  dataLength );
	if( cryptStatusOK( status ) )
		status = krnlSendMessage( handshakeInfo->serverSHA1context,
								  IMESSAGE_CTX_HASH, ( void * ) data, 
								  dataLength );
	return( status );
	}

/* Complete the dual MD5/SHA1 hash/MAC used in the finished message */

int completeSSLDualMAC( const CRYPT_CONTEXT md5context,
						const CRYPT_CONTEXT sha1context, BYTE *hashValues, 
						const char *label, const BYTE *masterSecret )
	{
	RESOURCE_DATA msgData;
	int status;

⌨️ 快捷键说明

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