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

📄 ssh1.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 5 页
字号:
	   encrypted first with the server key, then with the host key */
	setMechanismWrapInfo( &mechanismInfo, buffer, CRYPT_MAX_PKCSIZE, 
						  handshakeInfo->secretValue, SSH1_SECRET_SIZE, 
						  CRYPT_UNUSED, handshakeInfo->iServerCryptContext, 
						  CRYPT_UNUSED );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_EXPORT, 
							  &mechanismInfo, MECHANISM_PKCS1_RAW );
	if( cryptStatusError( status ) )
		return( status );
	length = mechanismInfo.wrappedDataLength;
	setMechanismWrapInfo( &mechanismInfo, 
						  bufPtr + SSH1_MPI_LENGTH_SIZE, CRYPT_MAX_PKCSIZE, 
						  buffer, length, CRYPT_UNUSED, 
						  sessionInfoPtr->iKeyexCryptContext, CRYPT_UNUSED );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_EXPORT, 
							  &mechanismInfo, MECHANISM_PKCS1_RAW );
	if( cryptStatusError( status ) )
		return( status );
	length = bytesToBits( mechanismInfo.wrappedDataLength );
	mputWord( bufPtr, length );
	bufPtr += mechanismInfo.wrappedDataLength;
	clearMechanismInfo( &mechanismInfo );

	/* XOR the state with the session ID to recover the actual state */
	for( i = 0; i < SSH1_SESSIONID_SIZE; i++ )
		handshakeInfo->secretValue[ i ] ^= handshakeInfo->sessionID[ i ];

	/* Write the various flags */
	mputLong( bufPtr, 0 );		/* Protocol flags */

	/* Move the data up in the buffer to allow for the variable-length
	   padding and send it to the server */
	dataLength = bufPtr - sessionInfoPtr->sendBuffer;
	memmove( sessionInfoPtr->sendBuffer + LENGTH_SIZE + \
			 getPadLength( dataLength ) + ID_SIZE,
			 sessionInfoPtr->sendBuffer, dataLength );
	return( sendPacketSsh1( sessionInfoPtr, SSH1_CMSG_SESSION_KEY,
							dataLength, 0 ) );
	}

/* Complete the handshake with the server */

