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

📄 ssh1.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 5 页
字号:
		   than that there was some general type of failure */
		if( packetType == SSH1_SMSG_FAILURE )
			retExt( sessionInfoPtr, CRYPT_ERROR_WRONGKEY,
					"Server indicated incorrect RSA key was used" );
		expectedType = SSH1_SMSG_AUTH_RSA_CHALLENGE;
		}
	if( expectedType == SSH1_MSG_SPECIAL_ANY )
		{
		/* If we're expecting any kind of data, save the type at the start
		   of the buffer.  The length increment means that we move one byte 
		   of data too much down, but this isn't a big deal since the 
		   returned data length excludes it, and it's not processed anyway - 
		   this packet pseudo-type is only used to eat client or server
		   chattiness at the end of the handshake */
		*bufPtr++ = packetType;
		length += ID_SIZE;
		}
	else
		if( packetType != expectedType )
			retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
					"Invalid packet type 0x%02X, expected 0x%02X", 
					packetType, expectedType );

	/* Move the data down in the buffer to get rid of the padding.  This 
	   isn't as inefficient as it seems since it's only used for short
	   handshake messages */
	memmove( bufPtr, sessionInfoPtr->receiveBuffer + padLength + ID_SIZE, 
			 length );

	return( length );
	}

/* Send an SSHv1 packet.  SSHv1 uses an awkward variable-length padding at 
   the start, when we're sending short control packets we can pre-calculate 
   the data start position or memmove() it into place, with longer data 
   quantities we can no longer easily do this so we build the header 
   backwards from the start of the data in the buffer.  Because of this we 
   perform all operations on the data relative to a variable start position 
   given by the parameter delta */

static int sendPacketSsh1( SESSION_INFO *sessionInfoPtr, 
						   const int packetType, const int dataLength,
						   const int delta )
	{
	RESOURCE_DATA msgData;
	BYTE *bufStartPtr = sessionInfoPtr->sendBuffer + delta;
	BYTE *bufPtr = bufStartPtr;
	unsigned long crc32;
	const int length = ID_SIZE + dataLength + SSH1_CRC_SIZE;
	const int padLength = getPadLength( dataLength );
	int status;

	/* Add the SSH packet header:
		uint32		length
		byte[]		padding, 8 - ( length & 7 ) bytes
		byte		type
		byte[]		data
		uint32		crc32	- Calculated over padding, type, and data */
	mputLong( bufPtr, ( long ) length );
	setMessageData( &msgData, bufPtr, padLength );
	krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S, 
					 &msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
	bufPtr[ padLength ] = packetType;
	if( ( sessionInfoPtr->flags & ( SESSION_ISCRYPTLIB | SESSION_ISSECURE ) ) == \
								  ( SESSION_ISCRYPTLIB | SESSION_ISSECURE ) )
		crc32 = calculateTruncatedMAC( sessionInfoPtr->iAuthInContext,
									   bufPtr, 
									   padLength + ID_SIZE + dataLength );
	else
		crc32 = calculateCRC( bufPtr, padLength + ID_SIZE + dataLength );
	bufPtr += padLength + ID_SIZE + dataLength;
	mputLong( bufPtr, crc32 );
	if( sessionInfoPtr->flags & SESSION_ISSECURE )
		{
		/* Encrypt the payload with handling for SSH's Blowfish
		   endianness bug */
		if( sessionInfoPtr->cryptAlgo == CRYPT_ALGO_BLOWFISH )
			longReverse( ( unsigned long * ) ( bufStartPtr + LENGTH_SIZE ),
						 padLength + length );
		status = krnlSendMessage( sessionInfoPtr->iCryptOutContext,
								  IMESSAGE_CTX_ENCRYPT, 
								  bufStartPtr + LENGTH_SIZE, 
								  padLength + length );
		if( sessionInfoPtr->cryptAlgo == CRYPT_ALGO_BLOWFISH )
			longReverse( ( unsigned long * ) ( bufStartPtr + LENGTH_SIZE ),
						 padLength + length );
		if( cryptStatusError( status ) )
			return( status );
		}
	status = swrite( &sessionInfoPtr->stream, bufStartPtr, 
					 LENGTH_SIZE + padLength + length );
	if( cryptStatusError( status ) )
		sNetGetErrorInfo( &sessionInfoPtr->stream, 
						  sessionInfoPtr->errorMessage,
						  &sessionInfoPtr->errorCode );

	return( status );
	}

/****************************************************************************
*																			*
*							Client-side Connect Functions					*
*																			*
****************************************************************************/

/* Perform the initial part of the handshake with the server */

