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

📄 ssh1.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 5 页
字号:
/****************************************************************************
*																			*
*						cryptlib SSHv1 Session Management					*
*						Copyright Peter Gutmann 1998-2001					*
*																			*
****************************************************************************/

#if defined( INC_ALL )
  #include "crypt.h"
  #include "session.h"
  #include "ssh.h"
#else
  #include "crypt.h"
  #include "session/session.h"
  #include "session/ssh.h"
#endif /* Compiler-specific includes */

#ifdef USE_SSH1

#error The SSHv1 protocol is insecure and obsolete, you should only enable this if absolutely necessary.

/* Determine the number of padding bytes required to make the packet size a
   multiple of 8 bytes */

#define getPadLength( length ) \
		( 8 - ( ( ID_SIZE + ( length ) + SSH1_CRC_SIZE ) & 7 ) )

/****************************************************************************
*																			*
*								Utility Functions							*
*																			*
****************************************************************************/

/* Byte-reverse an array of 32-bit words, needed for Blowfish encryption,
   which in the original SSH implementation got the endianness wrong.  This
   code is safe even for CPUs with a word size > 32 bits since on a little-
   endian CPU the important 32 bits are stored first, so that by zeroizing
   the first 32 bits and or-ing the reversed value back in we don't have to
   rely on the processor only writing 32 bits into memory */

static void longReverse( unsigned long *buffer, int count )
	{
#if defined( SYSTEM_64BIT )
	BYTE *bufPtr = ( BYTE * ) buffer, temp;

	assert( ( count % 4 ) == 0 );

	count /= 4;		/* sizeof( unsigned long ) != 4 */
	while( count-- > 0 )
		{
  #if 0
		unsigned long temp;

		/* This code is cursed */
		temp = value = *buffer & 0xFFFFFFFFUL;
		value = ( ( value & 0xFF00FF00UL ) >> 8  ) | \
				( ( value & 0x00FF00FFUL ) << 8 );
		value = ( ( value << 16 ) | ( value >> 16 ) ) ^ temp;
		*buffer ^= value;
		buffer = ( unsigned long * ) ( ( BYTE * ) buffer + 4 );
  #endif /* 0 */
		/* There's really no nice way to do this - the above code generates
		   misaligned accesses on processors with a word size > 32 bits, so
		   we have to work at the byte level (either that or turn misaligned
		   access warnings off by trapping the signal the access corresponds
		   to, however a context switch per memory access is probably
		   somewhat slower than the current byte-twiddling mess) */
		temp = bufPtr[ 3 ];
		bufPtr[ 3 ] = bufPtr[ 0 ];
		bufPtr[ 0 ] = temp;
		temp = bufPtr[ 2 ];
		bufPtr[ 2 ] = bufPtr[ 1 ];
		bufPtr[ 1 ] = temp;
		bufPtr += 4;
		}
#elif defined( __WIN32__ )
	assert( ( count % 4 ) == 0 );

	/* The following code, which makes use of bswap, is rather faster than
	   what the compiler would otherwise generate */
__asm {
	mov ecx, count
	mov edx, buffer
	shr ecx, 2
swapLoop:
	mov eax, [edx]
	bswap eax
	mov [edx], eax
	add edx, 4
	dec ecx
	jnz swapLoop
	}
#else
	unsigned long value;

	assert( ( count % 4 ) == 0 );
	assert( sizeof( unsigned long ) == 4 );

	count /= sizeof( unsigned long );
	while( count-- > 0 )
		{
		value = *buffer;
		value = ( ( value & 0xFF00FF00UL ) >> 8  ) | \
				( ( value & 0x00FF00FFUL ) << 8 );
		*buffer++ = ( value << 16 ) | ( value >> 16 );
		}
#endif /* SYSTEM_64BIT */
	}

/* Calculate the CRC32 for a data block.  This uses the slightly nonstandard
   variant from the original SSH code, which calculates the UART-style
   reflected value and doesn't pre-set the value to all ones (done to to
   catch leading zero bytes, which happens quite a bit with SSH because of
   the 32-bit length at the start) or XOR it with all ones before returning
   it.  This means that the resulting CRC is not the same as the one in
   Ethernet, Pkzip, and most other implementations */

