1
0
mirror of https://github.com/danog/phpseclib.git synced 2025-01-22 04:51:19 +01:00

Merge pull request #714 from bantu/diffie-hellman-group-exchange-sha256

Add support for RFC 4419: diffie-hellman-group-exchange-sha{1,256}

* bantu/diffie-hellman-group-exchange-sha256:
  Add support for RFC 4419: diffie-hellman-group-exchange-sha{1,256}
This commit is contained in:
Andreas Fischer 2015-07-08 15:43:46 +02:00
commit cdda621903

View File

@ -206,6 +206,33 @@ class Net_SSH2
*/ */
var $kex_algorithms = false; var $kex_algorithms = false;
/**
* Minimum Diffie-Hellman Group Bit Size in RFC 4419 Key Exchange Methods
*
* @see Net_SSH2::_key_exchange()
* @var Integer
* @access private
*/
var $kex_dh_group_size_min = 1536;
/**
* Preferred Diffie-Hellman Group Bit Size in RFC 4419 Key Exchange Methods
*
* @see Net_SSH2::_key_exchange()
* @var Integer
* @access private
*/
var $kex_dh_group_size_preferred = 2048;
/**
* Maximum Diffie-Hellman Group Bit Size in RFC 4419 Key Exchange Methods
*
* @see Net_SSH2::_key_exchange()
* @var Integer
* @access private
*/
var $kex_dh_group_size_max = 4096;
/** /**
* Server Host Key Algorithms * Server Host Key Algorithms
* *
@ -942,7 +969,13 @@ class Net_SSH2
array(60 => 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ'), array(60 => 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ'),
array(60 => 'NET_SSH2_MSG_USERAUTH_PK_OK'), array(60 => 'NET_SSH2_MSG_USERAUTH_PK_OK'),
array(60 => 'NET_SSH2_MSG_USERAUTH_INFO_REQUEST', array(60 => 'NET_SSH2_MSG_USERAUTH_INFO_REQUEST',
61 => 'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE') 61 => 'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE'),
// RFC 4419 - diffie-hellman-group-exchange-sha{1,256}
array(30 => 'NET_SSH2_MSG_KEXDH_GEX_REQUEST_OLD',
31 => 'NET_SSH2_MSG_KEXDH_GEX_GROUP',
32 => 'NET_SSH2_MSG_KEXDH_GEX_INIT',
33 => 'NET_SSH2_MSG_KEXDH_GEX_REPLY',
34 => 'NET_SSH2_MSG_KEXDH_GEX_REQUEST')
); );
$this->host = $host; $this->host = $host;
@ -1123,7 +1156,9 @@ class Net_SSH2
{ {
static $kex_algorithms = array( static $kex_algorithms = array(
'diffie-hellman-group1-sha1', // REQUIRED 'diffie-hellman-group1-sha1', // REQUIRED
'diffie-hellman-group14-sha1' // REQUIRED 'diffie-hellman-group14-sha1', // REQUIRED
'diffie-hellman-group-exchange-sha1', // RFC 4419
'diffie-hellman-group-exchange-sha256', // RFC 4419
); );
static $server_host_key_algorithms = array( static $server_host_key_algorithms = array(
@ -1403,6 +1438,48 @@ class Net_SSH2
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
} }
if (strpos($kex_algorithms[$i], 'diffie-hellman-group-exchange') === 0) {
$dh_group_sizes_packed = pack('NNN',
$this->kex_dh_group_size_min,
$this->kex_dh_group_size_preferred,
$this->kex_dh_group_size_max
);
$packet = pack('Ca*',
NET_SSH2_MSG_KEXDH_GEX_REQUEST,
$dh_group_sizes_packed
);
if (!$this->_send_binary_packet($packet)) {
return false;
}
$response = $this->_get_binary_packet();
if ($response === false) {
user_error('Connection closed by server');
return false;
}
extract(unpack('Ctype', $this->_string_shift($response, 1)));
if ($type != NET_SSH2_MSG_KEXDH_GEX_GROUP) {
user_error('Expected SSH_MSG_KEX_DH_GEX_GROUP');
return false;
}
extract(unpack('NprimeLength', $this->_string_shift($response, 4)));
$primeBytes = $this->_string_shift($response, $primeLength);
$prime = new Math_BigInteger($primeBytes, -256);
extract(unpack('NgLength', $this->_string_shift($response, 4)));
$gBytes = $this->_string_shift($response, $gLength);
$g = new Math_BigInteger($gBytes, -256);
$exchange_hash_rfc4419 = pack('a*Na*Na*',
$dh_group_sizes_packed,
$primeLength, $primeBytes,
$gLength, $gBytes
);
$clientKexInitMessage = NET_SSH2_MSG_KEXDH_GEX_INIT;
$serverKexReplyMessage = NET_SSH2_MSG_KEXDH_GEX_REPLY;
} else {
switch ($kex_algorithms[$i]) { switch ($kex_algorithms[$i]) {
// see http://tools.ietf.org/html/rfc2409#section-6.2 and // see http://tools.ietf.org/html/rfc2409#section-6.2 and
// http://tools.ietf.org/html/rfc2412, appendex E // http://tools.ietf.org/html/rfc2412, appendex E
@ -1424,13 +1501,22 @@ class Net_SSH2
'3995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF'; '3995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF';
break; break;
} }
// For both diffie-hellman-group1-sha1 and diffie-hellman-group14-sha1 // For both diffie-hellman-group1-sha1 and diffie-hellman-group14-sha1
// the generator field element is 2 (decimal) and the hash function is sha1. // the generator field element is 2 (decimal) and the hash function is sha1.
$g = new Math_BigInteger(2); $g = new Math_BigInteger(2);
$prime = new Math_BigInteger($prime, 16); $prime = new Math_BigInteger($prime, 16);
$exchange_hash_rfc4419 = '';
$clientKexInitMessage = NET_SSH2_MSG_KEXDH_INIT;
$serverKexReplyMessage = NET_SSH2_MSG_KEXDH_REPLY;
}
switch ($kex_algorithms[$i]) {
case 'diffie-hellman-group-exchange-sha256':
$kexHash = new Crypt_Hash('sha256');
break;
default:
$kexHash = new Crypt_Hash('sha1'); $kexHash = new Crypt_Hash('sha1');
//$q = $p->bitwise_rightShift(1); }
/* To increase the speed of the key exchange, both client and server may /* To increase the speed of the key exchange, both client and server may
reduce the size of their private exponents. It should be at least reduce the size of their private exponents. It should be at least
@ -1448,7 +1534,7 @@ class Net_SSH2
$e = $g->modPow($x, $prime); $e = $g->modPow($x, $prime);
$eBytes = $e->toBytes(true); $eBytes = $e->toBytes(true);
$data = pack('CNa*', NET_SSH2_MSG_KEXDH_INIT, strlen($eBytes), $eBytes); $data = pack('CNa*', $clientKexInitMessage, strlen($eBytes), $eBytes);
if (!$this->_send_binary_packet($data)) { if (!$this->_send_binary_packet($data)) {
user_error('Connection closed by server'); user_error('Connection closed by server');
@ -1462,7 +1548,7 @@ class Net_SSH2
} }
extract(unpack('Ctype', $this->_string_shift($response, 1))); extract(unpack('Ctype', $this->_string_shift($response, 1)));
if ($type != NET_SSH2_MSG_KEXDH_REPLY) { if ($type != $serverKexReplyMessage) {
user_error('Expected SSH_MSG_KEXDH_REPLY'); user_error('Expected SSH_MSG_KEXDH_REPLY');
return false; return false;
} }
@ -1486,11 +1572,16 @@ class Net_SSH2
$key = $f->modPow($x, $prime); $key = $f->modPow($x, $prime);
$keyBytes = $key->toBytes(true); $keyBytes = $key->toBytes(true);
$this->exchange_hash = pack('Na*Na*Na*Na*Na*Na*Na*Na*', $this->exchange_hash = pack('Na*Na*Na*Na*Na*a*Na*Na*Na*',
strlen($this->identifier), $this->identifier, strlen($this->server_identifier), $this->server_identifier, strlen($this->identifier), $this->identifier,
strlen($kexinit_payload_client), $kexinit_payload_client, strlen($kexinit_payload_server), strlen($this->server_identifier), $this->server_identifier,
$kexinit_payload_server, strlen($this->server_public_host_key), $this->server_public_host_key, strlen($eBytes), strlen($kexinit_payload_client), $kexinit_payload_client,
$eBytes, strlen($fBytes), $fBytes, strlen($keyBytes), $keyBytes strlen($kexinit_payload_server), $kexinit_payload_server,
strlen($this->server_public_host_key), $this->server_public_host_key,
$exchange_hash_rfc4419,
strlen($eBytes), $eBytes,
strlen($fBytes), $fBytes,
strlen($keyBytes), $keyBytes
); );
$this->exchange_hash = $kexHash->hash($this->exchange_hash); $this->exchange_hash = $kexHash->hash($this->exchange_hash);