static int beginClientHandshake( SESSION_INFO *sessionInfoPtr, 
								 SSH_HANDSHAKE_INFO *handshakeInfo )
	{
	MESSAGE_CREATEOBJECT_INFO createInfo;
	RESOURCE_DATA msgData;
	BYTE *bufPtr;
	BOOLEAN rsaOK, pwOK;
	int hostKeyLength, serverKeyLength, keyDataLength, length, value, status;

	/* The higher-level code has already read the server session info, send 
	   back our own version info (SSHv1 uses only a LF as terminator).  For 
	   SSHv1 we use the lowest common denominator of our version (1.5, 
	   described in the only existing spec for SSHv1) and whatever the 
	   server can handle */
	strcpy( sessionInfoPtr->sendBuffer, SSH1_ID_STRING "\n" );
	if( sessionInfoPtr->receiveBuffer[ 2 ] < \
							SSH1_ID_STRING[ SSH_ID_SIZE + 2 ] )
		sessionInfoPtr->sendBuffer[ SSH_ID_SIZE + 2 ] = \
								sessionInfoPtr->receiveBuffer[ 2 ];
	status = swrite( &sessionInfoPtr->stream, sessionInfoPtr->sendBuffer, 
					 strlen( sessionInfoPtr->sendBuffer ) );
	if( cryptStatusError( status ) )
		{
		sNetGetErrorInfo( &sessionInfoPtr->stream, 
						  sessionInfoPtr->errorMessage,
						  &sessionInfoPtr->errorCode );
		return( status );
		}

	/* Create the contexts to hold the server and host keys */
	setMessageCreateObjectInfo( &createInfo, CRYPT_ALGO_RSA );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT, 
							  &createInfo, OBJECT_TYPE_CONTEXT );
	if( cryptStatusError( status ) )
		return( status );
	handshakeInfo->iServerCryptContext = createInfo.cryptHandle;
	setMessageCreateObjectInfo( &createInfo, CRYPT_ALGO_RSA );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT,
							  &createInfo, OBJECT_TYPE_CONTEXT );
	if( cryptStatusError( status ) )
		return( status );
	sessionInfoPtr->iKeyexCryptContext = createInfo.cryptHandle;

	/* If the peer is using cryptlib, we use HMAC-SHA instead of CRC32 */
	if( sessionInfoPtr->flags & SESSION_ISCRYPTLIB )
		{
		setMessageCreateObjectInfo( &createInfo, CRYPT_ALGO_HMAC_SHA );
		status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
								  IMESSAGE_DEV_CREATEOBJECT, &createInfo, 
								  OBJECT_TYPE_CONTEXT );
		if( cryptStatusError( status ) )
			return( status );
		sessionInfoPtr->iAuthInContext = createInfo.cryptHandle;
		}

	/* Process the server public key packet:

		byte[8]		cookie
		uint32		keysize_bits		- Usually 768 bits
		mpint		serverkey_exponent
		mpint		serverkey_modulus
		uint32		keysize_bits		- Usually 1024 bits
		mpint		hostkey_exponent
		mpint		hostkey_modulus
		uint32		protocol_flags		- Not used
		uint32		offered_ciphers
		uint32		offered_authent */
	length = readPacketSSH1( sessionInfoPtr, SSH1_SMSG_PUBLIC_KEY );
	if( cryptStatusError( length ) )
		return( length );
	bufPtr = sessionInfoPtr->receiveBuffer;
	memcpy( handshakeInfo->cookie, bufPtr, SSH1_COOKIE_SIZE );
	bufPtr += SSH1_COOKIE_SIZE;
	length -= SSH1_COOKIE_SIZE;
	keyDataLength = status = processPublickeyData( handshakeInfo, bufPtr, 
												   length, TRUE, NULL );
	if( cryptStatusError( status ) )
		return( status );
	setMessageData( &msgData, bufPtr, keyDataLength );
	status = krnlSendMessage( handshakeInfo->iServerCryptContext, 
							  IMESSAGE_SETATTRIBUTE_S, &msgData, 
							  CRYPT_IATTRIBUTE_KEY_SSH1 );
	if( cryptStatusError( status ) )
		return( status );
	serverKeyLength = mgetLong( bufPtr );
	bufPtr += keyDataLength - LENGTH_SIZE;
	length -= keyDataLength;
	keyDataLength = status = processPublickeyData( handshakeInfo, bufPtr, 
												   length, FALSE, 
												   sessionInfoPtr );
	if( cryptStatusError( status ) )
		return( status );
	setMessageData( &msgData, bufPtr, keyDataLength );
	status = krnlSendMessage( sessionInfoPtr->iKeyexCryptContext, 
							  IMESSAGE_SETATTRIBUTE_S, &msgData, 
							  CRYPT_IATTRIBUTE_KEY_SSH1 );
	if( cryptStatusError( status ) )
		return( status );
	hostKeyLength = mgetLong( bufPtr );
	bufPtr += keyDataLength - LENGTH_SIZE + UINT_SIZE;	/* Skip protocol flags */
	length -= keyDataLength + UINT_SIZE;
	if( length != UINT_SIZE + UINT_SIZE )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid length %d, should be %d", length, 
				UINT_SIZE + UINT_SIZE );
	value = ( int ) mgetLong( bufPtr );		/* Offered ciphers */
	sessionInfoPtr->cryptAlgo = maskToAlgoID( value );
	if( sessionInfoPtr->cryptAlgo == CRYPT_ALGO_NONE )
		retExt( sessionInfoPtr, CRYPT_ERROR_NOTAVAIL,
				"No crypto algorithm compatible with the remote system "
				"could be found" );
	value = ( int ) mgetLong( bufPtr );		/* Offered authentication */
	pwOK = ( value & ( 1 << SSH1_AUTH_PASSWORD ) ) && \
		   sessionInfoPtr->passwordLength > 0;
	rsaOK = ( value & ( 1 << SSH1_AUTH_RSA ) ) && \
			sessionInfoPtr->privateKey != CRYPT_ERROR;
	if( !pwOK )
		{
		/* If neither RSA nor password authentication is possible, we can't 
		   authenticate ourselves */
		if( !rsaOK )
			{
			if( value & ( 1 << SSH1_AUTH_PASSWORD ) )
				{
				setErrorInfo( sessionInfoPtr, CRYPT_SESSINFO_PASSWORD,
							  CRYPT_ERRTYPE_ATTR_ABSENT );
				retExt( sessionInfoPtr, CRYPT_ERROR_NOTINITED,
						"Server requested password authentication but no "
						"password was available" );
				}
			setErrorInfo( sessionInfoPtr, CRYPT_SESSINFO_PRIVATEKEY,
						  CRYPT_ERRTYPE_ATTR_ABSENT );
			retExt( sessionInfoPtr, CRYPT_ERROR_NOTINITED,
					"Server requested public-key authentication but no "
					"key was available" );
			}

		/* Either the client or the server won't do passwords, turn it off 
		   explicitly at the client in case it's the server */
		if( sessionInfoPtr->passwordLength > 0 )
			{
			zeroise( sessionInfoPtr->password, 
					 sessionInfoPtr->passwordLength );
			sessionInfoPtr->passwordLength = 0;
			}
		}

	/* Although in theory the server key has to fit inside the host key, the 
	   spec is vague enough to allow either of the keys to be larger (and at 
	   least one SSH implementation has them the wrong way around), requiring 
	   that the two be swapped before they can be used (which makes you 
	   wonder why there's any distinction, since the two must be 
	   interchangeable in order for this to work) */
	if( hostKeyLength < serverKeyLength )
		{
		int temp;

		/* Swap the two keys around */
		temp = sessionInfoPtr->iKeyexCryptContext;
		sessionInfoPtr->iKeyexCryptContext = \
								handshakeInfo->iServerCryptContext;
		handshakeInfo->iServerCryptContext = temp;
		temp = hostKeyLength;
		hostKeyLength = serverKeyLength;
		serverKeyLength = temp;
		}

	/* Make sure that the smaller of the two keys will fit inside the 
	   larger */
	if( hostKeyLength < serverKeyLength + 128 )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA, 
				"Invalid host vs.server key lengths %d:%d bytes", 
				hostKeyLength, serverKeyLength );

	return( CRYPT_OK );
	}