static const FAR_BSS unsigned long crc32table[] = {
	0x00000000UL, 0x77073096UL, 0xEE0E612CUL, 0x990951BAUL,
	0x076DC419UL, 0x706AF48FUL, 0xE963A535UL, 0x9E6495A3UL,
	0x0EDB8832UL, 0x79DCB8A4UL, 0xE0D5E91EUL, 0x97D2D988UL,
	0x09B64C2BUL, 0x7EB17CBDUL, 0xE7B82D07UL, 0x90BF1D91UL,
	0x1DB71064UL, 0x6AB020F2UL, 0xF3B97148UL, 0x84BE41DEUL,
	0x1ADAD47DUL, 0x6DDDE4EBUL, 0xF4D4B551UL, 0x83D385C7UL,
	0x136C9856UL, 0x646BA8C0UL, 0xFD62F97AUL, 0x8A65C9ECUL,
	0x14015C4FUL, 0x63066CD9UL, 0xFA0F3D63UL, 0x8D080DF5UL,
	0x3B6E20C8UL, 0x4C69105EUL, 0xD56041E4UL, 0xA2677172UL,
	0x3C03E4D1UL, 0x4B04D447UL, 0xD20D85FDUL, 0xA50AB56BUL,
	0x35B5A8FAUL, 0x42B2986CUL, 0xDBBBC9D6UL, 0xACBCF940UL,
	0x32D86CE3UL, 0x45DF5C75UL, 0xDCD60DCFUL, 0xABD13D59UL,
	0x26D930ACUL, 0x51DE003AUL, 0xC8D75180UL, 0xBFD06116UL,
	0x21B4F4B5UL, 0x56B3C423UL, 0xCFBA9599UL, 0xB8BDA50FUL,
	0x2802B89EUL, 0x5F058808UL, 0xC60CD9B2UL, 0xB10BE924UL,
	0x2F6F7C87UL, 0x58684C11UL, 0xC1611DABUL, 0xB6662D3DUL,
	0x76DC4190UL, 0x01DB7106UL, 0x98D220BCUL, 0xEFD5102AUL,
	0x71B18589UL, 0x06B6B51FUL, 0x9FBFE4A5UL, 0xE8B8D433UL,
	0x7807C9A2UL, 0x0F00F934UL, 0x9609A88EUL, 0xE10E9818UL,
	0x7F6A0DBBUL, 0x086D3D2DUL, 0x91646C97UL, 0xE6635C01UL,
	0x6B6B51F4UL, 0x1C6C6162UL, 0x856530D8UL, 0xF262004EUL,
	0x6C0695EDUL, 0x1B01A57BUL, 0x8208F4C1UL, 0xF50FC457UL,
	0x65B0D9C6UL, 0x12B7E950UL, 0x8BBEB8EAUL, 0xFCB9887CUL,
	0x62DD1DDFUL, 0x15DA2D49UL, 0x8CD37CF3UL, 0xFBD44C65UL,
	0x4DB26158UL, 0x3AB551CEUL, 0xA3BC0074UL, 0xD4BB30E2UL,
	0x4ADFA541UL, 0x3DD895D7UL, 0xA4D1C46DUL, 0xD3D6F4FBUL,
	0x4369E96AUL, 0x346ED9FCUL, 0xAD678846UL, 0xDA60B8D0UL,
	0x44042D73UL, 0x33031DE5UL, 0xAA0A4C5FUL, 0xDD0D7CC9UL,
	0x5005713CUL, 0x270241AAUL, 0xBE0B1010UL, 0xC90C2086UL,
	0x5768B525UL, 0x206F85B3UL, 0xB966D409UL, 0xCE61E49FUL,
	0x5EDEF90EUL, 0x29D9C998UL, 0xB0D09822UL, 0xC7D7A8B4UL,
	0x59B33D17UL, 0x2EB40D81UL, 0xB7BD5C3BUL, 0xC0BA6CADUL,
	0xEDB88320UL, 0x9ABFB3B6UL, 0x03B6E20CUL, 0x74B1D29AUL,
	0xEAD54739UL, 0x9DD277AFUL, 0x04DB2615UL, 0x73DC1683UL,
	0xE3630B12UL, 0x94643B84UL, 0x0D6D6A3EUL, 0x7A6A5AA8UL,
	0xE40ECF0BUL, 0x9309FF9DUL, 0x0A00AE27UL, 0x7D079EB1UL,
	0xF00F9344UL, 0x8708A3D2UL, 0x1E01F268UL, 0x6906C2FEUL,
	0xF762575DUL, 0x806567CBUL, 0x196C3671UL, 0x6E6B06E7UL,
	0xFED41B76UL, 0x89D32BE0UL, 0x10DA7A5AUL, 0x67DD4ACCUL,
	0xF9B9DF6FUL, 0x8EBEEFF9UL, 0x17B7BE43UL, 0x60B08ED5UL,
	0xD6D6A3E8UL, 0xA1D1937EUL, 0x38D8C2C4UL, 0x4FDFF252UL,
	0xD1BB67F1UL, 0xA6BC5767UL, 0x3FB506DDUL, 0x48B2364BUL,
	0xD80D2BDAUL, 0xAF0A1B4CUL, 0x36034AF6UL, 0x41047A60UL,
	0xDF60EFC3UL, 0xA867DF55UL, 0x316E8EEFUL, 0x4669BE79UL,
	0xCB61B38CUL, 0xBC66831AUL, 0x256FD2A0UL, 0x5268E236UL,
	0xCC0C7795UL, 0xBB0B4703UL, 0x220216B9UL, 0x5505262FUL,
	0xC5BA3BBEUL, 0xB2BD0B28UL, 0x2BB45A92UL, 0x5CB36A04UL,
	0xC2D7FFA7UL, 0xB5D0CF31UL, 0x2CD99E8BUL, 0x5BDEAE1DUL,
	0x9B64C2B0UL, 0xEC63F226UL, 0x756AA39CUL, 0x026D930AUL,
	0x9C0906A9UL, 0xEB0E363FUL, 0x72076785UL, 0x05005713UL,
	0x95BF4A82UL, 0xE2B87A14UL, 0x7BB12BAEUL, 0x0CB61B38UL,
	0x92D28E9BUL, 0xE5D5BE0DUL, 0x7CDCEFB7UL, 0x0BDBDF21UL,
	0x86D3D2D4UL, 0xF1D4E242UL, 0x68DDB3F8UL, 0x1FDA836EUL,
	0x81BE16CDUL, 0xF6B9265BUL, 0x6FB077E1UL, 0x18B74777UL,
	0x88085AE6UL, 0xFF0F6A70UL, 0x66063BCAUL, 0x11010B5CUL,
	0x8F659EFFUL, 0xF862AE69UL, 0x616BFFD3UL, 0x166CCF45UL,
	0xA00AE278UL, 0xD70DD2EEUL, 0x4E048354UL, 0x3903B3C2UL,
	0xA7672661UL, 0xD06016F7UL, 0x4969474DUL, 0x3E6E77DBUL,
	0xAED16A4AUL, 0xD9D65ADCUL, 0x40DF0B66UL, 0x37D83BF0UL,
	0xA9BCAE53UL, 0xDEBB9EC5UL, 0x47B2CF7FUL, 0x30B5FFE9UL,
	0xBDBDF21CUL, 0xCABAC28AUL, 0x53B39330UL, 0x24B4A3A6UL,
	0xBAD03605UL, 0xCDD70693UL, 0x54DE5729UL, 0x23D967BFUL,
	0xB3667A2EUL, 0xC4614AB8UL, 0x5D681B02UL, 0x2A6F2B94UL,
	0xB40BBE37UL, 0xC30C8EA1UL, 0x5A05DF1BUL, 0x2D02EF8DUL
	};