static int completeClientHandshake( SESSION_INFO *sessionInfoPtr, 
									SSH_HANDSHAKE_INFO *handshakeInfo )
	{
	BYTE *bufPtr;
	int padLength, modulusLength, length, status;

	/* Set up the security information required for the session */
	status = initSecurityInfoSSH1( sessionInfoPtr, handshakeInfo );
	if( cryptStatusError( status ) )
		return( status );

	/* Read back the server ack and send the user name:
		string		username */
	status = readPacketSSH1( sessionInfoPtr, SSH1_SMSG_SUCCESS );
	if( cryptStatusError( status ) )
		return( status );
	padLength = getPadLength( LENGTH_SIZE + sessionInfoPtr->userNameLength );
	bufPtr = sessionInfoPtr->sendBuffer + LENGTH_SIZE + padLength + ID_SIZE;
	encodeString( bufPtr, sessionInfoPtr->userName, 
				  sessionInfoPtr->userNameLength );
	status = sendPacketSsh1( sessionInfoPtr, SSH1_CMSG_USER,
							 LENGTH_SIZE + sessionInfoPtr->userNameLength, 
							 0 );
	if( cryptStatusError( status ) )
		return( status );

	/* Read back the server ack and send the authentication information if 
	   required.  This information is optional, if the server returns a 
	   failure packet (converted to an OK_SPECIAL return status) it means 
	   authentication is required, otherwise it isn't and we're already 
	   logged in */
	status = readPacketSSH1( sessionInfoPtr, SSH1_MSG_SPECIAL_USEROPT );
	if( status == OK_SPECIAL )
		{
		/* If there's a password present, we're using password-based 
		   authentication:
			string		password */
		if( sessionInfoPtr->passwordLength > 0 )
			{
			int maxLen, packetType, i;

			/* Since SSHv1 sends the packet length in the clear and uses
			   implicit-length padding, it reveals the length of the 
			   encrypted password to an observer.  To get around this, we
			   send a series of packets of length 4...maxLen to the server,
			   one of which is the password, the rest are SSH_MSG_IGNOREs.
			   It's still possible for an attacker who can perform very
			   precise timing measurements to determine which one is the
			   password based on server response time, but it's a lot less
			   problematic than with a single packet.  Unfortunately, it's
			   also possible for an attacker to determine the password packet 
			   by checking which one generates the password response, unless
			   the server somehow knows how many packets are coming reads 
			   them all in a loop and only then sends a response, which 
			   means that this defence isn't as effective as it seems */
			status = CRYPT_OK;
			for( maxLen = 16; maxLen <= sessionInfoPtr->passwordLength;
				 maxLen <<= 1 );
			for( i = min( 4, sessionInfoPtr->passwordLength ); 
				 i < maxLen && cryptStatusOK( status ); i++ )
				{
				padLength = getPadLength( LENGTH_SIZE + i );
				bufPtr = sessionInfoPtr->sendBuffer + LENGTH_SIZE + \
													  padLength + ID_SIZE;
				if( i == sessionInfoPtr->passwordLength )
					{
					encodeString( bufPtr, sessionInfoPtr->password, 
								  sessionInfoPtr->passwordLength );
					packetType = SSH1_CMSG_AUTH_PASSWORD;
					}
				else
					{
					RESOURCE_DATA msgData;

					setMessageData( &msgData, sessionInfoPtr->receiveBuffer, 
									i );
					krnlSendMessage( SYSTEM_OBJECT_HANDLE, 
									 IMESSAGE_GETATTRIBUTE_S, &msgData, 
									 CRYPT_IATTRIBUTE_RANDOM_NONCE );
					encodeString( bufPtr, sessionInfoPtr->receiveBuffer, i );
					packetType = SSH1_MSG_IGNORE;
					}
				status = sendPacketSsh1( sessionInfoPtr, packetType,
										 LENGTH_SIZE + i, 0 );
				if( cryptStatusOK( status ) && \
					packetType == SSH1_CMSG_AUTH_PASSWORD )
					status = readPacketSSH1( sessionInfoPtr, 
											 SSH1_MSG_SPECIAL_PWOPT );
				}
			}
		else
			{
			MECHANISM_WRAP_INFO mechanismInfo;
			RESOURCE_DATA msgData;
			BYTE challenge[ SSH1_CHALLENGE_SIZE ], response[ SSH1_RESPONSE_SIZE ];
			BYTE modulusBuffer[ ( SSH1_MPI_LENGTH_SIZE + CRYPT_MAX_PKCSIZE ) * 2 ];
			BYTE *modulusPtr;

			/* We're using RSA authentication, initially we send just the user's
			   public-key info:

		        mpint	identity_public_modulus

			   First we get the modulus used to identify the client's key.
			   For no adequately explored reason this is only the modulus and
			   not the usual exponent+modulus combination, which means that
			   there's no way for a cryptlib server to identify the public 
			   key from it, although at a pinch we could try with e=17, 257, 
			   or F4 */
			setMessageData( &msgData, modulusBuffer, 
							( SSH1_MPI_LENGTH_SIZE + CRYPT_MAX_PKCSIZE ) * 2 );
			status = krnlSendMessage( sessionInfoPtr->privateKey, 
									  IMESSAGE_GETATTRIBUTE_S, &msgData, 
									  CRYPT_IATTRIBUTE_KEY_SSH1 );
			if( cryptStatusError( status ) )
				return( status );

			/* Skip the key size and exponent to get to the modulus.  We
			   don't have to perform safety checks here since the data is
			   coming from within cryptlib */
			modulusPtr = modulusBuffer + sizeof( LENGTH_SIZE );
			length = mgetWord( modulusPtr );			/* Exponent */
			length = bitsToBytes( length );
			modulusPtr += length;
			modulusLength = mgetWord( modulusPtr );		/* Modulus */
			modulusLength = bitsToBytes( modulusLength );
			length = SSH1_MPI_LENGTH_SIZE + modulusLength;
			modulusPtr -= SSH1_MPI_LENGTH_SIZE;

			/* Send the modulus to the server */
			padLength = getPadLength( length );
			bufPtr = sessionInfoPtr->sendBuffer + LENGTH_SIZE + \
												  padLength + ID_SIZE;
			memcpy( bufPtr, modulusPtr, length );
			status = sendPacketSsh1( sessionInfoPtr, SSH1_CMSG_AUTH_RSA, 
									 length, 0 );
			if( cryptStatusOK( status ) )
				status = readPacketSSH1( sessionInfoPtr, 
										 SSH1_MSG_SPECIAL_RSAOPT );
			if( cryptStatusError( status ) )
				return( status );

			/* The server recognises our key (no mean feat, considering that
			   e could be anything) and has sent an RSA challenge, decrypt 
			   it:

				mpint	encrypted_challenge */
			bufPtr = sessionInfoPtr->receiveBuffer;
			length = mgetWord( bufPtr );
			length = bitsToBytes( length );
			if( length < modulusLength - 8 || length > modulusLength )
				retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
						"Invalid encrypted challenge length %d for modulus "
						"length %d", length, modulusLength );
			setMechanismWrapInfo( &mechanismInfo, bufPtr, length, 
								  challenge, SSH1_CHALLENGE_SIZE, CRYPT_UNUSED, 
								  sessionInfoPtr->privateKey, CRYPT_UNUSED );
			status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
									  IMESSAGE_DEV_IMPORT, &mechanismInfo, 
									  MECHANISM_PKCS1_RAW );
			clearMechanismInfo( &mechanismInfo );
			if( cryptStatusError( status ) )
				return( status );

			/* Send the response to the challenge:

				byte[16]	MD5 of decrypted challenge

			   Since this completes the authentication, we expect to see 
			   either a success or failure packet once we're done */
			generateChallengeResponse( response, handshakeInfo, challenge );
			padLength = getPadLength( SSH1_RESPONSE_SIZE );
			bufPtr = sessionInfoPtr->sendBuffer + LENGTH_SIZE + 
												  padLength + ID_SIZE;
			memcpy( bufPtr, response, SSH1_RESPONSE_SIZE );
			status = sendPacketSsh1( sessionInfoPtr, 
									 SSH1_CMSG_AUTH_RSA_RESPONSE, 
									 SSH1_RESPONSE_SIZE, 0 );
			if( cryptStatusOK( status ) )
				status = readPacketSSH1( sessionInfoPtr, 
										 SSH1_MSG_SPECIAL_PWOPT );
			}
		}
	if( cryptStatusError( status ) )
		return( status );

	/* Tell the server to adjust its maximum packet size if required:

		uint32		packet_size */
	if( sessionInfoPtr->sendBufSize < EXTRA_PACKET_SIZE + MAX_PACKET_SIZE )
		{
		const int maxLength = sessionInfoPtr->sendBufSize - \
							  EXTRA_PACKET_SIZE;

		padLength = getPadLength( LENGTH_SIZE );
		bufPtr = sessionInfoPtr->sendBuffer + LENGTH_SIZE + padLength + ID_SIZE; 
		mputLong( bufPtr, maxLength );
		status = sendPacketSsh1( sessionInfoPtr, SSH1_CMSG_MAX_PACKET_SIZE,
								 LENGTH_SIZE, 0 );
		if( cryptStatusOK( status ) )
			status = readPacketSSH1( sessionInfoPtr, SSH1_SMSG_SUCCESS );
		if( cryptStatusError( status ) )
			return( status );
		}

	/* Request a pty from the server:

		string		TERM environment variable = "vt100"
		uint32		rows = 24
		uint32		cols = 80
		uint32		pixel_width = 0
		uint32		pixel_height = 0
		byte		tty_mode_info = 0 */
	padLength = getPadLength( ( LENGTH_SIZE + 5 ) + ( UINT_SIZE * 4 ) + 1 );
	bufPtr = sessionInfoPtr->sendBuffer + LENGTH_SIZE + padLength + ID_SIZE; 
	bufPtr += encodeString( bufPtr, "vt100", 0 );	/* Generic terminal type */
	mputLong( bufPtr, 24 );
	mputLong( bufPtr, 80 );			/* 24 x 80 */
	mputLong( bufPtr, 0 );
	mputLong( bufPtr, 0 );			/* No graphics capabilities */
	*bufPtr = 0;					/* No special TTY modes */
	status = sendPacketSsh1( sessionInfoPtr, SSH1_CMSG_REQUEST_PTY,
							 ( LENGTH_SIZE + 5 ) + ( UINT_SIZE * 4 ) + 1, 
							 0 );
	if( cryptStatusOK( status ) )
		status = readPacketSSH1( sessionInfoPtr, SSH1_SMSG_SUCCESS );
	if( cryptStatusError( status ) )
		return( status );

	/* Tell the server to create a shell for us.  This moves the server into
	   the interactive session mode, if we're talking to a standard Unix 
	   server implementing a remote shell we could read the stdout data 
	   response from starting the shell but this may not be the case so we 
	   leave the response for the user to process explicitly */
	return( sendPacketSsh1( sessionInfoPtr, SSH1_CMSG_EXEC_SHELL, 0, 0 ) );
	}