/* Exchange keys with the server */

static int exchangeClientKeys( SESSION_INFO *sessionInfoPtr, 
							   SSH_HANDSHAKE_INFO *handshakeInfo )
	{
	MECHANISM_WRAP_INFO mechanismInfo;
	RESOURCE_DATA msgData;
	BYTE buffer[ CRYPT_MAX_PKCSIZE ];
	BYTE *bufPtr = sessionInfoPtr->sendBuffer;
	int length, dataLength, value, i, status;

	/* Output the start of the session key packet:

		byte		cipher_type
		byte[8]		cookie
		mpint		double_enc_sessionkey
		uint32		protocol_flags */
	switch( sessionInfoPtr->cryptAlgo )
		{
		case CRYPT_ALGO_BLOWFISH:
			value = SSH1_CIPHER_BLOWFISH;
			break;
		case CRYPT_ALGO_DES:
			value = SSH1_CIPHER_DES;
			break;
		case CRYPT_ALGO_IDEA:
			value = SSH1_CIPHER_IDEA;
			break;
		case CRYPT_ALGO_RC4:
			value = SSH1_CIPHER_RC4;
			break;
		default:
			assert( NOTREACHED );
			return( CRYPT_ERROR_NOTAVAIL );
		}
	*bufPtr++ = value;
	memcpy( bufPtr, handshakeInfo->cookie, SSH1_COOKIE_SIZE );
	bufPtr += SSH1_COOKIE_SIZE;

	/* Generate the session ID and secure state information and XOR the 
	   secure state with the session ID */
	generateSessionID( handshakeInfo );
	setMessageData( &msgData, handshakeInfo->secretValue, SSH1_SECRET_SIZE );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S,
							  &msgData, CRYPT_IATTRIBUTE_RANDOM );
	if( cryptStatusError( status ) )
		return( status );
	handshakeInfo->secretValueLength = SSH1_SECRET_SIZE;
	for( i = 0; i < SSH1_SESSIONID_SIZE; i++ )
		handshakeInfo->secretValue[ i ] ^= handshakeInfo->sessionID[ i ];

	/* Export the secure state information in double-encrypted form, 

⌨️ 快捷键说明

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