static unsigned long calculateCRC( const BYTE *data, const int dataLength )
	{
	unsigned long crc32 = 0;
	int i;

	for( i = 0; i < dataLength; i++ )
		crc32 = crc32table[ ( int ) ( crc32 ^ data[ i ] ) & 0xFF ] ^ ( crc32 >> 8 );

	return( crc32 );
	}

/* If we detect that the other side is also running cryptlib, we use a
   truncated MAC instead of a CRC32 once we're running in secure mode.  This
   prevents extension attacks on the CRC-protected data.  The reason for
   the truncation is to make it the same length as the CRC, this makes it a
   bit weaker than a full-length MAC but no weaker than a cryptographically
   strong CRC (in any case the chances of a successful attack are only 1/2^31,
   since you only get one chance to get it right) */

static unsigned long calculateTruncatedMAC( const CRYPT_CONTEXT iMacContext,
											const BYTE *data,
											const int dataLength )
	{
	MESSAGE_DATA msgData;
	BYTE macBuffer[ CRYPT_MAX_HASHSIZE + 8 ], *bufPtr = macBuffer;
	unsigned long macValue;
	int status;

	/* MAC the data and return the 32-bit truncated MAC value */
	krnlSendMessage( iMacContext, IMESSAGE_DELETEATTRIBUTE, NULL,
					 CRYPT_CTXINFO_HASHVALUE );
	krnlSendMessage( iMacContext, IMESSAGE_CTX_HASH, ( void * ) data,
					 dataLength );
	krnlSendMessage( iMacContext, IMESSAGE_CTX_HASH, "", 0 );
	setMessageData( &msgData, macBuffer, CRYPT_MAX_HASHSIZE );
	status = krnlSendMessage( iMacContext, IMESSAGE_GETATTRIBUTE_S,
							  &msgData, CRYPT_CTXINFO_HASHVALUE );
	if( cryptStatusError( status ) )
		return( 0 );	/* Will cause a protocol failure */
	macValue = mgetLong( bufPtr );

	return( macValue );
	}

