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

📄 ssh2_cry.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 3 页
字号:
		{
		/* The data will fit into the buffer, copy it so that it can be 
		   hashed in one go */
		status = swrite( &stream, data, dataLength );
		}
	if( cryptStatusOK( status ) )
		{
		length = stell( &stream );
		status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, 
								  buffer, length );
		}
	if( cryptStatusOK( status ) && length < dataLength )
		{
		/* The data didn't fit into the buffer, hash it separately */
		status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH,
								  ( void * ) data, dataLength );
		}
	sMemClose( &stream );

	return( status );
	}

int hashAsMPI( const CRYPT_CONTEXT iHashContext, const BYTE *data,
			   const int dataLength )
	{
	STREAM stream;
	BYTE buffer[ 8 + 8 ];
	const int length = ( data[ 0 ] & 0x80 ) ? dataLength + 1 : dataLength;
	int headerLength = DUMMY_INIT, status;

	assert( isHandleRangeValid( iHashContext ) );
	assert( isReadPtr( data, dataLength ) );

	/* Prepend the MPI length to the data and hash it.  Since this is often
	   sensitive data, we don't take a local copy but hash it in two parts */
	sMemOpen( &stream, buffer, 8 );
	status = writeUint32( &stream, length );
	if( data[ 0 ] & 0x80 )
		{
		/* MPIs are signed values */
		status = sputc( &stream, 0 );
		}
	if( cryptStatusOK( status ) )
		headerLength = stell( &stream );
	sMemDisconnect( &stream );
	if( cryptStatusError( status ) )
		return( status );
	status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, 
							  buffer, headerLength );
	if( cryptStatusOK( status ) )
		status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH,
								  ( void * ) data, dataLength );
	return( status );
	}

/* MAC the payload of a data packet.  Since we may not have the whole packet
   available at once, we can do this in one go or incrementally */

static int macDataSSH( const CRYPT_CONTEXT iMacContext, const long seqNo,
					   IN_BUFFER( dataLength ) \
					   const BYTE *data, const int dataLength,
					   const int packetDataLength, const MAC_TYPE macType )
	{
	int status;

	assert( isHandleRangeValid( iMacContext ) );
	assert( macType == MAC_END || seqNo >= 2 );
			/* Since SSH starts counting packets from the first one but 
			   unlike SSL doesn't MAC them, the seqNo is already nonzero 
			   when we start */
	assert( dataLength == 0 || \
			isReadPtr( data, dataLength ) );
	assert( packetDataLength >= 0 && packetDataLength < MAX_INTLENGTH );
	assert( macType > MAC_NONE && macType < MAC_LAST );

	/* MAC the data and either compare the result to the stored MAC or
	   append the MAC value to the data:

		HMAC( seqNo || length || payload )

	   During the handshake process we have the entire packet at hand
	   (dataLength == packetDataLength) and can process it at once.  When
	   we're processing payload data (dataLength a subset of
	   packetDataLength) we have to process the header separately in order
	   to determine how much more we have to read, so we have to MAC the
	   packet in two parts */
	if( macType == MAC_START || macType == MAC_ALL )
		{
		STREAM stream;
		BYTE headerBuffer[ 16 + 8 ];
		int length = ( macType == MAC_ALL ) ? dataLength : packetDataLength;
		int headerLength = DUMMY_INIT;

		assert( ( macType == MAC_ALL && packetDataLength == 0 ) || \
				( macType == MAC_START && packetDataLength >= dataLength ) );

		/* Since the payload had the length stripped during the speculative
		   read if we're MAC'ing read data, we have to reconstruct it and
		   hash it separately before we hash the data.  If we're doing the
		   hash in parts, the amount of data being hashed won't match the
		   overall length so the caller needs to supply the overall packet
		   length as well as the current data length */
		sMemOpen( &stream, headerBuffer, 16 );
		writeUint32( &stream, seqNo );
		status = writeUint32( &stream, length );
		if( cryptStatusOK( status ) )
			headerLength = stell( &stream );
		sMemDisconnect( &stream );
		if( cryptStatusError( status ) )
			return( status );
		krnlSendMessage( iMacContext, IMESSAGE_DELETEATTRIBUTE, NULL,
						 CRYPT_CTXINFO_HASHVALUE );
		status = krnlSendMessage( iMacContext, IMESSAGE_CTX_HASH, 
								  headerBuffer, headerLength );
		if( cryptStatusError( status ) )
			return( status );
		}
	if( dataLength > 0 )
		{
		status = krnlSendMessage( iMacContext, IMESSAGE_CTX_HASH,
								  ( void * ) data, dataLength );
		if( cryptStatusError( status ) )
			return( status );
		}
	if( macType == MAC_END || macType == MAC_ALL )
		{
		status = krnlSendMessage( iMacContext, IMESSAGE_CTX_HASH, "", 0 );
		if( cryptStatusError( status ) )
			return( status );
		}

	return( CRYPT_OK );
	}

