?? ssh1.c
字號:
/****************************************************************************
* *
* 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 + -