コード例 #1
0
ファイル: SSH1.php プロジェクト: carlosmirandadiaz/LectoGeeks
 /**
  * Gets Binary Packets
  *
  * See 'The Binary Packet Protocol' of protocol-1.5.txt for more info.
  *
  * Also, this function could be improved upon by adding detection for the following exploit:
  * http://www.securiteam.com/securitynews/5LP042K3FY.html
  *
  * @see Net_SSH1::_send_binary_packet()
  * @return Array
  * @access private
  */
 function _get_binary_packet()
 {
     if (feof($this->fsock)) {
         //user_error('connection closed prematurely');
         return false;
     }
     if ($this->curTimeout) {
         $read = array($this->fsock);
         $write = $except = null;
         $start = strtok(microtime(), ' ') + strtok('');
         // http://php.net/microtime#61838
         $sec = floor($this->curTimeout);
         $usec = 1000000 * ($this->curTimeout - $sec);
         // on windows this returns a "Warning: Invalid CRT parameters detected" error
         if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {
             //$this->_disconnect('Timeout');
             return true;
         }
         $elapsed = strtok(microtime(), ' ') + strtok('') - $start;
         $this->curTimeout -= $elapsed;
     }
     $start = strtok(microtime(), ' ') + strtok('');
     // http://php.net/microtime#61838
     $temp = unpack('Nlength', fread($this->fsock, 4));
     $padding_length = 8 - ($temp['length'] & 7);
     $length = $temp['length'] + $padding_length;
     $raw = '';
     while ($length > 0) {
         $temp = fread($this->fsock, $length);
         $raw .= $temp;
         $length -= strlen($temp);
     }
     $stop = strtok(microtime(), ' ') + strtok('');
     if (strlen($raw) && $this->crypto !== false) {
         $raw = $this->crypto->decrypt($raw);
     }
     $padding = substr($raw, 0, $padding_length);
     $type = $raw[$padding_length];
     $data = substr($raw, $padding_length + 1, -4);
     $temp = unpack('Ncrc', substr($raw, -4));
     //if ( $temp['crc'] != $this->_crc($padding . $type . $data) ) {
     //    user_error('Bad CRC in packet from server');
     //    return false;
     //}
     $type = ord($type);
     if (defined('NET_SSH1_LOGGING')) {
         $temp = isset($this->protocol_flags[$type]) ? $this->protocol_flags[$type] : 'UNKNOWN';
         $temp = '<- ' . $temp . ' (' . round($stop - $start, 4) . 's)';
         $this->_append_log($temp, $data);
     }
     return array(NET_SSH1_RESPONSE_TYPE => $type, NET_SSH1_RESPONSE_DATA => $data);
 }
コード例 #2
0
 /**
  * Gets Binary Packets
  *
  * See '6. Binary Packet Protocol' of rfc4253 for more info.
  *
  * @see Net_SSH2::_send_binary_packet()
  * @return String
  * @access private
  */
 function _get_binary_packet()
 {
     if (!is_resource($this->fsock) || feof($this->fsock)) {
         user_error('Connection closed prematurely');
         $this->bitmap = 0;
         return false;
     }
     $start = strtok(microtime(), ' ') + strtok('');
     // http://php.net/microtime#61838
     $raw = fread($this->fsock, $this->decrypt_block_size);
     if (!strlen($raw)) {
         return '';
     }
     if ($this->decrypt !== false) {
         $raw = $this->decrypt->decrypt($raw);
     }
     if ($raw === false) {
         user_error('Unable to decrypt content');
         return false;
     }
     extract(unpack('Npacket_length/Cpadding_length', $this->_string_shift($raw, 5)));
     $remaining_length = $packet_length + 4 - $this->decrypt_block_size;
     // quoting <http://tools.ietf.org/html/rfc4253#section-6.1>,
     // "implementations SHOULD check that the packet length is reasonable"
     // PuTTY uses 0x9000 as the actual max packet size and so to shall we
     if ($remaining_length < -$this->decrypt_block_size || $remaining_length > 0x9000 || $remaining_length % $this->decrypt_block_size != 0) {
         user_error('Invalid size');
         return false;
     }
     $buffer = '';
     while ($remaining_length > 0) {
         $temp = fread($this->fsock, $remaining_length);
         if ($temp === false || feof($this->fsock)) {
             user_error('Error reading from socket');
             $this->bitmap = 0;
             return false;
         }
         $buffer .= $temp;
         $remaining_length -= strlen($temp);
     }
     $stop = strtok(microtime(), ' ') + strtok('');
     if (strlen($buffer)) {
         $raw .= $this->decrypt !== false ? $this->decrypt->decrypt($buffer) : $buffer;
     }
     $payload = $this->_string_shift($raw, $packet_length - $padding_length - 1);
     $padding = $this->_string_shift($raw, $padding_length);
     // should leave $raw empty
     if ($this->hmac_check !== false) {
         $hmac = fread($this->fsock, $this->hmac_size);
         if ($hmac === false || strlen($hmac) != $this->hmac_size) {
             user_error('Error reading socket');
             $this->bitmap = 0;
             return false;
         } elseif ($hmac != $this->hmac_check->hash(pack('NNCa*', $this->get_seq_no, $packet_length, $padding_length, $payload . $padding))) {
             user_error('Invalid HMAC');
             return false;
         }
     }
     //if ($this->decompress) {
     //    $payload = gzinflate(substr($payload, 2));
     //}
     $this->get_seq_no++;
     if (defined('NET_SSH2_LOGGING')) {
         $current = strtok(microtime(), ' ') + strtok('');
         $message_number = isset($this->message_numbers[ord($payload[0])]) ? $this->message_numbers[ord($payload[0])] : 'UNKNOWN (' . ord($payload[0]) . ')';
         $message_number = '<- ' . $message_number . ' (since last: ' . round($current - $this->last_packet, 4) . ', network: ' . round($stop - $start, 4) . 's)';
         $this->_append_log($message_number, $payload);
         $this->last_packet = $current;
     }
     return $this->_filter($payload);
 }