int checkMacSSH( const CRYPT_CONTEXT iMacContext, const long seqNo,
				 const BYTE *data, const int dataMaxLength, 
				 const int dataLength, const int packetDataLength, 
				 const MAC_TYPE macType, const int macLength )
	{
	MESSAGE_DATA msgData;
	int status;

	assert( isHandleRangeValid( iMacContext ) );
	assert( macType == MAC_END || seqNo >= 2 );
	assert( isReadPtr( data, dataMaxLength ) );
	assert( ( macType == MAC_START && \
			  dataMaxLength == dataLength ) || \
			( ( macType == MAC_ALL || macType == MAC_END ) && 
			  dataLength + macLength <= dataMaxLength ) );
	assert( packetDataLength >= 0 && packetDataLength < MAX_INTLENGTH );
	assert( macType > MAC_NONE && macType < MAC_LAST );
	assert( macLength >= 16 && macLength <= CRYPT_MAX_HASHSIZE );

	/* Sanity-check the state */
	if( dataLength + \
		( ( macType == MAC_START ) ? 0 : macLength ) > dataMaxLength )
		retIntError();

	/* MAC the payload */
	status = macDataSSH( iMacContext, seqNo, data, dataLength, 
						 packetDataLength, macType );
	if( cryptStatusError( status ) )
		return( status );

	/* If we're starting the ongoing hashing of a data block, we're done */
	if( macType == MAC_START )
		return( CRYPT_OK );

	/* Compare the calculated MAC value to the stored MAC value */
	setMessageData( &msgData, ( BYTE * ) data + dataLength, macLength );
	return( krnlSendMessage( iMacContext, IMESSAGE_COMPARE, &msgData, 
							 MESSAGE_COMPARE_HASH ) );
	}

