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

📄 ssh.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 5 页
字号:
		/* If we're expecting any kind of data, save the type at the start
		   of the buffer, move the data down in the buffer to get rid of
		   the padding, and return */
		sessionInfoPtr->receiveBuffer[ 0 ] = packetType;
		memmove( sessionInfoPtr->receiveBuffer + 1, 
				 sessionInfoPtr->receiveBuffer + padLength + ID_SIZE, 
				 length - ID_SIZE );
		return( length - ID_SIZE );
		}
	if( packetType != expectedType )
		return( CRYPT_ERROR_BADDATA );

	/* Move the data down in the buffer to get rid of the padding */
	memmove( sessionInfoPtr->receiveBuffer, 
			 sessionInfoPtr->receiveBuffer + padLength + ID_SIZE, 
			 length - ID_SIZE );

	return( length - ID_SIZE );
	}

/* 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 which arrive in multiple segments we can no longer 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 sendPacket1( SESSION_INFO *sessionInfoPtr, 
						const int packetType, const int dataLength,
						const int delta )
	{
	BYTE *bufStartPtr = sessionInfoPtr->sendBuffer + delta;
	BYTE *bufPtr = bufStartPtr;
	LONG crc32;
	const int length = getEffectiveLength1( dataLength );
	const int padLength = getPadLength1( 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 */
	mputBLong( bufPtr, ( long ) length );
	getNonce( bufPtr, padLength );
	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;
	mputBLong( 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( ( LONG * ) ( bufStartPtr + LENGTH_SIZE ),
						 padLength + length );
		status = krnlSendMessage( sessionInfoPtr->iCryptOutContext,
								  RESOURCE_IMESSAGE_CTX_ENCRYPT, 
								  bufStartPtr + LENGTH_SIZE, 
								  padLength + length );
		if( sessionInfoPtr->cryptAlgo == CRYPT_ALGO_BLOWFISH )
			longReverse( ( 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 );
	}

/* Send a disconnect packet */

static int sendDisconnect1( SESSION_INFO *sessionInfoPtr, 
							const char *message )
	{
	BYTE *bufPtr;
	const int messageLength = strlen( message );
	int padLength;

	/* Send a disconnect packet to the remote system:
		string		disconnection_reason */
	padLength = getPadLength1( LENGTH_SIZE + messageLength );
	bufPtr = sessionInfoPtr->sendBuffer + LENGTH_SIZE + padLength + ID_SIZE;
	mputBLong( bufPtr, messageLength );
	memcpy( bufPtr, message, messageLength );
	return( sendPacket1( sessionInfoPtr, SSH_MSG_DISCONNECT,
						 LENGTH_SIZE + messageLength, 0 ) );
	}

/****************************************************************************
*																			*
*								SSHv2 Functions								*
*																			*
****************************************************************************/

/* Load the fixed SSHv2 DH key into a context.  The prime is the value
   2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 }, from the Oakley spec.
   Unfortunately this value of q leads to a horribly inefficient key 
   agreement process, since it's 860 bits larger than it needs to be */

static const BYTE pValue[] = {
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 
	0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
	0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 
	0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 
	0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
	0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 
	0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, 
	0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
	0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 
	0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 
	0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
	0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 
	0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, 
	0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
	};
static const BYTE qValue[] = {
	0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A,
	0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68,
	0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A,
	0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91,
	0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E,
	0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D,
	0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B,
	0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22,
	0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63,
	0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5,
	0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6,
	0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2,
	0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3,
	0x24, 0x94, 0x33, 0x28, 0xF6, 0x73, 0x29, 0xC0,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
	};
static const BYTE gValue[] = { 0x02 };

static int loadDHcontext( const CRYPT_CONTEXT iCryptContext, 
						  const BOOLEAN isKey1 )
	{
	CRYPT_PKCINFO_DLP dhKey, *dhKeyPtr = &dhKey;
	RESOURCE_DATA msgData;
	int status;

	/* Load the key into the context */
	cryptInitComponents( dhKeyPtr, CRYPT_KEYTYPE_PUBLIC );
	cryptSetComponent( dhKeyPtr->p, pValue, 1024 );
	cryptSetComponent( dhKeyPtr->q, qValue, 1024 );
	cryptSetComponent( dhKeyPtr->g, gValue, 2 );
	setResourceData( &msgData, isKey1 ? \
					 "SSH DH key #1" : "SSH DH key #2", 13 );
	status = krnlSendMessage( iCryptContext, RESOURCE_IMESSAGE_SETATTRIBUTE_S,
							  &msgData, CRYPT_CTXINFO_LABEL );
	if( cryptStatusOK( status ) )
		{
		setResourceData( &msgData, dhKeyPtr, sizeof( CRYPT_PKCINFO_DLP ) );
		status = krnlSendMessage( iCryptContext, 
								  RESOURCE_IMESSAGE_SETATTRIBUTE_S,
								  &msgData, CRYPT_CTXINFO_KEY_COMPONENTS );
		}
	cryptDestroyComponents( dhKeyPtr );

	return( status );
	}

/* Convert an SSHv2 algorithm list to a cryptlib ID in preferred-algorithm 
   order, and return a list of available algorithms in SSHv2 algorithm list
   format.  For some bizarre reason the algorithm information is communicated
   as a comma-delimited list (in an otherwise binary protocol), so we have
   to unpack and pack them into this cumbersome format alongside just 
   choosing which algorithm to use */

static int getAlgoID( const ALGO_STRING_INFO *algoInfo, CRYPT_ALGO *algo, 
					  const CRYPT_ALGO preferredAlgo, const BYTE *string, 
					  const int maxLength )
	{
	int stringPos = 0, stringLen, algoIndex = 1000;

	/* Clear return value */
	if( algo != NULL )
		*algo = CRYPT_ALGO_NONE;

	/* Get the string length and make sure it's valid */
	stringLen = mgetBLong( string );
	if( stringLen <= 0 || stringLen > maxLength + LENGTH_SIZE )
		return( CRYPT_ERROR_BADDATA );

	/* Walk down the string looking for a recognised algorithm.  Since our
	   preference may not match the other side's preferences, we have to walk
	   down the entire list to find our preferred choice */
	while( stringPos < stringLen )
		{
		int len, i;

		/* Find the length of the next algorithm name */
		for( len = stringPos; len < stringLen && string[ len ] != ','; len++ );
		len -= stringPos;
		if( !len )
			{
			stringPos++;
			continue;
			}

		/* Check whether it's something we can handle.  SSH algorithms are 
		   used in pairs, one for incoming and the other for outgoing data.
		   To keep things simple, we always force these to be the same (all
		   implementation seem to do this anyway), so if the algorithm choice
		   for one direction has already been specified we make sure that the
		   algorithm for the other direction is the same */
		for( i = 0; algoInfo[ i ].name != NULL; i++ )
			if( !memcmp( algoInfo[ i ].name, string + stringPos, len ) )
				/* If we've found a new, more-preferred algorithm, remember 
				   its entry position */
				if( preferredAlgo == CRYPT_ALGO_NONE && i < algoIndex && \
					algoAvailable( algoInfo[ i ].algo ) )
					algoIndex = i;
				else
					/* We already know what we want, make sure it matches our
					   existing choice */
					if( preferredAlgo == algoInfo[ i ].algo )
						{
						if( algo != NULL )
							*algo = preferredAlgo;
						return( LENGTH_SIZE + stringLen );
						}

		/* No match, move on to the next name */
		stringPos += len + 1;
		}

	if( algoIndex != 1000 )
		{
		if( algo != NULL )
			*algo = algoInfo[ algoIndex ].algo;
		return( LENGTH_SIZE + stringLen );
		}
	return( CRYPT_ERROR_NOTAVAIL );
	}

static int getAlgoIDpair( const ALGO_STRING_INFO *algoInfo, CRYPT_ALGO *algo, 
						  const BYTE *string, const int maxLength )
	{
	CRYPT_ALGO preferredAlgo;
	int length1, length2;

	length1 = getAlgoID( algoInfo, &preferredAlgo, CRYPT_ALGO_NONE, string, 
						 maxLength );
	if( cryptStatusError( length1 ) )
		return( length1 );
	length2 = getAlgoID( algoInfo, algo, preferredAlgo, string + length1, 
						 maxLength - length1 );
	return( cryptStatusError( length2 ) ? length2 : length1 + length2 );
	}

static void putAlgoID( BYTE **bufPtrPtr, const CRYPT_ALGO algo )
	{
	BYTE *bufPtr = *bufPtrPtr;
	int length, i;

	/* Locate the name for this algorithm and encode it as an SSH string */
	for( i = 0; algoStringMapTbl[ i ].name != NULL && \
				algoStringMapTbl[ i ].algo != algo; i++ );
	assert( algoStringMapTbl[ i ].name != NULL );
	length = strlen( algoStringMapTbl[ i ].name );
	mputBLong( bufPtr, length );
	memcpy( bufPtr, algoStringMapTbl[ i ].name, length );
	*bufPtrPtr += LENGTH_SIZE + length;
	}

/* Encode a value as an SSHv2 MPI or string */

static int encodeMPI( BYTE *buffer, const BYTE *value, 
					  const int valueLength )
	{
	BYTE *bufPtr = buffer;
	const int mpiValueLength = valueLength + \
							   ( ( value[ 0 ] & 0x80 ) ? 1 : 0 );

	if( buffer != NULL )
		{
		mputBLong( bufPtr, mpiValueLength );
		if( value[ 0 ] & 0x80 )
			*bufPtr++ = 0;
		memcpy( bufPtr, value, valueLength );
		}

	return( LENGTH_SIZE + mpiValueLength );
	}

static int encodeString( BYTE *buffer, const BYTE *string, 
						 const int stringLength )
	{
	BYTE *bufPtr = buffer;
	const int length = ( stringLength ) ? stringLength : strlen( string );

	if( buffer != NULL )
		{
		mputBLong( bufPtr, length );
		memcpy( bufPtr, string, length );
		}

	return( LENGTH_SIZE + length );
	}

/* Hash a value encoded as an SSH string and MPI */

static int hashAsString( const CRYPT_CONTEXT iHashContext,
						 const BYTE *data, const int dataLength )
	{
	BYTE buffer[ 64 ], *bufPtr = buffer;
	int status;

	/* Prepend the string length to the data and hash it.  If it'll fit in
	   the buffer we copy it over to save a kernel call */
	mputBLong( bufPtr, dataLength );
	if( dataLength < 64 - LENGTH_SIZE )
		{
		memcpy( buffer + LENGTH_SIZE, data, dataLength );
		status = krnlSendMessage( iHashContext, RESOURCE_IMESSAGE_CTX_HASH, 
								  buffer, LENGTH_SIZE + dataLength );
		}
	else

⌨️ 快捷键说明

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