コード例 #3
0
 /**
  * Key Exchange
  *
  * @param String $kexinit_payload_server
  *
  * @access private
  */
 function _key_exchange($kexinit_payload_server)
 {
     static $kex_algorithms = array('diffie-hellman-group1-sha1', 'diffie-hellman-group14-sha1');
     static $server_host_key_algorithms = array('ssh-rsa', 'ssh-dss');
     static $encryption_algorithms = false;
     if ($encryption_algorithms === false) {
         $encryption_algorithms = array('arcfour256', 'arcfour128', 'aes128-ctr', 'aes192-ctr', 'aes256-ctr', 'twofish128-ctr', 'twofish192-ctr', 'twofish256-ctr', 'aes128-cbc', 'aes192-cbc', 'aes256-cbc', 'twofish128-cbc', 'twofish192-cbc', 'twofish256-cbc', 'twofish-cbc', 'blowfish-ctr', 'blowfish-cbc', '3des-ctr', '3des-cbc');
         if (phpseclib_resolve_include_path('Crypt/RC4.php') === false) {
             $encryption_algorithms = array_diff($encryption_algorithms, array('arcfour256', 'arcfour128', 'arcfour'));
         }
         if (phpseclib_resolve_include_path('Crypt/Rijndael.php') === false) {
             $encryption_algorithms = array_diff($encryption_algorithms, array('aes128-ctr', 'aes192-ctr', 'aes256-ctr', 'aes128-cbc', 'aes192-cbc', 'aes256-cbc'));
         }
         if (phpseclib_resolve_include_path('Crypt/Twofish.php') === false) {
             $encryption_algorithms = array_diff($encryption_algorithms, array('twofish128-ctr', 'twofish192-ctr', 'twofish256-ctr', 'twofish128-cbc', 'twofish192-cbc', 'twofish256-cbc', 'twofish-cbc'));
         }
         if (phpseclib_resolve_include_path('Crypt/Blowfish.php') === false) {
             $encryption_algorithms = array_diff($encryption_algorithms, array('blowfish-ctr', 'blowfish-cbc'));
         }
         if (phpseclib_resolve_include_path('Crypt/TripleDES.php') === false) {
             $encryption_algorithms = array_diff($encryption_algorithms, array('3des-ctr', '3des-cbc'));
         }
         $encryption_algorithms = array_values($encryption_algorithms);
     }
     $mac_algorithms = array('hmac-sha2-256', 'hmac-sha1-96', 'hmac-sha1', 'hmac-md5-96', 'hmac-md5');
     static $compression_algorithms = array('none');
     // some SSH servers have buggy implementations of some of the above algorithms
     switch ($this->server_identifier) {
         case 'SSH-2.0-SSHD':
             $mac_algorithms = array_values(array_diff($mac_algorithms, array('hmac-sha1-96', 'hmac-md5-96')));
     }
     static $str_kex_algorithms, $str_server_host_key_algorithms, $encryption_algorithms_server_to_client, $mac_algorithms_server_to_client, $compression_algorithms_server_to_client, $encryption_algorithms_client_to_server, $mac_algorithms_client_to_server, $compression_algorithms_client_to_server;
     if (empty($str_kex_algorithms)) {
         $str_kex_algorithms = implode(',', $kex_algorithms);
         $str_server_host_key_algorithms = implode(',', $server_host_key_algorithms);
         $encryption_algorithms_server_to_client = $encryption_algorithms_client_to_server = implode(',', $encryption_algorithms);
         $mac_algorithms_server_to_client = $mac_algorithms_client_to_server = implode(',', $mac_algorithms);
         $compression_algorithms_server_to_client = $compression_algorithms_client_to_server = implode(',', $compression_algorithms);
     }
     $client_cookie = crypt_random_string(16);
     $response = $kexinit_payload_server;
     $this->_string_shift($response, 1);
     // skip past the message number (it should be SSH_MSG_KEXINIT)
     $server_cookie = $this->_string_shift($response, 16);
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->kex_algorithms = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->server_host_key_algorithms = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->encryption_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->encryption_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->mac_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->mac_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->compression_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->compression_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->languages_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->languages_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
     extract(unpack('Cfirst_kex_packet_follows', $this->_string_shift($response, 1)));
     $first_kex_packet_follows = $first_kex_packet_follows != 0;
     // the sending of SSH2_MSG_KEXINIT could go in one of two places.  this is the second place.
     $kexinit_payload_client = pack('Ca*Na*Na*Na*Na*Na*Na*Na*Na*Na*Na*CN', NET_SSH2_MSG_KEXINIT, $client_cookie, strlen($str_kex_algorithms), $str_kex_algorithms, strlen($str_server_host_key_algorithms), $str_server_host_key_algorithms, strlen($encryption_algorithms_client_to_server), $encryption_algorithms_client_to_server, strlen($encryption_algorithms_server_to_client), $encryption_algorithms_server_to_client, strlen($mac_algorithms_client_to_server), $mac_algorithms_client_to_server, strlen($mac_algorithms_server_to_client), $mac_algorithms_server_to_client, strlen($compression_algorithms_client_to_server), $compression_algorithms_client_to_server, strlen($compression_algorithms_server_to_client), $compression_algorithms_server_to_client, 0, '', 0, '', 0, 0);
     if (!$this->_send_binary_packet($kexinit_payload_client)) {
         return false;
     }
     // here ends the second place.
     // we need to decide upon the symmetric encryption algorithms before we do the diffie-hellman key exchange
     for ($i = 0; $i < count($encryption_algorithms) && !in_array($encryption_algorithms[$i], $this->encryption_algorithms_server_to_client); $i++) {
     }
     if ($i == count($encryption_algorithms)) {
         user_error('No compatible server to client encryption algorithms found');
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     // we don't initialize any crypto-objects, yet - we do that, later. for now, we need the lengths to make the
     // diffie-hellman key exchange as fast as possible
     $decrypt = $encryption_algorithms[$i];
     switch ($decrypt) {
         case '3des-cbc':
         case '3des-ctr':
             $decryptKeyLength = 24;
             // eg. 192 / 8
             break;
         case 'aes256-cbc':
         case 'aes256-ctr':
         case 'twofish-cbc':
         case 'twofish256-cbc':
         case 'twofish256-ctr':
             $decryptKeyLength = 32;
             // eg. 256 / 8
             break;
         case 'aes192-cbc':
         case 'aes192-ctr':
         case 'twofish192-cbc':
         case 'twofish192-ctr':
             $decryptKeyLength = 24;
             // eg. 192 / 8
             break;
         case 'aes128-cbc':
         case 'aes128-ctr':
         case 'twofish128-cbc':
         case 'twofish128-ctr':
         case 'blowfish-cbc':
         case 'blowfish-ctr':
             $decryptKeyLength = 16;
             // eg. 128 / 8
             break;
         case 'arcfour':
         case 'arcfour128':
             $decryptKeyLength = 16;
             // eg. 128 / 8
             break;
         case 'arcfour256':
             $decryptKeyLength = 32;
             // eg. 128 / 8
             break;
         case 'none':
             $decryptKeyLength = 0;
     }
     for ($i = 0; $i < count($encryption_algorithms) && !in_array($encryption_algorithms[$i], $this->encryption_algorithms_client_to_server); $i++) {
     }
     if ($i == count($encryption_algorithms)) {
         user_error('No compatible client to server encryption algorithms found');
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     $encrypt = $encryption_algorithms[$i];
     switch ($encrypt) {
         case '3des-cbc':
         case '3des-ctr':
             $encryptKeyLength = 24;
             break;
         case 'aes256-cbc':
         case 'aes256-ctr':
         case 'twofish-cbc':
         case 'twofish256-cbc':
         case 'twofish256-ctr':
             $encryptKeyLength = 32;
             break;
         case 'aes192-cbc':
         case 'aes192-ctr':
         case 'twofish192-cbc':
         case 'twofish192-ctr':
             $encryptKeyLength = 24;
             break;
         case 'aes128-cbc':
         case 'aes128-ctr':
         case 'twofish128-cbc':
         case 'twofish128-ctr':
         case 'blowfish-cbc':
         case 'blowfish-ctr':
             $encryptKeyLength = 16;
             break;
         case 'arcfour':
         case 'arcfour128':
             $encryptKeyLength = 16;
             break;
         case 'arcfour256':
             $encryptKeyLength = 32;
             break;
         case 'none':
             $encryptKeyLength = 0;
     }
     $keyLength = $decryptKeyLength > $encryptKeyLength ? $decryptKeyLength : $encryptKeyLength;
     // through diffie-hellman key exchange a symmetric key is obtained
     for ($i = 0; $i < count($kex_algorithms) && !in_array($kex_algorithms[$i], $this->kex_algorithms); $i++) {
     }
     if ($i == count($kex_algorithms)) {
         user_error('No compatible key exchange algorithms found');
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     switch ($kex_algorithms[$i]) {
         // see http://tools.ietf.org/html/rfc2409#section-6.2 and
         // http://tools.ietf.org/html/rfc2412, appendex E
         case 'diffie-hellman-group1-sha1':
             $prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF';
             break;
             // see http://tools.ietf.org/html/rfc3526#section-3
         // see http://tools.ietf.org/html/rfc3526#section-3
         case 'diffie-hellman-group14-sha1':
             $prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' . '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' . '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' . 'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' . '3995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF';
             break;
     }
     // For both diffie-hellman-group1-sha1 and diffie-hellman-group14-sha1
     // the generator field element is 2 (decimal) and the hash function is sha1.
     $g = new Math_BigInteger(2);
     $prime = new Math_BigInteger($prime, 16);
     $kexHash = new Crypt_Hash('sha1');
     //$q = $p->bitwise_rightShift(1);
     /* 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
                twice as long as the key material that is generated from the shared
                secret.  For more details, see the paper by van Oorschot and Wiener
                [VAN-OORSCHOT].
     
                -- http://tools.ietf.org/html/rfc4419#section-6.2 */
     $one = new Math_BigInteger(1);
     $keyLength = min($keyLength, $kexHash->getLength());
     $max = $one->bitwise_leftShift(16 * $keyLength);
     // 2 * 8 * $keyLength
     $max = $max->subtract($one);
     $x = $one->random($one, $max);
     $e = $g->modPow($x, $prime);
     $eBytes = $e->toBytes(true);
     $data = pack('CNa*', NET_SSH2_MSG_KEXDH_INIT, strlen($eBytes), $eBytes);
     if (!$this->_send_binary_packet($data)) {
         user_error('Connection closed by server');
         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_REPLY) {
         user_error('Expected SSH_MSG_KEXDH_REPLY');
         return false;
     }
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->server_public_host_key = $server_public_host_key = $this->_string_shift($response, $temp['length']);
     $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
     $public_key_format = $this->_string_shift($server_public_host_key, $temp['length']);
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $fBytes = $this->_string_shift($response, $temp['length']);
     $f = new Math_BigInteger($fBytes, -256);
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->signature = $this->_string_shift($response, $temp['length']);
     $temp = unpack('Nlength', $this->_string_shift($this->signature, 4));
     $this->signature_format = $this->_string_shift($this->signature, $temp['length']);
     $key = $f->modPow($x, $prime);
     $keyBytes = $key->toBytes(true);
     $this->exchange_hash = pack('Na*Na*Na*Na*Na*Na*Na*Na*', strlen($this->identifier), $this->identifier, strlen($this->server_identifier), $this->server_identifier, strlen($kexinit_payload_client), $kexinit_payload_client, strlen($kexinit_payload_server), $kexinit_payload_server, strlen($this->server_public_host_key), $this->server_public_host_key, strlen($eBytes), $eBytes, strlen($fBytes), $fBytes, strlen($keyBytes), $keyBytes);
     $this->exchange_hash = $kexHash->hash($this->exchange_hash);
     if ($this->session_id === false) {
         $this->session_id = $this->exchange_hash;
     }
     for ($i = 0; $i < count($server_host_key_algorithms) && !in_array($server_host_key_algorithms[$i], $this->server_host_key_algorithms); $i++) {
     }
     if ($i == count($server_host_key_algorithms)) {
         user_error('No compatible server host key algorithms found');
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     if ($public_key_format != $server_host_key_algorithms[$i] || $this->signature_format != $server_host_key_algorithms[$i]) {
         user_error('Server Host Key Algorithm Mismatch');
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     $packet = pack('C', NET_SSH2_MSG_NEWKEYS);
     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_NEWKEYS) {
         user_error('Expected SSH_MSG_NEWKEYS');
         return false;
     }
     switch ($encrypt) {
         case '3des-cbc':
             if (!class_exists('Crypt_TripleDES')) {
                 include_once 'Crypt/TripleDES.php';
             }
             $this->encrypt = new Crypt_TripleDES();
             // $this->encrypt_block_size = 64 / 8 == the default
             break;
         case '3des-ctr':
             if (!class_exists('Crypt_TripleDES')) {
                 include_once 'Crypt/TripleDES.php';
             }
             $this->encrypt = new Crypt_TripleDES(CRYPT_DES_MODE_CTR);
             // $this->encrypt_block_size = 64 / 8 == the default
             break;
         case 'aes256-cbc':
         case 'aes192-cbc':
         case 'aes128-cbc':
             if (!class_exists('Crypt_Rijndael')) {
                 include_once 'Crypt/Rijndael.php';
             }
             $this->encrypt = new Crypt_Rijndael();
             $this->encrypt_block_size = 16;
             // eg. 128 / 8
             break;
         case 'aes256-ctr':
         case 'aes192-ctr':
         case 'aes128-ctr':
             if (!class_exists('Crypt_Rijndael')) {
                 include_once 'Crypt/Rijndael.php';
             }
             $this->encrypt = new Crypt_Rijndael(CRYPT_RIJNDAEL_MODE_CTR);
             $this->encrypt_block_size = 16;
             // eg. 128 / 8
             break;
         case 'blowfish-cbc':
             if (!class_exists('Crypt_Blowfish')) {
                 include_once 'Crypt/Blowfish.php';
             }
             $this->encrypt = new Crypt_Blowfish();
             $this->encrypt_block_size = 8;
             break;
         case 'blowfish-ctr':
             if (!class_exists('Crypt_Blowfish')) {
                 include_once 'Crypt/Blowfish.php';
             }
             $this->encrypt = new Crypt_Blowfish(CRYPT_BLOWFISH_MODE_CTR);
             $this->encrypt_block_size = 8;
             break;
         case 'twofish128-cbc':
         case 'twofish192-cbc':
         case 'twofish256-cbc':
         case 'twofish-cbc':
             if (!class_exists('Crypt_Twofish')) {
                 include_once 'Crypt/Twofish.php';
             }
             $this->encrypt = new Crypt_Twofish();
             $this->encrypt_block_size = 16;
             break;
         case 'twofish128-ctr':
         case 'twofish192-ctr':
         case 'twofish256-ctr':
             if (!class_exists('Crypt_Twofish')) {
                 include_once 'Crypt/Twofish.php';
             }
             $this->encrypt = new Crypt_Twofish(CRYPT_TWOFISH_MODE_CTR);
             $this->encrypt_block_size = 16;
             break;
         case 'arcfour':
         case 'arcfour128':
         case 'arcfour256':
             if (!class_exists('Crypt_RC4')) {
                 include_once 'Crypt/RC4.php';
             }
             $this->encrypt = new Crypt_RC4();
             break;
         case 'none':
             //$this->encrypt = new Crypt_Null();
     }
     switch ($decrypt) {
         case '3des-cbc':
             if (!class_exists('Crypt_TripleDES')) {
                 include_once 'Crypt/TripleDES.php';
             }
             $this->decrypt = new Crypt_TripleDES();
             break;
         case '3des-ctr':
             if (!class_exists('Crypt_TripleDES')) {
                 include_once 'Crypt/TripleDES.php';
             }
             $this->decrypt = new Crypt_TripleDES(CRYPT_DES_MODE_CTR);
             break;
         case 'aes256-cbc':
         case 'aes192-cbc':
         case 'aes128-cbc':
             if (!class_exists('Crypt_Rijndael')) {
                 include_once 'Crypt/Rijndael.php';
             }
             $this->decrypt = new Crypt_Rijndael();
             $this->decrypt_block_size = 16;
             break;
         case 'aes256-ctr':
         case 'aes192-ctr':
         case 'aes128-ctr':
             if (!class_exists('Crypt_Rijndael')) {
                 include_once 'Crypt/Rijndael.php';
             }
             $this->decrypt = new Crypt_Rijndael(CRYPT_RIJNDAEL_MODE_CTR);
             $this->decrypt_block_size = 16;
             break;
         case 'blowfish-cbc':
             if (!class_exists('Crypt_Blowfish')) {
                 include_once 'Crypt/Blowfish.php';
             }
             $this->decrypt = new Crypt_Blowfish();
             $this->decrypt_block_size = 8;
             break;
         case 'blowfish-ctr':
             if (!class_exists('Crypt_Blowfish')) {
                 include_once 'Crypt/Blowfish.php';
             }
             $this->decrypt = new Crypt_Blowfish(CRYPT_BLOWFISH_MODE_CTR);
             $this->decrypt_block_size = 8;
             break;
         case 'twofish128-cbc':
         case 'twofish192-cbc':
         case 'twofish256-cbc':
         case 'twofish-cbc':
             if (!class_exists('Crypt_Twofish')) {
                 include_once 'Crypt/Twofish.php';
             }
             $this->decrypt = new Crypt_Twofish();
             $this->decrypt_block_size = 16;
             break;
         case 'twofish128-ctr':
         case 'twofish192-ctr':
         case 'twofish256-ctr':
             if (!class_exists('Crypt_Twofish')) {
                 include_once 'Crypt/Twofish.php';
             }
             $this->decrypt = new Crypt_Twofish(CRYPT_TWOFISH_MODE_CTR);
             $this->decrypt_block_size = 16;
             break;
         case 'arcfour':
         case 'arcfour128':
         case 'arcfour256':
             if (!class_exists('Crypt_RC4')) {
                 include_once 'Crypt/RC4.php';
             }
             $this->decrypt = new Crypt_RC4();
             break;
         case 'none':
             //$this->decrypt = new Crypt_Null();
     }
     $keyBytes = pack('Na*', strlen($keyBytes), $keyBytes);
     if ($this->encrypt) {
         $this->encrypt->enableContinuousBuffer();
         $this->encrypt->disablePadding();
         $iv = $kexHash->hash($keyBytes . $this->exchange_hash . 'A' . $this->session_id);
         while ($this->encrypt_block_size > strlen($iv)) {
             $iv .= $kexHash->hash($keyBytes . $this->exchange_hash . $iv);
         }
         $this->encrypt->setIV(substr($iv, 0, $this->encrypt_block_size));
         $key = $kexHash->hash($keyBytes . $this->exchange_hash . 'C' . $this->session_id);
         while ($encryptKeyLength > strlen($key)) {
             $key .= $kexHash->hash($keyBytes . $this->exchange_hash . $key);
         }
         $this->encrypt->setKey(substr($key, 0, $encryptKeyLength));
     }
     if ($this->decrypt) {
         $this->decrypt->enableContinuousBuffer();
         $this->decrypt->disablePadding();
         $iv = $kexHash->hash($keyBytes . $this->exchange_hash . 'B' . $this->session_id);
         while ($this->decrypt_block_size > strlen($iv)) {
             $iv .= $kexHash->hash($keyBytes . $this->exchange_hash . $iv);
         }
         $this->decrypt->setIV(substr($iv, 0, $this->decrypt_block_size));
         $key = $kexHash->hash($keyBytes . $this->exchange_hash . 'D' . $this->session_id);
         while ($decryptKeyLength > strlen($key)) {
             $key .= $kexHash->hash($keyBytes . $this->exchange_hash . $key);
         }
         $this->decrypt->setKey(substr($key, 0, $decryptKeyLength));
     }
     /* The "arcfour128" algorithm is the RC4 cipher, as described in
                [SCHNEIER], using a 128-bit key.  The first 1536 bytes of keystream
                generated by the cipher MUST be discarded, and the first byte of the
                first encrypted packet MUST be encrypted using the 1537th byte of
                keystream.
     
                -- http://tools.ietf.org/html/rfc4345#section-4 */
     if ($encrypt == 'arcfour128' || $encrypt == 'arcfour256') {
         $this->encrypt->encrypt(str_repeat("", 1536));
     }
     if ($decrypt == 'arcfour128' || $decrypt == 'arcfour256') {
         $this->decrypt->decrypt(str_repeat("", 1536));
     }
     for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_client_to_server); $i++) {
     }
     if ($i == count($mac_algorithms)) {
         user_error('No compatible client to server message authentication algorithms found');
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     $createKeyLength = 0;
     // ie. $mac_algorithms[$i] == 'none'
     switch ($mac_algorithms[$i]) {
         case 'hmac-sha2-256':
             $this->hmac_create = new Crypt_Hash('sha256');
             $createKeyLength = 32;
             break;
         case 'hmac-sha1':
             $this->hmac_create = new Crypt_Hash('sha1');
             $createKeyLength = 20;
             break;
         case 'hmac-sha1-96':
             $this->hmac_create = new Crypt_Hash('sha1-96');
             $createKeyLength = 20;
             break;
         case 'hmac-md5':
             $this->hmac_create = new Crypt_Hash('md5');
             $createKeyLength = 16;
             break;
         case 'hmac-md5-96':
             $this->hmac_create = new Crypt_Hash('md5-96');
             $createKeyLength = 16;
     }
     for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_server_to_client); $i++) {
     }
     if ($i == count($mac_algorithms)) {
         user_error('No compatible server to client message authentication algorithms found');
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     $checkKeyLength = 0;
     $this->hmac_size = 0;
     switch ($mac_algorithms[$i]) {
         case 'hmac-sha2-256':
             $this->hmac_check = new Crypt_Hash('sha256');
             $checkKeyLength = 32;
             $this->hmac_size = 32;
             break;
         case 'hmac-sha1':
             $this->hmac_check = new Crypt_Hash('sha1');
             $checkKeyLength = 20;
             $this->hmac_size = 20;
             break;
         case 'hmac-sha1-96':
             $this->hmac_check = new Crypt_Hash('sha1-96');
             $checkKeyLength = 20;
             $this->hmac_size = 12;
             break;
         case 'hmac-md5':
             $this->hmac_check = new Crypt_Hash('md5');
             $checkKeyLength = 16;
             $this->hmac_size = 16;
             break;
         case 'hmac-md5-96':
             $this->hmac_check = new Crypt_Hash('md5-96');
             $checkKeyLength = 16;
             $this->hmac_size = 12;
     }
     $key = $kexHash->hash($keyBytes . $this->exchange_hash . 'E' . $this->session_id);
     while ($createKeyLength > strlen($key)) {
         $key .= $kexHash->hash($keyBytes . $this->exchange_hash . $key);
     }
     $this->hmac_create->setKey(substr($key, 0, $createKeyLength));
     $key = $kexHash->hash($keyBytes . $this->exchange_hash . 'F' . $this->session_id);
     while ($checkKeyLength > strlen($key)) {
         $key .= $kexHash->hash($keyBytes . $this->exchange_hash . $key);
     }
     $this->hmac_check->setKey(substr($key, 0, $checkKeyLength));
     for ($i = 0; $i < count($compression_algorithms) && !in_array($compression_algorithms[$i], $this->compression_algorithms_server_to_client); $i++) {
     }
     if ($i == count($compression_algorithms)) {
         user_error('No compatible server to client compression algorithms found');
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     $this->decompress = $compression_algorithms[$i] == 'zlib';
     for ($i = 0; $i < count($compression_algorithms) && !in_array($compression_algorithms[$i], $this->compression_algorithms_client_to_server); $i++) {
     }
     if ($i == count($compression_algorithms)) {
         user_error('No compatible client to server compression algorithms found');
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     $this->compress = $compression_algorithms[$i] == 'zlib';
     return true;
 }
コード例 #4
0
ファイル: SSH2.php プロジェクト: grimsmath/lavillafdn
 /**
  * Gets Binary Packets
  *
  * See '6. Binary Packet Protocol' of rfc4253 for more info.
  *
  * @see Net_SSH2::_send_binary_packet()
  * @return String
  * @access private
  */
 function _get_binary_packet()
 {
     if (feof($this->fsock)) {
         user_error('Connection closed prematurely', E_USER_NOTICE);
         return false;
     }
     $start = strtok(microtime(), ' ') + strtok('');
     // http://php.net/microtime#61838
     $raw = fread($this->fsock, $this->decrypt_block_size);
     $stop = strtok(microtime(), ' ') + strtok('');
     if (empty($raw)) {
         return '';
     }
     if ($this->decrypt !== false) {
         $raw = $this->decrypt->decrypt($raw);
     }
     extract(unpack('Npacket_length/Cpadding_length', $this->_string_shift($raw, 5)));
     $remaining_length = $packet_length + 4 - $this->decrypt_block_size;
     $buffer = '';
     while ($remaining_length > 0) {
         $temp = fread($this->fsock, $remaining_length);
         $buffer .= $temp;
         $remaining_length -= strlen($temp);
     }
     if (!empty($buffer)) {
         $raw .= $this->decrypt !== false ? $this->decrypt->decrypt($buffer) : $buffer;
         $buffer = $temp = '';
     }
     $payload = $this->_string_shift($raw, $packet_length - $padding_length - 1);
     $padding = $this->_string_shift($raw, $padding_length);
     // should leave $raw empty
     if ($this->hmac_check !== false) {
         $hmac = fread($this->fsock, $this->hmac_size);
         if ($hmac != $this->hmac_check->hash(pack('NNCa*', $this->get_seq_no, $packet_length, $padding_length, $payload . $padding))) {
             user_error('Invalid HMAC', E_USER_NOTICE);
             return false;
         }
     }
     //if ($this->decompress) {
     //    $payload = gzinflate(substr($payload, 2));
     //}
     $this->get_seq_no++;
     if (defined('NET_SSH2_LOGGING')) {
         $temp = isset($this->message_numbers[ord($payload[0])]) ? $this->message_numbers[ord($payload[0])] : 'UNKNOWN (' . ord($payload[0]) . ')';
         $this->message_number_log[] = '<- ' . $temp . ' (' . round($stop - $start, 4) . 's)';
         if (NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) {
             $this->message_log[] = substr($payload, 1);
         }
     }
     return $this->_filter($payload);
 }
コード例 #5
0
ファイル: SSH1.php プロジェクト: lahirwisada/orangehrm
 /**
  * Gets Binary Packets
  *
  * See 'The Binary Packet Protocol' of protocol-1.5.txt for more info.
  *
  * Also, this function could be improved upon by adding detection for the following exploit:
  * http://www.securiteam.com/securitynews/5LP042K3FY.html
  *
  * @see Net_SSH1::_send_binary_packet()
  * @return Array
  * @access private
  */
 function _get_binary_packet()
 {
     if (feof($this->fsock)) {
         //user_error('connection closed prematurely', E_USER_NOTICE);
         return false;
     }
     $temp = unpack('Nlength', fread($this->fsock, 4));
     $padding_length = 8 - ($temp['length'] & 7);
     $length = $temp['length'] + $padding_length;
     $raw = fread($this->fsock, $length);
     if ($this->crypto !== false) {
         $raw = $this->crypto->decrypt($raw);
     }
     $padding = substr($raw, 0, $padding_length);
     $type = $raw[$padding_length];
     $data = substr($raw, $padding_length + 1, -4);
     $temp = unpack('Ncrc', substr($raw, -4));
     //if ( $temp['crc'] != $this->_crc($padding . $type . $data) ) {
     //    user_error('Bad CRC in packet from server', E_USER_NOTICE);
     //    return false;
     //}
     return array(NET_SSH1_RESPONSE_TYPE => ord($type), NET_SSH1_RESPONSE_DATA => $data);
 }
コード例 #6
0
ファイル: SSH1.php プロジェクト: macconsultinggroup/WordPress
 /**
  * Gets Binary Packets
  *
  * See 'The Binary Packet Protocol' of protocol-1.5.txt for more info.
  *
  * Also, this function could be improved upon by adding detection for the following exploit:
  * http://www.securiteam.com/securitynews/5LP042K3FY.html
  *
  * @see Net_SSH1::_send_binary_packet()
  * @return Array
  * @access private
  */
 function _get_binary_packet()
 {
     if (feof($this->fsock)) {
         //user_error('connection closed prematurely', E_USER_NOTICE);
         return false;
     }
     $temp = unpack('Nlength', fread($this->fsock, 4));
     $padding_length = 8 - ($temp['length'] & 7);
     $length = $temp['length'] + $padding_length;
     $start = strtok(microtime(), ' ') + strtok('');
     // http://php.net/microtime#61838
     $raw = fread($this->fsock, $length);
     $stop = strtok(microtime(), ' ') + strtok('');
     if ($this->crypto !== false) {
         $raw = $this->crypto->decrypt($raw);
     }
     $padding = substr($raw, 0, $padding_length);
     $type = $raw[$padding_length];
     $data = substr($raw, $padding_length + 1, -4);
     $temp = unpack('Ncrc', substr($raw, -4));
     //if ( $temp['crc'] != $this->_crc($padding . $type . $data) ) {
     //    user_error('Bad CRC in packet from server', E_USER_NOTICE);
     //    return false;
     //}
     $type = ord($type);
     if (defined('NET_SSH1_LOGGING')) {
         $temp = isset($this->protocol_flags[$type]) ? $this->protocol_flags[$type] : 'UNKNOWN';
         $this->protocol_flags_log[] = '<- ' . $temp . ' (' . round($stop - $start, 4) . 's)';
         if (NET_SSH1_LOGGING == NET_SSH1_LOG_COMPLEX) {
             $this->message_log[] = $data;
         }
     }
     return array(NET_SSH1_RESPONSE_TYPE => $type, NET_SSH1_RESPONSE_DATA => $data);
 }
コード例 #7
0
ファイル: SSH2.php プロジェクト: HeliWang/EngSoc-Website
 /**
  * Gets Binary Packets
  *
  * See '6. Binary Packet Protocol' of rfc4253 for more info.
  *
  * @see Net_SSH2::_send_binary_packet()
  * @return String
  * @access private
  */
 function _get_binary_packet()
 {
     if (!is_resource($this->fsock) || feof($this->fsock)) {
         user_error('Connection closed prematurely');
         $this->bitmask = 0;
         return false;
     }
     $start = strtok(microtime(), ' ') + strtok('');
     // http://php.net/microtime#61838
     $raw = fread($this->fsock, $this->decrypt_block_size);
     $stop = strtok(microtime(), ' ') + strtok('');
     if (empty($raw)) {
         return '';
     }
     if ($this->decrypt !== false) {
         $raw = $this->decrypt->decrypt($raw);
     }
     if ($raw === false) {
         user_error('Unable to decrypt content');
         return false;
     }
     extract(unpack('Npacket_length/Cpadding_length', $this->_string_shift($raw, 5)));
     $remaining_length = $packet_length + 4 - $this->decrypt_block_size;
     $buffer = '';
     while ($remaining_length > 0) {
         $temp = fread($this->fsock, $remaining_length);
         $buffer .= $temp;
         $remaining_length -= strlen($temp);
     }
     if (!empty($buffer)) {
         $raw .= $this->decrypt !== false ? $this->decrypt->decrypt($buffer) : $buffer;
         $buffer = $temp = '';
     }
     $payload = $this->_string_shift($raw, $packet_length - $padding_length - 1);
     $padding = $this->_string_shift($raw, $padding_length);
     // should leave $raw empty
     if ($this->hmac_check !== false) {
         $hmac = fread($this->fsock, $this->hmac_size);
         if ($hmac != $this->hmac_check->hash(pack('NNCa*', $this->get_seq_no, $packet_length, $padding_length, $payload . $padding))) {
             user_error('Invalid HMAC');
             return false;
         }
     }
     //if ($this->decompress) {
     //    $payload = gzinflate(substr($payload, 2));
     //}
     $this->get_seq_no++;
     if (defined('NET_SSH2_LOGGING')) {
         $current = strtok(microtime(), ' ') + strtok('');
         $message_number = isset($this->message_numbers[ord($payload[0])]) ? $this->message_numbers[ord($payload[0])] : 'UNKNOWN (' . ord($payload[0]) . ')';
         $message_number = '<- ' . $message_number . ' (since last: ' . round($current - $this->last_packet, 4) . ', network: ' . round($stop - $start, 4) . 's)';
         $this->_append_log($message_number, $payload);
         $this->last_packet = $current;
     }
     return $this->_filter($payload);
 }
コード例 #8
0
ファイル: SSH2.php プロジェクト: qickrooms/flextermshell
 /**
  * Gets Binary Packets
  *
  * See '6. Binary Packet Protocol' of rfc4253 for more info.
  *
  * @see Net_SSH2::_send_binary_packet()
  * @return String
  * @access private
  */
 function _get_binary_packet()
 {
     if (feof($this->fsock)) {
         user_error('Connection closed prematurely', E_USER_NOTICE);
         return false;
     }
     $raw = fread($this->fsock, $this->decrypt_block_size);
     if ($this->decrypt !== false) {
         $raw = $this->decrypt->decrypt($raw);
     }
     $temp = unpack('Npacket_length/Cpadding_length', $this->_string_shift($raw, 5));
     $packet_length = $temp['packet_length'];
     $padding_length = $temp['padding_length'];
     $remaining_length = $packet_length + 4 - $this->decrypt_block_size;
     $buffer = '';
     while ($remaining_length > 0) {
         $temp = fread($this->fsock, $remaining_length);
         $buffer .= $temp;
         $remaining_length -= strlen($temp);
     }
     if (!empty($buffer)) {
         $raw .= $this->decrypt !== false ? $this->decrypt->decrypt($buffer) : $buffer;
         $buffer = $temp = '';
     }
     $payload = $this->_string_shift($raw, $packet_length - $padding_length - 1);
     $padding = $this->_string_shift($raw, $padding_length);
     // should leave $raw empty
     if ($this->hmac_check !== false) {
         $hmac = fread($this->fsock, $this->hmac_size);
         if ($hmac != $this->hmac_check->hash(pack('NNCa*', $this->get_seq_no, $packet_length, $padding_length, $payload . $padding))) {
             user_error('Invalid HMAC', E_USER_NOTICE);
             return false;
         }
     }
     //if ($this->decompress) {
     //    $payload = gzinflate(substr($payload, 2));
     //}
     $this->get_seq_no++;
     if (defined('NET_SSH2_LOGGING')) {
         $this->message_number_log[] = '<- ' . $this->message_numbers[ord($payload[0])];
         $this->message_log[] = $payload;
     }
     return $this->_filter($payload);
 }
コード例 #9
0
ファイル: SSH2.php プロジェクト: BozzaCoon/SPHERE-Framework
 /**
  * Key Exchange
  *
  * @param String $kexinit_payload_server
  *
  * @access private
  */
 function _key_exchange($kexinit_payload_server)
 {
     static $kex_algorithms = array('*****@*****.**', 'diffie-hellman-group1-sha1', 'diffie-hellman-group14-sha1', 'diffie-hellman-group-exchange-sha1', 'diffie-hellman-group-exchange-sha256');
     if (!class_exists('\\Sodium')) {
         $kex_algorithms = array_diff($kex_algorithms, array('*****@*****.**'));
     }
     static $server_host_key_algorithms = array('ssh-rsa', 'ssh-dss');
     static $encryption_algorithms = false;
     if ($encryption_algorithms === false) {
         $encryption_algorithms = array('arcfour256', 'arcfour128', 'aes128-ctr', 'aes192-ctr', 'aes256-ctr', 'twofish128-ctr', 'twofish192-ctr', 'twofish256-ctr', 'aes128-cbc', 'aes192-cbc', 'aes256-cbc', 'twofish128-cbc', 'twofish192-cbc', 'twofish256-cbc', 'twofish-cbc', 'blowfish-ctr', 'blowfish-cbc', '3des-ctr', '3des-cbc');
         if (extension_loaded('openssl') && !extension_loaded('mcrypt')) {
             // OpenSSL does not support arcfour256 in any capacity and arcfour128 / arcfour support is limited to
             // instances that do not use continuous buffers
             $encryption_algorithms = array_diff($encryption_algorithms, array('arcfour256', 'arcfour128', 'arcfour'));
         }
         if (class_exists('\\phpseclib\\Crypt\\RC4') === false) {
             $encryption_algorithms = array_diff($encryption_algorithms, array('arcfour256', 'arcfour128', 'arcfour'));
         }
         if (class_exists('\\phpseclib\\Crypt\\Rijndael') === false) {
             $encryption_algorithms = array_diff($encryption_algorithms, array('aes128-ctr', 'aes192-ctr', 'aes256-ctr', 'aes128-cbc', 'aes192-cbc', 'aes256-cbc'));
         }
         if (class_exists('\\phpseclib\\Crypt\\Twofish') === false) {
             $encryption_algorithms = array_diff($encryption_algorithms, array('twofish128-ctr', 'twofish192-ctr', 'twofish256-ctr', 'twofish128-cbc', 'twofish192-cbc', 'twofish256-cbc', 'twofish-cbc'));
         }
         if (class_exists('\\phpseclib\\Crypt\\Blowfish') === false) {
             $encryption_algorithms = array_diff($encryption_algorithms, array('blowfish-ctr', 'blowfish-cbc'));
         }
         if (class_exists('\\phpseclib\\Crypt\\TripleDES') === false) {
             $encryption_algorithms = array_diff($encryption_algorithms, array('3des-ctr', '3des-cbc'));
         }
         $encryption_algorithms = array_values($encryption_algorithms);
     }
     $mac_algorithms = array('hmac-sha2-256', 'hmac-sha1-96', 'hmac-sha1', 'hmac-md5-96', 'hmac-md5');
     static $compression_algorithms = array('none');
     // some SSH servers have buggy implementations of some of the above algorithms
     switch ($this->server_identifier) {
         case 'SSH-2.0-SSHD':
             $mac_algorithms = array_values(array_diff($mac_algorithms, array('hmac-sha1-96', 'hmac-md5-96')));
     }
     static $str_kex_algorithms, $str_server_host_key_algorithms, $encryption_algorithms_server_to_client, $mac_algorithms_server_to_client, $compression_algorithms_server_to_client, $encryption_algorithms_client_to_server, $mac_algorithms_client_to_server, $compression_algorithms_client_to_server;
     if (empty($str_kex_algorithms)) {
         $str_kex_algorithms = implode(',', $kex_algorithms);
         $str_server_host_key_algorithms = implode(',', $server_host_key_algorithms);
         $encryption_algorithms_server_to_client = $encryption_algorithms_client_to_server = implode(',', $encryption_algorithms);
         $mac_algorithms_server_to_client = $mac_algorithms_client_to_server = implode(',', $mac_algorithms);
         $compression_algorithms_server_to_client = $compression_algorithms_client_to_server = implode(',', $compression_algorithms);
     }
     $client_cookie = Random::string(16);
     $response = $kexinit_payload_server;
     $this->_string_shift($response, 1);
     // skip past the message number (it should be SSH_MSG_KEXINIT)
     $server_cookie = $this->_string_shift($response, 16);
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->kex_algorithms = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->server_host_key_algorithms = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->encryption_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->encryption_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->mac_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->mac_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->compression_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->compression_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->languages_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->languages_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
     extract(unpack('Cfirst_kex_packet_follows', $this->_string_shift($response, 1)));
     $first_kex_packet_follows = $first_kex_packet_follows != 0;
     // the sending of SSH2_MSG_KEXINIT could go in one of two places.  this is the second place.
     $kexinit_payload_client = pack('Ca*Na*Na*Na*Na*Na*Na*Na*Na*Na*Na*CN', NET_SSH2_MSG_KEXINIT, $client_cookie, strlen($str_kex_algorithms), $str_kex_algorithms, strlen($str_server_host_key_algorithms), $str_server_host_key_algorithms, strlen($encryption_algorithms_client_to_server), $encryption_algorithms_client_to_server, strlen($encryption_algorithms_server_to_client), $encryption_algorithms_server_to_client, strlen($mac_algorithms_client_to_server), $mac_algorithms_client_to_server, strlen($mac_algorithms_server_to_client), $mac_algorithms_server_to_client, strlen($compression_algorithms_client_to_server), $compression_algorithms_client_to_server, strlen($compression_algorithms_server_to_client), $compression_algorithms_server_to_client, 0, '', 0, '', 0, 0);
     if (!$this->_send_binary_packet($kexinit_payload_client)) {
         return false;
     }
     // here ends the second place.
     // we need to decide upon the symmetric encryption algorithms before we do the diffie-hellman key exchange
     // we don't initialize any crypto-objects, yet - we do that, later. for now, we need the lengths to make the
     // diffie-hellman key exchange as fast as possible
     $decrypt = $this->_array_intersect_first($encryption_algorithms, $this->encryption_algorithms_server_to_client);
     $decryptKeyLength = $this->_encryption_algorithm_to_key_size($decrypt);
     if ($decryptKeyLength === null) {
         user_error('No compatible server to client encryption algorithms found');
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     $encrypt = $this->_array_intersect_first($encryption_algorithms, $this->encryption_algorithms_client_to_server);
     $encryptKeyLength = $this->_encryption_algorithm_to_key_size($encrypt);
     if ($encryptKeyLength === null) {
         user_error('No compatible client to server encryption algorithms found');
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     // through diffie-hellman key exchange a symmetric key is obtained
     $kex_algorithm = $this->_array_intersect_first($kex_algorithms, $this->kex_algorithms);
     if ($kex_algorithm === false) {
         user_error('No compatible key exchange algorithms found');
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     // Only relevant in diffie-hellman-group-exchange-sha{1,256}, otherwise empty.
     $exchange_hash_rfc4419 = '';
     if ($kex_algorithm === '*****@*****.**') {
         $x = Random::string(32);
         $eBytes = \Sodium::crypto_box_publickey_from_secretkey($x);
         $clientKexInitMessage = NET_SSH2_MSG_KEX_ECDH_INIT;
         $serverKexReplyMessage = NET_SSH2_MSG_KEX_ECDH_REPLY;
         $kexHash = new Hash('sha256');
     } else {
         if (strpos($kex_algorithm, '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 BigInteger($primeBytes, -256);
             extract(unpack('NgLength', $this->_string_shift($response, 4)));
             $gBytes = $this->_string_shift($response, $gLength);
             $g = new 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_algorithm) {
                 // see http://tools.ietf.org/html/rfc2409#section-6.2 and
                 // http://tools.ietf.org/html/rfc2412, appendex E
                 case 'diffie-hellman-group1-sha1':
                     $prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF';
                     break;
                     // see http://tools.ietf.org/html/rfc3526#section-3
                 // see http://tools.ietf.org/html/rfc3526#section-3
                 case 'diffie-hellman-group14-sha1':
                     $prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' . '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' . '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' . 'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' . '3995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF';
                     break;
             }
             // For both diffie-hellman-group1-sha1 and diffie-hellman-group14-sha1
             // the generator field element is 2 (decimal) and the hash function is sha1.
             $g = new BigInteger(2);
             $prime = new BigInteger($prime, 16);
             $clientKexInitMessage = NET_SSH2_MSG_KEXDH_INIT;
             $serverKexReplyMessage = NET_SSH2_MSG_KEXDH_REPLY;
         }
         switch ($kex_algorithm) {
             case 'diffie-hellman-group-exchange-sha256':
                 $kexHash = new Hash('sha256');
                 break;
             default:
                 $kexHash = new Hash('sha1');
         }
         /* 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
                     twice as long as the key material that is generated from the shared
                     secret.  For more details, see the paper by van Oorschot and Wiener
                     [VAN-OORSCHOT].
         
                     -- http://tools.ietf.org/html/rfc4419#section-6.2 */
         $one = new BigInteger(1);
         $keyLength = min($kexHash->getLength(), max($encryptKeyLength, $decryptKeyLength));
         $max = $one->bitwise_leftShift(16 * $keyLength);
         // 2 * 8 * $keyLength
         $max = $max->subtract($one);
         $x = $one->random($one, $max);
         $e = $g->modPow($x, $prime);
         $eBytes = $e->toBytes(true);
     }
     $data = pack('CNa*', $clientKexInitMessage, strlen($eBytes), $eBytes);
     if (!$this->_send_binary_packet($data)) {
         user_error('Connection closed by server');
         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 != $serverKexReplyMessage) {
         user_error('Expected SSH_MSG_KEXDH_REPLY');
         return false;
     }
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->server_public_host_key = $server_public_host_key = $this->_string_shift($response, $temp['length']);
     $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
     $public_key_format = $this->_string_shift($server_public_host_key, $temp['length']);
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $fBytes = $this->_string_shift($response, $temp['length']);
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->signature = $this->_string_shift($response, $temp['length']);
     $temp = unpack('Nlength', $this->_string_shift($this->signature, 4));
     $this->signature_format = $this->_string_shift($this->signature, $temp['length']);
     if ($kex_algorithm === '*****@*****.**') {
         if (strlen($fBytes) !== 32) {
             user_error('Received curve25519 public key of invalid length.');
             return false;
         }
         $key = new BigInteger(\Sodium::crypto_scalarmult($x, $fBytes), 256);
         \Sodium::sodium_memzero($x);
     } else {
         $f = new BigInteger($fBytes, -256);
         $key = $f->modPow($x, $prime);
     }
     $keyBytes = $key->toBytes(true);
     $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($kexinit_payload_client), $kexinit_payload_client, 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);
     if ($this->session_id === false) {
         $this->session_id = $this->exchange_hash;
     }
     $server_host_key_algorithm = $this->_array_intersect_first($server_host_key_algorithms, $this->server_host_key_algorithms);
     if ($server_host_key_algorithm === false) {
         user_error('No compatible server host key algorithms found');
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     if ($public_key_format != $server_host_key_algorithm || $this->signature_format != $server_host_key_algorithm) {
         user_error('Server Host Key Algorithm Mismatch');
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     $packet = pack('C', NET_SSH2_MSG_NEWKEYS);
     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_NEWKEYS) {
         user_error('Expected SSH_MSG_NEWKEYS');
         return false;
     }
     $keyBytes = pack('Na*', strlen($keyBytes), $keyBytes);
     $this->encrypt = $this->_encryption_algorithm_to_crypt_instance($encrypt);
     if ($this->encrypt) {
         if ($this->crypto_engine) {
             $this->encrypt->setEngine($this->crypto_engine);
         }
         if ($this->encrypt->block_size) {
             $this->encrypt_block_size = $this->encrypt->block_size;
         }
         $this->encrypt->enableContinuousBuffer();
         $this->encrypt->disablePadding();
         $iv = $kexHash->hash($keyBytes . $this->exchange_hash . 'A' . $this->session_id);
         while ($this->encrypt_block_size > strlen($iv)) {
             $iv .= $kexHash->hash($keyBytes . $this->exchange_hash . $iv);
         }
         $this->encrypt->setIV(substr($iv, 0, $this->encrypt_block_size));
         $key = $kexHash->hash($keyBytes . $this->exchange_hash . 'C' . $this->session_id);
         while ($encryptKeyLength > strlen($key)) {
             $key .= $kexHash->hash($keyBytes . $this->exchange_hash . $key);
         }
         $this->encrypt->setKey(substr($key, 0, $encryptKeyLength));
     }
     $this->decrypt = $this->_encryption_algorithm_to_crypt_instance($decrypt);
     if ($this->decrypt) {
         if ($this->crypto_engine) {
             $this->decrypt->setEngine($this->crypto_engine);
         }
         if ($this->decrypt->block_size) {
             $this->decrypt_block_size = $this->decrypt->block_size;
         }
         $this->decrypt->enableContinuousBuffer();
         $this->decrypt->disablePadding();
         $iv = $kexHash->hash($keyBytes . $this->exchange_hash . 'B' . $this->session_id);
         while ($this->decrypt_block_size > strlen($iv)) {
             $iv .= $kexHash->hash($keyBytes . $this->exchange_hash . $iv);
         }
         $this->decrypt->setIV(substr($iv, 0, $this->decrypt_block_size));
         $key = $kexHash->hash($keyBytes . $this->exchange_hash . 'D' . $this->session_id);
         while ($decryptKeyLength > strlen($key)) {
             $key .= $kexHash->hash($keyBytes . $this->exchange_hash . $key);
         }
         $this->decrypt->setKey(substr($key, 0, $decryptKeyLength));
     }
     /* The "arcfour128" algorithm is the RC4 cipher, as described in
                [SCHNEIER], using a 128-bit key.  The first 1536 bytes of keystream
                generated by the cipher MUST be discarded, and the first byte of the
                first encrypted packet MUST be encrypted using the 1537th byte of
                keystream.
     
                -- http://tools.ietf.org/html/rfc4345#section-4 */
     if ($encrypt == 'arcfour128' || $encrypt == 'arcfour256') {
         $this->encrypt->encrypt(str_repeat("", 1536));
     }
     if ($decrypt == 'arcfour128' || $decrypt == 'arcfour256') {
         $this->decrypt->decrypt(str_repeat("", 1536));
     }
     $mac_algorithm = $this->_array_intersect_first($mac_algorithms, $this->mac_algorithms_client_to_server);
     if ($mac_algorithm === false) {
         user_error('No compatible client to server message authentication algorithms found');
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     $createKeyLength = 0;
     // ie. $mac_algorithm == 'none'
     switch ($mac_algorithm) {
         case 'hmac-sha2-256':
             $this->hmac_create = new Hash('sha256');
             $createKeyLength = 32;
             break;
         case 'hmac-sha1':
             $this->hmac_create = new Hash('sha1');
             $createKeyLength = 20;
             break;
         case 'hmac-sha1-96':
             $this->hmac_create = new Hash('sha1-96');
             $createKeyLength = 20;
             break;
         case 'hmac-md5':
             $this->hmac_create = new Hash('md5');
             $createKeyLength = 16;
             break;
         case 'hmac-md5-96':
             $this->hmac_create = new Hash('md5-96');
             $createKeyLength = 16;
     }
     $mac_algorithm = $this->_array_intersect_first($mac_algorithms, $this->mac_algorithms_server_to_client);
     if ($mac_algorithm === false) {
         user_error('No compatible server to client message authentication algorithms found');
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     $checkKeyLength = 0;
     $this->hmac_size = 0;
     switch ($mac_algorithm) {
         case 'hmac-sha2-256':
             $this->hmac_check = new Hash('sha256');
             $checkKeyLength = 32;
             $this->hmac_size = 32;
             break;
         case 'hmac-sha1':
             $this->hmac_check = new Hash('sha1');
             $checkKeyLength = 20;
             $this->hmac_size = 20;
             break;
         case 'hmac-sha1-96':
             $this->hmac_check = new Hash('sha1-96');
             $checkKeyLength = 20;
             $this->hmac_size = 12;
             break;
         case 'hmac-md5':
             $this->hmac_check = new Hash('md5');
             $checkKeyLength = 16;
             $this->hmac_size = 16;
             break;
         case 'hmac-md5-96':
             $this->hmac_check = new Hash('md5-96');
             $checkKeyLength = 16;
             $this->hmac_size = 12;
     }
     $key = $kexHash->hash($keyBytes . $this->exchange_hash . 'E' . $this->session_id);
     while ($createKeyLength > strlen($key)) {
         $key .= $kexHash->hash($keyBytes . $this->exchange_hash . $key);
     }
     $this->hmac_create->setKey(substr($key, 0, $createKeyLength));
     $key = $kexHash->hash($keyBytes . $this->exchange_hash . 'F' . $this->session_id);
     while ($checkKeyLength > strlen($key)) {
         $key .= $kexHash->hash($keyBytes . $this->exchange_hash . $key);
     }
     $this->hmac_check->setKey(substr($key, 0, $checkKeyLength));
     $compression_algorithm = $this->_array_intersect_first($compression_algorithms, $this->compression_algorithms_server_to_client);
     if ($compression_algorithm === false) {
         user_error('No compatible server to client compression algorithms found');
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     $this->decompress = $compression_algorithm == 'zlib';
     $compression_algorithm = $this->_array_intersect_first($compression_algorithms, $this->compression_algorithms_client_to_server);
     if ($compression_algorithm === false) {
         user_error('No compatible client to server compression algorithms found');
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     $this->compress = $compression_algorithm == 'zlib';
     return true;
 }