int createMacSSH( const CRYPT_CONTEXT iMacContext, const long seqNo,
				  BYTE *data, const int dataMaxLength, const int dataLength )
	{
	MESSAGE_DATA msgData;
	BYTE mac[ CRYPT_MAX_HASHSIZE + 8 ];
	int status;

	assert( isHandleRangeValid( iMacContext ) );
	assert( seqNo >= 2 );
	assert( isWritePtr( data, dataLength ) );

	/* MAC the payload */
	status = macDataSSH( iMacContext, seqNo, data, dataLength, 0, MAC_ALL );
	if( cryptStatusError( status ) )
		return( status );

	/* Write the calculated MAC value to the stream */
	setMessageData( &msgData, mac, CRYPT_MAX_HASHSIZE );
	status = krnlSendMessage( iMacContext, IMESSAGE_GETATTRIBUTE_S, &msgData, 
							  CRYPT_CTXINFO_HASHVALUE );
	if( cryptStatusError( status ) )
		return( status );
	assert( dataLength + msgData.length <= dataMaxLength );
	memcpy( data + dataLength, mac, msgData.length );
	
	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*							Miscellaneous Functions							*
*																			*
****************************************************************************/

/* Complete the DH key agreement */

int completeKeyex( SESSION_INFO *sessionInfoPtr,
				   SSH_HANDSHAKE_INFO *handshakeInfo,
				   const BOOLEAN isServer )
	{
	KEYAGREE_PARAMS keyAgreeParams;
	MESSAGE_DATA msgData;
	STREAM stream;
	int status;

	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
	assert( isWritePtr( handshakeInfo, sizeof( SSH_HANDSHAKE_INFO ) ) );

	/* Read the other side's key agreement information.  Note that the size
	   check has already been performed at a higher level when the overall
	   key agreement value was read, this is a secondary check of the MPI
	   payload */
	memset( &keyAgreeParams, 0, sizeof( KEYAGREE_PARAMS ) );
	if( isServer )
		sMemConnect( &stream, handshakeInfo->clientKeyexValue,
					 handshakeInfo->clientKeyexValueLength );
	else
		sMemConnect( &stream, handshakeInfo->serverKeyexValue,
					 handshakeInfo->serverKeyexValueLength );
	status = readInteger32( &stream, keyAgreeParams.publicValue,
							&keyAgreeParams.publicValueLen, MIN_PKCSIZE,
							CRYPT_MAX_PKCSIZE );
	sMemDisconnect( &stream );
	if( cryptStatusOK( status ) && \
		!isValidDHsize( keyAgreeParams.publicValueLen,
						handshakeInfo->serverKeySize, 0 ) )
		status = CRYPT_ERROR_BADDATA;
	if( cryptStatusError( status ) )
		{
		retExt( CRYPT_ERROR_BADDATA,
				( CRYPT_ERROR_BADDATA, SESSION_ERRINFO, 
				  "Invalid DH phase 1 MPI" ) );
		}

	/* Perform phase 2 of the DH key agreement */
	status = krnlSendMessage( handshakeInfo->iServerCryptContext,
							  IMESSAGE_CTX_DECRYPT, &keyAgreeParams,
							  sizeof( KEYAGREE_PARAMS ) );
	if( cryptStatusOK( status ) )
		{
		memcpy( handshakeInfo->secretValue, keyAgreeParams.wrappedKey,
				keyAgreeParams.wrappedKeyLen );
		handshakeInfo->secretValueLength = keyAgreeParams.wrappedKeyLen;
		}
	zeroise( &keyAgreeParams, sizeof( KEYAGREE_PARAMS ) );
	if( cryptStatusError( status ) )
		return( status );

	/* If we're using ephemeral DH, hash the requested keyex key length(s)
	   and DH p and g values.  Since this has been deferred until long after
	   the keyex negotiation took place (so that the original data isn't 
	   available any more), we have to recreate the original encoded values 
	   here */
	if( handshakeInfo->requestedServerKeySize > 0 )
		{
		BYTE keyexBuffer[ 128 + ( CRYPT_MAX_PKCSIZE * 2 ) + 8 ];
		const int extraLength = LENGTH_SIZE + sizeofString32( "ssh-dh", 6 );

		status = krnlSendMessage( handshakeInfo->iExchangeHashcontext,
								  IMESSAGE_CTX_HASH,
								  handshakeInfo->encodedReqKeySizes,
								  handshakeInfo->encodedReqKeySizesLength );
		if( cryptStatusError( status ) )
			return( status );
		setMessageData( &msgData, keyexBuffer,
						128 + ( CRYPT_MAX_PKCSIZE * 2 ) );
		status = krnlSendMessage( handshakeInfo->iServerCryptContext,
								  IMESSAGE_GETATTRIBUTE_S, &msgData,
								  CRYPT_IATTRIBUTE_KEY_SSH );
		if( cryptStatusOK( status ) )
			{
			status = krnlSendMessage( handshakeInfo->iExchangeHashcontext,
									  IMESSAGE_CTX_HASH, 
									  keyexBuffer + extraLength,
									  msgData.length - extraLength );
			}
		if( cryptStatusError( status ) )
			return( status );
		}

	/* Hash the client and server DH values and shared secret */
	status = krnlSendMessage( handshakeInfo->iExchangeHashcontext, 
							  IMESSAGE_CTX_HASH,
							  handshakeInfo->clientKeyexValue,
							  handshakeInfo->clientKeyexValueLength );
	if( cryptStatusOK( status ) )
		status = krnlSendMessage( handshakeInfo->iExchangeHashcontext, 
								  IMESSAGE_CTX_HASH,
								  handshakeInfo->serverKeyexValue,
								  handshakeInfo->serverKeyexValueLength );
	if( cryptStatusOK( status ) )
		status = hashAsMPI( handshakeInfo->iExchangeHashcontext,
							handshakeInfo->secretValue,
							handshakeInfo->secretValueLength );
	if( cryptStatusError( status ) )
		return( status );

	/* Complete the hashing to obtain the exchange hash and then hash *that*
	   to get the hash that the server signs and sends to the client.  The
	   overall hashed data for the exchange hash is:

		string	V_C, client version string (CR and NL excluded)
		string	V_S, server version string (CR and NL excluded)
		string	I_C, client hello
		string	I_S, server hello
		string	K_S, the host key
	 [[	uint32	min, min.preferred keyex key size for ephemeral DH ]]
	  [	uint32	n, preferred keyex key size for ephemeral DH ]
	 [[	uint32	max, max.preferred keyex key size for ephemeral DH ]]
	  [	mpint	p, DH p for ephemeral DH ]
	  [	mpint	g, DH g for ephemeral DH ]
		mpint	e, client DH keyex value
		mpint	f, server DH keyex value
		mpint	K, the shared secret

	   The client and server version string ahd hellos and the host key were
	   hashed inline during the handshake.  The optional parameters are for
	   negotiated DH values (see the conditional-hashing code above).  The
	   double-optional parameters are for the revised version of the DH
	   negotiation mechanism, the original only had n, the revised version
	   allowed a { min, n, max } range */
	status = krnlSendMessage( handshakeInfo->iExchangeHashcontext, 
							  IMESSAGE_CTX_HASH, "", 0 );
	if( cryptStatusOK( status ) )
		{
		setMessageData( &msgData, handshakeInfo->sessionID, 
						CRYPT_MAX_HASHSIZE );
		status = krnlSendMessage( handshakeInfo->iExchangeHashcontext,
								  IMESSAGE_GETATTRIBUTE_S, &msgData,
								  CRYPT_CTXINFO_HASHVALUE );
		if( cryptStatusOK( status ) )
			handshakeInfo->sessionIDlength = msgData.length;
		}
	if( cryptStatusError( status ) )
		return( status );
	krnlSendMessage( handshakeInfo->iExchangeHashcontext,
					 IMESSAGE_DELETEATTRIBUTE, NULL,
					 CRYPT_CTXINFO_HASHVALUE );
	krnlSendMessage( handshakeInfo->iExchangeHashcontext,
					 IMESSAGE_CTX_HASH, handshakeInfo->sessionID,
					 handshakeInfo->sessionIDlength );
	return( krnlSendMessage( handshakeInfo->iExchangeHashcontext,
							 IMESSAGE_CTX_HASH, "", 0 ) );
	}
#endif /* USE_SSH */

⌨️ 快捷键说明

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