/* Convert an SSHv1 algorithm ID to a cryptlib ID in preferred-algorithm
   order, and return a list of available algorithms in SSHv1 cipher-mask
   format.  We can't use 3DES since this uses inner-CBC which is both
   nonstandard and has known (although not serious) weaknesses.  If we
   wanted to implement it in a portable manner (i.e. usable with external
   drivers and devices) we'd have to synthesize it using three lots of
   DES-CBC since nothing implements the variant that SSHv1 uses.  SSHv2
   fixed this so it's no longer a problem in that case */

static CRYPT_ALGO_TYPE maskToAlgoID( const int value )
	{
	if( ( value & ( 1 << SSH1_CIPHER_BLOWFISH ) ) && \
		algoAvailable( CRYPT_ALGO_BLOWFISH ) )
		return( CRYPT_ALGO_BLOWFISH );
	if( ( value & ( 1 << SSH1_CIPHER_IDEA ) ) && \
		algoAvailable( CRYPT_ALGO_IDEA ) )
		return( CRYPT_ALGO_IDEA );
	if( ( value & ( 1 << SSH1_CIPHER_RC4 ) ) && \
		algoAvailable( CRYPT_ALGO_RC4 ) )
		return( CRYPT_ALGO_RC4 );
	if( value & ( 1 << SSH1_CIPHER_DES ) )
		return( CRYPT_ALGO_DES );

	return( CRYPT_ALGO_NONE );
	}

static CRYPT_ALGO_TYPE sshIDToAlgoID( const int value )
	{
	switch( value )
		{
		case SSH1_CIPHER_IDEA:
			if( algoAvailable( CRYPT_ALGO_IDEA ) )
				return( CRYPT_ALGO_IDEA );
			break;

		case SSH1_CIPHER_DES:
			return( CRYPT_ALGO_DES );

		case SSH1_CIPHER_RC4:
			if( algoAvailable( CRYPT_ALGO_RC4 ) )
				return( CRYPT_ALGO_RC4 );
			break;

		case SSH1_CIPHER_BLOWFISH:
			if( algoAvailable( CRYPT_ALGO_BLOWFISH ) )
				return( CRYPT_ALGO_BLOWFISH );
			break;
		}

	return( CRYPT_ALGO_NONE );
	}

static long getAlgorithmMask( void )
	{
	long value = 0;

	if( algoAvailable( CRYPT_ALGO_DES ) )
		value |= 1 << SSH1_CIPHER_DES;
	if( algoAvailable( CRYPT_ALGO_BLOWFISH ) )
		value |= 1 << SSH1_CIPHER_BLOWFISH;
	if( algoAvailable( CRYPT_ALGO_IDEA ) )
		value |= 1 << SSH1_CIPHER_IDEA;
	if( algoAvailable( CRYPT_ALGO_RC4 ) )
		value |= 1 << SSH1_CIPHER_RC4;

	return( value );
	}

/* Encode a value as an SSH string */

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

	if( buffer != NULL )
		{
		mputLong( bufPtr, length );
		memcpy( bufPtr, string, length );
		}
	return( LENGTH_SIZE + length );
	}

/* Generate an SSH session ID */

static void generateSessionID( SSH_HANDSHAKE_INFO *handshakeInfo )
	{
	HASHFUNCTION hashFunction;
	HASHINFO hashInfo;

	/* Get the hash algorithm information and hash the server key modulus,
	   host key modulus, and cookie.  The SSH documentation and source code
	   are quite confusing on this issue, giving the key components to be
	   hashed multiple names (server key, host key, session key, public key,
	   etc etc).  The correct order is:
		hash( host modulus || server modulus || cookie ) */
	getHashParameters( CRYPT_ALGO_MD5, &hashFunction, NULL );
	hashFunction( hashInfo, NULL, handshakeInfo->hostModulus,
				  handshakeInfo->hostModulusLength, HASH_START );
	hashFunction( hashInfo, NULL, handshakeInfo->serverModulus,
				  handshakeInfo->serverModulusLength, HASH_CONTINUE );
	hashFunction( hashInfo, handshakeInfo->sessionID,
				  handshakeInfo->cookie, SSH1_COOKIE_SIZE, HASH_END );
	handshakeInfo->sessionIDlength = SSH1_SESSIONID_SIZE;
	}

/* Generate/check an SSHv1 key fingerprint.  This is the same easily-
   spoofable MD5 hash of the raw RSA n and e values used by PGP 2.x */

⌨️ 快捷键说明

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