/****************************************************************************
*																			*
*							Server-side Connect Functions					*
*																			*
****************************************************************************/

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

static int beginServerHandshake( SESSION_INFO *sessionInfoPtr, 
								 SSH_HANDSHAKE_INFO *handshakeInfo )
	{
	MESSAGE_CREATEOBJECT_INFO createInfo;
	RESOURCE_DATA msgData;
	BYTE *bufPtr = sessionInfoPtr->sendBuffer;
	static const int keyLength = bitsToBytes( 768 );
	long value;
	int length, status;

	krnlSendMessage( sessionInfoPtr->privateKey, IMESSAGE_GETATTRIBUTE, 
					 &handshakeInfo->serverKeySize, CRYPT_CTXINFO_KEYSIZE );

	/* Generate the 768-bit RSA server key.  It would be better to do this
	   before the listen on the socket, but we can't do it until we know that 
	   the client is v1, which we only know after the initial message 
	   exchange */
	setMessageCreateObjectInfo( &createInfo, CRYPT_ALGO_RSA );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT,
							  &createInfo, OBJECT_TYPE_CONTEXT );
	if( cryptStatusError( status ) )
		return( status );
	setMessageData( &msgData, "SSH server key", 14 );
	status = krnlSendMessage( createInfo.cryptHandle, 
							  IMESSAGE_SETATTRIBUTE_S, &msgData, 
							  CRYPT_CTXINFO_LABEL );
	if( cryptStatusOK( status ) )
		status = krnlSendMessage( createInfo.cryptHandle, 
								  IMESSAGE_SETATTRIBUTE, ( int * ) &keyLength, 
								  CRYPT_CTXINFO_KEYSIZE );
	if( cryptStatusOK( status ) )
		status = krnlSendMessage( createInfo.cryptHandle, 
								  IMESSAGE_CTX_GENKEY, NULL, FALSE );
	if( cryptStatusError( status ) )
		{
		krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
		return( status );
		}
	handshakeInfo->iServerCryptContext = createInfo.cryptHandle;

	/* Send 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

⌨️ 快捷键说明

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