883        $this->message_numbers = array(
 
  884            1 => 
'NET_SSH2_MSG_DISCONNECT',
 
  885            2 => 
'NET_SSH2_MSG_IGNORE',
 
  886            3 => 
'NET_SSH2_MSG_UNIMPLEMENTED',
 
  887            4 => 
'NET_SSH2_MSG_DEBUG',
 
  888            5 => 
'NET_SSH2_MSG_SERVICE_REQUEST',
 
  889            6 => 
'NET_SSH2_MSG_SERVICE_ACCEPT',
 
  890            20 => 
'NET_SSH2_MSG_KEXINIT',
 
  891            21 => 
'NET_SSH2_MSG_NEWKEYS',
 
  892            30 => 
'NET_SSH2_MSG_KEXDH_INIT',
 
  893            31 => 
'NET_SSH2_MSG_KEXDH_REPLY',
 
  894            50 => 
'NET_SSH2_MSG_USERAUTH_REQUEST',
 
  895            51 => 
'NET_SSH2_MSG_USERAUTH_FAILURE',
 
  896            52 => 
'NET_SSH2_MSG_USERAUTH_SUCCESS',
 
  897            53 => 
'NET_SSH2_MSG_USERAUTH_BANNER',
 
  899            80 => 
'NET_SSH2_MSG_GLOBAL_REQUEST',
 
  900            81 => 
'NET_SSH2_MSG_REQUEST_SUCCESS',
 
  901            82 => 
'NET_SSH2_MSG_REQUEST_FAILURE',
 
  902            90 => 
'NET_SSH2_MSG_CHANNEL_OPEN',
 
  903            91 => 
'NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION',
 
  904            92 => 
'NET_SSH2_MSG_CHANNEL_OPEN_FAILURE',
 
  905            93 => 
'NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST',
 
  906            94 => 
'NET_SSH2_MSG_CHANNEL_DATA',
 
  907            95 => 
'NET_SSH2_MSG_CHANNEL_EXTENDED_DATA',
 
  908            96 => 
'NET_SSH2_MSG_CHANNEL_EOF',
 
  909            97 => 
'NET_SSH2_MSG_CHANNEL_CLOSE',
 
  910            98 => 
'NET_SSH2_MSG_CHANNEL_REQUEST',
 
  911            99 => 
'NET_SSH2_MSG_CHANNEL_SUCCESS',
 
  912            100 => 
'NET_SSH2_MSG_CHANNEL_FAILURE' 
  914        $this->disconnect_reasons = array(
 
  915            1 => 
'NET_SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT',
 
  916            2 => 
'NET_SSH2_DISCONNECT_PROTOCOL_ERROR',
 
  917            3 => 
'NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED',
 
  918            4 => 
'NET_SSH2_DISCONNECT_RESERVED',
 
  919            5 => 
'NET_SSH2_DISCONNECT_MAC_ERROR',
 
  920            6 => 
'NET_SSH2_DISCONNECT_COMPRESSION_ERROR',
 
  921            7 => 
'NET_SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE',
 
  922            8 => 
'NET_SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED',
 
  923            9 => 
'NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE',
 
  924            10 => 
'NET_SSH2_DISCONNECT_CONNECTION_LOST',
 
  925            11 => 
'NET_SSH2_DISCONNECT_BY_APPLICATION',
 
  926            12 => 
'NET_SSH2_DISCONNECT_TOO_MANY_CONNECTIONS',
 
  927            13 => 
'NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER',
 
  928            14 => 
'NET_SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE',
 
  929            15 => 
'NET_SSH2_DISCONNECT_ILLEGAL_USER_NAME' 
  931        $this->channel_open_failure_reasons = array(
 
  932            1 => 
'NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED' 
  934        $this->terminal_modes = array(
 
  935            0 => 
'NET_SSH2_TTY_OP_END' 
  937        $this->channel_extended_data_type_codes = array(
 
  938            1 => 
'NET_SSH2_EXTENDED_DATA_STDERR' 
  942            $this->message_numbers,
 
  943            $this->disconnect_reasons,
 
  944            $this->channel_open_failure_reasons,
 
  945            $this->terminal_modes,
 
  946            $this->channel_extended_data_type_codes,
 
  947            array(60 => 
'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ'),
 
  948            array(60 => 
'NET_SSH2_MSG_USERAUTH_PK_OK'),
 
  949            array(60 => 
'NET_SSH2_MSG_USERAUTH_INFO_REQUEST',
 
  950                  61 => 
'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE'),
 
  952            array(30 => 
'NET_SSH2_MSG_KEXDH_GEX_REQUEST_OLD',
 
  953                  31 => 
'NET_SSH2_MSG_KEXDH_GEX_GROUP',
 
  954                  32 => 
'NET_SSH2_MSG_KEXDH_GEX_INIT',
 
  955                  33 => 
'NET_SSH2_MSG_KEXDH_GEX_REPLY',
 
  956                  34 => 
'NET_SSH2_MSG_KEXDH_GEX_REQUEST'),
 
  958            array(30 => 
'NET_SSH2_MSG_KEX_ECDH_INIT',
 
  959                  31 => 
'NET_SSH2_MSG_KEX_ECDH_REPLY')
 
  962        if (is_resource(
$host)) {
 
  963            $this->fsock = 
$host;
 
  967        if (is_string(
$host)) {
 
  985        $this->crypto_engine = 
$engine;
 
  996        if ($this->bitmap & self::MASK_CONSTRUCTOR) {
 
 1004        $this->last_packet = microtime(
true);
 
 1006        if (!is_resource($this->fsock)) {
 
 1007            $start = microtime(
true);
 
 1008            $this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $this->curTimeout);
 
 1009            if (!$this->fsock) {
 
 1011                user_error(rtrim(
"Cannot connect to $host. Error $errno. $errstr"));
 
 1014            $elapsed = microtime(
true) - 
$start;
 
 1016            $this->curTimeout-= $elapsed;
 
 1018            if ($this->curTimeout <= 0) {
 
 1019                $this->is_timeout = 
true;
 
 1033        while (!feof($this->fsock) && !preg_match(
'#^SSH-(\d\.\d+)#', $temp, $matches)) {
 
 1034            if (substr($temp, -2) == 
"\r\n") {
 
 1039            if ($this->curTimeout) {
 
 1040                if ($this->curTimeout < 0) {
 
 1041                    $this->is_timeout = 
true;
 
 1044                $read = array($this->fsock);
 
 1045                $write = $except = 
null;
 
 1046                $start = microtime(
true);
 
 1047                $sec = floor($this->curTimeout);
 
 1048                $usec = 1000000 * ($this->curTimeout - $sec);
 
 1051                if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {
 
 1052                    $this->is_timeout = 
true;
 
 1055                $elapsed = microtime(
true) - 
$start;
 
 1056                $this->curTimeout-= $elapsed;
 
 1059            $temp.= fgets($this->fsock, 255);
 
 1062        if (feof($this->fsock)) {
 
 1063            user_error(
'Connection closed by server');
 
 1069        if (defined(
'NET_SSH2_LOGGING')) {
 
 1071            $this->
_append_log(
'->', $this->identifier . 
"\r\n");
 
 1074        $this->server_identifier = trim($temp, 
"\r\n");
 
 1075        if (strlen($extra)) {
 
 1076            $this->errors[] = utf8_decode($extra);
 
 1079        if ($matches[1] != 
'1.99' && $matches[1] != 
'2.0') {
 
 1080            user_error(
"Cannot connect to SSH $matches[1] servers");
 
 1084        fputs($this->fsock, $this->identifier . 
"\r\n");
 
 1088            user_error(
'Connection closed by server');
 
 1092        if (ord(
$response[0]) != NET_SSH2_MSG_KEXINIT) {
 
 1093            user_error(
'Expected SSH_MSG_KEXINIT');
 
 1119        if (extension_loaded(
'libsodium')) {
 
 1120            $ext[] = 
'libsodium';
 
 1123        if (extension_loaded(
'openssl')) {
 
 1125        } elseif (extension_loaded(
'mcrypt')) {
 
 1129        if (extension_loaded(
'gmp')) {
 
 1131        } elseif (extension_loaded(
'bcmath')) {
 
 1154            'curve25519-sha256@libssh.org',
 
 1158            'diffie-hellman-group1-sha1', 
 
 1159            'diffie-hellman-group14-sha1', 
 
 1160            'diffie-hellman-group-exchange-sha1', 
 
 1161            'diffie-hellman-group-exchange-sha256', 
 
 1163        if (!class_exists(
'\Sodium')) {
 
 1166                array(
'curve25519-sha256@libssh.org')
 
 1175        $encryption_algorithms = array(
 
 1211        if (extension_loaded(
'openssl') && !extension_loaded(
'mcrypt')) {
 
 1214            $encryption_algorithms = array_diff(
 
 1215                $encryption_algorithms,
 
 1216                array(
'arcfour256', 
'arcfour128', 
'arcfour')
 
 1220        if (class_exists(
'\phpseclib\Crypt\RC4') === 
false) {
 
 1221            $encryption_algorithms = array_diff(
 
 1222                $encryption_algorithms,
 
 1223                array(
'arcfour256', 
'arcfour128', 
'arcfour')
 
 1226        if (class_exists(
'\phpseclib\Crypt\Rijndael') === 
false) {
 
 1227            $encryption_algorithms = array_diff(
 
 1228                $encryption_algorithms,
 
 1229                array(
'aes128-ctr', 
'aes192-ctr', 
'aes256-ctr', 
'aes128-cbc', 
'aes192-cbc', 
'aes256-cbc')
 
 1232        if (class_exists(
'\phpseclib\Crypt\Twofish') === 
false) {
 
 1233            $encryption_algorithms = array_diff(
 
 1234                $encryption_algorithms,
 
 1235                array(
'twofish128-ctr', 
'twofish192-ctr', 
'twofish256-ctr', 
'twofish128-cbc', 
'twofish192-cbc', 
'twofish256-cbc', 
'twofish-cbc')
 
 1238        if (class_exists(
'\phpseclib\Crypt\Blowfish') === 
false) {
 
 1239            $encryption_algorithms = array_diff(
 
 1240                $encryption_algorithms,
 
 1241                array(
'blowfish-ctr', 
'blowfish-cbc')
 
 1244        if (class_exists(
'\phpseclib\Crypt\TripleDES') === 
false) {
 
 1245            $encryption_algorithms = array_diff(
 
 1246                $encryption_algorithms,
 
 1247                array(
'3des-ctr', 
'3des-cbc')
 
 1250        $encryption_algorithms = array_values($encryption_algorithms);
 
 1252        $mac_algorithms = array(
 
 1263        $compression_algorithms = array(
 
 1269        switch ($this->server_identifier) {
 
 1270            case 'SSH-2.0-SSHD':
 
 1271                $mac_algorithms = array_values(array_diff(
 
 1273                    array(
'hmac-sha1-96', 
'hmac-md5-96')
 
 1296        $this->encryption_algorithms_client_to_server = explode(
',', $this->
_string_shift(
$response, $temp[
'length']));
 
 1299        $this->encryption_algorithms_server_to_client = explode(
',', $this->
_string_shift(
$response, $temp[
'length']));
 
 1308        $this->compression_algorithms_client_to_server = explode(
',', $this->
_string_shift(
$response, $temp[
'length']));
 
 1311        $this->compression_algorithms_server_to_client = explode(
',', $this->
_string_shift(
$response, $temp[
'length']));
 
 1320        $first_kex_packet_follows = $first_kex_packet_follows != 0;
 
 1323        $kexinit_payload_client = pack(
 
 1324            'Ca*Na*Na*Na*Na*Na*Na*Na*Na*Na*Na*CN',
 
 1325            NET_SSH2_MSG_KEXINIT,
 
 1327            strlen($str_kex_algorithms),
 
 1328            $str_kex_algorithms,
 
 1329            strlen($str_server_host_key_algorithms),
 
 1330            $str_server_host_key_algorithms,
 
 1361        if ($decryptKeyLength === 
null) {
 
 1362            user_error(
'No compatible server to client encryption algorithms found');
 
 1363            return $this->
_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
 
 1368        if ($encryptKeyLength === 
null) {
 
 1369            user_error(
'No compatible client to server encryption algorithms found');
 
 1370            return $this->
_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
 
 1375        if ($kex_algorithm === 
false) {
 
 1376            user_error(
'No compatible key exchange algorithms found');
 
 1377            return $this->
_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
 
 1381        $exchange_hash_rfc4419 = 
'';
 
 1383        if ($kex_algorithm === 
'curve25519-sha256@libssh.org') {
 
 1385            $eBytes = \Sodium::crypto_box_publickey_from_secretkey(
$x);
 
 1386            $clientKexInitMessage = NET_SSH2_MSG_KEX_ECDH_INIT;
 
 1387            $serverKexReplyMessage = NET_SSH2_MSG_KEX_ECDH_REPLY;
 
 1388            $kexHash = 
new Hash(
'sha256');
 
 1390            if (strpos($kex_algorithm, 
'diffie-hellman-group-exchange') === 0) {
 
 1391                $dh_group_sizes_packed = pack(
 
 1393                    $this->kex_dh_group_size_min,
 
 1394                    $this->kex_dh_group_size_preferred,
 
 1395                    $this->kex_dh_group_size_max
 
 1399                    NET_SSH2_MSG_KEXDH_GEX_REQUEST,
 
 1400                    $dh_group_sizes_packed
 
 1408                    user_error(
'Connection closed by server');
 
 1412                if (
$type != NET_SSH2_MSG_KEXDH_GEX_GROUP) {
 
 1413                    user_error(
'Expected SSH_MSG_KEX_DH_GEX_GROUP');
 
 1425                $exchange_hash_rfc4419 = pack(
 
 1427                    $dh_group_sizes_packed,
 
 1434                $clientKexInitMessage = NET_SSH2_MSG_KEXDH_GEX_INIT;
 
 1435                $serverKexReplyMessage = NET_SSH2_MSG_KEXDH_GEX_REPLY;
 
 1437                switch ($kex_algorithm) {
 
 1440                    case 'diffie-hellman-group1-sha1':
 
 1441                        $prime = 
'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' .
 
 1442                                '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' .
 
 1443                                '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
 
 1444                                'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF';
 
 1447                    case 'diffie-hellman-group14-sha1':
 
 1448                        $prime = 
'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' .
 
 1449                                '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' .
 
 1450                                '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
 
 1451                                'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' .
 
 1452                                '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' .
 
 1453                                '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' .
 
 1454                                'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' .
 
 1455                                '3995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF';
 
 1462                $clientKexInitMessage = NET_SSH2_MSG_KEXDH_INIT;
 
 1463                $serverKexReplyMessage = NET_SSH2_MSG_KEXDH_REPLY;
 
 1466            switch ($kex_algorithm) {
 
 1467                case 'diffie-hellman-group-exchange-sha256':
 
 1468                    $kexHash = 
new Hash(
'sha256');
 
 1471                    $kexHash = 
new Hash(
'sha1');
 
 1482            $keyLength = min($kexHash->getLength(), max($encryptKeyLength, $decryptKeyLength));
 
 1483            $max = $one->bitwise_leftShift(16 * $keyLength); 
 
 1484            $max = $max->subtract($one);
 
 1486            $x = $one->random($one, $max);
 
 1487            $e = $g->modPow(
$x, $prime);
 
 1489            $eBytes = $e->toBytes(
true);
 
 1491        $data = pack(
'CNa*', $clientKexInitMessage, strlen($eBytes), $eBytes);
 
 1494            user_error(
'Connection closed by server');
 
 1500            user_error(
'Connection closed by server');
 
 1505        if (
$type != $serverKexReplyMessage) {
 
 1506            user_error(
'Expected SSH_MSG_KEXDH_REPLY');
 
 1513        $temp = unpack(
'Nlength', $this->
_string_shift($server_public_host_key, 4));
 
 1514        $public_key_format = $this->
_string_shift($server_public_host_key, $temp[
'length']);
 
 1522        $temp = unpack(
'Nlength', $this->
_string_shift($this->signature, 4));
 
 1523        $this->signature_format = $this->
_string_shift($this->signature, $temp[
'length']);
 
 1525        if ($kex_algorithm === 
'curve25519-sha256@libssh.org') {
 
 1526            if (strlen($fBytes) !== 32) {
 
 1527                user_error(
'Received curve25519 public key of invalid length.');
 
 1531            \Sodium::sodium_memzero(
$x);
 
 1536        $keyBytes = 
$key->toBytes(
true);
 
 1538        $this->exchange_hash = pack(
 
 1539            'Na*Na*Na*Na*Na*a*Na*Na*Na*',
 
 1540            strlen($this->identifier),
 
 1542            strlen($this->server_identifier),
 
 1543            $this->server_identifier,
 
 1544            strlen($kexinit_payload_client),
 
 1545            $kexinit_payload_client,
 
 1546            strlen($kexinit_payload_server),
 
 1547            $kexinit_payload_server,
 
 1548            strlen($this->server_public_host_key),
 
 1549            $this->server_public_host_key,
 
 1550            $exchange_hash_rfc4419,
 
 1559        $this->exchange_hash = $kexHash->hash($this->exchange_hash);
 
 1561        if ($this->session_id === 
false) {
 
 1565        $server_host_key_algorithm = $this->
_array_intersect_first($server_host_key_algorithms, $this->server_host_key_algorithms);
 
 1566        if ($server_host_key_algorithm === 
false) {
 
 1567            user_error(
'No compatible server host key algorithms found');
 
 1568            return $this->
_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
 
 1571        if ($public_key_format != $server_host_key_algorithm || $this->signature_format != $server_host_key_algorithm) {
 
 1572            user_error(
'Server Host Key Algorithm Mismatch');
 
 1573            return $this->
_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
 
 1578            NET_SSH2_MSG_NEWKEYS
 
 1588            user_error(
'Connection closed by server');
 
 1594        if (
$type != NET_SSH2_MSG_NEWKEYS) {
 
 1595            user_error(
'Expected SSH_MSG_NEWKEYS');
 
 1599        $keyBytes = pack(
'Na*', strlen($keyBytes), $keyBytes);
 
 1602        if ($this->encrypt) {
 
 1603            if ($this->crypto_engine) {
 
 1604                $this->encrypt->setEngine($this->crypto_engine);
 
 1606            if ($this->encrypt->block_size) {
 
 1607                $this->encrypt_block_size = $this->encrypt->block_size;
 
 1609            $this->encrypt->enableContinuousBuffer();
 
 1610            $this->encrypt->disablePadding();
 
 1612            $iv = $kexHash->hash($keyBytes . $this->exchange_hash . 
'A' . $this->session_id);
 
 1613            while ($this->encrypt_block_size > strlen($iv)) {
 
 1614                $iv.= $kexHash->hash($keyBytes . $this->exchange_hash . $iv);
 
 1616            $this->encrypt->setIV(substr($iv, 0, $this->encrypt_block_size));
 
 1618            $key = $kexHash->hash($keyBytes . $this->exchange_hash . 
'C' . $this->session_id);
 
 1619            while ($encryptKeyLength > strlen(
$key)) {
 
 1620                $key.= $kexHash->hash($keyBytes . $this->exchange_hash . 
$key);
 
 1622            $this->encrypt->setKey(substr(
$key, 0, $encryptKeyLength));
 
 1626        if ($this->decrypt) {
 
 1627            if ($this->crypto_engine) {
 
 1628                $this->decrypt->setEngine($this->crypto_engine);
 
 1630            if ($this->decrypt->block_size) {
 
 1631                $this->decrypt_block_size = $this->decrypt->block_size;
 
 1633            $this->decrypt->enableContinuousBuffer();
 
 1634            $this->decrypt->disablePadding();
 
 1636            $iv = $kexHash->hash($keyBytes . $this->exchange_hash . 
'B' . $this->session_id);
 
 1637            while ($this->decrypt_block_size > strlen($iv)) {
 
 1638                $iv.= $kexHash->hash($keyBytes . $this->exchange_hash . $iv);
 
 1640            $this->decrypt->setIV(substr($iv, 0, $this->decrypt_block_size));
 
 1642            $key = $kexHash->hash($keyBytes . $this->exchange_hash . 
'D' . $this->session_id);
 
 1643            while ($decryptKeyLength > strlen(
$key)) {
 
 1644                $key.= $kexHash->hash($keyBytes . $this->exchange_hash . 
$key);
 
 1646            $this->decrypt->setKey(substr(
$key, 0, $decryptKeyLength));
 
 1657            $this->encrypt->encrypt(str_repeat(
"\0", 1536));
 
 1660            $this->decrypt->decrypt(str_repeat(
"\0", 1536));
 
 1664        if ($mac_algorithm === 
false) {
 
 1665            user_error(
'No compatible client to server message authentication algorithms found');
 
 1666            return $this->
_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
 
 1669        $createKeyLength = 0; 
 
 1670        switch ($mac_algorithm) {
 
 1671            case 'hmac-sha2-256':
 
 1672                $this->hmac_create = 
new Hash(
'sha256');
 
 1673                $createKeyLength = 32;
 
 1676                $this->hmac_create = 
new Hash(
'sha1');
 
 1677                $createKeyLength = 20;
 
 1679            case 'hmac-sha1-96':
 
 1680                $this->hmac_create = 
new Hash(
'sha1-96');
 
 1681                $createKeyLength = 20;
 
 1684                $this->hmac_create = 
new Hash(
'md5');
 
 1685                $createKeyLength = 16;
 
 1688                $this->hmac_create = 
new Hash(
'md5-96');
 
 1689                $createKeyLength = 16;
 
 1693        if ($mac_algorithm === 
false) {
 
 1694            user_error(
'No compatible server to client message authentication algorithms found');
 
 1695            return $this->
_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
 
 1698        $checkKeyLength = 0;
 
 1699        $this->hmac_size = 0;
 
 1700        switch ($mac_algorithm) {
 
 1701            case 'hmac-sha2-256':
 
 1702                $this->hmac_check = 
new Hash(
'sha256');
 
 1703                $checkKeyLength = 32;
 
 1704                $this->hmac_size = 32;
 
 1707                $this->hmac_check = 
new Hash(
'sha1');
 
 1708                $checkKeyLength = 20;
 
 1709                $this->hmac_size = 20;
 
 1711            case 'hmac-sha1-96':
 
 1712                $this->hmac_check = 
new Hash(
'sha1-96');
 
 1713                $checkKeyLength = 20;
 
 1714                $this->hmac_size = 12;
 
 1717                $this->hmac_check = 
new Hash(
'md5');
 
 1718                $checkKeyLength = 16;
 
 1719                $this->hmac_size = 16;
 
 1722                $this->hmac_check = 
new Hash(
'md5-96');
 
 1723                $checkKeyLength = 16;
 
 1724                $this->hmac_size = 12;
 
 1727        $key = $kexHash->hash($keyBytes . $this->exchange_hash . 
'E' . $this->session_id);
 
 1728        while ($createKeyLength > strlen(
$key)) {
 
 1729            $key.= $kexHash->hash($keyBytes . $this->exchange_hash . 
$key);
 
 1731        $this->hmac_create->setKey(substr(
$key, 0, $createKeyLength));
 
 1733        $key = $kexHash->hash($keyBytes . $this->exchange_hash . 
'F' . $this->session_id);
 
 1734        while ($checkKeyLength > strlen(
$key)) {
 
 1735            $key.= $kexHash->hash($keyBytes . $this->exchange_hash . 
$key);
 
 1737        $this->hmac_check->setKey(substr(
$key, 0, $checkKeyLength));
 
 1739        $compression_algorithm = $this->
_array_intersect_first($compression_algorithms, $this->compression_algorithms_server_to_client);
 
 1740        if ($compression_algorithm === 
false) {
 
 1741            user_error(
'No compatible server to client compression algorithms found');
 
 1742            return $this->
_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
 
 1744        $this->decompress = $compression_algorithm == 
'zlib';
 
 1746        $compression_algorithm = $this->
_array_intersect_first($compression_algorithms, $this->compression_algorithms_client_to_server);
 
 1747        if ($compression_algorithm === 
false) {
 
 1748            user_error(
'No compatible client to server compression algorithms found');
 
 1749            return $this->
_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
 
 1751        $this->compress = $compression_algorithm == 
'zlib';
 
 1765        switch ($algorithm) {
 
 1772            case 'blowfish-cbc':
 
 1773            case 'blowfish-ctr':
 
 1774            case 'twofish128-cbc':
 
 1775            case 'twofish128-ctr':
 
 1781            case 'twofish192-cbc':
 
 1782            case 'twofish192-ctr':
 
 1788            case 'twofish256-cbc':
 
 1789            case 'twofish256-ctr':
 
 1805        switch ($algorithm) {
 
 1818            case 'blowfish-cbc':
 
 1820            case 'blowfish-ctr':
 
 1822            case 'twofish128-cbc':
 
 1823            case 'twofish192-cbc':
 
 1824            case 'twofish256-cbc':
 
 1827            case 'twofish128-ctr':
 
 1828            case 'twofish192-ctr':
 
 1829            case 'twofish256-ctr':
 
 1853        $args = func_get_args();
 
 1854        return call_user_func_array(array(&$this, 
'_login'), $args);
 
 1869        if (!($this->bitmap & self::MASK_CONSTRUCTOR)) {
 
 1875        $args = array_slice(func_get_args(), 1);
 
 1880        foreach ($args as $arg) {
 
 1900        if (!($this->bitmap & self::MASK_CONNECTED)) {
 
 1904        if (!($this->bitmap & self::MASK_LOGIN_REQ)) {
 
 1907                NET_SSH2_MSG_SERVICE_REQUEST,
 
 1908                strlen(
'ssh-userauth'),
 
 1918                user_error(
'Connection closed by server');
 
 1924            if (
$type != NET_SSH2_MSG_SERVICE_ACCEPT) {
 
 1925                user_error(
'Expected SSH_MSG_SERVICE_ACCEPT');
 
 1931        if (strlen($this->last_interactive_response)) {
 
 1952                NET_SSH2_MSG_USERAUTH_REQUEST,
 
 1955                strlen(
'ssh-connection'),
 
 1967                user_error(
'Connection closed by server');
 
 1974                case NET_SSH2_MSG_USERAUTH_SUCCESS:
 
 1985            NET_SSH2_MSG_USERAUTH_REQUEST,
 
 1988            strlen(
'ssh-connection'),
 
 1998        if (!defined(
'NET_SSH2_LOGGING')) {
 
 2003                NET_SSH2_MSG_USERAUTH_REQUEST,
 
 2006                strlen(
'ssh-connection'),
 
 2022            user_error(
'Connection closed by server');
 
 2029            case NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ: 
 
 2030                if (defined(
'NET_SSH2_LOGGING')) {
 
 2031                    $this->message_number_log[count($this->message_number_log) - 1] = 
'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ';
 
 2034                $this->errors[] = 
'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ: ' . utf8_decode($this->
_string_shift(
$response, $length));
 
 2035                return $this->
_disconnect(NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER);
 
 2036            case NET_SSH2_MSG_USERAUTH_FAILURE:
 
 2042                $partial_success = $partial_success != 0;
 
 2044                if (!$partial_success && in_array(
'keyboard-interactive', $auth_methods)) {
 
 2052            case NET_SSH2_MSG_USERAUTH_SUCCESS:
 
 2074            NET_SSH2_MSG_USERAUTH_REQUEST,
 
 2077            strlen(
'ssh-connection'),
 
 2079            strlen(
'keyboard-interactive'),
 
 2080            'keyboard-interactive',
 
 2103        $responses = func_get_args();
 
 2105        if (strlen($this->last_interactive_response)) {
 
 2110                user_error(
'Connection closed by server');
 
 2118            case NET_SSH2_MSG_USERAUTH_INFO_REQUEST:
 
 2127                for (
$i = 0; 
$i < count($responses); 
$i++) {
 
 2128                    if (is_array($responses[
$i])) {
 
 2129                        foreach ($responses[
$i] as 
$key => $value) {
 
 2130                            $this->keyboard_requests_responses[
$key] = $value;
 
 2132                        unset($responses[
$i]);
 
 2135                $responses = array_values($responses);
 
 2137                if (isset($this->keyboard_requests_responses)) {
 
 2138                    for (
$i = 0; 
$i < $num_prompts; 
$i++) {
 
 2143                        foreach ($this->keyboard_requests_responses as 
$key => $value) {
 
 2144                            if (substr($prompt, 0, strlen(
$key)) == 
$key) {
 
 2145                                $responses[] = $value;
 
 2153                if (strlen($this->last_interactive_response)) {
 
 2154                    $this->last_interactive_response = 
'';
 
 2155                } elseif (defined(
'NET_SSH2_LOGGING')) {
 
 2156                    $this->message_number_log[count($this->message_number_log) - 1] = str_replace(
 
 2158                        'NET_SSH2_MSG_USERAUTH_INFO_REQUEST',
 
 2159                        $this->message_number_log[count($this->message_number_log) - 1]
 
 2163                if (!count($responses) && $num_prompts) {
 
 2164                    $this->last_interactive_response = $orig;
 
 2173                $packet = $logged = pack(
'CN', NET_SSH2_MSG_USERAUTH_INFO_RESPONSE, count($responses));
 
 2174                for (
$i = 0; 
$i < count($responses); 
$i++) {
 
 2175                    $packet.= pack(
'Na*', strlen($responses[
$i]), $responses[
$i]);
 
 2176                    $logged.= pack(
'Na*', strlen(
'dummy-answer'), 
'dummy-answer');
 
 2183                if (defined(
'NET_SSH2_LOGGING') && NET_SSH2_LOGGING == self::LOG_COMPLEX) {
 
 2184                    $this->message_number_log[count($this->message_number_log) - 1] = str_replace(
 
 2186                        'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE',
 
 2187                        $this->message_number_log[count($this->message_number_log) - 1]
 
 2199            case NET_SSH2_MSG_USERAUTH_SUCCESS:
 
 2201            case NET_SSH2_MSG_USERAUTH_FAILURE:
 
 2243        if ($publickey === 
false) {
 
 2248            'e' => $publickey[
'e']->toBytes(
true),
 
 2249            'n' => $publickey[
'n']->toBytes(
true)
 
 2255            strlen($publickey[
'e']),
 
 2257            strlen($publickey[
'n']),
 
 2263            NET_SSH2_MSG_USERAUTH_REQUEST,
 
 2266            strlen(
'ssh-connection'),
 
 2268            strlen(
'publickey'),
 
 2271        $part2 = pack(
'Na*Na*', strlen(
'ssh-rsa'), 
'ssh-rsa', strlen($publickey), $publickey);
 
 2273        $packet = $part1 . chr(0) . $part2;
 
 2280            user_error(
'Connection closed by server');
 
 2287            case NET_SSH2_MSG_USERAUTH_FAILURE:
 
 2291            case NET_SSH2_MSG_USERAUTH_PK_OK:
 
 2294                if (defined(
'NET_SSH2_LOGGING') && NET_SSH2_LOGGING == self::LOG_COMPLEX) {
 
 2295                    $this->message_number_log[count($this->message_number_log) - 1] = str_replace(
 
 2297                        'NET_SSH2_MSG_USERAUTH_PK_OK',
 
 2298                        $this->message_number_log[count($this->message_number_log) - 1]
 
 2303        $packet = $part1 . chr(1) . $part2;
 
 2305        $signature = $privatekey->sign(pack(
'Na*a*', strlen($this->session_id), $this->session_id, $packet));
 
 2315            user_error(
'Connection closed by server');
 
 2322            case NET_SSH2_MSG_USERAUTH_FAILURE:
 
 2325            case NET_SSH2_MSG_USERAUTH_SUCCESS:
 
 2344        $this->timeout = $this->curTimeout = 
$timeout;
 
 2368    function exec($command, $callback = 
null)
 
 2371        $this->is_timeout = 
false;
 
 2372        $this->stdErrorLog = 
'';
 
 2374        if (!($this->bitmap & self::MASK_LOGIN)) {
 
 2385        $packet_size = 0x4000;
 
 2389            NET_SSH2_MSG_CHANNEL_OPEN,
 
 2393            $this->window_size_server_to_client[self::CHANNEL_EXEC],
 
 2408        if ($this->request_pty === 
true) {
 
 2412                NET_SSH2_MSG_CHANNEL_REQUEST,
 
 2413                $this->server_channels[self::CHANNEL_EXEC],
 
 2419                $this->windowColumns,
 
 2433                user_error(
'Connection closed by server');
 
 2440                case NET_SSH2_MSG_CHANNEL_SUCCESS:
 
 2442                case NET_SSH2_MSG_CHANNEL_FAILURE:
 
 2444                    user_error(
'Unable to request pseudo-terminal');
 
 2445                    return $this->
_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
 
 2447            $this->in_request_pty_exec = 
true;
 
 2461            NET_SSH2_MSG_CHANNEL_REQUEST,
 
 2462            $this->server_channels[self::CHANNEL_EXEC],
 
 2482        if ($callback === 
false || $this->in_request_pty_exec) {
 
 2490                case $temp === 
true:
 
 2491                    return is_callable($callback) ? true : 
$output;
 
 2492                case $temp === 
false:
 
 2495                    if (is_callable($callback)) {
 
 2496                        if (call_user_func($callback, $temp) === 
true) {
 
 2517        if ($this->in_request_pty_exec === 
true) {
 
 2522        $packet_size = 0x4000;
 
 2526            NET_SSH2_MSG_CHANNEL_OPEN,
 
 2529            self::CHANNEL_SHELL,
 
 2530            $this->window_size_server_to_client[self::CHANNEL_SHELL],
 
 2548            NET_SSH2_MSG_CHANNEL_REQUEST,
 
 2549            $this->server_channels[self::CHANNEL_SHELL],
 
 2555            $this->windowColumns,
 
 2569            user_error(
'Connection closed by server');
 
 2576            case NET_SSH2_MSG_CHANNEL_SUCCESS:
 
 2578            case NET_SSH2_MSG_CHANNEL_FAILURE:
 
 2581                user_error(
'Unable to request pseudo-terminal');
 
 2582                return $this->
_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
 
 2587            NET_SSH2_MSG_CHANNEL_REQUEST,
 
 2588            $this->server_channels[self::CHANNEL_SHELL],
 
 2622            case $this->in_subsystem:
 
 2624            case $this->in_request_pty_exec:
 
 2641            if (isset($this->channel_status[$channel]) && $this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_OPEN) {
 
 2644        } 
while ($channel++ < self::CHANNEL_SUBSYSTEM);
 
 2661    function read($expect = 
'', $mode = self::READ_SIMPLE)
 
 2664        $this->is_timeout = 
false;
 
 2666        if (!($this->bitmap & self::MASK_LOGIN)) {
 
 2667            user_error(
'Operation disallowed prior to login()');
 
 2671        if (!($this->bitmap & self::MASK_SHELL) && !$this->
_initShell()) {
 
 2672            user_error(
'Unable to initiate an interactive shell session');
 
 2680            if ($mode == self::READ_REGEX) {
 
 2681                preg_match($expect, substr($this->interactiveBuffer, -1024), $matches);
 
 2682                $match = isset($matches[0]) ? $matches[0] : 
'';
 
 2684            $pos = strlen($match) ? strpos($this->interactiveBuffer, $match) : 
false;
 
 2685            if ($pos !== 
false) {
 
 2686                return $this->
_string_shift($this->interactiveBuffer, $pos + strlen($match));
 
 2690                $this->in_request_pty_exec = 
false;
 
 2691                return $response ? $this->
_string_shift($this->interactiveBuffer, strlen($this->interactiveBuffer)) : 
false;
 
 2708        if (!($this->bitmap & self::MASK_LOGIN)) {
 
 2709            user_error(
'Operation disallowed prior to login()');
 
 2713        if (!($this->bitmap & self::MASK_SHELL) && !$this->
_initShell()) {
 
 2714            user_error(
'Unable to initiate an interactive shell session');
 
 2741            NET_SSH2_MSG_CHANNEL_OPEN,
 
 2744            self::CHANNEL_SUBSYSTEM,
 
 2762            NET_SSH2_MSG_CHANNEL_REQUEST,
 
 2763            $this->server_channels[self::CHANNEL_SUBSYSTEM],
 
 2764            strlen(
'subsystem'),
 
 2785        $this->in_subsystem = 
true;
 
 2799        $this->in_subsystem = 
false;
 
 2835        $this->
_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
 
 2836        if (isset($this->realtime_log_file) && is_resource($this->realtime_log_file)) {
 
 2837            fclose($this->realtime_log_file);
 
 2887        if (!is_resource($this->fsock) || feof($this->fsock)) {
 
 2888            user_error(
'Connection closed prematurely');
 
 2893        $start = microtime(
true);
 
 2894        $raw = fread($this->fsock, $this->decrypt_block_size);
 
 2896        if (!strlen($raw)) {
 
 2900        if ($this->decrypt !== 
false) {
 
 2901            $raw = $this->decrypt->decrypt($raw);
 
 2903        if ($raw === 
false) {
 
 2904            user_error(
'Unable to decrypt content');
 
 2908        extract(unpack(
'Npacket_length/Cpadding_length', $this->
_string_shift($raw, 5)));
 
 2915        if ($remaining_length < -$this->decrypt_block_size || $remaining_length > 0x9000 || $remaining_length % $this->decrypt_block_size != 0) {
 
 2916            user_error(
'Invalid size');
 
 2921        while ($remaining_length > 0) {
 
 2922            $temp = fread($this->fsock, $remaining_length);
 
 2923            if ($temp === 
false || feof($this->fsock)) {
 
 2924                user_error(
'Error reading from socket');
 
 2929            $remaining_length-= strlen($temp);
 
 2931        $stop = microtime(
true);
 
 2932        if (strlen($buffer)) {
 
 2933            $raw.= $this->decrypt !== 
false ? $this->decrypt->decrypt($buffer) : $buffer;
 
 2936        $payload = $this->
_string_shift($raw, $packet_length - $padding_length - 1);
 
 2939        if ($this->hmac_check !== 
false) {
 
 2940            $hmac = fread($this->fsock, $this->hmac_size);
 
 2941            if ($hmac === 
false || strlen($hmac) != $this->hmac_size) {
 
 2942                user_error(
'Error reading socket');
 
 2945            } elseif ($hmac != $this->hmac_check->hash(pack(
'NNCa*', $this->get_seq_no, $packet_length, $padding_length, $payload . $padding))) {
 
 2946                user_error(
'Invalid HMAC');
 
 2955        $this->get_seq_no++;
 
 2957        if (defined(
'NET_SSH2_LOGGING')) {
 
 2959            $message_number = isset($this->message_numbers[ord($payload[0])]) ? $this->message_numbers[ord($payload[0])] : 
'UNKNOWN (' . ord($payload[0]) . 
')';
 
 2960            $message_number = 
'<- ' . $message_number .
 
 2961                              ' (since last: ' . round(
$current - $this->last_packet, 4) . 
', network: ' . round($stop - 
$start, 4) . 
's)';
 
 2966        return $this->
_filter($payload);
 
 2980        switch (ord($payload[0])) {
 
 2981            case NET_SSH2_MSG_DISCONNECT:
 
 2983                extract(unpack(
'Nreason_code/Nlength', $this->
_string_shift($payload, 8)));
 
 2984                $this->errors[] = 
'SSH_MSG_DISCONNECT: ' . $this->disconnect_reasons[$reason_code] . 
"\r\n" . utf8_decode($this->
_string_shift($payload, $length));
 
 2987            case NET_SSH2_MSG_IGNORE:
 
 2990            case NET_SSH2_MSG_DEBUG:
 
 2992                extract(unpack(
'Nlength', $this->
_string_shift($payload, 4)));
 
 2993                $this->errors[] = 
'SSH_MSG_DEBUG: ' . utf8_decode($this->
_string_shift($payload, $length));
 
 2996            case NET_SSH2_MSG_UNIMPLEMENTED:
 
 2998            case NET_SSH2_MSG_KEXINIT:
 
 2999                if ($this->session_id !== 
false) {
 
 3009        if (($this->bitmap & self::MASK_CONNECTED) && !($this->bitmap & self::MASK_LOGIN) && ord($payload[0]) == NET_SSH2_MSG_USERAUTH_BANNER) {
 
 3011            extract(unpack(
'Nlength', $this->
_string_shift($payload, 4)));
 
 3012            $this->banner_message = utf8_decode($this->
_string_shift($payload, $length));
 
 3017        if (($this->bitmap & self::MASK_CONNECTED) && ($this->bitmap & self::MASK_LOGIN)) {
 
 3018            switch (ord($payload[0])) {
 
 3019                case NET_SSH2_MSG_GLOBAL_REQUEST: 
 
 3020                    extract(unpack(
'Nlength', $this->
_string_shift($payload, 4)));
 
 3021                    $this->errors[] = 
'SSH_MSG_GLOBAL_REQUEST: ' . $this->
_string_shift($payload, $length);
 
 3024                        return $this->
_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
 
 3029                case NET_SSH2_MSG_CHANNEL_OPEN: 
 
 3031                    extract(unpack(
'Nlength', $this->
_string_shift($payload, 4)));
 
 3033                    extract(unpack(
'Nserver_channel', $this->
_string_shift($payload, 4)));
 
 3036                        case 'auth-agent@openssh.com':
 
 3037                            if (isset($this->agent)) {
 
 3040                                extract(unpack(
'Nremote_window_size', $this->
_string_shift($payload, 4)));
 
 3041                                extract(unpack(
'Nremote_maximum_packet_size', $this->
_string_shift($payload, 4)));
 
 3043                                $this->packet_size_client_to_server[$new_channel] = $remote_window_size;
 
 3044                                $this->window_size_server_to_client[$new_channel] = $remote_maximum_packet_size;
 
 3047                                $packet_size = 0x4000;
 
 3051                                    NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION,
 
 3058                                $this->server_channels[$new_channel] = $server_channel;
 
 3059                                $this->channel_status[$new_channel] = NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION;
 
 3068                                NET_SSH2_MSG_REQUEST_FAILURE,
 
 3070                                NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED,
 
 3078                                return $this->
_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
 
 3083                case NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST:
 
 3085                    extract(unpack(
'Nchannel', $this->
_string_shift($payload, 4)));
 
 3086                    extract(unpack(
'Nwindow_size', $this->
_string_shift($payload, 4)));
 
 3087                    $this->window_size_client_to_server[$channel]+= 
$window_size;
 
 3105        $this->quiet_mode = 
true;
 
 3117        $this->quiet_mode = 
false;
 
 3140        $this->request_pty = 
true;
 
 3150        $this->request_pty = 
false;
 
 3177        if (!empty($this->channel_buffers[$client_channel])) {
 
 3178            return array_shift($this->channel_buffers[$client_channel]);
 
 3182            if ($this->curTimeout) {
 
 3183                if ($this->curTimeout < 0) {
 
 3184                    $this->is_timeout = 
true;
 
 3188                $read = array($this->fsock);
 
 3189                $write = $except = 
null;
 
 3191                $start = microtime(
true);
 
 3192                $sec = floor($this->curTimeout);
 
 3193                $usec = 1000000 * ($this->curTimeout - $sec);
 
 3195                if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {
 
 3196                    $this->is_timeout = 
true;
 
 3199                $elapsed = microtime(
true) - 
$start;
 
 3200                $this->curTimeout-= $elapsed;
 
 3205                user_error(
'Connection closed by server');
 
 3208            if ($client_channel == -1 && 
$response === 
true) {
 
 3217            if (
$type == NET_SSH2_MSG_CHANNEL_OPEN) {
 
 3224            if (isset($channel) && isset($this->channel_status[$channel]) && isset($this->window_size_server_to_client[$channel])) {
 
 3225                $this->window_size_server_to_client[$channel]-= strlen(
$response);
 
 3228                if ($this->window_size_server_to_client[$channel] < 0) {
 
 3229                    $packet = pack(
'CNN', NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST, $this->server_channels[$channel], $this->window_size);
 
 3236                switch ($this->channel_status[$channel]) {
 
 3237                    case NET_SSH2_MSG_CHANNEL_OPEN:
 
 3239                            case NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION:
 
 3241                                $this->server_channels[$channel] = $server_channel;
 
 3243                                if ($window_size < 0) {
 
 3247                                $this->window_size_client_to_server[$channel] = 
$window_size;
 
 3249                                $this->packet_size_client_to_server[$channel] = $temp[
'packet_size_client_to_server'];
 
 3255                                user_error(
'Unable to open channel');
 
 3256                                return $this->
_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
 
 3259                    case NET_SSH2_MSG_CHANNEL_REQUEST:
 
 3261                            case NET_SSH2_MSG_CHANNEL_SUCCESS:
 
 3263                            case NET_SSH2_MSG_CHANNEL_FAILURE:
 
 3266                                user_error(
'Unable to fulfill channel request');
 
 3267                                return $this->
_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
 
 3269                    case NET_SSH2_MSG_CHANNEL_CLOSE:
 
 3277                case NET_SSH2_MSG_CHANNEL_DATA:
 
 3290                    if ($channel == self::CHANNEL_AGENT_FORWARD) {
 
 3291                        $agent_response = $this->agent->_forward_data(
$data);
 
 3292                        if (!is_bool($agent_response)) {
 
 3298                    if ($client_channel == $channel) {
 
 3301                    if (!isset($this->channel_buffers[$channel])) {
 
 3302                        $this->channel_buffers[$channel] = array();
 
 3304                    $this->channel_buffers[$channel][] = 
$data;
 
 3306                case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA:
 
 3315                    $this->stdErrorLog.= 
$data;
 
 3316                    if ($skip_extended || $this->quiet_mode) {
 
 3319                    if ($client_channel == $channel) {
 
 3322                    if (!isset($this->channel_buffers[$channel])) {
 
 3323                        $this->channel_buffers[$channel] = array();
 
 3325                    $this->channel_buffers[$channel][] = 
$data;
 
 3327                case NET_SSH2_MSG_CHANNEL_REQUEST:
 
 3341                            $this->
_send_binary_packet(pack(
'CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$client_channel]));
 
 3342                            $this->
_send_binary_packet(pack(
'CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel]));
 
 3344                            $this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_EOF;
 
 3361                case NET_SSH2_MSG_CHANNEL_CLOSE:
 
 3362                    $this->curTimeout = 0;
 
 3364                    if ($this->bitmap & self::MASK_SHELL) {
 
 3367                    if ($this->channel_status[$channel] != NET_SSH2_MSG_CHANNEL_EOF) {
 
 3368                        $this->
_send_binary_packet(pack(
'CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel]));
 
 3371                    $this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_CLOSE;
 
 3373                case NET_SSH2_MSG_CHANNEL_EOF:
 
 3376                    user_error(
'Error reading channel data');
 
 3377                    return $this->
_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
 
 3395        if (!is_resource($this->fsock) || feof($this->fsock)) {
 
 3396            user_error(
'Connection closed prematurely');
 
 3408        $packet_length = strlen(
$data) + 9;
 
 3412        $padding_length = $packet_length - strlen(
$data) - 5;
 
 3416        $packet = pack(
'NCa*', $packet_length - 4, $padding_length, 
$data . $padding);
 
 3418        $hmac = $this->hmac_create !== 
false ? $this->hmac_create->hash(pack(
'Na*', $this->send_seq_no, $packet)) : 
'';
 
 3419        $this->send_seq_no++;
 
 3421        if ($this->encrypt !== 
false) {
 
 3422            $packet = $this->encrypt->encrypt($packet);
 
 3427        $start = microtime(
true);
 
 3428        $result = strlen($packet) == fputs($this->fsock, $packet);
 
 3429        $stop = microtime(
true);
 
 3431        if (defined(
'NET_SSH2_LOGGING')) {
 
 3433            $message_number = isset($this->message_numbers[ord(
$data[0])]) ? $this->message_numbers[ord(
$data[0])] : 
'UNKNOWN (' . ord(
$data[0]) . 
')';
 
 3434            $message_number = 
'-> ' . $message_number .
 
 3435                              ' (since last: ' . round(
$current - $this->last_packet, 4) . 
', network: ' . round($stop - 
$start, 4) . 
's)';
 
 3454        if (strlen($message_number) > 2) {
 
 3458        switch (NET_SSH2_LOGGING) {
 
 3461                $this->message_number_log[] = $message_number;
 
 3465                $this->message_number_log[] = $message_number;
 
 3466                $this->log_size+= strlen(
$message);
 
 3468                while ($this->log_size > self::LOG_MAX_SIZE) {
 
 3469                    $this->log_size-= strlen(array_shift($this->message_log));
 
 3470                    array_shift($this->message_number_log);
 
 3494                if (!isset($this->realtime_log_file)) {
 
 3496                    $filename = self::LOG_REALTIME_FILENAME;
 
 3498                    $this->realtime_log_file = $fp;
 
 3500                if (!is_resource($this->realtime_log_file)) {
 
 3504                if ($this->realtime_log_wrap) {
 
 3505                    $temp = 
"<<< START >>>\r\n";
 
 3507                    fseek($this->realtime_log_file, ftell($this->realtime_log_file) - strlen($temp));
 
 3509                $this->realtime_log_size+= strlen($entry);
 
 3510                if ($this->realtime_log_size > self::LOG_MAX_SIZE) {
 
 3511                    fseek($this->realtime_log_file, 0);
 
 3512                    $this->realtime_log_size = strlen($entry);
 
 3513                    $this->realtime_log_wrap = 
true;
 
 3515                fputs($this->realtime_log_file, $entry);
 
 3531        while (strlen(
$data)) {
 
 3532            if (!$this->window_size_client_to_server[$client_channel]) {
 
 3544                $this->packet_size_client_to_server[$client_channel],
 
 3545                $this->window_size_client_to_server[$client_channel]
 
 3551                NET_SSH2_MSG_CHANNEL_DATA,
 
 3552                $this->server_channels[$client_channel],
 
 3556            $this->window_size_client_to_server[$client_channel]-= strlen($temp);
 
 3581        $this->
_send_binary_packet(pack(
'CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$client_channel]));
 
 3584            $this->
_send_binary_packet(pack(
'CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$client_channel]));
 
 3587        $this->channel_status[$client_channel] = NET_SSH2_MSG_CHANNEL_CLOSE;
 
 3589        $this->curTimeout = 0;
 
 3595            $this->
_send_binary_packet(pack(
'CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$client_channel]));
 
 3598        if ($this->bitmap & self::MASK_SHELL) {
 
 3612        if ($this->bitmap & self::MASK_CONNECTED) {
 
 3613            $data = pack(
'CNNa*Na*', NET_SSH2_MSG_DISCONNECT, $reason, 0, 
'', 0, 
'');
 
 3616            fclose($this->fsock);
 
 3633        $substr = substr($string, 0, 
$index);
 
 3634        $string = substr($string, 
$index);
 
 3650        $args = func_get_args();
 
 3651        foreach ($args as $arg) {
 
 3652            foreach ($arg as 
$key => $value) {
 
 3653                if (!defined($value)) {
 
 3654                    define($value, 
$key);
 
 3672        if (!defined(
'NET_SSH2_LOGGING')) {
 
 3676        switch (NET_SSH2_LOGGING) {
 
 3681                return $this->
_format_log($this->message_log, $this->message_number_log);
 
 3704                if (strlen($current_log)) {
 
 3705                    $output.= str_pad(dechex($j), 7, 
'0', STR_PAD_LEFT) . 
'0  ';
 
 3707                $fragment = $this->
_string_shift($current_log, $this->log_short_width);
 
 3708                $hex = substr(preg_replace_callback(
'#.#s', array($this, 
'_format_log_helper'), $fragment), strlen($this->log_boundary));
 
 3712                $raw = preg_replace(
'#[^\x20-\x7E]|<#', 
'.', $fragment);
 
 3713                $output.= str_pad($hex, $this->log_long_width - $this->log_short_width, 
' ') . $raw . 
"\r\n";
 
 3715            } 
while (strlen($current_log));
 
 3733        return $this->log_boundary . str_pad(dechex(ord($matches[0])), 2, 
'0', STR_PAD_LEFT);
 
 3747        if (isset($this->agent)) {
 
 3748            $this->agent->_on_channel_open($this);
 
 3763        foreach ($array1 as $value) {
 
 3764            if (in_array($value, $array2)) {
 
 3790        $count = count($this->errors);
 
 3793            return $this->errors[$count - 1];
 
 3965        if (!($this->bitmap & self::MASK_CONSTRUCTOR)) {
 
 3974        extract(unpack(
'Nlength', $this->
_string_shift($server_public_host_key, 4)));
 
 3977        if ($this->signature_validated) {
 
 3978            return $this->bitmap ?
 
 3979                $this->signature_format . 
' ' . base64_encode($this->server_public_host_key) :
 
 3983        $this->signature_validated = 
true;
 
 3985        switch ($this->signature_format) {
 
 3989                $temp = unpack(
'Nlength', $this->
_string_shift($server_public_host_key, 4));
 
 3992                $temp = unpack(
'Nlength', $this->
_string_shift($server_public_host_key, 4));
 
 3995                $temp = unpack(
'Nlength', $this->
_string_shift($server_public_host_key, 4));
 
 3998                $temp = unpack(
'Nlength', $this->
_string_shift($server_public_host_key, 4));
 
 4004                $temp = unpack(
'Nlength', $this->
_string_shift($signature, 4));
 
 4005                if ($temp[
'length'] != 40) {
 
 4006                    user_error(
'Invalid signature');
 
 4007                    return $this->
_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
 
 4014                    case $r->equals($zero):
 
 4015                    case $r->compare($q) >= 0:
 
 4016                    case $s->equals($zero):
 
 4017                    case $s->compare($q) >= 0:
 
 4018                        user_error(
'Invalid signature');
 
 4019                        return $this->
_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
 
 4022                $w = 
$s->modInverse($q);
 
 4024                $u1 = 
$w->multiply(
new BigInteger(sha1($this->exchange_hash), 16));
 
 4025                list(, $u1) = $u1->divide($q);
 
 4027                $u2 = 
$w->multiply(
$r);
 
 4028                list(, $u2) = $u2->divide($q);
 
 4030                $g = $g->modPow($u1, $p);
 
 4031                $y = 
$y->modPow($u2, $p);
 
 4033                $v = $g->multiply(
$y);
 
 4034                list(, $v) = $v->divide($p);
 
 4035                list(, $v) = $v->divide($q);
 
 4037                if (!$v->equals(
$r)) {
 
 4038                    user_error(
'Bad server signature');
 
 4039                    return $this->
_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
 
 4044                $temp = unpack(
'Nlength', $this->
_string_shift($server_public_host_key, 4));
 
 4047                $temp = unpack(
'Nlength', $this->
_string_shift($server_public_host_key, 4));
 
 4048                $rawN = $this->
_string_shift($server_public_host_key, $temp[
'length']);
 
 4050                $nLength = strlen(ltrim($rawN, 
"\0"));
 
 4065                $temp = unpack(
'Nlength', $this->
_string_shift($signature, 4));
 
 4075                    user_error(
'Invalid signature');
 
 4076                    return $this->
_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
 
 4082                $h = pack(
'N4H*', 0x00302130, 0x0906052B, 0x0E03021A, 0x05000414, sha1($this->exchange_hash));
 
 4083                $h = chr(0x01) . str_repeat(chr(0xFF), $nLength - 2 - strlen(
$h)) . 
$h;
 
 4086                    user_error(
'Bad server signature');
 
 4087                    return $this->
_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
 
 4091                user_error(
'Unsupported signature format');
 
 4092                return $this->
_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
 
 4095        return $this->signature_format . 
' ' . base64_encode($this->server_public_host_key);
 
 4106        if (is_null($this->exit_status)) {
 
 4142        $this->windowColumns = $value;
 
 4153        $this->windowRows = $value;
 
 4166        $this->windowRows = 
$rows;
 
An exception for terminatinating execution or to throw for unit testing.
const MODE_CTR
#+ @access public
const PUBLIC_FORMAT_RAW
#-
const SIGNATURE_PKCS1
Use the PKCS#1 scheme by default.
static string($length)
Generate a random string.
$quiet_mode
Flag to suppress stderr from output.
_login($username)
Login Helper.
_encryption_algorithm_to_crypt_instance($algorithm)
Maps an encryption algorithm name to an instance of a subclass of \phpseclib\Crypt\Base.
read($expect='', $mode=self::READ_SIMPLE)
Returns the output of an interactive shell.
getServerPublicHostKey()
Returns the server public host key.
_get_channel_packet($client_channel, $skip_extended=false)
Gets channel data.
$channel_extended_data_type_codes
_connect()
Connect to an SSHv2 server.
_format_log_helper($matches)
Helper function for _format_log.
getLog()
Returns a log of the packets that have been sent and received.
setWindowColumns($value)
Sets the number of columns for the terminal window size.
isQuietModeEnabled()
Returns whether Quiet Mode is enabled or not.
_send_channel_packet($client_channel, $data)
Sends channel data.
disablePTY()
Disable request-pty when using exec()
$mac_algorithms_server_to_client
isConnected()
Is the connection still active?
$languages_client_to_server
setWindowRows($value)
Sets the number of rows for the terminal window size.
const CHANNEL_AGENT_FORWARD
isPTYEnabled()
Returns whether request-pty is enabled or not.
write($cmd)
Inputs a command into an interactive shell.
_string_shift(&$string, $index=1)
String Shift.
$server_host_key_algorithms
getErrors()
Returns all errors.
setCryptoEngine($engine)
Set Crypto Engine Mode.
getExitStatus()
Returns the exit status of an SSH command or false.
$window_size_client_to_server
__construct($host, $port=22, $timeout=10)
Default Constructor.
$languages_server_to_client
getStdError()
Get the output from stdError.
getWindowColumns()
Returns the number of columns for the terminal window size.
getWindowRows()
Returns the number of rows for the terminal window size.
_close_channel($client_channel, $want_reply=false)
Closes and flushes a channel.
enableQuietMode()
Enable Quiet Mode.
getKexAlgorithms()
Return a list of the key exchange algorithms the server supports.
$last_interactive_response
getEncryptionAlgorithmsClient2Server()
Return a list of the (symmetric key) encryption algorithms the server supports, when receiving stuff ...
const LOG_COMPLEX
Returns the message content.
getEncryptionAlgorithmsServer2Client()
Return a list of the (symmetric key) encryption algorithms the server supports, when sending stuff to...
$compression_algorithms_server_to_client
enablePTY()
Enable request-pty when using exec()
setWindowSize($columns=80, $rows=24)
Sets the number of columns and rows for the terminal window size.
getServerIdentification()
Return the server identification.
$encryption_algorithms_client_to_server
$keyboard_requests_responses
getMACAlgorithmsServer2Client()
Return a list of the MAC algorithms the server supports, when sending stuff to the client.
getCompressionAlgorithmsServer2Client()
Return a list of the compression algorithms the server supports, when sending stuff to the client.
const LOG_MAX_SIZE
Make sure that the log never gets larger than this.
$window_size_server_to_client
_disconnect($reason)
Disconnect.
getMACAlgorithmsClient2Server()
Return a list of the MAC algorithms the server supports, when receiving stuff from the client.
_get_open_channel()
Return an available open channel.
_define_array()
Define Array.
_ssh_agent_login($username, $agent)
Login with an ssh-agent provided key.
_initShell()
Creates an interactive shell.
_keyboard_interactive_process()
Handle the keyboard-interactive requests / responses.
isAuthenticated()
Have you successfully been logged in?
getServerHostKeyAlgorithms()
Return a list of the host key (public key) algorithms the server supports.
getCompressionAlgorithmsClient2Server()
Return a list of the compression algorithms the server supports, when receiving stuff from the client...
setTimeout($timeout)
Set Timeout.
$compression_algorithms_client_to_server
getLanguagesClient2Server()
Return a list of the languages the server supports, when receiving stuff from the client.
$packet_size_client_to_server
_keyboard_interactive_login($username, $password)
Login via keyboard-interactive authentication.
_encryption_algorithm_to_key_size($algorithm)
Maps an encryption algorithm name to the number of key bytes.
startSubsystem($subsystem)
Start a subsystem.
$mac_algorithms_client_to_server
_get_binary_packet()
Gets Binary Packets.
stopSubsystem()
Stops a subsystem.
_login_helper($username, $password=null)
Login Helper.
getBannerMessage()
Returns the banner message.
_filter($payload)
Filter Binary Packets.
$curTimeout
Current Timeout.
getLanguagesServer2Client()
Return a list of the languages the server supports, when sending stuff to the client.
_on_channel_open()
Helper function for agent->_on_channel_open()
const MASK_CONSTRUCTOR
#+ Execution Bitmap Masks
_privatekey_login($username, $privatekey)
Login with an RSA private key.
exec($command, $callback=null)
Execute Command.
getLastError()
Returns the last error.
$channel_open_failure_reasons
_key_exchange($kexinit_payload_server)
Key Exchange.
_get_interactive_channel()
Return the channel to be used with read() / write()
$kex_dh_group_size_preferred
_array_intersect_first($array1, $array2)
Returns the first value of the intersection of two arrays or false if the intersection is empty.
_append_log($message_number, $message)
Logs data packets.
_generate_identifier()
Generates the SSH identifier.
_send_binary_packet($data, $logged=null)
Sends Binary Packets.
$encryption_algorithms_server_to_client
disableQuietMode()
Disable Quiet Mode.
const READ_REGEX
Returns when a string matching the regular expression $expect is found.
const LOG_REALTIME
Outputs the content real-time.
$realtime_log_wrap
Real-time log file wrap boolean.
_format_log($message_log, $message_number_log)
Formats a log for printing.
const LOG_REALTIME_FILE
Dumps the content real-time to a file.
catch(Exception $e) $message
Pure-PHP arbitrary precision integer arithmetic library.
Pure-PHP implementation of Blowfish.
Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic...
Pure-PHP implementation of RC4.
Pure-PHP PKCS#1 compliant implementation of RSA.
Pure-PHP implementation of Rijndael.
Pure-PHP implementation of SSHv2.
Pure-PHP implementation of Triple DES.
Pure-PHP implementation of Twofish.