vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php line 1201

Open in your IDE?
  1. <?php
  2. /**
  3.  * Pure-PHP implementation of SSHv2.
  4.  *
  5.  * PHP version 5
  6.  *
  7.  * Here are some examples of how to use this library:
  8.  * <code>
  9.  * <?php
  10.  *    include 'vendor/autoload.php';
  11.  *
  12.  *    $ssh = new \phpseclib3\Net\SSH2('www.domain.tld');
  13.  *    if (!$ssh->login('username', 'password')) {
  14.  *        exit('Login Failed');
  15.  *    }
  16.  *
  17.  *    echo $ssh->exec('pwd');
  18.  *    echo $ssh->exec('ls -la');
  19.  * ?>
  20.  * </code>
  21.  *
  22.  * <code>
  23.  * <?php
  24.  *    include 'vendor/autoload.php';
  25.  *
  26.  *    $key = \phpseclib3\Crypt\PublicKeyLoader::load('...', '(optional) password');
  27.  *
  28.  *    $ssh = new \phpseclib3\Net\SSH2('www.domain.tld');
  29.  *    if (!$ssh->login('username', $key)) {
  30.  *        exit('Login Failed');
  31.  *    }
  32.  *
  33.  *    echo $ssh->read('username@username:~$');
  34.  *    $ssh->write("ls -la\n");
  35.  *    echo $ssh->read('username@username:~$');
  36.  * ?>
  37.  * </code>
  38.  *
  39.  * @category  Net
  40.  * @package   SSH2
  41.  * @author    Jim Wigginton <terrafrost@php.net>
  42.  * @copyright 2007 Jim Wigginton
  43.  * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
  44.  * @link      http://phpseclib.sourceforge.net
  45.  */
  46. namespace phpseclib3\Net;
  47. use phpseclib3\Crypt\Blowfish;
  48. use phpseclib3\Crypt\Hash;
  49. use phpseclib3\Crypt\Random;
  50. use phpseclib3\Crypt\RC4;
  51. use phpseclib3\Crypt\Rijndael;
  52. use phpseclib3\Crypt\Common\PrivateKey;
  53. use phpseclib3\Crypt\RSA;
  54. use phpseclib3\Crypt\DSA;
  55. use phpseclib3\Crypt\EC;
  56. use phpseclib3\Crypt\DH;
  57. use phpseclib3\Crypt\TripleDES;
  58. use phpseclib3\Crypt\Twofish;
  59. use phpseclib3\Crypt\ChaCha20;
  60. use phpseclib3\Math\BigInteger// Used to do Diffie-Hellman key exchange and DSA/RSA signature verification.
  61. use phpseclib3\System\SSH\Agent;
  62. use phpseclib3\System\SSH\Agent\Identity as AgentIdentity;
  63. use phpseclib3\Exception\NoSupportedAlgorithmsException;
  64. use phpseclib3\Exception\UnsupportedAlgorithmException;
  65. use phpseclib3\Exception\UnsupportedCurveException;
  66. use phpseclib3\Exception\ConnectionClosedException;
  67. use phpseclib3\Exception\UnableToConnectException;
  68. use phpseclib3\Exception\InsufficientSetupException;
  69. use phpseclib3\Common\Functions\Strings;
  70. /**
  71.  * Pure-PHP implementation of SSHv2.
  72.  *
  73.  * @package SSH2
  74.  * @author  Jim Wigginton <terrafrost@php.net>
  75.  * @access  public
  76.  */
  77. class SSH2
  78. {
  79.     // Execution Bitmap Masks
  80.     const MASK_CONSTRUCTOR   0x00000001;
  81.     const MASK_CONNECTED     0x00000002;
  82.     const MASK_LOGIN_REQ     0x00000004;
  83.     const MASK_LOGIN         0x00000008;
  84.     const MASK_SHELL         0x00000010;
  85.     const MASK_WINDOW_ADJUST 0x00000020;
  86.     /*
  87.      * Channel constants
  88.      *
  89.      * RFC4254 refers not to client and server channels but rather to sender and recipient channels.  we don't refer
  90.      * to them in that way because RFC4254 toggles the meaning. the client sends a SSH_MSG_CHANNEL_OPEN message with
  91.      * a sender channel and the server sends a SSH_MSG_CHANNEL_OPEN_CONFIRMATION in response, with a sender and a
  92.      * recipient channel.  at first glance, you might conclude that SSH_MSG_CHANNEL_OPEN_CONFIRMATION's sender channel
  93.      * would be the same thing as SSH_MSG_CHANNEL_OPEN's sender channel, but it's not, per this snippet:
  94.      *     The 'recipient channel' is the channel number given in the original
  95.      *     open request, and 'sender channel' is the channel number allocated by
  96.      *     the other side.
  97.      *
  98.      * @see \phpseclib3\Net\SSH2::send_channel_packet()
  99.      * @see \phpseclib3\Net\SSH2::get_channel_packet()
  100.      * @access private
  101.      */
  102.     const CHANNEL_EXEC          1// PuTTy uses 0x100
  103.     const CHANNEL_SHELL         2;
  104.     const CHANNEL_SUBSYSTEM     3;
  105.     const CHANNEL_AGENT_FORWARD 4;
  106.     const CHANNEL_KEEP_ALIVE    5;
  107.     /**
  108.      * Returns the message numbers
  109.      *
  110.      * @access public
  111.      * @see \phpseclib3\Net\SSH2::getLog()
  112.      */
  113.     const LOG_SIMPLE 1;
  114.     /**
  115.      * Returns the message content
  116.      *
  117.      * @access public
  118.      * @see \phpseclib3\Net\SSH2::getLog()
  119.      */
  120.     const LOG_COMPLEX 2;
  121.     /**
  122.      * Outputs the content real-time
  123.      *
  124.      * @access public
  125.      * @see \phpseclib3\Net\SSH2::getLog()
  126.      */
  127.     const LOG_REALTIME 3;
  128.     /**
  129.      * Dumps the content real-time to a file
  130.      *
  131.      * @access public
  132.      * @see \phpseclib3\Net\SSH2::getLog()
  133.      */
  134.     const LOG_REALTIME_FILE 4;
  135.     /**
  136.      * Make sure that the log never gets larger than this
  137.      *
  138.      * @access public
  139.      * @see \phpseclib3\Net\SSH2::getLog()
  140.      */
  141.     const LOG_MAX_SIZE 1048576// 1024 * 1024
  142.     /**
  143.      * Returns when a string matching $expect exactly is found
  144.      *
  145.      * @access public
  146.      * @see \phpseclib3\Net\SSH2::read()
  147.      */
  148.     const READ_SIMPLE 1;
  149.     /**
  150.      * Returns when a string matching the regular expression $expect is found
  151.      *
  152.      * @access public
  153.      * @see \phpseclib3\Net\SSH2::read()
  154.      */
  155.     const READ_REGEX 2;
  156.     /**
  157.      * Returns whenever a data packet is received.
  158.      *
  159.      * Some data packets may only contain a single character so it may be necessary
  160.      * to call read() multiple times when using this option
  161.      *
  162.      * @access public
  163.      * @see \phpseclib3\Net\SSH2::read()
  164.      */
  165.     const READ_NEXT 3;
  166.     /**
  167.      * The SSH identifier
  168.      *
  169.      * @var string
  170.      * @access private
  171.      */
  172.     private $identifier;
  173.     /**
  174.      * The Socket Object
  175.      *
  176.      * @var object
  177.      * @access private
  178.      */
  179.     public $fsock;
  180.     /**
  181.      * Execution Bitmap
  182.      *
  183.      * The bits that are set represent functions that have been called already.  This is used to determine
  184.      * if a requisite function has been successfully executed.  If not, an error should be thrown.
  185.      *
  186.      * @var int
  187.      * @access private
  188.      */
  189.     protected $bitmap 0;
  190.     /**
  191.      * Error information
  192.      *
  193.      * @see self::getErrors()
  194.      * @see self::getLastError()
  195.      * @var array
  196.      * @access private
  197.      */
  198.     private $errors = [];
  199.     /**
  200.      * Server Identifier
  201.      *
  202.      * @see self::getServerIdentification()
  203.      * @var array|false
  204.      * @access private
  205.      */
  206.     private $server_identifier false;
  207.     /**
  208.      * Key Exchange Algorithms
  209.      *
  210.      * @see self::getKexAlgorithims()
  211.      * @var array|false
  212.      * @access private
  213.      */
  214.     private $kex_algorithms false;
  215.     /**
  216.      * Key Exchange Algorithm
  217.      *
  218.      * @see self::getMethodsNegotiated()
  219.      * @var string|false
  220.      * @access private
  221.      */
  222.     private $kex_algorithm false;
  223.     /**
  224.      * Minimum Diffie-Hellman Group Bit Size in RFC 4419 Key Exchange Methods
  225.      *
  226.      * @see self::_key_exchange()
  227.      * @var int
  228.      * @access private
  229.      */
  230.     private $kex_dh_group_size_min 1536;
  231.     /**
  232.      * Preferred Diffie-Hellman Group Bit Size in RFC 4419 Key Exchange Methods
  233.      *
  234.      * @see self::_key_exchange()
  235.      * @var int
  236.      * @access private
  237.      */
  238.     private $kex_dh_group_size_preferred 2048;
  239.     /**
  240.      * Maximum Diffie-Hellman Group Bit Size in RFC 4419 Key Exchange Methods
  241.      *
  242.      * @see self::_key_exchange()
  243.      * @var int
  244.      * @access private
  245.      */
  246.     private $kex_dh_group_size_max 4096;
  247.     /**
  248.      * Server Host Key Algorithms
  249.      *
  250.      * @see self::getServerHostKeyAlgorithms()
  251.      * @var array|false
  252.      * @access private
  253.      */
  254.     private $server_host_key_algorithms false;
  255.     /**
  256.      * Encryption Algorithms: Client to Server
  257.      *
  258.      * @see self::getEncryptionAlgorithmsClient2Server()
  259.      * @var array|false
  260.      * @access private
  261.      */
  262.     private $encryption_algorithms_client_to_server false;
  263.     /**
  264.      * Encryption Algorithms: Server to Client
  265.      *
  266.      * @see self::getEncryptionAlgorithmsServer2Client()
  267.      * @var array|false
  268.      * @access private
  269.      */
  270.     private $encryption_algorithms_server_to_client false;
  271.     /**
  272.      * MAC Algorithms: Client to Server
  273.      *
  274.      * @see self::getMACAlgorithmsClient2Server()
  275.      * @var array|false
  276.      * @access private
  277.      */
  278.     private $mac_algorithms_client_to_server false;
  279.     /**
  280.      * MAC Algorithms: Server to Client
  281.      *
  282.      * @see self::getMACAlgorithmsServer2Client()
  283.      * @var array|false
  284.      * @access private
  285.      */
  286.     private $mac_algorithms_server_to_client false;
  287.     /**
  288.      * Compression Algorithms: Client to Server
  289.      *
  290.      * @see self::getCompressionAlgorithmsClient2Server()
  291.      * @var array|false
  292.      * @access private
  293.      */
  294.     private $compression_algorithms_client_to_server false;
  295.     /**
  296.      * Compression Algorithms: Server to Client
  297.      *
  298.      * @see self::getCompressionAlgorithmsServer2Client()
  299.      * @var array|false
  300.      * @access private
  301.      */
  302.     private $compression_algorithms_server_to_client false;
  303.     /**
  304.      * Languages: Server to Client
  305.      *
  306.      * @see self::getLanguagesServer2Client()
  307.      * @var array|false
  308.      * @access private
  309.      */
  310.     private $languages_server_to_client false;
  311.     /**
  312.      * Languages: Client to Server
  313.      *
  314.      * @see self::getLanguagesClient2Server()
  315.      * @var array|false
  316.      * @access private
  317.      */
  318.     private $languages_client_to_server false;
  319.     /**
  320.      * Preferred Algorithms
  321.      *
  322.      * @see self::setPreferredAlgorithms()
  323.      * @var array
  324.      * @access private
  325.      */
  326.     private $preferred = [];
  327.     /**
  328.      * Block Size for Server to Client Encryption
  329.      *
  330.      * "Note that the length of the concatenation of 'packet_length',
  331.      *  'padding_length', 'payload', and 'random padding' MUST be a multiple
  332.      *  of the cipher block size or 8, whichever is larger.  This constraint
  333.      *  MUST be enforced, even when using stream ciphers."
  334.      *
  335.      *  -- http://tools.ietf.org/html/rfc4253#section-6
  336.      *
  337.      * @see self::__construct()
  338.      * @see self::_send_binary_packet()
  339.      * @var int
  340.      * @access private
  341.      */
  342.     private $encrypt_block_size 8;
  343.     /**
  344.      * Block Size for Client to Server Encryption
  345.      *
  346.      * @see self::__construct()
  347.      * @see self::_get_binary_packet()
  348.      * @var int
  349.      * @access private
  350.      */
  351.     private $decrypt_block_size 8;
  352.     /**
  353.      * Server to Client Encryption Object
  354.      *
  355.      * @see self::_get_binary_packet()
  356.      * @var object
  357.      * @access private
  358.      */
  359.     private $decrypt false;
  360.     /**
  361.      * Server to Client Length Encryption Object
  362.      *
  363.      * @see self::_get_binary_packet()
  364.      * @var object
  365.      * @access private
  366.      */
  367.     private $lengthDecrypt false;
  368.     /**
  369.      * Client to Server Encryption Object
  370.      *
  371.      * @see self::_send_binary_packet()
  372.      * @var object
  373.      * @access private
  374.      */
  375.     private $encrypt false;
  376.     /**
  377.      * Client to Server Length Encryption Object
  378.      *
  379.      * @see self::_send_binary_packet()
  380.      * @var object
  381.      * @access private
  382.      */
  383.     private $lengthEncrypt false;
  384.     /**
  385.      * Client to Server HMAC Object
  386.      *
  387.      * @see self::_send_binary_packet()
  388.      * @var object
  389.      * @access private
  390.      */
  391.     private $hmac_create false;
  392.     /**
  393.      * Server to Client HMAC Object
  394.      *
  395.      * @see self::_get_binary_packet()
  396.      * @var object
  397.      * @access private
  398.      */
  399.     private $hmac_check false;
  400.     /**
  401.      * Size of server to client HMAC
  402.      *
  403.      * We need to know how big the HMAC will be for the server to client direction so that we know how many bytes to read.
  404.      * For the client to server side, the HMAC object will make the HMAC as long as it needs to be.  All we need to do is
  405.      * append it.
  406.      *
  407.      * @see self::_get_binary_packet()
  408.      * @var int
  409.      * @access private
  410.      */
  411.     private $hmac_size false;
  412.     /**
  413.      * Server Public Host Key
  414.      *
  415.      * @see self::getServerPublicHostKey()
  416.      * @var string
  417.      * @access private
  418.      */
  419.     private $server_public_host_key;
  420.     /**
  421.      * Session identifier
  422.      *
  423.      * "The exchange hash H from the first key exchange is additionally
  424.      *  used as the session identifier, which is a unique identifier for
  425.      *  this connection."
  426.      *
  427.      *  -- http://tools.ietf.org/html/rfc4253#section-7.2
  428.      *
  429.      * @see self::_key_exchange()
  430.      * @var string
  431.      * @access private
  432.      */
  433.     private $session_id false;
  434.     /**
  435.      * Exchange hash
  436.      *
  437.      * The current exchange hash
  438.      *
  439.      * @see self::_key_exchange()
  440.      * @var string
  441.      * @access private
  442.      */
  443.     private $exchange_hash false;
  444.     /**
  445.      * Message Numbers
  446.      *
  447.      * @see self::__construct()
  448.      * @var array
  449.      * @access private
  450.      */
  451.     private $message_numbers = [];
  452.     /**
  453.      * Disconnection Message 'reason codes' defined in RFC4253
  454.      *
  455.      * @see self::__construct()
  456.      * @var array
  457.      * @access private
  458.      */
  459.     private $disconnect_reasons = [];
  460.     /**
  461.      * SSH_MSG_CHANNEL_OPEN_FAILURE 'reason codes', defined in RFC4254
  462.      *
  463.      * @see self::__construct()
  464.      * @var array
  465.      * @access private
  466.      */
  467.     private $channel_open_failure_reasons = [];
  468.     /**
  469.      * Terminal Modes
  470.      *
  471.      * @link http://tools.ietf.org/html/rfc4254#section-8
  472.      * @see self::__construct()
  473.      * @var array
  474.      * @access private
  475.      */
  476.     private $terminal_modes = [];
  477.     /**
  478.      * SSH_MSG_CHANNEL_EXTENDED_DATA's data_type_codes
  479.      *
  480.      * @link http://tools.ietf.org/html/rfc4254#section-5.2
  481.      * @see self::__construct()
  482.      * @var array
  483.      * @access private
  484.      */
  485.     private $channel_extended_data_type_codes = [];
  486.     /**
  487.      * Send Sequence Number
  488.      *
  489.      * See 'Section 6.4.  Data Integrity' of rfc4253 for more info.
  490.      *
  491.      * @see self::_send_binary_packet()
  492.      * @var int
  493.      * @access private
  494.      */
  495.     private $send_seq_no 0;
  496.     /**
  497.      * Get Sequence Number
  498.      *
  499.      * See 'Section 6.4.  Data Integrity' of rfc4253 for more info.
  500.      *
  501.      * @see self::_get_binary_packet()
  502.      * @var int
  503.      * @access private
  504.      */
  505.     private $get_seq_no 0;
  506.     /**
  507.      * Server Channels
  508.      *
  509.      * Maps client channels to server channels
  510.      *
  511.      * @see self::get_channel_packet()
  512.      * @see self::exec()
  513.      * @var array
  514.      * @access private
  515.      */
  516.     protected $server_channels = [];
  517.     /**
  518.      * Channel Buffers
  519.      *
  520.      * If a client requests a packet from one channel but receives two packets from another those packets should
  521.      * be placed in a buffer
  522.      *
  523.      * @see self::get_channel_packet()
  524.      * @see self::exec()
  525.      * @var array
  526.      * @access private
  527.      */
  528.     private $channel_buffers = [];
  529.     /**
  530.      * Channel Status
  531.      *
  532.      * Contains the type of the last sent message
  533.      *
  534.      * @see self::get_channel_packet()
  535.      * @var array
  536.      * @access private
  537.      */
  538.     protected $channel_status = [];
  539.     /**
  540.      * Packet Size
  541.      *
  542.      * Maximum packet size indexed by channel
  543.      *
  544.      * @see self::send_channel_packet()
  545.      * @var array
  546.      * @access private
  547.      */
  548.     private $packet_size_client_to_server = [];
  549.     /**
  550.      * Message Number Log
  551.      *
  552.      * @see self::getLog()
  553.      * @var array
  554.      * @access private
  555.      */
  556.     private $message_number_log = [];
  557.     /**
  558.      * Message Log
  559.      *
  560.      * @see self::getLog()
  561.      * @var array
  562.      * @access private
  563.      */
  564.     private $message_log = [];
  565.     /**
  566.      * The Window Size
  567.      *
  568.      * Bytes the other party can send before it must wait for the window to be adjusted (0x7FFFFFFF = 2GB)
  569.      *
  570.      * @var int
  571.      * @see self::send_channel_packet()
  572.      * @see self::exec()
  573.      * @access private
  574.      */
  575.     protected $window_size 0x7FFFFFFF;
  576.     /**
  577.      * What we resize the window to
  578.      *
  579.      * When PuTTY resizes the window it doesn't add an additional 0x7FFFFFFF bytes - it adds 0x40000000 bytes.
  580.      * Some SFTP clients (GoAnywhere) don't support adding 0x7FFFFFFF to the window size after the fact so
  581.      * we'll just do what PuTTY does
  582.      *
  583.      * @var int
  584.      * @see self::_send_channel_packet()
  585.      * @see self::exec()
  586.      * @access private
  587.      */
  588.     var $window_resize 0x40000000;
  589.     /**
  590.      * Window size, server to client
  591.      *
  592.      * Window size indexed by channel
  593.      *
  594.      * @see self::send_channel_packet()
  595.      * @var array
  596.      * @access private
  597.      */
  598.     protected $window_size_server_to_client = [];
  599.     /**
  600.      * Window size, client to server
  601.      *
  602.      * Window size indexed by channel
  603.      *
  604.      * @see self::get_channel_packet()
  605.      * @var array
  606.      * @access private
  607.      */
  608.     private $window_size_client_to_server = [];
  609.     /**
  610.      * Server signature
  611.      *
  612.      * Verified against $this->session_id
  613.      *
  614.      * @see self::getServerPublicHostKey()
  615.      * @var string
  616.      * @access private
  617.      */
  618.     private $signature '';
  619.     /**
  620.      * Server signature format
  621.      *
  622.      * ssh-rsa or ssh-dss.
  623.      *
  624.      * @see self::getServerPublicHostKey()
  625.      * @var string
  626.      * @access private
  627.      */
  628.     private $signature_format '';
  629.     /**
  630.      * Interactive Buffer
  631.      *
  632.      * @see self::read()
  633.      * @var array
  634.      * @access private
  635.      */
  636.     private $interactiveBuffer '';
  637.     /**
  638.      * Current log size
  639.      *
  640.      * Should never exceed self::LOG_MAX_SIZE
  641.      *
  642.      * @see self::_send_binary_packet()
  643.      * @see self::_get_binary_packet()
  644.      * @var int
  645.      * @access private
  646.      */
  647.     private $log_size;
  648.     /**
  649.      * Timeout
  650.      *
  651.      * @see self::setTimeout()
  652.      * @access private
  653.      */
  654.     protected $timeout;
  655.     /**
  656.      * Current Timeout
  657.      *
  658.      * @see self::get_channel_packet()
  659.      * @access private
  660.      */
  661.     protected $curTimeout;
  662.     /**
  663.      * Keep Alive Interval
  664.      *
  665.      * @see self::setKeepAlive()
  666.      * @access private
  667.      */
  668.     var $keepAlive;
  669.     /**
  670.      * Real-time log file pointer
  671.      *
  672.      * @see self::_append_log()
  673.      * @var resource
  674.      * @access private
  675.      */
  676.     private $realtime_log_file;
  677.     /**
  678.      * Real-time log file size
  679.      *
  680.      * @see self::_append_log()
  681.      * @var int
  682.      * @access private
  683.      */
  684.     private $realtime_log_size;
  685.     /**
  686.      * Has the signature been validated?
  687.      *
  688.      * @see self::getServerPublicHostKey()
  689.      * @var bool
  690.      * @access private
  691.      */
  692.     private $signature_validated false;
  693.     /**
  694.      * Real-time log file wrap boolean
  695.      *
  696.      * @see self::_append_log()
  697.      * @access private
  698.      */
  699.     private $realtime_log_wrap;
  700.     /**
  701.      * Flag to suppress stderr from output
  702.      *
  703.      * @see self::enableQuietMode()
  704.      * @access private
  705.      */
  706.     private $quiet_mode false;
  707.     /**
  708.      * Time of first network activity
  709.      *
  710.      * @var int
  711.      * @access private
  712.      */
  713.     private $last_packet;
  714.     /**
  715.      * Exit status returned from ssh if any
  716.      *
  717.      * @var int
  718.      * @access private
  719.      */
  720.     private $exit_status;
  721.     /**
  722.      * Flag to request a PTY when using exec()
  723.      *
  724.      * @var bool
  725.      * @see self::enablePTY()
  726.      * @access private
  727.      */
  728.     private $request_pty false;
  729.     /**
  730.      * Flag set while exec() is running when using enablePTY()
  731.      *
  732.      * @var bool
  733.      * @access private
  734.      */
  735.     private $in_request_pty_exec false;
  736.     /**
  737.      * Flag set after startSubsystem() is called
  738.      *
  739.      * @var bool
  740.      * @access private
  741.      */
  742.     private $in_subsystem;
  743.     /**
  744.      * Contents of stdError
  745.      *
  746.      * @var string
  747.      * @access private
  748.      */
  749.     private $stdErrorLog;
  750.     /**
  751.      * The Last Interactive Response
  752.      *
  753.      * @see self::_keyboard_interactive_process()
  754.      * @var string
  755.      * @access private
  756.      */
  757.     private $last_interactive_response '';
  758.     /**
  759.      * Keyboard Interactive Request / Responses
  760.      *
  761.      * @see self::_keyboard_interactive_process()
  762.      * @var array
  763.      * @access private
  764.      */
  765.     private $keyboard_requests_responses = [];
  766.     /**
  767.      * Banner Message
  768.      *
  769.      * Quoting from the RFC, "in some jurisdictions, sending a warning message before
  770.      * authentication may be relevant for getting legal protection."
  771.      *
  772.      * @see self::_filter()
  773.      * @see self::getBannerMessage()
  774.      * @var string
  775.      * @access private
  776.      */
  777.     private $banner_message '';
  778.     /**
  779.      * Did read() timeout or return normally?
  780.      *
  781.      * @see self::isTimeout()
  782.      * @var bool
  783.      * @access private
  784.      */
  785.     private $is_timeout false;
  786.     /**
  787.      * Log Boundary
  788.      *
  789.      * @see self::_format_log()
  790.      * @var string
  791.      * @access private
  792.      */
  793.     private $log_boundary ':';
  794.     /**
  795.      * Log Long Width
  796.      *
  797.      * @see self::_format_log()
  798.      * @var int
  799.      * @access private
  800.      */
  801.     private $log_long_width 65;
  802.     /**
  803.      * Log Short Width
  804.      *
  805.      * @see self::_format_log()
  806.      * @var int
  807.      * @access private
  808.      */
  809.     private $log_short_width 16;
  810.     /**
  811.      * Hostname
  812.      *
  813.      * @see self::__construct()
  814.      * @see self::_connect()
  815.      * @var string
  816.      * @access private
  817.      */
  818.     private $host;
  819.     /**
  820.      * Port Number
  821.      *
  822.      * @see self::__construct()
  823.      * @see self::_connect()
  824.      * @var int
  825.      * @access private
  826.      */
  827.     private $port;
  828.     /**
  829.      * Number of columns for terminal window size
  830.      *
  831.      * @see self::getWindowColumns()
  832.      * @see self::setWindowColumns()
  833.      * @see self::setWindowSize()
  834.      * @var int
  835.      * @access private
  836.      */
  837.     private $windowColumns 80;
  838.     /**
  839.      * Number of columns for terminal window size
  840.      *
  841.      * @see self::getWindowRows()
  842.      * @see self::setWindowRows()
  843.      * @see self::setWindowSize()
  844.      * @var int
  845.      * @access private
  846.      */
  847.     private $windowRows 24;
  848.     /**
  849.      * Crypto Engine
  850.      *
  851.      * @see self::setCryptoEngine()
  852.      * @see self::_key_exchange()
  853.      * @var int
  854.      * @access private
  855.      */
  856.     private static $crypto_engine false;
  857.     /**
  858.      * A System_SSH_Agent for use in the SSH2 Agent Forwarding scenario
  859.      *
  860.      * @var \phpseclib3\System\Ssh\Agent
  861.      * @access private
  862.      */
  863.     private $agent;
  864.     /**
  865.      * Connection storage to replicates ssh2 extension functionality:
  866.      * {@link http://php.net/manual/en/wrappers.ssh2.php#refsect1-wrappers.ssh2-examples}
  867.      *
  868.      * @var SSH2[]
  869.      */
  870.     private static $connections;
  871.     /**
  872.      * Send the identification string first?
  873.      *
  874.      * @var bool
  875.      * @access private
  876.      */
  877.     private $send_id_string_first true;
  878.     /**
  879.      * Send the key exchange initiation packet first?
  880.      *
  881.      * @var bool
  882.      * @access private
  883.      */
  884.     private $send_kex_first true;
  885.     /**
  886.      * Some versions of OpenSSH incorrectly calculate the key size
  887.      *
  888.      * @var bool
  889.      * @access private
  890.      */
  891.     private $bad_key_size_fix false;
  892.     /**
  893.      * Should we try to re-connect to re-establish keys?
  894.      *
  895.      * @var bool
  896.      * @access private
  897.      */
  898.     private $retry_connect false;
  899.     /**
  900.      * Binary Packet Buffer
  901.      *
  902.      * @var string|false
  903.      * @access private
  904.      */
  905.     private $binary_packet_buffer false;
  906.     /**
  907.      * Preferred Signature Format
  908.      *
  909.      * @var string|false
  910.      * @access private
  911.      */
  912.     protected $preferred_signature_format false;
  913.     /**
  914.      * Authentication Credentials
  915.      *
  916.      * @var array
  917.      * @access private
  918.      */
  919.     protected $auth = [];
  920.     /**
  921.      * Default Constructor.
  922.      *
  923.      * $host can either be a string, representing the host, or a stream resource.
  924.      *
  925.      * @param mixed $host
  926.      * @param int $port
  927.      * @param int $timeout
  928.      * @see self::login()
  929.      * @return SSH2|void
  930.      * @access public
  931.      */
  932.     public function __construct($host$port 22$timeout 10)
  933.     {
  934.         $this->message_numbers = [
  935.             => 'NET_SSH2_MSG_DISCONNECT',
  936.             => 'NET_SSH2_MSG_IGNORE',
  937.             => 'NET_SSH2_MSG_UNIMPLEMENTED',
  938.             => 'NET_SSH2_MSG_DEBUG',
  939.             => 'NET_SSH2_MSG_SERVICE_REQUEST',
  940.             => 'NET_SSH2_MSG_SERVICE_ACCEPT',
  941.             20 => 'NET_SSH2_MSG_KEXINIT',
  942.             21 => 'NET_SSH2_MSG_NEWKEYS',
  943.             30 => 'NET_SSH2_MSG_KEXDH_INIT',
  944.             31 => 'NET_SSH2_MSG_KEXDH_REPLY',
  945.             50 => 'NET_SSH2_MSG_USERAUTH_REQUEST',
  946.             51 => 'NET_SSH2_MSG_USERAUTH_FAILURE',
  947.             52 => 'NET_SSH2_MSG_USERAUTH_SUCCESS',
  948.             53 => 'NET_SSH2_MSG_USERAUTH_BANNER',
  949.             80 => 'NET_SSH2_MSG_GLOBAL_REQUEST',
  950.             81 => 'NET_SSH2_MSG_REQUEST_SUCCESS',
  951.             82 => 'NET_SSH2_MSG_REQUEST_FAILURE',
  952.             90 => 'NET_SSH2_MSG_CHANNEL_OPEN',
  953.             91 => 'NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION',
  954.             92 => 'NET_SSH2_MSG_CHANNEL_OPEN_FAILURE',
  955.             93 => 'NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST',
  956.             94 => 'NET_SSH2_MSG_CHANNEL_DATA',
  957.             95 => 'NET_SSH2_MSG_CHANNEL_EXTENDED_DATA',
  958.             96 => 'NET_SSH2_MSG_CHANNEL_EOF',
  959.             97 => 'NET_SSH2_MSG_CHANNEL_CLOSE',
  960.             98 => 'NET_SSH2_MSG_CHANNEL_REQUEST',
  961.             99 => 'NET_SSH2_MSG_CHANNEL_SUCCESS',
  962.             100 => 'NET_SSH2_MSG_CHANNEL_FAILURE'
  963.         ];
  964.         $this->disconnect_reasons = [
  965.             => 'NET_SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT',
  966.             => 'NET_SSH2_DISCONNECT_PROTOCOL_ERROR',
  967.             => 'NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED',
  968.             => 'NET_SSH2_DISCONNECT_RESERVED',
  969.             => 'NET_SSH2_DISCONNECT_MAC_ERROR',
  970.             => 'NET_SSH2_DISCONNECT_COMPRESSION_ERROR',
  971.             => 'NET_SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE',
  972.             => 'NET_SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED',
  973.             => 'NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE',
  974.             10 => 'NET_SSH2_DISCONNECT_CONNECTION_LOST',
  975.             11 => 'NET_SSH2_DISCONNECT_BY_APPLICATION',
  976.             12 => 'NET_SSH2_DISCONNECT_TOO_MANY_CONNECTIONS',
  977.             13 => 'NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER',
  978.             14 => 'NET_SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE',
  979.             15 => 'NET_SSH2_DISCONNECT_ILLEGAL_USER_NAME'
  980.         ];
  981.         $this->channel_open_failure_reasons = [
  982.             => 'NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED'
  983.         ];
  984.         $this->terminal_modes = [
  985.             => 'NET_SSH2_TTY_OP_END'
  986.         ];
  987.         $this->channel_extended_data_type_codes = [
  988.             => 'NET_SSH2_EXTENDED_DATA_STDERR'
  989.         ];
  990.         $this->define_array(
  991.             $this->message_numbers,
  992.             $this->disconnect_reasons,
  993.             $this->channel_open_failure_reasons,
  994.             $this->terminal_modes,
  995.             $this->channel_extended_data_type_codes,
  996.             [60 => 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ'],
  997.             [60 => 'NET_SSH2_MSG_USERAUTH_PK_OK'],
  998.             [60 => 'NET_SSH2_MSG_USERAUTH_INFO_REQUEST',
  999.                   61 => 'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE'],
  1000.             // RFC 4419 - diffie-hellman-group-exchange-sha{1,256}
  1001.             [30 => 'NET_SSH2_MSG_KEXDH_GEX_REQUEST_OLD',
  1002.                   31 => 'NET_SSH2_MSG_KEXDH_GEX_GROUP',
  1003.                   32 => 'NET_SSH2_MSG_KEXDH_GEX_INIT',
  1004.                   33 => 'NET_SSH2_MSG_KEXDH_GEX_REPLY',
  1005.                   34 => 'NET_SSH2_MSG_KEXDH_GEX_REQUEST'],
  1006.             // RFC 5656 - Elliptic Curves (for curve25519-sha256@libssh.org)
  1007.             [30 => 'NET_SSH2_MSG_KEX_ECDH_INIT',
  1008.                   31 => 'NET_SSH2_MSG_KEX_ECDH_REPLY']
  1009.         );
  1010.         self::$connections[$this->getResourceId()] = $this;
  1011.         if (is_resource($host)) {
  1012.             $this->fsock $host;
  1013.             return;
  1014.         }
  1015.         if (is_string($host)) {
  1016.             $this->host $host;
  1017.             $this->port $port;
  1018.             $this->timeout $timeout;
  1019.         }
  1020.     }
  1021.     /**
  1022.      * Set Crypto Engine Mode
  1023.      *
  1024.      * Possible $engine values:
  1025.      * OpenSSL, mcrypt, Eval, PHP
  1026.      *
  1027.      * @param int $engine
  1028.      * @access public
  1029.      */
  1030.     public static function setCryptoEngine($engine)
  1031.     {
  1032.         self::$crypto_engine $engine;
  1033.     }
  1034.     /**
  1035.      * Send Identification String First
  1036.      *
  1037.      * https://tools.ietf.org/html/rfc4253#section-4.2 says "when the connection has been established,
  1038.      * both sides MUST send an identification string". It does not say which side sends it first. In
  1039.      * theory it shouldn't matter but it is a fact of life that some SSH servers are simply buggy
  1040.      *
  1041.      * @access public
  1042.      */
  1043.     public function sendIdentificationStringFirst()
  1044.     {
  1045.         $this->send_id_string_first true;
  1046.     }
  1047.     /**
  1048.      * Send Identification String Last
  1049.      *
  1050.      * https://tools.ietf.org/html/rfc4253#section-4.2 says "when the connection has been established,
  1051.      * both sides MUST send an identification string". It does not say which side sends it first. In
  1052.      * theory it shouldn't matter but it is a fact of life that some SSH servers are simply buggy
  1053.      *
  1054.      * @access public
  1055.      */
  1056.     public function sendIdentificationStringLast()
  1057.     {
  1058.         $this->send_id_string_first false;
  1059.     }
  1060.     /**
  1061.      * Send SSH_MSG_KEXINIT First
  1062.      *
  1063.      * https://tools.ietf.org/html/rfc4253#section-7.1 says "key exchange begins by each sending
  1064.      * sending the [SSH_MSG_KEXINIT] packet". It does not say which side sends it first. In theory
  1065.      * it shouldn't matter but it is a fact of life that some SSH servers are simply buggy
  1066.      *
  1067.      * @access public
  1068.      */
  1069.     public function sendKEXINITFirst()
  1070.     {
  1071.         $this->send_kex_first true;
  1072.     }
  1073.     /**
  1074.      * Send SSH_MSG_KEXINIT Last
  1075.      *
  1076.      * https://tools.ietf.org/html/rfc4253#section-7.1 says "key exchange begins by each sending
  1077.      * sending the [SSH_MSG_KEXINIT] packet". It does not say which side sends it first. In theory
  1078.      * it shouldn't matter but it is a fact of life that some SSH servers are simply buggy
  1079.      *
  1080.      * @access public
  1081.      */
  1082.     public function sendKEXINITLast()
  1083.     {
  1084.         $this->send_kex_first false;
  1085.     }
  1086.     /**
  1087.      * Connect to an SSHv2 server
  1088.      *
  1089.      * @return bool
  1090.      * @throws \UnexpectedValueException on receipt of unexpected packets
  1091.      * @throws \RuntimeException on other errors
  1092.      * @access private
  1093.      */
  1094.     private function connect()
  1095.     {
  1096.         if ($this->bitmap self::MASK_CONSTRUCTOR) {
  1097.             return false;
  1098.         }
  1099.         $this->bitmap |= self::MASK_CONSTRUCTOR;
  1100.         $this->curTimeout $this->timeout;
  1101.         $this->last_packet microtime(true);
  1102.         if (!is_resource($this->fsock)) {
  1103.             $start microtime(true);
  1104.             // with stream_select a timeout of 0 means that no timeout takes place;
  1105.             // with fsockopen a timeout of 0 means that you instantly timeout
  1106.             // to resolve this incompatibility a timeout of 100,000 will be used for fsockopen if timeout is 0
  1107.             $this->fsock = @fsockopen($this->host$this->port$errno$errstr$this->curTimeout == 100000 $this->curTimeout);
  1108.             if (!$this->fsock) {
  1109.                 $host $this->host ':' $this->port;
  1110.                 throw new UnableToConnectException(rtrim("Cannot connect to $host. Error $errno$errstr"));
  1111.             }
  1112.             $elapsed microtime(true) - $start;
  1113.             if ($this->curTimeout) {
  1114.                 $this->curTimeout-= $elapsed;
  1115.                 if ($this->curTimeout 0) {
  1116.                     $this->is_timeout true;
  1117.                     return false;
  1118.                 }
  1119.             }
  1120.         }
  1121.         $this->identifier $this->generate_identifier();
  1122.         if ($this->send_id_string_first) {
  1123.             fputs($this->fsock$this->identifier "\r\n");
  1124.         }
  1125.         /* According to the SSH2 specs,
  1126.           "The server MAY send other lines of data before sending the version
  1127.            string.  Each line SHOULD be terminated by a Carriage Return and Line
  1128.            Feed.  Such lines MUST NOT begin with "SSH-", and SHOULD be encoded
  1129.            in ISO-10646 UTF-8 [RFC3629] (language is not specified).  Clients
  1130.            MUST be able to process such lines." */
  1131.         $data '';
  1132.         while (!feof($this->fsock) && !preg_match('#(.*)^(SSH-(\d\.\d+).*)#ms'$data$matches)) {
  1133.             $line '';
  1134.             while (true) {
  1135.                 if ($this->curTimeout) {
  1136.                     if ($this->curTimeout 0) {
  1137.                         $this->is_timeout true;
  1138.                         return false;
  1139.                     }
  1140.                     $read = [$this->fsock];
  1141.                     $write $except null;
  1142.                     $start microtime(true);
  1143.                     $sec floor($this->curTimeout);
  1144.                     $usec 1000000 * ($this->curTimeout $sec);
  1145.                     if (@stream_select($read$write$except$sec$usec) === false) {
  1146.                         $this->is_timeout true;
  1147.                         return false;
  1148.                     }
  1149.                     $elapsed microtime(true) - $start;
  1150.                     $this->curTimeout-= $elapsed;
  1151.                 }
  1152.                 $temp stream_get_line($this->fsock255"\n");
  1153.                 if (strlen($temp) == 255) {
  1154.                     continue;
  1155.                 }
  1156.                 if ($temp === false) {
  1157.                     return false;
  1158.                 }
  1159.                 $line.= "$temp\n";
  1160.                 // quoting RFC4253, "Implementers who wish to maintain
  1161.                 // compatibility with older, undocumented versions of this protocol may
  1162.                 // want to process the identification string without expecting the
  1163.                 // presence of the carriage return character for reasons described in
  1164.                 // Section 5 of this document."
  1165.                 //if (substr($line, -2) == "\r\n") {
  1166.                 //    break;
  1167.                 //}
  1168.                 break;
  1169.             }
  1170.             $data.= $line;
  1171.         }
  1172.         if (feof($this->fsock)) {
  1173.             $this->bitmap 0;
  1174.             throw new ConnectionClosedException('Connection closed by server');
  1175.         }
  1176.         $extra $matches[1];
  1177.         if (defined('NET_SSH2_LOGGING')) {
  1178.             $this->append_log('<-'$matches[0]);
  1179.             $this->append_log('->'$this->identifier "\r\n");
  1180.         }
  1181.         $this->server_identifier trim($temp"\r\n");
  1182.         if (strlen($extra)) {
  1183.             $this->errors[] = $data;
  1184.         }
  1185.         if (version_compare($matches[3], '1.99''<')) {
  1186.             $this->bitmap 0;
  1187.             throw new UnableToConnectException("Cannot connect to SSH $matches[3] servers");
  1188.         }
  1189.         if (!$this->send_id_string_first) {
  1190.             fputs($this->fsock$this->identifier "\r\n");
  1191.         }
  1192.         if (!$this->send_kex_first) {
  1193.             $response $this->get_binary_packet();
  1194.             if ($response === false) {
  1195.                 $this->bitmap 0;
  1196.                 throw new ConnectionClosedException('Connection closed by server');
  1197.             }
  1198.             if (!strlen($response) || ord($response[0]) != NET_SSH2_MSG_KEXINIT) {
  1199.                 $this->bitmap 0;
  1200.                 throw new \UnexpectedValueException('Expected SSH_MSG_KEXINIT');
  1201.             }
  1202.             if (!$this->key_exchange($response)) {
  1203.                 return false;
  1204.             }
  1205.         }
  1206.         if ($this->send_kex_first && !$this->key_exchange()) {
  1207.             return false;
  1208.         }
  1209.         $this->bitmap|= self::MASK_CONNECTED;
  1210.         return true;
  1211.     }
  1212.     /**
  1213.      * Generates the SSH identifier
  1214.      *
  1215.      * You should overwrite this method in your own class if you want to use another identifier
  1216.      *
  1217.      * @access protected
  1218.      * @return string
  1219.      */
  1220.     private function generate_identifier()
  1221.     {
  1222.         $identifier 'SSH-2.0-phpseclib_3.0';
  1223.         $ext = [];
  1224.         if (extension_loaded('sodium')) {
  1225.             $ext[] = 'libsodium';
  1226.         }
  1227.         if (extension_loaded('openssl')) {
  1228.             $ext[] = 'openssl';
  1229.         } elseif (extension_loaded('mcrypt')) {
  1230.             $ext[] = 'mcrypt';
  1231.         }
  1232.         if (extension_loaded('gmp')) {
  1233.             $ext[] = 'gmp';
  1234.         } elseif (extension_loaded('bcmath')) {
  1235.             $ext[] = 'bcmath';
  1236.         }
  1237.         if (!empty($ext)) {
  1238.             $identifier .= ' (' implode(', '$ext) . ')';
  1239.         }
  1240.         return $identifier;
  1241.     }
  1242.     /**
  1243.      * Key Exchange
  1244.      *
  1245.      * @return bool
  1246.      * @param string|bool $kexinit_payload_server optional
  1247.      * @throws \UnexpectedValueException on receipt of unexpected packets
  1248.      * @throws \RuntimeException on other errors
  1249.      * @throws \phpseclib3\Exception\NoSupportedAlgorithmsException when none of the algorithms phpseclib has loaded are compatible
  1250.      * @access private
  1251.      */
  1252.     private function key_exchange($kexinit_payload_server false)
  1253.     {
  1254.         $preferred $this->preferred;
  1255.         $kex_algorithms = isset($preferred['kex']) ?
  1256.             $preferred['kex'] :
  1257.             SSH2::getSupportedKEXAlgorithms();
  1258.         $server_host_key_algorithms = isset($preferred['hostkey']) ?
  1259.             $preferred['hostkey'] :
  1260.             SSH2::getSupportedHostKeyAlgorithms();
  1261.         $s2c_encryption_algorithms = isset($preferred['server_to_client']['crypt']) ?
  1262.             $preferred['server_to_client']['crypt'] :
  1263.             SSH2::getSupportedEncryptionAlgorithms();
  1264.         $c2s_encryption_algorithms = isset($preferred['client_to_server']['crypt']) ?
  1265.             $preferred['client_to_server']['crypt'] :
  1266.             SSH2::getSupportedEncryptionAlgorithms();
  1267.         $s2c_mac_algorithms = isset($preferred['server_to_client']['mac']) ?
  1268.             $preferred['server_to_client']['mac'] :
  1269.             SSH2::getSupportedMACAlgorithms();
  1270.         $c2s_mac_algorithms = isset($preferred['client_to_server']['mac']) ?
  1271.             $preferred['client_to_server']['mac'] :
  1272.             SSH2::getSupportedMACAlgorithms();
  1273.         $s2c_compression_algorithms = isset($preferred['server_to_client']['comp']) ?
  1274.             $preferred['server_to_client']['comp'] :
  1275.             SSH2::getSupportedCompressionAlgorithms();
  1276.         $c2s_compression_algorithms = isset($preferred['client_to_server']['comp']) ?
  1277.             $preferred['client_to_server']['comp'] :
  1278.             SSH2::getSupportedCompressionAlgorithms();
  1279.         // some SSH servers have buggy implementations of some of the above algorithms
  1280.         switch (true) {
  1281.             case $this->server_identifier == 'SSH-2.0-SSHD':
  1282.             case substr($this->server_identifier013) == 'SSH-2.0-DLINK':
  1283.                 if (!isset($preferred['server_to_client']['mac'])) {
  1284.                     $s2c_mac_algorithms array_values(array_diff(
  1285.                         $s2c_mac_algorithms,
  1286.                         ['hmac-sha1-96''hmac-md5-96']
  1287.                     ));
  1288.                 }
  1289.                 if (!isset($preferred['client_to_server']['mac'])) {
  1290.                     $c2s_mac_algorithms array_values(array_diff(
  1291.                         $c2s_mac_algorithms,
  1292.                         ['hmac-sha1-96''hmac-md5-96']
  1293.                     ));
  1294.                 }
  1295.         }
  1296.         $client_cookie Random::string(16);
  1297.         $kexinit_payload_client pack('Ca*'NET_SSH2_MSG_KEXINIT$client_cookie);
  1298.         $kexinit_payload_client.= Strings::packSSH2(
  1299.             'L10bN',
  1300.             $kex_algorithms,
  1301.             $server_host_key_algorithms,
  1302.             $c2s_encryption_algorithms,
  1303.             $s2c_encryption_algorithms,
  1304.             $c2s_mac_algorithms,
  1305.             $s2c_mac_algorithms,
  1306.             $c2s_compression_algorithms,
  1307.             $s2c_compression_algorithms,
  1308.             [], // language, client to server
  1309.             [], // language, server to client
  1310.             false// first_kex_packet_follows
  1311.             // reserved for future extension
  1312.         );
  1313.         if ($this->send_kex_first) {
  1314.             $this->send_binary_packet($kexinit_payload_client);
  1315.             $kexinit_payload_server $this->get_binary_packet();
  1316.             if ($kexinit_payload_server === false) {
  1317.                 $this->disconnect_helper(NET_SSH2_DISCONNECT_CONNECTION_LOST);
  1318.                 throw new ConnectionClosedException('Connection closed by server');
  1319.             }
  1320.             if (!strlen($kexinit_payload_server) || ord($kexinit_payload_server[0]) != NET_SSH2_MSG_KEXINIT) {
  1321.                 $this->disconnect_helper(NET_SSH2_DISCONNECT_PROTOCOL_ERROR);
  1322.                 throw new \UnexpectedValueException('Expected SSH_MSG_KEXINIT');
  1323.             }
  1324.         }
  1325.         $response $kexinit_payload_server;
  1326.         Strings::shift($response1); // skip past the message number (it should be SSH_MSG_KEXINIT)
  1327.         $server_cookie Strings::shift($response16);
  1328.         list(
  1329.             $this->kex_algorithms,
  1330.             $this->server_host_key_algorithms,
  1331.             $this->encryption_algorithms_client_to_server,
  1332.             $this->encryption_algorithms_server_to_client,
  1333.             $this->mac_algorithms_client_to_server,
  1334.             $this->mac_algorithms_server_to_client,
  1335.             $this->compression_algorithms_client_to_server,
  1336.             $this->compression_algorithms_server_to_client,
  1337.             $this->languages_client_to_server,
  1338.             $this->languages_server_to_client,
  1339.             $first_kex_packet_follows
  1340.         ) = Strings::unpackSSH2('L10C'$response);
  1341.         if (!$this->send_kex_first) {
  1342.             $this->send_binary_packet($kexinit_payload_client);
  1343.         }
  1344.         // we need to decide upon the symmetric encryption algorithms before we do the diffie-hellman key exchange
  1345.         // we don't initialize any crypto-objects, yet - we do that, later. for now, we need the lengths to make the
  1346.         // diffie-hellman key exchange as fast as possible
  1347.         $decrypt self::array_intersect_first($s2c_encryption_algorithms$this->encryption_algorithms_server_to_client);
  1348.         $decryptKeyLength $this->encryption_algorithm_to_key_size($decrypt);
  1349.         if ($decryptKeyLength === null) {
  1350.             $this->disconnect_helper(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  1351.             throw new NoSupportedAlgorithmsException('No compatible server to client encryption algorithms found');
  1352.         }
  1353.         $encrypt self::array_intersect_first($c2s_encryption_algorithms$this->encryption_algorithms_client_to_server);
  1354.         $encryptKeyLength $this->encryption_algorithm_to_key_size($encrypt);
  1355.         if ($encryptKeyLength === null) {
  1356.             $this->disconnect_helper(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  1357.             throw new NoSupportedAlgorithmsException('No compatible client to server encryption algorithms found');
  1358.         }
  1359.         // through diffie-hellman key exchange a symmetric key is obtained
  1360.         $this->kex_algorithm self::array_intersect_first($kex_algorithms$this->kex_algorithms);
  1361.         if ($this->kex_algorithm === false) {
  1362.             $this->disconnect_helper(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  1363.             throw new NoSupportedAlgorithmsException('No compatible key exchange algorithms found');
  1364.         }
  1365.         $server_host_key_algorithm self::array_intersect_first($server_host_key_algorithms$this->server_host_key_algorithms);
  1366.         if ($server_host_key_algorithm === false) {
  1367.             $this->disconnect_helper(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  1368.             throw new NoSupportedAlgorithmsException('No compatible server host key algorithms found');
  1369.         }
  1370.         $mac_algorithm_out self::array_intersect_first($c2s_mac_algorithms$this->mac_algorithms_client_to_server);
  1371.         if ($mac_algorithm_out === false) {
  1372.             $this->disconnect_helper(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  1373.             throw new NoSupportedAlgorithmsException('No compatible client to server message authentication algorithms found');
  1374.         }
  1375.         $mac_algorithm_in self::array_intersect_first($s2c_mac_algorithms$this->mac_algorithms_server_to_client);
  1376.         if ($mac_algorithm_in === false) {
  1377.             $this->disconnect_helper(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  1378.             throw new NoSupportedAlgorithmsException('No compatible server to client message authentication algorithms found');
  1379.         }
  1380.         $compression_algorithm_in self::array_intersect_first($s2c_compression_algorithms$this->compression_algorithms_server_to_client);
  1381.         if ($compression_algorithm_in === false) {
  1382.             $this->disconnect_helper(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  1383.             throw new NoSupportedAlgorithmsException('No compatible server to client compression algorithms found');
  1384.         }
  1385.         $this->decompress $compression_algorithm_in == 'zlib';
  1386.         $compression_algorithm_out self::array_intersect_first($c2s_compression_algorithms$this->compression_algorithms_client_to_server);
  1387.         if ($compression_algorithm_out === false) {
  1388.             $this->disconnect_helper(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  1389.             throw new NoSupportedAlgorithmsException('No compatible client to server compression algorithms found');
  1390.         }
  1391.         $this->compress $compression_algorithm_out == 'zlib';
  1392.         switch ($this->kex_algorithm) {
  1393.             case 'diffie-hellman-group15-sha512':
  1394.             case 'diffie-hellman-group16-sha512':
  1395.             case 'diffie-hellman-group17-sha512':
  1396.             case 'diffie-hellman-group18-sha512':
  1397.             case 'ecdh-sha2-nistp521':
  1398.                 $kexHash = new Hash('sha512');
  1399.                 break;
  1400.             case 'ecdh-sha2-nistp384':
  1401.                 $kexHash = new Hash('sha384');
  1402.                 break;
  1403.             case 'diffie-hellman-group-exchange-sha256':
  1404.             case 'diffie-hellman-group14-sha256':
  1405.             case 'ecdh-sha2-nistp256':
  1406.             case 'curve25519-sha256@libssh.org':
  1407.             case 'curve25519-sha256':
  1408.                 $kexHash = new Hash('sha256');
  1409.                 break;
  1410.             default:
  1411.                 $kexHash = new Hash('sha1');
  1412.         }
  1413.         // Only relevant in diffie-hellman-group-exchange-sha{1,256}, otherwise empty.
  1414.         $exchange_hash_rfc4419 '';
  1415.         if (strpos($this->kex_algorithm'curve25519-sha256') === || strpos($this->kex_algorithm'ecdh-sha2-nistp') === 0) {
  1416.             $curve strpos($this->kex_algorithm'curve25519-sha256') === ?
  1417.                 'Curve25519' :
  1418.                 substr($this->kex_algorithm10);
  1419.             $ourPrivate EC::createKey($curve);
  1420.             $ourPublicBytes $ourPrivate->getPublicKey()->getEncodedCoordinates();
  1421.             $clientKexInitMessage 'NET_SSH2_MSG_KEX_ECDH_INIT';
  1422.             $serverKexReplyMessage 'NET_SSH2_MSG_KEX_ECDH_REPLY';
  1423.         } else {
  1424.             if (strpos($this->kex_algorithm'diffie-hellman-group-exchange') === 0) {
  1425.                 $dh_group_sizes_packed pack(
  1426.                     'NNN',
  1427.                     $this->kex_dh_group_size_min,
  1428.                     $this->kex_dh_group_size_preferred,
  1429.                     $this->kex_dh_group_size_max
  1430.                 );
  1431.                 $packet pack(
  1432.                     'Ca*',
  1433.                     NET_SSH2_MSG_KEXDH_GEX_REQUEST,
  1434.                     $dh_group_sizes_packed
  1435.                 );
  1436.                 $this->send_binary_packet($packet);
  1437.                 $this->updateLogHistory('UNKNOWN (34)''NET_SSH2_MSG_KEXDH_GEX_REQUEST');
  1438.                 $response $this->get_binary_packet();
  1439.                 if ($response === false) {
  1440.                     $this->disconnect_helper(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  1441.                     throw new ConnectionClosedException('Connection closed by server');
  1442.                 }
  1443.                 list($type$primeBytes$gBytes) = Strings::unpackSSH2('Css'$response);
  1444.                 if ($type != NET_SSH2_MSG_KEXDH_GEX_GROUP) {
  1445.                     $this->disconnect_helper(NET_SSH2_DISCONNECT_PROTOCOL_ERROR);
  1446.                     throw new \UnexpectedValueException('Expected SSH_MSG_KEX_DH_GEX_GROUP');
  1447.                 }
  1448.                 $this->updateLogHistory('NET_SSH2_MSG_KEXDH_REPLY''NET_SSH2_MSG_KEXDH_GEX_GROUP');
  1449.                 $prime = new BigInteger($primeBytes, -256);
  1450.                 $g = new BigInteger($gBytes, -256);
  1451.                 $exchange_hash_rfc4419 $dh_group_sizes_packed Strings::packSSH2(
  1452.                     'ss',
  1453.                     $primeBytes,
  1454.                     $gBytes
  1455.                 );
  1456.                 $params DH::createParameters($prime$g);
  1457.                 $clientKexInitMessage 'NET_SSH2_MSG_KEXDH_GEX_INIT';
  1458.                 $serverKexReplyMessage 'NET_SSH2_MSG_KEXDH_GEX_REPLY';
  1459.             } else {
  1460.                 $params DH::createParameters($this->kex_algorithm);
  1461.                 $clientKexInitMessage 'NET_SSH2_MSG_KEXDH_INIT';
  1462.                 $serverKexReplyMessage 'NET_SSH2_MSG_KEXDH_REPLY';
  1463.             }
  1464.             $keyLength min($kexHash->getLengthInBytes(), max($encryptKeyLength$decryptKeyLength));
  1465.             $ourPrivate DH::createKey($params16 $keyLength); // 2 * 8 * $keyLength
  1466.             $ourPublic $ourPrivate->getPublicKey()->toBigInteger();
  1467.             $ourPublicBytes $ourPublic->toBytes(true);
  1468.         }
  1469.         $data pack('CNa*'constant($clientKexInitMessage), strlen($ourPublicBytes), $ourPublicBytes);
  1470.         $this->send_binary_packet($data);
  1471.         switch ($clientKexInitMessage) {
  1472.             case 'NET_SSH2_MSG_KEX_ECDH_INIT':
  1473.                 $this->updateLogHistory('NET_SSH2_MSG_KEXDH_INIT''NET_SSH2_MSG_KEX_ECDH_INIT');
  1474.                 break;
  1475.             case 'NET_SSH2_MSG_KEXDH_GEX_INIT':
  1476.                 $this->updateLogHistory('UNKNOWN (32)''NET_SSH2_MSG_KEXDH_GEX_INIT');
  1477.         }
  1478.         $response $this->get_binary_packet();
  1479.         if ($response === false) {
  1480.             $this->disconnect_helper(NET_SSH2_DISCONNECT_CONNECTION_LOST);
  1481.             throw new ConnectionClosedException('Connection closed by server');
  1482.         }
  1483.         if (!strlen($response)) {
  1484.             return false;
  1485.         }
  1486.         list(
  1487.             $type,
  1488.             $server_public_host_key,
  1489.             $theirPublicBytes,
  1490.             $this->signature
  1491.         ) = Strings::unpackSSH2('Csss'$response);
  1492.         if ($type != constant($serverKexReplyMessage)) {
  1493.             $this->disconnect_helper(NET_SSH2_DISCONNECT_PROTOCOL_ERROR);
  1494.             throw new \UnexpectedValueException("Expected $serverKexReplyMessage");
  1495.         }
  1496.         switch ($serverKexReplyMessage) {
  1497.             case 'NET_SSH2_MSG_KEX_ECDH_REPLY':
  1498.                 $this->updateLogHistory('NET_SSH2_MSG_KEXDH_REPLY''NET_SSH2_MSG_KEX_ECDH_REPLY');
  1499.                 break;
  1500.             case 'NET_SSH2_MSG_KEXDH_GEX_REPLY':
  1501.                 $this->updateLogHistory('UNKNOWN (33)''NET_SSH2_MSG_KEXDH_GEX_REPLY');
  1502.         }
  1503.         $this->server_public_host_key $server_public_host_key;
  1504.         list($public_key_format) = Strings::unpackSSH2('s'$server_public_host_key);
  1505.         if (strlen($this->signature) < 4) {
  1506.             return false;
  1507.         }
  1508.         $temp unpack('Nlength'substr($this->signature04));
  1509.         $this->signature_format substr($this->signature4$temp['length']);
  1510.         $keyBytes DH::computeSecret($ourPrivate$theirPublicBytes);
  1511.         if (($keyBytes "\xFF\x80") === "\x00\x00") {
  1512.             $keyBytes substr($keyBytes1);
  1513.         } elseif (($keyBytes[0] & "\x80") === "\x80") {
  1514.             $keyBytes "\0$keyBytes";
  1515.         }
  1516.         $this->exchange_hash Strings::packSSH2('s5',
  1517.             $this->identifier,
  1518.             $this->server_identifier,
  1519.             $kexinit_payload_client,
  1520.             $kexinit_payload_server,
  1521.             $this->server_public_host_key
  1522.         );
  1523.         $this->exchange_hash.= $exchange_hash_rfc4419;
  1524.         $this->exchange_hash.= Strings::packSSH2('s3',
  1525.             $ourPublicBytes,
  1526.             $theirPublicBytes,
  1527.             $keyBytes
  1528.         );
  1529.         $this->exchange_hash $kexHash->hash($this->exchange_hash);
  1530.         if ($this->session_id === false) {
  1531.             $this->session_id $this->exchange_hash;
  1532.         }
  1533.         switch ($server_host_key_algorithm) {
  1534.             case 'rsa-sha2-256':
  1535.             case 'rsa-sha2-512':
  1536.             //case 'ssh-rsa':
  1537.                 $expected_key_format 'ssh-rsa';
  1538.                 break;
  1539.             default:
  1540.                 $expected_key_format $server_host_key_algorithm;
  1541.         }
  1542.         if ($public_key_format != $expected_key_format || $this->signature_format != $server_host_key_algorithm) {
  1543.             switch (true) {
  1544.                 case $this->signature_format == $server_host_key_algorithm:
  1545.                 case $server_host_key_algorithm != 'rsa-sha2-256' && $server_host_key_algorithm != 'rsa-sha2-512':
  1546.                 case $this->signature_format != 'ssh-rsa':
  1547.                     $this->disconnect_helper(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
  1548.                     throw new \RuntimeException('Server Host Key Algorithm Mismatch');
  1549.             }
  1550.         }
  1551.         $packet pack('C'NET_SSH2_MSG_NEWKEYS);
  1552.         $this->send_binary_packet($packet);
  1553.         $response $this->get_binary_packet();
  1554.         if ($response === false) {
  1555.             $this->disconnect_helper(NET_SSH2_DISCONNECT_CONNECTION_LOST);
  1556.             throw new ConnectionClosedException('Connection closed by server');
  1557.         }
  1558.         list($type) = Strings::unpackSSH2('C'$response);
  1559.         if ($type != NET_SSH2_MSG_NEWKEYS) {
  1560.             $this->disconnect_helper(NET_SSH2_DISCONNECT_PROTOCOL_ERROR);
  1561.             throw new \UnexpectedValueException('Expected SSH_MSG_NEWKEYS');
  1562.         }
  1563.         $keyBytes pack('Na*'strlen($keyBytes), $keyBytes);
  1564.         $this->encrypt self::encryption_algorithm_to_crypt_instance($encrypt);
  1565.         if ($this->encrypt) {
  1566.             if (self::$crypto_engine) {
  1567.                 $this->encrypt->setPreferredEngine(self::$crypto_engine);
  1568.             }
  1569.             if ($this->encrypt->getBlockLengthInBytes()) {
  1570.                 $this->encrypt_block_size $this->encrypt->getBlockLengthInBytes();
  1571.             }
  1572.             $this->encrypt->disablePadding();
  1573.             if ($this->encrypt->usesIV()) {
  1574.                 $iv $kexHash->hash($keyBytes $this->exchange_hash 'A' $this->session_id);
  1575.                 while ($this->encrypt_block_size strlen($iv)) {
  1576.                     $iv.= $kexHash->hash($keyBytes $this->exchange_hash $iv);
  1577.                 }
  1578.                 $this->encrypt->setIV(substr($iv0$this->encrypt_block_size));
  1579.             }
  1580.             switch ($encrypt) {
  1581.                 case 'aes128-gcm@openssh.com':
  1582.                 case 'aes256-gcm@openssh.com':
  1583.                     $nonce $kexHash->hash($keyBytes $this->exchange_hash 'A' $this->session_id);
  1584.                     $this->encrypt->fixed substr($nonce04);
  1585.                     $this->encrypt->invocation_counter substr($nonce48);
  1586.                 case 'chacha20-poly1305@openssh.com':
  1587.                     break;
  1588.                 default:
  1589.                     $this->encrypt->enableContinuousBuffer();
  1590.             }
  1591.             $key $kexHash->hash($keyBytes $this->exchange_hash 'C' $this->session_id);
  1592.             while ($encryptKeyLength strlen($key)) {
  1593.                 $key.= $kexHash->hash($keyBytes $this->exchange_hash $key);
  1594.             }
  1595.             switch ($encrypt) {
  1596.                 case 'chacha20-poly1305@openssh.com':
  1597.                     $encryptKeyLength 32;
  1598.                     $this->lengthEncrypt self::encryption_algorithm_to_crypt_instance($encrypt);
  1599.                     $this->lengthEncrypt->setKey(substr($key3232));
  1600.             }
  1601.             $this->encrypt->setKey(substr($key0$encryptKeyLength));
  1602.             $this->encrypt->name $encrypt;
  1603.         }
  1604.         $this->decrypt self::encryption_algorithm_to_crypt_instance($decrypt);
  1605.         if ($this->decrypt) {
  1606.             if (self::$crypto_engine) {
  1607.                 $this->decrypt->setPreferredEngine(self::$crypto_engine);
  1608.             }
  1609.             if ($this->decrypt->getBlockLengthInBytes()) {
  1610.                 $this->decrypt_block_size $this->decrypt->getBlockLengthInBytes();
  1611.             }
  1612.             $this->decrypt->disablePadding();
  1613.             if ($this->decrypt->usesIV()) {
  1614.                 $iv $kexHash->hash($keyBytes $this->exchange_hash 'B' $this->session_id);
  1615.                 while ($this->decrypt_block_size strlen($iv)) {
  1616.                     $iv.= $kexHash->hash($keyBytes $this->exchange_hash $iv);
  1617.                 }
  1618.                 $this->decrypt->setIV(substr($iv0$this->decrypt_block_size));
  1619.             }
  1620.             switch ($decrypt) {
  1621.                 case 'aes128-gcm@openssh.com':
  1622.                 case 'aes256-gcm@openssh.com':
  1623.                     // see https://tools.ietf.org/html/rfc5647#section-7.1
  1624.                     $nonce $kexHash->hash($keyBytes $this->exchange_hash 'B' $this->session_id);
  1625.                     $this->decrypt->fixed substr($nonce04);
  1626.                     $this->decrypt->invocation_counter substr($nonce48);
  1627.                 case 'chacha20-poly1305@openssh.com':
  1628.                     break;
  1629.                 default:
  1630.                     $this->decrypt->enableContinuousBuffer();
  1631.             }
  1632.             $key $kexHash->hash($keyBytes $this->exchange_hash 'D' $this->session_id);
  1633.             while ($decryptKeyLength strlen($key)) {
  1634.                 $key.= $kexHash->hash($keyBytes $this->exchange_hash $key);
  1635.             }
  1636.             switch ($decrypt) {
  1637.                 case 'chacha20-poly1305@openssh.com':
  1638.                     $decryptKeyLength 32;
  1639.                     $this->lengthDecrypt self::encryption_algorithm_to_crypt_instance($decrypt);
  1640.                     $this->lengthDecrypt->setKey(substr($key3232));
  1641.             }
  1642.             $this->decrypt->setKey(substr($key0$decryptKeyLength));
  1643.             $this->decrypt->name $decrypt;
  1644.         }
  1645.         /* The "arcfour128" algorithm is the RC4 cipher, as described in
  1646.            [SCHNEIER], using a 128-bit key.  The first 1536 bytes of keystream
  1647.            generated by the cipher MUST be discarded, and the first byte of the
  1648.            first encrypted packet MUST be encrypted using the 1537th byte of
  1649.            keystream.
  1650.            -- http://tools.ietf.org/html/rfc4345#section-4 */
  1651.         if ($encrypt == 'arcfour128' || $encrypt == 'arcfour256') {
  1652.             $this->encrypt->encrypt(str_repeat("\0"1536));
  1653.         }
  1654.         if ($decrypt == 'arcfour128' || $decrypt == 'arcfour256') {
  1655.             $this->decrypt->decrypt(str_repeat("\0"1536));
  1656.         }
  1657.         if (!$this->encrypt->usesNonce()) {
  1658.             list($this->hmac_create$createKeyLength) = self::mac_algorithm_to_hash_instance($mac_algorithm_out);
  1659.         } else {
  1660.             $this->hmac_create = new \stdClass;
  1661.             $this->hmac_create->name $mac_algorithm_out;
  1662.             //$mac_algorithm_out = 'none';
  1663.             $createKeyLength 0;
  1664.         }
  1665.         if ($this->hmac_create instanceof Hash) {
  1666.             $key $kexHash->hash($keyBytes $this->exchange_hash 'E' $this->session_id);
  1667.             while ($createKeyLength strlen($key)) {
  1668.                 $key.= $kexHash->hash($keyBytes $this->exchange_hash $key);
  1669.             }
  1670.             $this->hmac_create->setKey(substr($key0$createKeyLength));
  1671.             $this->hmac_create->name $mac_algorithm_out;
  1672.             $this->hmac_create->etm preg_match('#-etm@openssh\.com$#'$mac_algorithm_out);
  1673.         }
  1674.         if (!$this->decrypt->usesNonce()) {
  1675.             list($this->hmac_check$checkKeyLength) = self::mac_algorithm_to_hash_instance($mac_algorithm_in);
  1676.             $this->hmac_size $this->hmac_check->getLengthInBytes();
  1677.         } else {
  1678.             $this->hmac_check = new \stdClass;
  1679.             $this->hmac_check->name $mac_algorithm_in;
  1680.             //$mac_algorithm_in = 'none';
  1681.             $checkKeyLength 0;
  1682.             $this->hmac_size 0;
  1683.         }
  1684.         if ($this->hmac_check instanceof Hash) {
  1685.             $key $kexHash->hash($keyBytes $this->exchange_hash 'F' $this->session_id);
  1686.             while ($checkKeyLength strlen($key)) {
  1687.                 $key.= $kexHash->hash($keyBytes $this->exchange_hash $key);
  1688.             }
  1689.             $this->hmac_check->setKey(substr($key0$checkKeyLength));
  1690.             $this->hmac_check->name $mac_algorithm_in;
  1691.             $this->hmac_check->etm preg_match('#-etm@openssh\.com$#'$mac_algorithm_in);
  1692.         }
  1693.         return true;
  1694.     }
  1695.     /**
  1696.      * Maps an encryption algorithm name to the number of key bytes.
  1697.      *
  1698.      * @param string $algorithm Name of the encryption algorithm
  1699.      * @return int|null Number of bytes as an integer or null for unknown
  1700.      * @access private
  1701.      */
  1702.     private function encryption_algorithm_to_key_size($algorithm)
  1703.     {
  1704.         if ($this->bad_key_size_fix && self::bad_algorithm_candidate($algorithm)) {
  1705.             return 16;
  1706.         }
  1707.         switch ($algorithm) {
  1708.             case 'none':
  1709.                 return 0;
  1710.             case 'aes128-gcm@openssh.com':
  1711.             case 'aes128-cbc':
  1712.             case 'aes128-ctr':
  1713.             case 'arcfour':
  1714.             case 'arcfour128':
  1715.             case 'blowfish-cbc':
  1716.             case 'blowfish-ctr':
  1717.             case 'twofish128-cbc':
  1718.             case 'twofish128-ctr':
  1719.                 return 16;
  1720.             case '3des-cbc':
  1721.             case '3des-ctr':
  1722.             case 'aes192-cbc':
  1723.             case 'aes192-ctr':
  1724.             case 'twofish192-cbc':
  1725.             case 'twofish192-ctr':
  1726.                 return 24;
  1727.             case 'aes256-gcm@openssh.com':
  1728.             case 'aes256-cbc':
  1729.             case 'aes256-ctr':
  1730.             case 'arcfour256':
  1731.             case 'twofish-cbc':
  1732.             case 'twofish256-cbc':
  1733.             case 'twofish256-ctr':
  1734.                 return 32;
  1735.             case 'chacha20-poly1305@openssh.com':
  1736.                 return 64;
  1737.         }
  1738.         return null;
  1739.     }
  1740.     /**
  1741.      * Maps an encryption algorithm name to an instance of a subclass of
  1742.      * \phpseclib3\Crypt\Common\SymmetricKey.
  1743.      *
  1744.      * @param string $algorithm Name of the encryption algorithm
  1745.      * @return mixed Instance of \phpseclib3\Crypt\Common\SymmetricKey or null for unknown
  1746.      * @access private
  1747.      */
  1748.     private static function encryption_algorithm_to_crypt_instance($algorithm)
  1749.     {
  1750.         switch ($algorithm) {
  1751.             case '3des-cbc':
  1752.                 return new TripleDES('cbc');
  1753.             case '3des-ctr':
  1754.                 return new TripleDES('ctr');
  1755.             case 'aes256-cbc':
  1756.             case 'aes192-cbc':
  1757.             case 'aes128-cbc':
  1758.                 return new Rijndael('cbc');
  1759.             case 'aes256-ctr':
  1760.             case 'aes192-ctr':
  1761.             case 'aes128-ctr':
  1762.                 return new Rijndael('ctr');
  1763.             case 'blowfish-cbc':
  1764.                 return new Blowfish('cbc');
  1765.             case 'blowfish-ctr':
  1766.                 return new Blowfish('ctr');
  1767.             case 'twofish128-cbc':
  1768.             case 'twofish192-cbc':
  1769.             case 'twofish256-cbc':
  1770.             case 'twofish-cbc':
  1771.                 return new Twofish('cbc');
  1772.             case 'twofish128-ctr':
  1773.             case 'twofish192-ctr':
  1774.             case 'twofish256-ctr':
  1775.                 return new Twofish('ctr');
  1776.             case 'arcfour':
  1777.             case 'arcfour128':
  1778.             case 'arcfour256':
  1779.                 return new RC4();
  1780.             case 'aes128-gcm@openssh.com':
  1781.             case 'aes256-gcm@openssh.com':
  1782.                 return new Rijndael('gcm');
  1783.             case 'chacha20-poly1305@openssh.com':
  1784.                 return new ChaCha20();
  1785.         }
  1786.         return null;
  1787.     }
  1788.     /**
  1789.      * Maps an encryption algorithm name to an instance of a subclass of
  1790.      * \phpseclib3\Crypt\Hash.
  1791.      *
  1792.      * @param string $algorithm Name of the encryption algorithm
  1793.      * @return mixed Instance of \phpseclib3\Crypt\Hash or null for unknown
  1794.      * @access private
  1795.      */
  1796.     private static function mac_algorithm_to_hash_instance($algorithm)
  1797.     {
  1798.         switch ($algorithm) {
  1799.             case 'umac-64@openssh.com':
  1800.             case 'umac-64-etm@openssh.com':
  1801.                 return [new Hash('umac-64'), 16];
  1802.             case 'umac-128@openssh.com':
  1803.             case 'umac-128-etm@openssh.com':
  1804.                 return [new Hash('umac-128'), 16];
  1805.             case 'hmac-sha2-512':
  1806.             case 'hmac-sha2-512-etm@openssh.com':
  1807.                 return [new Hash('sha512'), 64];
  1808.             case 'hmac-sha2-256':
  1809.             case 'hmac-sha2-256-etm@openssh.com':
  1810.                 return [new Hash('sha256'), 32];
  1811.             case 'hmac-sha1':
  1812.             case 'hmac-sha1-etm@openssh.com':
  1813.                 return [new Hash('sha1'), 20];
  1814.             case 'hmac-sha1-96':
  1815.                 return [new Hash('sha1-96'), 20];
  1816.             case 'hmac-md5':
  1817.                 return [new Hash('md5'), 16];
  1818.             case 'hmac-md5-96':
  1819.                 return [new Hash('md5-96'), 16];
  1820.         }
  1821.     }
  1822.     /*
  1823.      * Tests whether or not proposed algorithm has a potential for issues
  1824.      *
  1825.      * @link https://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/ssh2-aesctr-openssh.html
  1826.      * @link https://bugzilla.mindrot.org/show_bug.cgi?id=1291
  1827.      * @param string $algorithm Name of the encryption algorithm
  1828.      * @return bool
  1829.      * @access private
  1830.      */
  1831.     private static function bad_algorithm_candidate($algorithm)
  1832.     {
  1833.         switch ($algorithm) {
  1834.             case 'arcfour256':
  1835.             case 'aes192-ctr':
  1836.             case 'aes256-ctr':
  1837.                 return true;
  1838.         }
  1839.         return false;
  1840.     }
  1841.     /**
  1842.      * Login
  1843.      *
  1844.      * The $password parameter can be a plaintext password, a \phpseclib3\Crypt\RSA object or an array
  1845.      *
  1846.      * @param string $username
  1847.      * @param string[] ...$args
  1848.      * @return bool
  1849.      * @see self::_login()
  1850.      * @access public
  1851.      */
  1852.     public function login($username, ...$args)
  1853.     {
  1854.         $this->auth[] = func_get_args();
  1855.         // try logging with 'none' as an authentication method first since that's what
  1856.         // PuTTY does
  1857.         if (substr($this->server_identifier013) != 'SSH-2.0-CoreFTP') {
  1858.             if ($this->sublogin($username)) {
  1859.                 return true;
  1860.             }
  1861.             if (!count($args)) {
  1862.                 return false;
  1863.             }
  1864.         }
  1865.         return $this->sublogin($username, ...$args);
  1866.     }
  1867.     /**
  1868.      * Login Helper
  1869.      *
  1870.      * @param string $username
  1871.      * @param string[] ...$args
  1872.      * @return bool
  1873.      * @see self::_login_helper()
  1874.      * @access private
  1875.      */
  1876.     protected function sublogin($username, ...$args)
  1877.     {
  1878.         if (!($this->bitmap self::MASK_CONSTRUCTOR)) {
  1879.             if (!$this->connect()) {
  1880.                 return false;
  1881.             }
  1882.         }
  1883.         if (empty($args)) {
  1884.             return $this->login_helper($username);
  1885.         }
  1886.         foreach ($args as $arg) {
  1887.             if ($this->login_helper($username$arg)) {
  1888.                 return true;
  1889.             }
  1890.         }
  1891.         return false;
  1892.     }
  1893.     /**
  1894.      * Login Helper
  1895.      *
  1896.      * {@internal It might be worthwhile, at some point, to protect against {@link http://tools.ietf.org/html/rfc4251#section-9.3.9 traffic analysis}
  1897.      *           by sending dummy SSH_MSG_IGNORE messages.}
  1898.      *
  1899.      * @param string $username
  1900.      * @param string $password
  1901.      * @return bool
  1902.      * @throws \UnexpectedValueException on receipt of unexpected packets
  1903.      * @throws \RuntimeException on other errors
  1904.      * @access private
  1905.      */
  1906.     private function login_helper($username$password null)
  1907.     {
  1908.         if (!($this->bitmap self::MASK_CONNECTED)) {
  1909.             return false;
  1910.         }
  1911.         if (!($this->bitmap self::MASK_LOGIN_REQ)) {
  1912.             $packet Strings::packSSH2('Cs'NET_SSH2_MSG_SERVICE_REQUEST'ssh-userauth');
  1913.             $this->send_binary_packet($packet);
  1914.             $response $this->get_binary_packet();
  1915.             if ($response === false) {
  1916.                 if ($this->retry_connect) {
  1917.                     $this->retry_connect false;
  1918.                     if (!$this->connect()) {
  1919.                         return false;
  1920.                     }
  1921.                     return $this->login_helper($username$password);
  1922.                 }
  1923.                 $this->disconnect_helper(NET_SSH2_DISCONNECT_CONNECTION_LOST);
  1924.                 throw new ConnectionClosedException('Connection closed by server');
  1925.             }
  1926.             list($type$service) = Strings::unpackSSH2('Cs'$response);
  1927.             if ($type != NET_SSH2_MSG_SERVICE_ACCEPT || $service != 'ssh-userauth') {
  1928.                 $this->disconnect_helper(NET_SSH2_DISCONNECT_PROTOCOL_ERROR);
  1929.                 throw new \UnexpectedValueException('Expected SSH_MSG_SERVICE_ACCEPT');
  1930.             }
  1931.             $this->bitmap |= self::MASK_LOGIN_REQ;
  1932.         }
  1933.         if (strlen($this->last_interactive_response)) {
  1934.             return !is_string($password) && !is_array($password) ? false $this->keyboard_interactive_process($password);
  1935.         }
  1936.         if ($password instanceof PrivateKey) {
  1937.             return $this->privatekey_login($username$password);
  1938.         }
  1939.         if ($password instanceof Agent) {
  1940.             return $this->ssh_agent_login($username$password);
  1941.         }
  1942.         if (is_array($password)) {
  1943.             if ($this->keyboard_interactive_login($username$password)) {
  1944.                 $this->bitmap |= self::MASK_LOGIN;
  1945.                 return true;
  1946.             }
  1947.             return false;
  1948.         }
  1949.         if (!isset($password)) {
  1950.            $packet Strings::packSSH2(
  1951.                'Cs3',
  1952.                NET_SSH2_MSG_USERAUTH_REQUEST,
  1953.                $username,
  1954.                'ssh-connection',
  1955.                'none'
  1956.             );
  1957.             $this->send_binary_packet($packet);
  1958.             $response $this->get_binary_packet();
  1959.             if ($response === false) {
  1960.                 $this->disconnect_helper(NET_SSH2_DISCONNECT_CONNECTION_LOST);
  1961.                 throw new ConnectionClosedException('Connection closed by server');
  1962.             }
  1963.             list($type) = Strings::unpackSSH2('C'$response);
  1964.             switch ($type) {
  1965.                 case NET_SSH2_MSG_USERAUTH_SUCCESS:
  1966.                     $this->bitmap |= self::MASK_LOGIN;
  1967.                     return true;
  1968.                 //case NET_SSH2_MSG_USERAUTH_FAILURE:
  1969.                 default:
  1970.                     return false;
  1971.             }
  1972.         }
  1973.         if (!is_string($password)) {
  1974.             throw new \UnexpectedValueException('$password needs to either be an instance of \phpseclib3\Crypt\Common\PrivateKey, \System\SSH\Agent, an array or a string');
  1975.         }
  1976.         $packet Strings::packSSH2(
  1977.             'Cs3bs',
  1978.             NET_SSH2_MSG_USERAUTH_REQUEST,
  1979.             $username,
  1980.             'ssh-connection',
  1981.             'password',
  1982.             false,
  1983.             $password
  1984.         );
  1985.         // remove the username and password from the logged packet
  1986.         if (!defined('NET_SSH2_LOGGING')) {
  1987.             $logged null;
  1988.         } else {
  1989.             $logged Strings::packSSH2(
  1990.                 'Cs3bs',
  1991.                 NET_SSH2_MSG_USERAUTH_REQUEST,
  1992.                 $username,
  1993.                 'ssh-connection',
  1994.                 'password',
  1995.                 false,
  1996.                 'password'
  1997.             );
  1998.         }
  1999.         $this->send_binary_packet($packet$logged);
  2000.         $response $this->get_binary_packet();
  2001.         if ($response === false) {
  2002.             $this->disconnect_helper(NET_SSH2_DISCONNECT_CONNECTION_LOST);
  2003.             throw new ConnectionClosedException('Connection closed by server');
  2004.         }
  2005.         list($type) = Strings::unpackSSH2('C'$response);
  2006.         switch ($type) {
  2007.             case NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ// in theory, the password can be changed
  2008.                 $this->updateLogHistory('UNKNOWN (60)''NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ');
  2009.                 list($message) = Strings::unpackSSH2('s'$response);
  2010.                 $this->errors[] = 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ: ' $message;
  2011.                 return $this->disconnect_helper(NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER);
  2012.             case NET_SSH2_MSG_USERAUTH_FAILURE:
  2013.                 // can we use keyboard-interactive authentication?  if not then either the login is bad or the server employees
  2014.                 // multi-factor authentication
  2015.                 list($auth_methods$partial_success) = Strings::unpackSSH2('Lb'$response);
  2016.                 if (!$partial_success && in_array('keyboard-interactive'$auth_methods)) {
  2017.                     if ($this->keyboard_interactive_login($username$password)) {
  2018.                         $this->bitmap |= self::MASK_LOGIN;
  2019.                         return true;
  2020.                     }
  2021.                     return false;
  2022.                 }
  2023.                 return false;
  2024.             case NET_SSH2_MSG_USERAUTH_SUCCESS:
  2025.                 $this->bitmap |= self::MASK_LOGIN;
  2026.                 return true;
  2027.         }
  2028.         return false;
  2029.     }
  2030.     /**
  2031.      * Login via keyboard-interactive authentication
  2032.      *
  2033.      * See {@link http://tools.ietf.org/html/rfc4256 RFC4256} for details.  This is not a full-featured keyboard-interactive authenticator.
  2034.      *
  2035.      * @param string $username
  2036.      * @param string $password
  2037.      * @return bool
  2038.      * @access private
  2039.      */
  2040.     private function keyboard_interactive_login($username$password)
  2041.     {
  2042.         $packet Strings::packSSH2(
  2043.             'Cs5',
  2044.             NET_SSH2_MSG_USERAUTH_REQUEST,
  2045.             $username,
  2046.             'ssh-connection',
  2047.             'keyboard-interactive',
  2048.             ''// language tag
  2049.             '' // submethods
  2050.         );
  2051.         $this->send_binary_packet($packet);
  2052.         return $this->keyboard_interactive_process($password);
  2053.     }
  2054.     /**
  2055.      * Handle the keyboard-interactive requests / responses.
  2056.      *
  2057.      * @param mixed[] ...$responses
  2058.      * @return bool
  2059.      * @throws \RuntimeException on connection error
  2060.      * @access private
  2061.      */
  2062.     private function keyboard_interactive_process(...$responses)
  2063.     {
  2064.         if (strlen($this->last_interactive_response)) {
  2065.             $response $this->last_interactive_response;
  2066.         } else {
  2067.             $orig $response $this->get_binary_packet();
  2068.             if ($response === false) {
  2069.                 $this->disconnect_helper(NET_SSH2_DISCONNECT_CONNECTION_LOST);
  2070.                 throw new ConnectionClosedException('Connection closed by server');
  2071.             }
  2072.         }
  2073.         list($type) = Strings::unpackSSH2('C'$response);
  2074.         switch ($type) {
  2075.             case NET_SSH2_MSG_USERAUTH_INFO_REQUEST:
  2076.                 list(
  2077.                     , // name; may be empty
  2078.                     // instruction; may be empty
  2079.                     // language tag; may be empty
  2080.                     $num_prompts
  2081.                 ) = Strings::unpackSSH2('s3N'$response);
  2082.                 for ($i 0$i count($responses); $i++) {
  2083.                     if (is_array($responses[$i])) {
  2084.                         foreach ($responses[$i] as $key => $value) {
  2085.                             $this->keyboard_requests_responses[$key] = $value;
  2086.                         }
  2087.                         unset($responses[$i]);
  2088.                     }
  2089.                 }
  2090.                 $responses array_values($responses);
  2091.                 if (isset($this->keyboard_requests_responses)) {
  2092.                     for ($i 0$i $num_prompts$i++) {
  2093.                         list(
  2094.                             $prompt// prompt - ie. "Password: "; must not be empty
  2095.                             // echo
  2096.                         ) = Strings::unpackSSH2('sC'$response);
  2097.                         foreach ($this->keyboard_requests_responses as $key => $value) {
  2098.                             if (substr($prompt0strlen($key)) == $key) {
  2099.                                 $responses[] = $value;
  2100.                                 break;
  2101.                             }
  2102.                         }
  2103.                     }
  2104.                 }
  2105.                 // see http://tools.ietf.org/html/rfc4256#section-3.2
  2106.                 if (strlen($this->last_interactive_response)) {
  2107.                     $this->last_interactive_response '';
  2108.                 } else {
  2109.                     $this->updateLogHistory('UNKNOWN (60)''NET_SSH2_MSG_USERAUTH_INFO_REQUEST');
  2110.                 }
  2111.                 if (!count($responses) && $num_prompts) {
  2112.                     $this->last_interactive_response $orig;
  2113.                     return false;
  2114.                 }
  2115.                 /*
  2116.                    After obtaining the requested information from the user, the client
  2117.                    MUST respond with an SSH_MSG_USERAUTH_INFO_RESPONSE message.
  2118.                 */
  2119.                 // see http://tools.ietf.org/html/rfc4256#section-3.4
  2120.                 $packet $logged pack('CN'NET_SSH2_MSG_USERAUTH_INFO_RESPONSEcount($responses));
  2121.                 for ($i 0$i count($responses); $i++) {
  2122.                     $packet.= Strings::packSSH2('s'$responses[$i]);
  2123.                     $logged.= Strings::packSSH2('s''dummy-answer');
  2124.                 }
  2125.                 $this->send_binary_packet($packet$logged);
  2126.                 $this->updateLogHistory('UNKNOWN (61)''NET_SSH2_MSG_USERAUTH_INFO_RESPONSE');
  2127.                 /*
  2128.                    After receiving the response, the server MUST send either an
  2129.                    SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, or another
  2130.                    SSH_MSG_USERAUTH_INFO_REQUEST message.
  2131.                 */
  2132.                 // maybe phpseclib should force close the connection after x request / responses?  unless something like that is done
  2133.                 // there could be an infinite loop of request / responses.
  2134.                 return $this->keyboard_interactive_process();
  2135.             case NET_SSH2_MSG_USERAUTH_SUCCESS:
  2136.                 return true;
  2137.             case NET_SSH2_MSG_USERAUTH_FAILURE:
  2138.                 return false;
  2139.         }
  2140.         return false;
  2141.     }
  2142.     /**
  2143.      * Login with an ssh-agent provided key
  2144.      *
  2145.      * @param string $username
  2146.      * @param \phpseclib3\System\SSH\Agent $agent
  2147.      * @return bool
  2148.      * @access private
  2149.      */
  2150.     private function ssh_agent_login($usernameAgent $agent)
  2151.     {
  2152.         $this->agent $agent;
  2153.         $keys $agent->requestIdentities();
  2154.         foreach ($keys as $key) {
  2155.             if ($this->privatekey_login($username$key)) {
  2156.                 return true;
  2157.             }
  2158.         }
  2159.         return false;
  2160.     }
  2161.     /**
  2162.      * Login with an RSA private key
  2163.      *
  2164.      * {@internal It might be worthwhile, at some point, to protect against {@link http://tools.ietf.org/html/rfc4251#section-9.3.9 traffic analysis}
  2165.      *           by sending dummy SSH_MSG_IGNORE messages.}
  2166.      *
  2167.      * @param string $username
  2168.      * @param \phpseclib3\Crypt\Common\PrivateKey $privatekey
  2169.      * @return bool
  2170.      * @throws \RuntimeException on connection error
  2171.      * @access private
  2172.      */
  2173.     private function privatekey_login($usernamePrivateKey $privatekey)
  2174.     {
  2175.         $publickey $privatekey->getPublicKey();
  2176.         if ($publickey instanceof RSA) {
  2177.             $privatekey $privatekey->withPadding(RSA::SIGNATURE_PKCS1);
  2178.             $algos = ['rsa-sha2-256''rsa-sha2-512''ssh-rsa'];
  2179.             if (isset($this->preferred['hostkey'])) {
  2180.                 $algos array_intersect($this->preferred['hostkey'] , $algos);
  2181.             }
  2182.             $algo self::array_intersect_first($algos$this->server_host_key_algorithms);
  2183.             switch ($algo) {
  2184.                 case 'rsa-sha2-512':
  2185.                     $hash 'sha512';
  2186.                     $signatureType 'rsa-sha2-512';
  2187.                     break;
  2188.                 case 'rsa-sha2-256':
  2189.                     $hash 'sha256';
  2190.                     $signatureType 'rsa-sha2-256';
  2191.                     break;
  2192.                 //case 'ssh-rsa':
  2193.                 default:
  2194.                     $hash 'sha1';
  2195.                     $signatureType 'ssh-rsa';
  2196.             }
  2197.         } else if ($publickey instanceof EC) {
  2198.             $privatekey $privatekey->withSignatureFormat('SSH2');
  2199.             $curveName $privatekey->getCurve();
  2200.             switch ($curveName) {
  2201.                 case 'Ed25519':
  2202.                     $hash 'sha512';
  2203.                     $signatureType 'ssh-ed25519';
  2204.                     break;
  2205.                 case 'secp256r1'// nistp256
  2206.                     $hash 'sha256';
  2207.                     $signatureType 'ecdsa-sha2-nistp256';
  2208.                     break;
  2209.                 case 'secp384r1'// nistp384
  2210.                     $hash 'sha384';
  2211.                     $signatureType 'ecdsa-sha2-nistp384';
  2212.                     break;
  2213.                 case 'secp521r1'// nistp521
  2214.                     $hash 'sha512';
  2215.                     $signatureType 'ecdsa-sha2-nistp521';
  2216.                     break;
  2217.                 default:
  2218.                     if (is_array($curveName)) {
  2219.                         throw new UnsupportedCurveException('Specified Curves are not supported by SSH2');
  2220.                     }
  2221.                     throw new UnsupportedCurveException('Named Curve of ' $curveName ' is not supported by phpseclib3\'s SSH2 implementation');
  2222.             }
  2223.         } else if ($publickey instanceof DSA) {
  2224.             $privatekey $privatekey->withSignatureFormat('SSH2');
  2225.             $hash 'sha1';
  2226.             $signatureType 'ssh-dss';
  2227.         } else {
  2228.             throw new UnsupportedAlgorithmException('Please use either an RSA key, an EC one or a DSA key');
  2229.         }
  2230.         $publickeyStr $publickey->toString('OpenSSH', ['binary' => true]);
  2231.         $part1 Strings::packSSH2(
  2232.             'Csss',
  2233.             NET_SSH2_MSG_USERAUTH_REQUEST,
  2234.             $username,
  2235.             'ssh-connection',
  2236.             'publickey'
  2237.         );
  2238.         $part2 Strings::packSSH2('ss'$signatureType$publickeyStr);
  2239.         $packet $part1 chr(0) . $part2;
  2240.         $this->send_binary_packet($packet);
  2241.         $response $this->get_binary_packet();
  2242.         if ($response === false) {
  2243.             $this->disconnect_helper(NET_SSH2_DISCONNECT_CONNECTION_LOST);
  2244.             throw new ConnectionClosedException('Connection closed by server');
  2245.         }
  2246.         list($type) = Strings::unpackSSH2('C'$response);
  2247.         switch ($type) {
  2248.             case NET_SSH2_MSG_USERAUTH_FAILURE:
  2249.                 list($message) = Strings::unpackSSH2('s'$response);
  2250.                 $this->errors[] = 'SSH_MSG_USERAUTH_FAILURE: ' $message;
  2251.                 return false;
  2252.             case NET_SSH2_MSG_USERAUTH_PK_OK:
  2253.                 // we'll just take it on faith that the public key blob and the public key algorithm name are as
  2254.                 // they should be
  2255.                 $this->updateLogHistory('UNKNOWN (60)''NET_SSH2_MSG_USERAUTH_PK_OK');
  2256.                 break;
  2257.             case NET_SSH2_MSG_USERAUTH_SUCCESS:
  2258.                 $this->bitmap |= self::MASK_LOGIN;
  2259.                 return true;
  2260.             default:
  2261.                 $this->disconnect_helper(NET_SSH2_DISCONNECT_BY_APPLICATION);
  2262.                 throw new ConnectionClosedException('Unexpected response to publickey authentication pt 1');
  2263.         }
  2264.         $packet $part1 chr(1) . $part2;
  2265.         $privatekey $privatekey->withHash($hash);
  2266.         $signature $privatekey->sign(Strings::packSSH2('s'$this->session_id) . $packet);
  2267.         if ($publickey instanceof RSA) {
  2268.             $signature Strings::packSSH2('ss'$signatureType$signature);
  2269.         }
  2270.         $packet.= Strings::packSSH2('s'$signature);
  2271.         $this->send_binary_packet($packet);
  2272.         $response $this->get_binary_packet();
  2273.         if ($response === false) {
  2274.             $this->disconnect_helper(NET_SSH2_DISCONNECT_CONNECTION_LOST);
  2275.             throw new ConnectionClosedException('Connection closed by server');
  2276.         }
  2277.         list($type) = Strings::unpackSSH2('C'$response);
  2278.         switch ($type) {
  2279.             case NET_SSH2_MSG_USERAUTH_FAILURE:
  2280.                 // either the login is bad or the server employs multi-factor authentication
  2281.                 return false;
  2282.             case NET_SSH2_MSG_USERAUTH_SUCCESS:
  2283.                 $this->bitmap |= self::MASK_LOGIN;
  2284.                 return true;
  2285.         }
  2286.         $this->disconnect_helper(NET_SSH2_DISCONNECT_BY_APPLICATION);
  2287.         throw new ConnectionClosedException('Unexpected response to publickey authentication pt 2');
  2288.     }
  2289.     /**
  2290.      * Set Timeout
  2291.      *
  2292.      * $ssh->exec('ping 127.0.0.1'); on a Linux host will never return and will run indefinitely.  setTimeout() makes it so it'll timeout.
  2293.      * Setting $timeout to false or 0 will mean there is no timeout.
  2294.      *
  2295.      * @param mixed $timeout
  2296.      * @access public
  2297.      */
  2298.     public function setTimeout($timeout)
  2299.     {
  2300.         $this->timeout $this->curTimeout $timeout;
  2301.     }
  2302.     /**
  2303.      * Set Keep Alive
  2304.      *
  2305.      * Sends an SSH2_MSG_IGNORE message every x seconds, if x is a positive non-zero number.
  2306.      *
  2307.      * @param int $interval
  2308.      * @access public
  2309.      */
  2310.     function setKeepAlive($interval)
  2311.     {
  2312.         $this->keepAlive $interval;
  2313.     }
  2314.     /**
  2315.      * Get the output from stdError
  2316.      *
  2317.      * @access public
  2318.      */
  2319.     public function getStdError()
  2320.     {
  2321.         return $this->stdErrorLog;
  2322.     }
  2323.     /**
  2324.      * Execute Command
  2325.      *
  2326.      * If $callback is set to false then \phpseclib3\Net\SSH2::get_channel_packet(self::CHANNEL_EXEC) will need to be called manually.
  2327.      * In all likelihood, this is not a feature you want to be taking advantage of.
  2328.      *
  2329.      * @param string $command
  2330.      * @param Callback $callback
  2331.      * @return string
  2332.      * @throws \RuntimeException on connection error
  2333.      * @access public
  2334.      */
  2335.     public function exec($command$callback null)
  2336.     {
  2337.         $this->curTimeout $this->timeout;
  2338.         $this->is_timeout false;
  2339.         $this->stdErrorLog '';
  2340.         if (!$this->isAuthenticated()) {
  2341.             return false;
  2342.         }
  2343.         if ($this->in_request_pty_exec) {
  2344.             throw new \RuntimeException('If you want to run multiple exec()\'s you will need to disable (and re-enable if appropriate) a PTY for each one.');
  2345.         }
  2346.         // RFC4254 defines the (client) window size as "bytes the other party can send before it must wait for the window to
  2347.         // be adjusted".  0x7FFFFFFF is, at 2GB, the max size.  technically, it should probably be decremented, but,
  2348.         // honestly, if you're transferring more than 2GB, you probably shouldn't be using phpseclib, anyway.
  2349.         // see http://tools.ietf.org/html/rfc4254#section-5.2 for more info
  2350.         $this->window_size_server_to_client[self::CHANNEL_EXEC] = $this->window_size;
  2351.         // 0x8000 is the maximum max packet size, per http://tools.ietf.org/html/rfc4253#section-6.1, although since PuTTy
  2352.         // uses 0x4000, that's what will be used here, as well.
  2353.         $packet_size 0x4000;
  2354.         $packet Strings::packSSH2(
  2355.             'CsN3',
  2356.             NET_SSH2_MSG_CHANNEL_OPEN,
  2357.             'session',
  2358.             self::CHANNEL_EXEC,
  2359.             $this->window_size_server_to_client[self::CHANNEL_EXEC],
  2360.             $packet_size
  2361.         );
  2362.         $this->send_binary_packet($packet);
  2363.         $this->channel_status[self::CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_OPEN;
  2364.         $response $this->get_channel_packet(self::CHANNEL_EXEC);
  2365.         if ($response === false) {
  2366.             return false;
  2367.         }
  2368.         if ($this->request_pty === true) {
  2369.             $terminal_modes pack('C'NET_SSH2_TTY_OP_END);
  2370.             $packet Strings::packSSH2(
  2371.                 'CNsCsN4s',
  2372.                 NET_SSH2_MSG_CHANNEL_REQUEST,
  2373.                 $this->server_channels[self::CHANNEL_EXEC],
  2374.                 'pty-req',
  2375.                 1,
  2376.                 'vt100',
  2377.                 $this->windowColumns,
  2378.                 $this->windowRows,
  2379.                 0,
  2380.                 0,
  2381.                 $terminal_modes
  2382.             );
  2383.             $this->send_binary_packet($packet);
  2384.             $response $this->get_binary_packet();
  2385.             if ($response === false) {
  2386.                 $this->disconnect_helper(NET_SSH2_DISCONNECT_CONNECTION_LOST);
  2387.                 throw new ConnectionClosedException('Connection closed by server');
  2388.             }
  2389.             list($type) = Strings::unpackSSH2('C'$response);
  2390.             switch ($type) {
  2391.                 case NET_SSH2_MSG_CHANNEL_SUCCESS:
  2392.                     break;
  2393.                 case NET_SSH2_MSG_CHANNEL_FAILURE:
  2394.                 default:
  2395.                     $this->disconnect_helper(NET_SSH2_DISCONNECT_BY_APPLICATION);
  2396.                     throw new \RuntimeException('Unable to request pseudo-terminal');
  2397.             }
  2398.             $this->in_request_pty_exec true;
  2399.         }
  2400.         // sending a pty-req SSH_MSG_CHANNEL_REQUEST message is unnecessary and, in fact, in most cases, slows things
  2401.         // down.  the one place where it might be desirable is if you're doing something like \phpseclib3\Net\SSH2::exec('ping localhost &').
  2402.         // with a pty-req SSH_MSG_CHANNEL_REQUEST, exec() will return immediately and the ping process will then
  2403.         // then immediately terminate.  without such a request exec() will loop indefinitely.  the ping process won't end but
  2404.         // neither will your script.
  2405.         // although, in theory, the size of SSH_MSG_CHANNEL_REQUEST could exceed the maximum packet size established by
  2406.         // SSH_MSG_CHANNEL_OPEN_CONFIRMATION, RFC4254#section-5.1 states that the "maximum packet size" refers to the
  2407.         // "maximum size of an individual data packet". ie. SSH_MSG_CHANNEL_DATA.  RFC4254#section-5.2 corroborates.
  2408.         $packet Strings::packSSH2(
  2409.             'CNsCs',
  2410.             NET_SSH2_MSG_CHANNEL_REQUEST,
  2411.             $this->server_channels[self::CHANNEL_EXEC],
  2412.             'exec',
  2413.             1,
  2414.             $command
  2415.         );
  2416.         $this->send_binary_packet($packet);
  2417.         $this->channel_status[self::CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_REQUEST;
  2418.         $response $this->get_channel_packet(self::CHANNEL_EXEC);
  2419.         if ($response === false) {
  2420.             return false;
  2421.         }
  2422.         $this->channel_status[self::CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_DATA;
  2423.         if ($callback === false || $this->in_request_pty_exec) {
  2424.             return true;
  2425.         }
  2426.         $output '';
  2427.         while (true) {
  2428.             $temp $this->get_channel_packet(self::CHANNEL_EXEC);
  2429.             switch (true) {
  2430.                 case $temp === true:
  2431.                     return is_callable($callback) ? true $output;
  2432.                 case $temp === false:
  2433.                     return false;
  2434.                 default:
  2435.                     if (is_callable($callback)) {
  2436.                         if ($callback($temp) === true) {
  2437.                             $this->close_channel(self::CHANNEL_EXEC);
  2438.                             return true;
  2439.                         }
  2440.                     } else {
  2441.                         $output.= $temp;
  2442.                     }
  2443.             }
  2444.         }
  2445.     }
  2446.     /**
  2447.      * Creates an interactive shell
  2448.      *
  2449.      * @see self::read()
  2450.      * @see self::write()
  2451.      * @return bool
  2452.      * @throws \UnexpectedValueException on receipt of unexpected packets
  2453.      * @throws \RuntimeException on other errors
  2454.      * @access private
  2455.      */
  2456.     private function initShell()
  2457.     {
  2458.         if ($this->in_request_pty_exec === true) {
  2459.             return true;
  2460.         }
  2461.         $this->window_size_server_to_client[self::CHANNEL_SHELL] = $this->window_size;
  2462.         $packet_size 0x4000;
  2463.         $packet Strings::packSSH2(
  2464.             'CsN3',
  2465.             NET_SSH2_MSG_CHANNEL_OPEN,
  2466.             'session',
  2467.             self::CHANNEL_SHELL,
  2468.             $this->window_size_server_to_client[self::CHANNEL_SHELL],
  2469.             $packet_size
  2470.         );
  2471.         $this->send_binary_packet($packet);
  2472.         $this->channel_status[self::CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_OPEN;
  2473.         $response $this->get_channel_packet(self::CHANNEL_SHELL);
  2474.         if ($response === false) {
  2475.             return false;
  2476.         }
  2477.         $terminal_modes pack('C'NET_SSH2_TTY_OP_END);
  2478.         $packet Strings::packSSH2(
  2479.             'CNsCsN4s',
  2480.             NET_SSH2_MSG_CHANNEL_REQUEST,
  2481.             $this->server_channels[self::CHANNEL_SHELL],
  2482.             'pty-req',
  2483.             1,
  2484.             'vt100',
  2485.             $this->windowColumns,
  2486.             $this->windowRows,
  2487.             0,
  2488.             0,
  2489.             $terminal_modes
  2490.         );
  2491.         $this->send_binary_packet($packet);
  2492.         $response $this->get_binary_packet();
  2493.         if ($response === false) {
  2494.             $this->disconnect_helper(NET_SSH2_DISCONNECT_CONNECTION_LOST);
  2495.             throw new ConnectionClosedException('Connection closed by server');
  2496.         }
  2497.         list($type) = Strings::unpackSSH2('C'$response);
  2498.         switch ($type) {
  2499.             case NET_SSH2_MSG_CHANNEL_SUCCESS:
  2500.             // if a pty can't be opened maybe commands can still be executed
  2501.             case NET_SSH2_MSG_CHANNEL_FAILURE:
  2502.                 break;
  2503.             default:
  2504.                 $this->disconnect_helper(NET_SSH2_DISCONNECT_BY_APPLICATION);
  2505.                 throw new \UnexpectedValueException('Unable to request pseudo-terminal');
  2506.         }
  2507.         $packet Strings::packSSH2(
  2508.             'CNsb',
  2509.             NET_SSH2_MSG_CHANNEL_REQUEST,
  2510.             $this->server_channels[self::CHANNEL_SHELL],
  2511.             'shell',
  2512.             true // want reply
  2513.         );
  2514.         $this->send_binary_packet($packet);
  2515.         $this->channel_status[self::CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_REQUEST;
  2516.         $response $this->get_channel_packet(self::CHANNEL_SHELL);
  2517.         if ($response === false) {
  2518.             return false;
  2519.         }
  2520.         $this->channel_status[self::CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_DATA;
  2521.         $this->bitmap |= self::MASK_SHELL;
  2522.         return true;
  2523.     }
  2524.     /**
  2525.      * Return the channel to be used with read() / write()
  2526.      *
  2527.      * @see self::read()
  2528.      * @see self::write()
  2529.      * @return int
  2530.      * @access public
  2531.      */
  2532.     private function get_interactive_channel()
  2533.     {
  2534.         switch (true) {
  2535.             case $this->in_subsystem:
  2536.                 return self::CHANNEL_SUBSYSTEM;
  2537.             case $this->in_request_pty_exec:
  2538.                 return self::CHANNEL_EXEC;
  2539.             default:
  2540.                 return self::CHANNEL_SHELL;
  2541.         }
  2542.     }
  2543.     /**
  2544.      * Return an available open channel
  2545.      *
  2546.      * @return int
  2547.      * @access public
  2548.      */
  2549.     private function get_open_channel()
  2550.     {
  2551.         $channel self::CHANNEL_EXEC;
  2552.         do {
  2553.             if (isset($this->channel_status[$channel]) && $this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_OPEN) {
  2554.                 return $channel;
  2555.             }
  2556.         } while ($channel++ < self::CHANNEL_SUBSYSTEM);
  2557.         return false;
  2558.     }
  2559.     /**
  2560.      * Request agent forwarding of remote server
  2561.      *
  2562.      * @return bool
  2563.      * @access public
  2564.      */
  2565.     public function requestAgentForwarding()
  2566.     {
  2567.         $request_channel $this->get_open_channel();
  2568.         if ($request_channel === false) {
  2569.             return false;
  2570.         }
  2571.         $packet Strings::packSSH2(
  2572.             'CNsC',
  2573.             NET_SSH2_MSG_CHANNEL_REQUEST,
  2574.             $this->server_channels[$request_channel],
  2575.             'auth-agent-req@openssh.com',
  2576.             1
  2577.         );
  2578.         $this->channel_status[$request_channel] = NET_SSH2_MSG_CHANNEL_REQUEST;
  2579.         $this->send_binary_packet($packet);
  2580.         $response $this->get_channel_packet($request_channel);
  2581.         if ($response === false) {
  2582.             return false;
  2583.         }
  2584.         $this->channel_status[$request_channel] = NET_SSH2_MSG_CHANNEL_OPEN;
  2585.         return true;
  2586.     }
  2587.     /**
  2588.      * Returns the output of an interactive shell
  2589.      *
  2590.      * Returns when there's a match for $expect, which can take the form of a string literal or,
  2591.      * if $mode == self::READ_REGEX, a regular expression.
  2592.      *
  2593.      * @see self::write()
  2594.      * @param string $expect
  2595.      * @param int $mode
  2596.      * @return string|bool|null
  2597.      * @throws \RuntimeException on connection error
  2598.      * @access public
  2599.      */
  2600.     public function read($expect ''$mode self::READ_SIMPLE)
  2601.     {
  2602.         $this->curTimeout $this->timeout;
  2603.         $this->is_timeout false;
  2604.         if (!$this->isAuthenticated()) {
  2605.             throw new InsufficientSetupException('Operation disallowed prior to login()');
  2606.         }
  2607.         if (!($this->bitmap self::MASK_SHELL) && !$this->initShell()) {
  2608.             throw new \RuntimeException('Unable to initiate an interactive shell session');
  2609.         }
  2610.         $channel $this->get_interactive_channel();
  2611.         if ($mode == self::READ_NEXT) {
  2612.             return $this->get_channel_packet($channel);
  2613.         }
  2614.         $match $expect;
  2615.         while (true) {
  2616.             if ($mode == self::READ_REGEX) {
  2617.                 preg_match($expectsubstr($this->interactiveBuffer, -1024), $matches);
  2618.                 $match = isset($matches[0]) ? $matches[0] : '';
  2619.             }
  2620.             $pos strlen($match) ? strpos($this->interactiveBuffer$match) : false;
  2621.             if ($pos !== false) {
  2622.                 return Strings::shift($this->interactiveBuffer$pos strlen($match));
  2623.             }
  2624.             $response $this->get_channel_packet($channel);
  2625.             if (is_bool($response)) {
  2626.                 $this->in_request_pty_exec false;
  2627.                 return $response Strings::shift($this->interactiveBufferstrlen($this->interactiveBuffer)) : false;
  2628.             }
  2629.             $this->interactiveBuffer.= $response;
  2630.         }
  2631.     }
  2632.     /**
  2633.      * Inputs a command into an interactive shell.
  2634.      *
  2635.      * @see self::read()
  2636.      * @param string $cmd
  2637.      * @return bool
  2638.      * @throws \RuntimeException on connection error
  2639.      * @access public
  2640.      */
  2641.     public function write($cmd)
  2642.     {
  2643.         if (!$this->isAuthenticated()) {
  2644.             throw new InsufficientSetupException('Operation disallowed prior to login()');
  2645.         }
  2646.         if (!($this->bitmap self::MASK_SHELL) && !$this->initShell()) {
  2647.             throw new \RuntimeException('Unable to initiate an interactive shell session');
  2648.         }
  2649.         return $this->send_channel_packet($this->get_interactive_channel(), $cmd);
  2650.     }
  2651.     /**
  2652.      * Start a subsystem.
  2653.      *
  2654.      * Right now only one subsystem at a time is supported. To support multiple subsystem's stopSubsystem() could accept
  2655.      * a string that contained the name of the subsystem, but at that point, only one subsystem of each type could be opened.
  2656.      * To support multiple subsystem's of the same name maybe it'd be best if startSubsystem() generated a new channel id and
  2657.      * returns that and then that that was passed into stopSubsystem() but that'll be saved for a future date and implemented
  2658.      * if there's sufficient demand for such a feature.
  2659.      *
  2660.      * @see self::stopSubsystem()
  2661.      * @param string $subsystem
  2662.      * @return bool
  2663.      * @access public
  2664.      */
  2665.     public function startSubsystem($subsystem)
  2666.     {
  2667.         $this->window_size_server_to_client[self::CHANNEL_SUBSYSTEM] = $this->window_size;
  2668.         $packet Strings::packSSH2(
  2669.             'CsN3',
  2670.             NET_SSH2_MSG_CHANNEL_OPEN,
  2671.             'session',
  2672.             self::CHANNEL_SUBSYSTEM,
  2673.             $this->window_size,
  2674.             0x4000
  2675.         );
  2676.         $this->send_binary_packet($packet);
  2677.         $this->channel_status[self::CHANNEL_SUBSYSTEM] = NET_SSH2_MSG_CHANNEL_OPEN;
  2678.         $response $this->get_channel_packet(self::CHANNEL_SUBSYSTEM);
  2679.         if ($response === false) {
  2680.             return false;
  2681.         }
  2682.         $packet Strings::packSSH2(
  2683.             'CNsCs',
  2684.             NET_SSH2_MSG_CHANNEL_REQUEST,
  2685.             $this->server_channels[self::CHANNEL_SUBSYSTEM],
  2686.             'subsystem',
  2687.             1,
  2688.             $subsystem
  2689.         );
  2690.         $this->send_binary_packet($packet);
  2691.         $this->channel_status[self::CHANNEL_SUBSYSTEM] = NET_SSH2_MSG_CHANNEL_REQUEST;
  2692.         $response $this->get_channel_packet(self::CHANNEL_SUBSYSTEM);
  2693.         if ($response === false) {
  2694.             return false;
  2695.         }
  2696.         $this->channel_status[self::CHANNEL_SUBSYSTEM] = NET_SSH2_MSG_CHANNEL_DATA;
  2697.         $this->bitmap |= self::MASK_SHELL;
  2698.         $this->in_subsystem true;
  2699.         return true;
  2700.     }
  2701.     /**
  2702.      * Stops a subsystem.
  2703.      *
  2704.      * @see self::startSubsystem()
  2705.      * @return bool
  2706.      * @access public
  2707.      */
  2708.     public function stopSubsystem()
  2709.     {
  2710.         $this->in_subsystem false;
  2711.         $this->close_channel(self::CHANNEL_SUBSYSTEM);
  2712.         return true;
  2713.     }
  2714.     /**
  2715.      * Closes a channel
  2716.      *
  2717.      * If read() timed out you might want to just close the channel and have it auto-restart on the next read() call
  2718.      *
  2719.      * @access public
  2720.      */
  2721.     public function reset()
  2722.     {
  2723.         $this->close_channel($this->get_interactive_channel());
  2724.     }
  2725.     /**
  2726.      * Is timeout?
  2727.      *
  2728.      * Did exec() or read() return because they timed out or because they encountered the end?
  2729.      *
  2730.      * @access public
  2731.      */
  2732.     public function isTimeout()
  2733.     {
  2734.         return $this->is_timeout;
  2735.     }
  2736.     /**
  2737.      * Disconnect
  2738.      *
  2739.      * @access public
  2740.      */
  2741.     public function disconnect()
  2742.     {
  2743.         $this->disconnect_helper(NET_SSH2_DISCONNECT_BY_APPLICATION);
  2744.         if (isset($this->realtime_log_file) && is_resource($this->realtime_log_file)) {
  2745.             fclose($this->realtime_log_file);
  2746.         }
  2747.         unset(self::$connections[$this->getResourceId()]);
  2748.     }
  2749.     /**
  2750.      * Destructor.
  2751.      *
  2752.      * Will be called, automatically, if you're supporting just PHP5.  If you're supporting PHP4, you'll need to call
  2753.      * disconnect().
  2754.      *
  2755.      * @access public
  2756.      */
  2757.     public function __destruct()
  2758.     {
  2759.         $this->disconnect();
  2760.     }
  2761.     /**
  2762.      * Is the connection still active?
  2763.      *
  2764.      * @return bool
  2765.      * @access public
  2766.      */
  2767.     public function isConnected()
  2768.     {
  2769.         return (bool) ($this->bitmap self::MASK_CONNECTED);
  2770.     }
  2771.     /**
  2772.      * Have you successfully been logged in?
  2773.      *
  2774.      * @return bool
  2775.      * @access public
  2776.      */
  2777.     public function isAuthenticated()
  2778.     {
  2779.         return (bool) ($this->bitmap self::MASK_LOGIN);
  2780.     }
  2781.     /**
  2782.      * Pings a server connection, or tries to reconnect if the connection has gone down
  2783.      *
  2784.      * Inspired by http://php.net/manual/en/mysqli.ping.php
  2785.      *
  2786.      * @return bool
  2787.      */
  2788.     public function ping()
  2789.     {
  2790.         if (!$this->isAuthenticated()) {
  2791.             if (!empty($this->auth)) {
  2792.                 return $this->reconnect();
  2793.             }
  2794.             return false;
  2795.         }
  2796.         $this->window_size_server_to_client[self::CHANNEL_KEEP_ALIVE] = $this->window_size;
  2797.         $packet_size 0x4000;
  2798.         $packet Strings::packSSH2(
  2799.             'CsN3',
  2800.             NET_SSH2_MSG_CHANNEL_OPEN,
  2801.             'session',
  2802.             self::CHANNEL_KEEP_ALIVE,
  2803.             $this->window_size_server_to_client[self::CHANNEL_KEEP_ALIVE],
  2804.             $packet_size
  2805.         );
  2806.         try {
  2807.             $this->send_binary_packet($packet);
  2808.             $this->channel_status[self::CHANNEL_KEEP_ALIVE] = NET_SSH2_MSG_CHANNEL_OPEN;
  2809.             $response $this->get_channel_packet(self::CHANNEL_KEEP_ALIVE);
  2810.         } catch (\RuntimeException $e) {
  2811.             return $this->reconnect();
  2812.         }
  2813.         $this->close_channel(NET_SSH2_CHANNEL_KEEP_ALIVE);
  2814.         return true;
  2815.     }
  2816.     /**
  2817.      * In situ reconnect method
  2818.      *
  2819.      * @return boolean
  2820.      */
  2821.     private function reconnect()
  2822.     {
  2823.         $this->reset_connection(NET_SSH2_DISCONNECT_CONNECTION_LOST);
  2824.         $this->retry_connect true;
  2825.         if (!$this->connect()) {
  2826.             return false;
  2827.         }
  2828.         foreach ($this->auth as $auth) {
  2829.             $result $this->login(...$auth);
  2830.         }
  2831.         return $result;
  2832.     }
  2833.     /**
  2834.      * Resets a connection for re-use
  2835.      *
  2836.      * @param int $reason
  2837.      * @access private
  2838.      */
  2839.     protected function reset_connection($reason)
  2840.     {
  2841.         $this->disconnect_helper($reason);
  2842.         $this->decrypt $this->encrypt false;
  2843.         $this->decrypt_block_size $this->encrypt_block_size 8;
  2844.         $this->hmac_check $this->hmac_create false;
  2845.         $this->hmac_size false;
  2846.         $this->session_id false;
  2847.         $this->retry_connect true;
  2848.         $this->get_seq_no $this->send_seq_no 0;
  2849.     }
  2850.     /**
  2851.      * Gets Binary Packets
  2852.      *
  2853.      * See '6. Binary Packet Protocol' of rfc4253 for more info.
  2854.      *
  2855.      * @see self::_send_binary_packet()
  2856.      * @param bool $skip_channel_filter
  2857.      * @return string
  2858.      * @access private
  2859.      */
  2860.     private function get_binary_packet($skip_channel_filter false)
  2861.     {
  2862.         if ($skip_channel_filter) {
  2863.             $read = [$this->fsock];
  2864.             $write $except null;
  2865.             if ($this->curTimeout <= 0) {
  2866.                 if ($this->keepAlive <= 0) {
  2867.                     @stream_select($read$write$exceptnull);
  2868.                 } else {
  2869.                     if (!@stream_select($read$write$except$this->keepAlive)) {
  2870.                         $this->send_binary_packet(pack('CN'NET_SSH2_MSG_IGNORE0));
  2871.                         return $this->get_binary_packet(true);
  2872.                     }
  2873.                 }
  2874.             } else {
  2875.                 if ($this->curTimeout 0) {
  2876.                     $this->is_timeout true;
  2877.                     return true;
  2878.                 }
  2879.                 $read = [$this->fsock];
  2880.                 $write $except null;
  2881.                 $start microtime(true);
  2882.                 if ($this->keepAlive && $this->keepAlive $this->curTimeout) {
  2883.                     if (!@stream_select($read$write$except$this->keepAlive)) {
  2884.                         $this->send_binary_packet(pack('CN'NET_SSH2_MSG_IGNORE0));
  2885.                         $elapsed microtime(true) - $start;
  2886.                         $this->curTimeout-= $elapsed;
  2887.                         return $this->get_binary_packet(true);
  2888.                     }
  2889.                     $elapsed microtime(true) - $start;
  2890.                     $this->curTimeout-= $elapsed;
  2891.                 }
  2892.                 $sec floor($this->curTimeout);
  2893.                 $usec 1000000 * ($this->curTimeout $sec);
  2894.                 // this can return a "stream_select(): unable to select [4]: Interrupted system call" error
  2895.                 if (!@stream_select($read$write$except$sec$usec)) {
  2896.                     $this->is_timeout true;
  2897.                     return true;
  2898.                 }
  2899.                 $elapsed microtime(true) - $start;
  2900.                 $this->curTimeout-= $elapsed;
  2901.             }
  2902.         }
  2903.         if (!is_resource($this->fsock) || feof($this->fsock)) {
  2904.             $this->bitmap 0;
  2905.             throw new ConnectionClosedException('Connection closed prematurely');
  2906.         }
  2907.         $start microtime(true);
  2908.         $raw stream_get_contents($this->fsock$this->decrypt_block_size);
  2909.         if (!strlen($raw)) {
  2910.             return '';
  2911.         }
  2912.         if ($this->decrypt) {
  2913.             switch ($this->decrypt->name) {
  2914.                 case 'aes128-gcm@openssh.com':
  2915.                 case 'aes256-gcm@openssh.com':
  2916.                     $this->decrypt->setNonce(
  2917.                         $this->decrypt->fixed .
  2918.                         $this->decrypt->invocation_counter
  2919.                     );
  2920.                     Strings::increment_str($this->decrypt->invocation_counter);
  2921.                     $this->decrypt->setAAD($temp Strings::shift($raw4));
  2922.                     extract(unpack('Npacket_length'$temp));
  2923.                     /**
  2924.                      * @var integer $packet_length
  2925.                      */
  2926.                     $raw.= $this->read_remaining_bytes($packet_length $this->decrypt_block_size 4);
  2927.                     $stop microtime(true);
  2928.                     $tag stream_get_contents($this->fsock$this->decrypt_block_size);
  2929.                     $this->decrypt->setTag($tag);
  2930.                     $raw $this->decrypt->decrypt($raw);
  2931.                     $raw $temp $raw;
  2932.                     $remaining_length 0;
  2933.                     break;
  2934.                 case 'chacha20-poly1305@openssh.com':
  2935.                     $nonce pack('N2'0$this->get_seq_no);
  2936.                     $this->lengthDecrypt->setNonce($nonce);
  2937.                     $temp $this->lengthDecrypt->decrypt($aad Strings::shift($raw4));
  2938.                     extract(unpack('Npacket_length'$temp));
  2939.                     /**
  2940.                      * @var integer $packet_length
  2941.                      */
  2942.                     $raw.= $this->read_remaining_bytes($packet_length $this->decrypt_block_size 4);
  2943.                     $stop microtime(true);
  2944.                     $tag stream_get_contents($this->fsock16);
  2945.                     $this->decrypt->setNonce($nonce);
  2946.                     $this->decrypt->setCounter(0);
  2947.                     // this is the same approach that's implemented in Salsa20::createPoly1305Key()
  2948.                     // but we don't want to use the same AEAD construction that RFC8439 describes
  2949.                     // for ChaCha20-Poly1305 so we won't rely on it (see Salsa20::poly1305())
  2950.                     $this->decrypt->setPoly1305Key(
  2951.                         $this->decrypt->encrypt(str_repeat("\0"32))
  2952.                     );
  2953.                     $this->decrypt->setAAD($aad);
  2954.                     $this->decrypt->setCounter(1);
  2955.                     $this->decrypt->setTag($tag);
  2956.                     $raw $this->decrypt->decrypt($raw);
  2957.                     $raw $temp $raw;
  2958.                     $remaining_length 0;
  2959.                     break;
  2960.                 default:
  2961.                     if (!$this->hmac_check instanceof Hash || !$this->hmac_check->etm) {
  2962.                         $raw $this->decrypt->decrypt($raw);
  2963.                         break;
  2964.                     }
  2965.                     extract(unpack('Npacket_length'$temp Strings::shift($raw4)));
  2966.                     /**
  2967.                      * @var integer $packet_length
  2968.                      */
  2969.                     $raw.= $this->read_remaining_bytes($packet_length $this->decrypt_block_size 4);
  2970.                     $stop microtime(true);
  2971.                     $encrypted $temp $raw;
  2972.                     $raw $temp $this->decrypt->decrypt($raw);
  2973.                     $remaining_length 0;
  2974.             }
  2975.         }
  2976.         if (strlen($raw) < 5) {
  2977.             return false;
  2978.         }
  2979.         extract(unpack('Npacket_length/Cpadding_length'Strings::shift($raw5)));
  2980.         /**
  2981.          * @var integer $packet_length
  2982.          * @var integer $padding_length
  2983.          */
  2984.         if (!isset($remaining_length)) {
  2985.             $remaining_length $packet_length $this->decrypt_block_size;
  2986.         }
  2987.         $buffer $this->read_remaining_bytes($remaining_length);
  2988.         if (!isset($stop)) {
  2989.             $stop microtime(true);
  2990.         }
  2991.         if (strlen($buffer)) {
  2992.             $raw.= $this->decrypt $this->decrypt->decrypt($buffer) : $buffer;
  2993.         }
  2994.         $payload Strings::shift($raw$packet_length $padding_length 1);
  2995.         $padding Strings::shift($raw$padding_length); // should leave $raw empty
  2996.         if ($this->hmac_check instanceof Hash) {
  2997.             $hmac stream_get_contents($this->fsock$this->hmac_size);
  2998.             if ($hmac === false || strlen($hmac) != $this->hmac_size) {
  2999.                 $this->disconnect_helper(NET_SSH2_DISCONNECT_MAC_ERROR);
  3000.                 throw new \RuntimeException('Error reading socket');
  3001.             }
  3002.             $reconstructed = !$this->hmac_check->etm ?
  3003.                 pack('NCa*'$packet_length$padding_length$payload $padding) :
  3004.                 $encrypted;
  3005.             if (($this->hmac_check->getHash() & "\xFF\xFF\xFF\xFF") == 'umac') {
  3006.                 $this->hmac_check->setNonce("\0\0\0\0" pack('N'$this->get_seq_no));
  3007.                 if ($hmac != $this->hmac_check->hash($reconstructed)) {
  3008.                     $this->disconnect_helper(NET_SSH2_DISCONNECT_MAC_ERROR);
  3009.                     throw new \RuntimeException('Invalid UMAC');
  3010.                 }
  3011.             } else {
  3012.                 if ($hmac != $this->hmac_check->hash(pack('Na*'$this->get_seq_no$reconstructed))) {
  3013.                     $this->disconnect_helper(NET_SSH2_DISCONNECT_MAC_ERROR);
  3014.                     throw new \RuntimeException('Invalid HMAC');
  3015.                 }
  3016.             }
  3017.         }
  3018.         //if ($this->decompress) {
  3019.         //    $payload = gzinflate(substr($payload, 2));
  3020.         //}
  3021.         $this->get_seq_no++;
  3022.         if (defined('NET_SSH2_LOGGING')) {
  3023.             $current microtime(true);
  3024.             $message_number = isset($this->message_numbers[ord($payload[0])]) ? $this->message_numbers[ord($payload[0])] : 'UNKNOWN (' ord($payload[0]) . ')';
  3025.             $message_number '<- ' $message_number .
  3026.                               ' (since last: ' round($current $this->last_packet4) . ', network: ' round($stop $start4) . 's)';
  3027.             $this->append_log($message_number$payload);
  3028.             $this->last_packet $current;
  3029.         }
  3030.         return $this->filter($payload$skip_channel_filter);
  3031.     }
  3032.     /**
  3033.      * Read Remaining Bytes
  3034.      *
  3035.      * @see self::get_binary_packet()
  3036.      * @param int $remaining_length
  3037.      * @return string
  3038.      * @access private
  3039.      */
  3040.     private function read_remaining_bytes($remaining_length)
  3041.     {
  3042.         if (!$remaining_length) {
  3043.             return '';
  3044.         }
  3045.         $adjustLength false;
  3046.         if ($this->decrypt) {
  3047.             switch (true) {
  3048.                 case $this->decrypt->name == 'aes128-gcm@openssh.com':
  3049.                 case $this->decrypt->name == 'aes256-gcm@openssh.com':
  3050.                 case $this->decrypt->name == 'chacha20-poly1305@openssh.com':
  3051.                 case $this->hmac_check instanceof Hash && $this->hmac_check->etm:
  3052.                     $remaining_length+= $this->decrypt_block_size 4;
  3053.                     $adjustLength true;
  3054.             }
  3055.         }
  3056.         // quoting <http://tools.ietf.org/html/rfc4253#section-6.1>,
  3057.         // "implementations SHOULD check that the packet length is reasonable"
  3058.         // PuTTY uses 0x9000 as the actual max packet size and so to shall we
  3059.         // don't do this when GCM mode is used since GCM mode doesn't encrypt the length
  3060.         if ($remaining_length < -$this->decrypt_block_size || $remaining_length 0x9000 || $remaining_length $this->decrypt_block_size != 0) {
  3061.             if (!$this->bad_key_size_fix && self::bad_algorithm_candidate($this->decrypt $this->decrypt->name '') && !($this->bitmap SSH2::MASK_LOGIN)) {
  3062.                 $this->bad_key_size_fix true;
  3063.                 $this->reset_connection(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  3064.                 return false;
  3065.             }
  3066.             throw new \RuntimeException('Invalid size');
  3067.         }
  3068.         if ($adjustLength) {
  3069.             $remaining_length-= $this->decrypt_block_size 4;
  3070.         }
  3071.         $buffer '';
  3072.         while ($remaining_length 0) {
  3073.             $temp stream_get_contents($this->fsock$remaining_length);
  3074.             if ($temp === false || feof($this->fsock)) {
  3075.                 $this->disconnect_helper(NET_SSH2_DISCONNECT_CONNECTION_LOST);
  3076.                 throw new \RuntimeException('Error reading from socket');
  3077.             }
  3078.             $buffer.= $temp;
  3079.             $remaining_length-= strlen($temp);
  3080.         }
  3081.         return $buffer;
  3082.     }
  3083.     /**
  3084.      * Filter Binary Packets
  3085.      *
  3086.      * Because some binary packets need to be ignored...
  3087.      *
  3088.      * @see self::_get_binary_packet()
  3089.      * @param string $payload
  3090.      * @param bool $skip_channel_filter
  3091.      * @return string
  3092.      * @access private
  3093.      */
  3094.     private function filter($payload$skip_channel_filter)
  3095.     {
  3096.         switch (ord($payload[0])) {
  3097.             case NET_SSH2_MSG_DISCONNECT:
  3098.                 Strings::shift($payload1);
  3099.                 list($reason_code$message) = Strings::unpackSSH2('Ns'$payload);
  3100.                 $this->errors[] = 'SSH_MSG_DISCONNECT: ' $this->disconnect_reasons[$reason_code] . "\r\n$message";
  3101.                 $this->bitmap 0;
  3102.                 return false;
  3103.             case NET_SSH2_MSG_IGNORE:
  3104.                 $payload $this->get_binary_packet($skip_channel_filter);
  3105.                 break;
  3106.             case NET_SSH2_MSG_DEBUG:
  3107.                 Strings::shift($payload2); // second byte is "always_display"
  3108.                 list($message) = Strings::unpackSSH2('s'$payload);
  3109.                 $this->errors[] = "SSH_MSG_DEBUG: $message";
  3110.                 $payload $this->get_binary_packet($skip_channel_filter);
  3111.                 break;
  3112.             case NET_SSH2_MSG_UNIMPLEMENTED:
  3113.                 return false;
  3114.             case NET_SSH2_MSG_KEXINIT:
  3115.                 if ($this->session_id !== false) {
  3116.                     if (!$this->key_exchange($payload)) {
  3117.                         $this->bitmap 0;
  3118.                         return false;
  3119.                     }
  3120.                     $payload $this->get_binary_packet($skip_channel_filter);
  3121.                 }
  3122.         }
  3123.         // see http://tools.ietf.org/html/rfc4252#section-5.4; only called when the encryption has been activated and when we haven't already logged in
  3124.         if (($this->bitmap self::MASK_CONNECTED) && !$this->isAuthenticated() && ord($payload[0]) == NET_SSH2_MSG_USERAUTH_BANNER) {
  3125.             Strings::shift($payload1);
  3126.             list($this->banner_message) = Strings::unpackSSH2('s'$payload);
  3127.             $payload $this->get_binary_packet();
  3128.         }
  3129.         // only called when we've already logged in
  3130.         if (($this->bitmap self::MASK_CONNECTED) && $this->isAuthenticated()) {
  3131.             switch (ord($payload[0])) {
  3132.                 case NET_SSH2_MSG_CHANNEL_REQUEST:
  3133.                     if (strlen($payload) == 31) {
  3134.                         extract(unpack('cpacket_type/Nchannel/Nlength'$payload));
  3135.                         if (substr($payload9$length) == 'keepalive@openssh.com' && isset($this->server_channels[$channel])) {
  3136.                             if (ord(substr($payload$length))) { // want reply
  3137.                                 $this->send_binary_packet(pack('CN'NET_SSH2_MSG_CHANNEL_SUCCESS$this->server_channels[$channel]));
  3138.                             }
  3139.                             $payload $this->get_binary_packet($skip_channel_filter);
  3140.                         }
  3141.                     }
  3142.                     break;
  3143.                 case NET_SSH2_MSG_CHANNEL_DATA:
  3144.                 case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA:
  3145.                 case NET_SSH2_MSG_CHANNEL_CLOSE:
  3146.                 case NET_SSH2_MSG_CHANNEL_EOF:
  3147.                     if (!$skip_channel_filter && !empty($this->server_channels)) {
  3148.                         $this->binary_packet_buffer $payload;
  3149.                         $this->get_channel_packet(true);
  3150.                         $payload $this->get_binary_packet();
  3151.                     }
  3152.                     break;
  3153.                 case NET_SSH2_MSG_GLOBAL_REQUEST// see http://tools.ietf.org/html/rfc4254#section-4
  3154.                     Strings::shift($payload1);
  3155.                     list($request_name) = Strings::unpackSSH2('s'$payload);
  3156.                     $this->errors[] = "SSH_MSG_GLOBAL_REQUEST: $request_name";
  3157.                     try {
  3158.                         $this->send_binary_packet(pack('C'NET_SSH2_MSG_REQUEST_FAILURE));
  3159.                     } catch (\RuntimeException $e) {
  3160.                         return $this->disconnect_helper(NET_SSH2_DISCONNECT_BY_APPLICATION);
  3161.                     }
  3162.                     $payload $this->get_binary_packet($skip_channel_filter);
  3163.                     break;
  3164.                 case NET_SSH2_MSG_CHANNEL_OPEN// see http://tools.ietf.org/html/rfc4254#section-5.1
  3165.                     Strings::shift($payload1);
  3166.                     list($data$server_channel) = Strings::unpackSSH2('sN'$payload);
  3167.                     switch ($data) {
  3168.                         case 'auth-agent':
  3169.                         case 'auth-agent@openssh.com':
  3170.                             if (isset($this->agent)) {
  3171.                                 $new_channel self::CHANNEL_AGENT_FORWARD;
  3172.                                 list(
  3173.                                     $remote_window_size,
  3174.                                     $remote_maximum_packet_size
  3175.                                 ) = Strings::unpackSSH2('NN'$payload);
  3176.                                 $this->packet_size_client_to_server[$new_channel] = $remote_window_size;
  3177.                                 $this->window_size_server_to_client[$new_channel] = $remote_maximum_packet_size;
  3178.                                 $this->window_size_client_to_server[$new_channel] = $this->window_size;
  3179.                                 $packet_size 0x4000;
  3180.                                 $packet pack(
  3181.                                     'CN4',
  3182.                                     NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION,
  3183.                                     $server_channel,
  3184.                                     $new_channel,
  3185.                                     $packet_size,
  3186.                                     $packet_size
  3187.                                 );
  3188.                                 $this->server_channels[$new_channel] = $server_channel;
  3189.                                 $this->channel_status[$new_channel] = NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION;
  3190.                                 $this->send_binary_packet($packet);
  3191.                             }
  3192.                             break;
  3193.                         default:
  3194.                             $packet Strings::packSSH2(
  3195.                                 'CN2ss',
  3196.                                 NET_SSH2_MSG_CHANNEL_OPEN_FAILURE,
  3197.                                 $server_channel,
  3198.                                 NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED,
  3199.                                 ''// description
  3200.                                 '' // language tag
  3201.                             );
  3202.                             try {
  3203.                                 $this->send_binary_packet($packet);
  3204.                             } catch (\RuntimeException $e) {
  3205.                                 return $this->disconnect_helper(NET_SSH2_DISCONNECT_BY_APPLICATION);
  3206.                             }
  3207.                     }
  3208.                     $payload $this->get_binary_packet($skip_channel_filter);
  3209.                     break;
  3210.                 case NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST:
  3211.                     Strings::shift($payload1);
  3212.                     list($channel$window_size) = Strings::unpackSSH2('NN'$payload);
  3213.                     $this->window_size_client_to_server[$channel]+= $window_size;
  3214.                     $payload = ($this->bitmap self::MASK_WINDOW_ADJUST) ? true $this->get_binary_packet($skip_channel_filter);
  3215.             }
  3216.         }
  3217.         return $payload;
  3218.     }
  3219.     /**
  3220.      * Enable Quiet Mode
  3221.      *
  3222.      * Suppress stderr from output
  3223.      *
  3224.      * @access public
  3225.      */
  3226.     public function enableQuietMode()
  3227.     {
  3228.         $this->quiet_mode true;
  3229.     }
  3230.     /**
  3231.      * Disable Quiet Mode
  3232.      *
  3233.      * Show stderr in output
  3234.      *
  3235.      * @access public
  3236.      */
  3237.     public function disableQuietMode()
  3238.     {
  3239.         $this->quiet_mode false;
  3240.     }
  3241.     /**
  3242.      * Returns whether Quiet Mode is enabled or not
  3243.      *
  3244.      * @see self::enableQuietMode()
  3245.      * @see self::disableQuietMode()
  3246.      * @access public
  3247.      * @return bool
  3248.      */
  3249.     public function isQuietModeEnabled()
  3250.     {
  3251.         return $this->quiet_mode;
  3252.     }
  3253.     /**
  3254.      * Enable request-pty when using exec()
  3255.      *
  3256.      * @access public
  3257.      */
  3258.     public function enablePTY()
  3259.     {
  3260.         $this->request_pty true;
  3261.     }
  3262.     /**
  3263.      * Disable request-pty when using exec()
  3264.      *
  3265.      * @access public
  3266.      */
  3267.     public function disablePTY()
  3268.     {
  3269.         if ($this->in_request_pty_exec) {
  3270.             $this->close_channel(self::CHANNEL_EXEC);
  3271.             $this->in_request_pty_exec false;
  3272.         }
  3273.         $this->request_pty false;
  3274.     }
  3275.     /**
  3276.      * Returns whether request-pty is enabled or not
  3277.      *
  3278.      * @see self::enablePTY()
  3279.      * @see self::disablePTY()
  3280.      * @access public
  3281.      * @return bool
  3282.      */
  3283.     public function isPTYEnabled()
  3284.     {
  3285.         return $this->request_pty;
  3286.     }
  3287.     /**
  3288.      * Gets channel data
  3289.      *
  3290.      * Returns the data as a string if it's available and false if not.
  3291.      *
  3292.      * @param int $client_channel
  3293.      * @param bool $skip_extended
  3294.      * @return mixed
  3295.      * @throws \RuntimeException on connection error
  3296.      * @access private
  3297.      */
  3298.     protected function get_channel_packet($client_channel$skip_extended false)
  3299.     {
  3300.         if (!empty($this->channel_buffers[$client_channel])) {
  3301.             return array_shift($this->channel_buffers[$client_channel]);
  3302.         }
  3303.         while (true) {
  3304.             if ($this->binary_packet_buffer !== false) {
  3305.                 $response $this->binary_packet_buffer;
  3306.                 $this->binary_packet_buffer false;
  3307.             } else {
  3308.                 $response $this->get_binary_packet(true);
  3309.                 if ($response === true && $this->is_timeout) {
  3310.                     if ($client_channel == self::CHANNEL_EXEC && !$this->request_pty) {
  3311.                         $this->close_channel($client_channel);
  3312.                     }
  3313.                     return true;
  3314.                 }
  3315.                 if ($response === false) {
  3316.                     $this->disconnect_helper(NET_SSH2_DISCONNECT_CONNECTION_LOST);
  3317.                     throw new ConnectionClosedException('Connection closed by server');
  3318.                 }
  3319.             }
  3320.             if ($client_channel == -&& $response === true) {
  3321.                 return true;
  3322.             }
  3323.             list($type$channel) = Strings::unpackSSH2('CN'$response);
  3324.             // will not be setup yet on incoming channel open request
  3325.             if (isset($channel) && isset($this->channel_status[$channel]) && isset($this->window_size_server_to_client[$channel])) {
  3326.                 $this->window_size_server_to_client[$channel]-= strlen($response);
  3327.                 // resize the window, if appropriate
  3328.                 if ($this->window_size_server_to_client[$channel] < 0) {
  3329.                 // PuTTY does something more analogous to the following:
  3330.                 //if ($this->window_size_server_to_client[$channel] < 0x3FFFFFFF) {
  3331.                     $packet pack('CNN'NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST$this->server_channels[$channel], $this->window_resize);
  3332.                     $this->send_binary_packet($packet);
  3333.                     $this->window_size_server_to_client[$channel]+= $this->window_resize;
  3334.                 }
  3335.                 switch ($type) {
  3336.                     case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA:
  3337.                         /*
  3338.                         if ($client_channel == self::CHANNEL_EXEC) {
  3339.                             $this->send_channel_packet($client_channel, chr(0));
  3340.                         }
  3341.                         */
  3342.                         // currently, there's only one possible value for $data_type_code: NET_SSH2_EXTENDED_DATA_STDERR
  3343.                         list($data_type_code$data) = Strings::unpackSSH2('Ns'$response);
  3344.                         $this->stdErrorLog.= $data;
  3345.                         if ($skip_extended || $this->quiet_mode) {
  3346.                             continue 2;
  3347.                         }
  3348.                         if ($client_channel == $channel && $this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_DATA) {
  3349.                             return $data;
  3350.                         }
  3351.                         if (!isset($this->channel_buffers[$channel])) {
  3352.                             $this->channel_buffers[$channel] = [];
  3353.                         }
  3354.                         $this->channel_buffers[$channel][] = $data;
  3355.                         continue 2;
  3356.                     case NET_SSH2_MSG_CHANNEL_REQUEST:
  3357.                         if ($this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_CLOSE) {
  3358.                             continue 2;
  3359.                         }
  3360.                         list($value) = Strings::unpackSSH2('s'$response);
  3361.                         switch ($value) {
  3362.                             case 'exit-signal':
  3363.                                 list(
  3364.                                     , // FALSE
  3365.                                     $signal_name,
  3366.                                     , // core dumped
  3367.                                     $error_message
  3368.                                 ) = Strings::unpackSSH2('bsbs'$response);
  3369.                                 $this->errors[] = "SSH_MSG_CHANNEL_REQUEST (exit-signal): $signal_name";
  3370.                                 if (strlen($error_message)) {
  3371.                                     $this->errors[count($this->errors) - 1].= "\r\n$error_message";
  3372.                                 }
  3373.                                 $this->send_binary_packet(pack('CN'NET_SSH2_MSG_CHANNEL_EOF$this->server_channels[$client_channel]));
  3374.                                 $this->send_binary_packet(pack('CN'NET_SSH2_MSG_CHANNEL_CLOSE$this->server_channels[$channel]));
  3375.                                 $this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_EOF;
  3376.                                 continue 3;
  3377.                             case 'exit-status':
  3378.                                 list(, $this->exit_status) = Strings::unpackSSH2('CN'$response);
  3379.                                 // "The client MAY ignore these messages."
  3380.                                 // -- http://tools.ietf.org/html/rfc4254#section-6.10
  3381.                                 continue 3;
  3382.                             default:
  3383.                                 // "Some systems may not implement signals, in which case they SHOULD ignore this message."
  3384.                                 //  -- http://tools.ietf.org/html/rfc4254#section-6.9
  3385.                                 continue 3;
  3386.                         }
  3387.                 }
  3388.                 switch ($this->channel_status[$channel]) {
  3389.                     case NET_SSH2_MSG_CHANNEL_OPEN:
  3390.                         switch ($type) {
  3391.                             case NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION:
  3392.                                 list(
  3393.                                     $this->server_channels[$channel],
  3394.                                     $window_size,
  3395.                                     $this->packet_size_client_to_server[$channel]
  3396.                                 ) = Strings::unpackSSH2('NNN'$response);
  3397.                                 if ($window_size 0) {
  3398.                                     $window_size&= 0x7FFFFFFF;
  3399.                                     $window_size+= 0x80000000;
  3400.                                 }
  3401.                                 $this->window_size_client_to_server[$channel] = $window_size;
  3402.                                 $result $client_channel == $channel true $this->get_channel_packet($client_channel$skip_extended);
  3403.                                 $this->on_channel_open();
  3404.                                 return $result;
  3405.                             //case NET_SSH2_MSG_CHANNEL_OPEN_FAILURE:
  3406.                             default:
  3407.                                 $this->disconnect_helper(NET_SSH2_DISCONNECT_BY_APPLICATION);
  3408.                                 throw new \RuntimeException('Unable to open channel');
  3409.                         }
  3410.                         break;
  3411.                     case NET_SSH2_MSG_CHANNEL_REQUEST:
  3412.                         switch ($type) {
  3413.                             case NET_SSH2_MSG_CHANNEL_SUCCESS:
  3414.                                 return true;
  3415.                             case NET_SSH2_MSG_CHANNEL_FAILURE:
  3416.                                 return false;
  3417.                             default:
  3418.                                 $this->disconnect_helper(NET_SSH2_DISCONNECT_BY_APPLICATION);
  3419.                                 throw new \RuntimeException('Unable to fulfill channel request');
  3420.                         }
  3421.                     case NET_SSH2_MSG_CHANNEL_CLOSE:
  3422.                         return $type == NET_SSH2_MSG_CHANNEL_CLOSE true $this->get_channel_packet($client_channel$skip_extended);
  3423.                 }
  3424.             }
  3425.             // ie. $this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_DATA
  3426.             switch ($type) {
  3427.                 case NET_SSH2_MSG_CHANNEL_DATA:
  3428.                     /*
  3429.                     if ($channel == self::CHANNEL_EXEC) {
  3430.                         // SCP requires null packets, such as this, be sent.  further, in the case of the ssh.com SSH server
  3431.                         // this actually seems to make things twice as fast.  more to the point, the message right after
  3432.                         // SSH_MSG_CHANNEL_DATA (usually SSH_MSG_IGNORE) won't block for as long as it would have otherwise.
  3433.                         // in OpenSSH it slows things down but only by a couple thousandths of a second.
  3434.                         $this->send_channel_packet($channel, chr(0));
  3435.                     }
  3436.                     */
  3437.                     list($data) = Strings::unpackSSH2('s'$response);
  3438.                     if ($channel == self::CHANNEL_AGENT_FORWARD) {
  3439.                         $agent_response $this->agent->forwardData($data);
  3440.                         if (!is_bool($agent_response)) {
  3441.                             $this->send_channel_packet($channel$agent_response);
  3442.                         }
  3443.                         break;
  3444.                     }
  3445.                     if ($client_channel == $channel) {
  3446.                         return $data;
  3447.                     }
  3448.                     if (!isset($this->channel_buffers[$channel])) {
  3449.                         $this->channel_buffers[$channel] = [];
  3450.                     }
  3451.                     $this->channel_buffers[$channel][] = $data;
  3452.                     break;
  3453.                 case NET_SSH2_MSG_CHANNEL_CLOSE:
  3454.                     $this->curTimeout 5;
  3455.                     if ($this->bitmap self::MASK_SHELL) {
  3456.                         $this->bitmap&= ~self::MASK_SHELL;
  3457.                     }
  3458.                     if ($this->channel_status[$channel] != NET_SSH2_MSG_CHANNEL_EOF) {
  3459.                         $this->send_binary_packet(pack('CN'NET_SSH2_MSG_CHANNEL_CLOSE$this->server_channels[$channel]));
  3460.                     }
  3461.                     $this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_CLOSE;
  3462.                     if ($client_channel == $channel) {
  3463.                         return true;
  3464.                     }
  3465.                 case NET_SSH2_MSG_CHANNEL_EOF:
  3466.                     break;
  3467.                 default:
  3468.                     $this->disconnect_helper(NET_SSH2_DISCONNECT_BY_APPLICATION);
  3469.                     throw new \RuntimeException('Error reading channel data');
  3470.             }
  3471.         }
  3472.     }
  3473.     /**
  3474.      * Sends Binary Packets
  3475.      *
  3476.      * See '6. Binary Packet Protocol' of rfc4253 for more info.
  3477.      *
  3478.      * @param string $data
  3479.      * @param string $logged
  3480.      * @see self::_get_binary_packet()
  3481.      * @return bool
  3482.      * @access private
  3483.      */
  3484.     protected function send_binary_packet($data$logged null)
  3485.     {
  3486.         if (!is_resource($this->fsock) || feof($this->fsock)) {
  3487.             $this->bitmap 0;
  3488.             throw new ConnectionClosedException('Connection closed prematurely');
  3489.         }
  3490.         //if ($this->compress) {
  3491.         //    // the -4 removes the checksum:
  3492.         //    // http://php.net/function.gzcompress#57710
  3493.         //    $data = substr(gzcompress($data), 0, -4);
  3494.         //}
  3495.         // 4 (packet length) + 1 (padding length) + 4 (minimal padding amount) == 9
  3496.         $packet_length strlen($data) + 9;
  3497.         if ($this->encrypt && $this->encrypt->usesNonce()) {
  3498.             $packet_length-= 4;
  3499.         }
  3500.         // round up to the nearest $this->encrypt_block_size
  3501.         $packet_length+= (($this->encrypt_block_size 1) * $packet_length) % $this->encrypt_block_size;
  3502.         // subtracting strlen($data) is obvious - subtracting 5 is necessary because of packet_length and padding_length
  3503.         $padding_length $packet_length strlen($data) - 5;
  3504.         switch (true) {
  3505.             case $this->encrypt && $this->encrypt->usesNonce():
  3506.             case $this->hmac_create instanceof Hash && $this->hmac_create->etm:
  3507.                 $padding_length+= 4;
  3508.                 $packet_length+= 4;
  3509.         }
  3510.         $padding Random::string($padding_length);
  3511.         // we subtract 4 from packet_length because the packet_length field isn't supposed to include itself
  3512.         $packet pack('NCa*'$packet_length 4$padding_length$data $padding);
  3513.         $hmac '';
  3514.         if ($this->hmac_create instanceof Hash && !$this->hmac_create->etm) {
  3515.             if (($this->hmac_create->getHash() & "\xFF\xFF\xFF\xFF") == 'umac') {
  3516.                 $this->hmac_create->setNonce("\0\0\0\0" pack('N'$this->send_seq_no));
  3517.                 $hmac $this->hmac_create->hash($packet);
  3518.             } else {
  3519.                 $hmac $this->hmac_create->hash(pack('Na*'$this->send_seq_no$packet));
  3520.             }
  3521.         }
  3522.         if ($this->encrypt) {
  3523.             switch ($this->encrypt->name) {
  3524.                 case 'aes128-gcm@openssh.com':
  3525.                 case 'aes256-gcm@openssh.com':
  3526.                     $this->encrypt->setNonce(
  3527.                         $this->encrypt->fixed .
  3528.                         $this->encrypt->invocation_counter
  3529.                     );
  3530.                     Strings::increment_str($this->encrypt->invocation_counter);
  3531.                     $this->encrypt->setAAD($temp = ($packet "\xFF\xFF\xFF\xFF"));
  3532.                     $packet $temp $this->encrypt->encrypt(substr($packet4));
  3533.                     break;
  3534.                 case 'chacha20-poly1305@openssh.com':
  3535.                     $nonce pack('N2'0$this->send_seq_no);
  3536.                     $this->encrypt->setNonce($nonce);
  3537.                     $this->lengthEncrypt->setNonce($nonce);
  3538.                     $length $this->lengthEncrypt->encrypt($packet "\xFF\xFF\xFF\xFF");
  3539.                     $this->encrypt->setCounter(0);
  3540.                     // this is the same approach that's implemented in Salsa20::createPoly1305Key()
  3541.                     // but we don't want to use the same AEAD construction that RFC8439 describes
  3542.                     // for ChaCha20-Poly1305 so we won't rely on it (see Salsa20::poly1305())
  3543.                     $this->encrypt->setPoly1305Key(
  3544.                         $this->encrypt->encrypt(str_repeat("\0"32))
  3545.                     );
  3546.                     $this->encrypt->setAAD($length);
  3547.                     $this->encrypt->setCounter(1);
  3548.                     $packet $length $this->encrypt->encrypt(substr($packet4));
  3549.                     break;
  3550.                 default:
  3551.                     $packet $this->hmac_create instanceof Hash && $this->hmac_create->etm ?
  3552.                         ($packet "\xFF\xFF\xFF\xFF") . $this->encrypt->encrypt(substr($packet4)) :
  3553.                         $this->encrypt->encrypt($packet);
  3554.             }
  3555.         }
  3556.         if ($this->hmac_create instanceof Hash && $this->hmac_create->etm) {
  3557.             if (($this->hmac_create->getHash() & "\xFF\xFF\xFF\xFF") == 'umac') {
  3558.                 $this->hmac_create->setNonce("\0\0\0\0" pack('N'$this->send_seq_no));
  3559.                 $hmac $this->hmac_create->hash($packet);
  3560.             } else {
  3561.                 $hmac $this->hmac_create->hash(pack('Na*'$this->send_seq_no$packet));
  3562.             }
  3563.         }
  3564.         $this->send_seq_no++;
  3565.         $packet.= $this->encrypt && $this->encrypt->usesNonce() ? $this->encrypt->getTag() : $hmac;
  3566.         $start microtime(true);
  3567.         $sent = @fputs($this->fsock$packet);
  3568.         $stop microtime(true);
  3569.         if (defined('NET_SSH2_LOGGING')) {
  3570.             $current microtime(true);
  3571.             $message_number = isset($this->message_numbers[ord($data[0])]) ? $this->message_numbers[ord($data[0])] : 'UNKNOWN (' ord($data[0]) . ')';
  3572.             $message_number '-> ' $message_number .
  3573.                               ' (since last: ' round($current $this->last_packet4) . ', network: ' round($stop $start4) . 's)';
  3574.             $this->append_log($message_number, isset($logged) ? $logged $data);
  3575.             $this->last_packet $current;
  3576.         }
  3577.         if (strlen($packet) != $sent) {
  3578.             $this->bitmap 0;
  3579.             throw new \RuntimeException("Only $sent of " strlen($packet) . " bytes were sent");
  3580.         }
  3581.     }
  3582.     /**
  3583.      * Logs data packets
  3584.      *
  3585.      * Makes sure that only the last 1MB worth of packets will be logged
  3586.      *
  3587.      * @param string $message_number
  3588.      * @param string $message
  3589.      * @access private
  3590.      */
  3591.     private function append_log($message_number$message)
  3592.     {
  3593.         // remove the byte identifying the message type from all but the first two messages (ie. the identification strings)
  3594.         if (strlen($message_number) > 2) {
  3595.             Strings::shift($message);
  3596.         }
  3597.         switch (NET_SSH2_LOGGING) {
  3598.             // useful for benchmarks
  3599.             case self::LOG_SIMPLE:
  3600.                 $this->message_number_log[] = $message_number;
  3601.                 break;
  3602.             // the most useful log for SSH2
  3603.             case self::LOG_COMPLEX:
  3604.                 $this->message_number_log[] = $message_number;
  3605.                 $this->log_size+= strlen($message);
  3606.                 $this->message_log[] = $message;
  3607.                 while ($this->log_size self::LOG_MAX_SIZE) {
  3608.                     $this->log_size-= strlen(array_shift($this->message_log));
  3609.                     array_shift($this->message_number_log);
  3610.                 }
  3611.                 break;
  3612.             // dump the output out realtime; packets may be interspersed with non packets,
  3613.             // passwords won't be filtered out and select other packets may not be correctly
  3614.             // identified
  3615.             case self::LOG_REALTIME:
  3616.                 switch (PHP_SAPI) {
  3617.                     case 'cli':
  3618.                         $start $stop "\r\n";
  3619.                         break;
  3620.                     default:
  3621.                         $start '<pre>';
  3622.                         $stop '</pre>';
  3623.                 }
  3624.                 echo $start $this->format_log([$message], [$message_number]) . $stop;
  3625.                 @flush();
  3626.                 @ob_flush();
  3627.                 break;
  3628.             // basically the same thing as self::LOG_REALTIME with the caveat that NET_SSH2_LOG_REALTIME_FILENAME
  3629.             // needs to be defined and that the resultant log file will be capped out at self::LOG_MAX_SIZE.
  3630.             // the earliest part of the log file is denoted by the first <<< START >>> and is not going to necessarily
  3631.             // at the beginning of the file
  3632.             case self::LOG_REALTIME_FILE:
  3633.                 if (!isset($this->realtime_log_file)) {
  3634.                     // PHP doesn't seem to like using constants in fopen()
  3635.                     $filename NET_SSH2_LOG_REALTIME_FILENAME;
  3636.                     $fp fopen($filename'w');
  3637.                     $this->realtime_log_file $fp;
  3638.                 }
  3639.                 if (!is_resource($this->realtime_log_file)) {
  3640.                     break;
  3641.                 }
  3642.                 $entry $this->format_log([$message], [$message_number]);
  3643.                 if ($this->realtime_log_wrap) {
  3644.                     $temp "<<< START >>>\r\n";
  3645.                     $entry.= $temp;
  3646.                     fseek($this->realtime_log_fileftell($this->realtime_log_file) - strlen($temp));
  3647.                 }
  3648.                 $this->realtime_log_size+= strlen($entry);
  3649.                 if ($this->realtime_log_size self::LOG_MAX_SIZE) {
  3650.                     fseek($this->realtime_log_file0);
  3651.                     $this->realtime_log_size strlen($entry);
  3652.                     $this->realtime_log_wrap true;
  3653.                 }
  3654.                 fputs($this->realtime_log_file$entry);
  3655.         }
  3656.     }
  3657.     /**
  3658.      * Sends channel data
  3659.      *
  3660.      * Spans multiple SSH_MSG_CHANNEL_DATAs if appropriate
  3661.      *
  3662.      * @param int $client_channel
  3663.      * @param string $data
  3664.      * @return bool
  3665.      * @access private
  3666.      */
  3667.     protected function send_channel_packet($client_channel$data)
  3668.     {
  3669.         while (strlen($data)) {
  3670.             if (!$this->window_size_client_to_server[$client_channel]) {
  3671.                 $this->bitmap^= self::MASK_WINDOW_ADJUST;
  3672.                 // using an invalid channel will let the buffers be built up for the valid channels
  3673.                 $this->get_channel_packet(-1);
  3674.                 $this->bitmap^= self::MASK_WINDOW_ADJUST;
  3675.             }
  3676.             /* The maximum amount of data allowed is determined by the maximum
  3677.                packet size for the channel, and the current window size, whichever
  3678.                is smaller.
  3679.                  -- http://tools.ietf.org/html/rfc4254#section-5.2 */
  3680.             $max_size min(
  3681.                 $this->packet_size_client_to_server[$client_channel],
  3682.                 $this->window_size_client_to_server[$client_channel]
  3683.             );
  3684.             $temp Strings::shift($data$max_size);
  3685.             $packet Strings::packSSH2(
  3686.                 'CNs',
  3687.                 NET_SSH2_MSG_CHANNEL_DATA,
  3688.                 $this->server_channels[$client_channel],
  3689.                 $temp
  3690.             );
  3691.             $this->window_size_client_to_server[$client_channel]-= strlen($temp);
  3692.             $this->send_binary_packet($packet);
  3693.         }
  3694.         return true;
  3695.     }
  3696.     /**
  3697.      * Closes and flushes a channel
  3698.      *
  3699.      * \phpseclib3\Net\SSH2 doesn't properly close most channels.  For exec() channels are normally closed by the server
  3700.      * and for SFTP channels are presumably closed when the client disconnects.  This functions is intended
  3701.      * for SCP more than anything.
  3702.      *
  3703.      * @param int $client_channel
  3704.      * @param bool $want_reply
  3705.      * @return bool
  3706.      * @access private
  3707.      */
  3708.     private function close_channel($client_channel$want_reply false)
  3709.     {
  3710.         // see http://tools.ietf.org/html/rfc4254#section-5.3
  3711.         $this->send_binary_packet(pack('CN'NET_SSH2_MSG_CHANNEL_EOF$this->server_channels[$client_channel]));
  3712.         if (!$want_reply) {
  3713.             $this->send_binary_packet(pack('CN'NET_SSH2_MSG_CHANNEL_CLOSE$this->server_channels[$client_channel]));
  3714.         }
  3715.         $this->channel_status[$client_channel] = NET_SSH2_MSG_CHANNEL_CLOSE;
  3716.         $this->curTimeout 5;
  3717.         while (!is_bool($this->get_channel_packet($client_channel))) {
  3718.         }
  3719.         if ($this->is_timeout) {
  3720.             $this->disconnect();
  3721.         }
  3722.         if ($want_reply) {
  3723.             $this->send_binary_packet(pack('CN'NET_SSH2_MSG_CHANNEL_CLOSE$this->server_channels[$client_channel]));
  3724.         }
  3725.         if ($this->bitmap self::MASK_SHELL) {
  3726.             $this->bitmap&= ~self::MASK_SHELL;
  3727.         }
  3728.     }
  3729.     /**
  3730.      * Disconnect
  3731.      *
  3732.      * @param int $reason
  3733.      * @return bool
  3734.      * @access protected
  3735.      */
  3736.     protected function disconnect_helper($reason)
  3737.     {
  3738.         if ($this->bitmap self::MASK_CONNECTED) {
  3739.             $data Strings::packSSH2('CNss'NET_SSH2_MSG_DISCONNECT$reason'''');
  3740.             try {
  3741.                 $this->send_binary_packet($data);
  3742.             } catch (\Exception $e) {
  3743.             }
  3744.         }
  3745.         $this->bitmap 0;
  3746.         if (is_resource($this->fsock) && get_resource_type($this->fsock) == 'stream') {
  3747.             fclose($this->fsock);
  3748.         }
  3749.         return false;
  3750.     }
  3751.     /**
  3752.      * Define Array
  3753.      *
  3754.      * Takes any number of arrays whose indices are integers and whose values are strings and defines a bunch of
  3755.      * named constants from it, using the value as the name of the constant and the index as the value of the constant.
  3756.      * If any of the constants that would be defined already exists, none of the constants will be defined.
  3757.      *
  3758.      * @param mixed[] ...$args
  3759.      * @access protected
  3760.      */
  3761.     protected function define_array(...$args)
  3762.     {
  3763.         foreach ($args as $arg) {
  3764.             foreach ($arg as $key => $value) {
  3765.                 if (!defined($value)) {
  3766.                     define($value$key);
  3767.                 } else {
  3768.                     break 2;
  3769.                 }
  3770.             }
  3771.         }
  3772.     }
  3773.     /**
  3774.      * Returns a log of the packets that have been sent and received.
  3775.      *
  3776.      * Returns a string if NET_SSH2_LOGGING == self::LOG_COMPLEX, an array if NET_SSH2_LOGGING == self::LOG_SIMPLE and false if !defined('NET_SSH2_LOGGING')
  3777.      *
  3778.      * @access public
  3779.      * @return array|false|string
  3780.      */
  3781.     public function getLog()
  3782.     {
  3783.         if (!defined('NET_SSH2_LOGGING')) {
  3784.             return false;
  3785.         }
  3786.         switch (NET_SSH2_LOGGING) {
  3787.             case self::LOG_SIMPLE:
  3788.                 return $this->message_number_log;
  3789.             case self::LOG_COMPLEX:
  3790.                 $log $this->format_log($this->message_log$this->message_number_log);
  3791.                 return PHP_SAPI == 'cli' $log '<pre>' $log '</pre>';
  3792.             default:
  3793.                 return false;
  3794.         }
  3795.     }
  3796.     /**
  3797.      * Formats a log for printing
  3798.      *
  3799.      * @param array $message_log
  3800.      * @param array $message_number_log
  3801.      * @access private
  3802.      * @return string
  3803.      */
  3804.     protected function format_log($message_log$message_number_log)
  3805.     {
  3806.         $output '';
  3807.         for ($i 0$i count($message_log); $i++) {
  3808.             $output.= $message_number_log[$i] . "\r\n";
  3809.             $current_log $message_log[$i];
  3810.             $j 0;
  3811.             do {
  3812.                 if (strlen($current_log)) {
  3813.                     $output.= str_pad(dechex($j), 7'0'STR_PAD_LEFT) . '0  ';
  3814.                 }
  3815.                 $fragment Strings::shift($current_log$this->log_short_width);
  3816.                 $hex substr(preg_replace_callback('#.#s', function ($matches) {
  3817.                     return $this->log_boundary str_pad(dechex(ord($matches[0])), 2'0'STR_PAD_LEFT);
  3818.                 }, $fragment), strlen($this->log_boundary));
  3819.                 // replace non ASCII printable characters with dots
  3820.                 // http://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters
  3821.                 // also replace < with a . since < messes up the output on web browsers
  3822.                 $raw preg_replace('#[^\x20-\x7E]|<#''.'$fragment);
  3823.                 $output.= str_pad($hex$this->log_long_width $this->log_short_width' ') . $raw "\r\n";
  3824.                 $j++;
  3825.             } while (strlen($current_log));
  3826.             $output.= "\r\n";
  3827.         }
  3828.         return $output;
  3829.     }
  3830.     /**
  3831.      * Helper function for agent->on_channel_open()
  3832.      *
  3833.      * Used when channels are created to inform agent
  3834.      * of said channel opening. Must be called after
  3835.      * channel open confirmation received
  3836.      *
  3837.      * @access private
  3838.      */
  3839.     private function on_channel_open()
  3840.     {
  3841.         if (isset($this->agent)) {
  3842.             $this->agent->registerChannelOpen($this);
  3843.         }
  3844.     }
  3845.     /**
  3846.      * Returns the first value of the intersection of two arrays or false if
  3847.      * the intersection is empty. The order is defined by the first parameter.
  3848.      *
  3849.      * @param array $array1
  3850.      * @param array $array2
  3851.      * @return mixed False if intersection is empty, else intersected value.
  3852.      * @access private
  3853.      */
  3854.     private static function array_intersect_first($array1$array2)
  3855.     {
  3856.         foreach ($array1 as $value) {
  3857.             if (in_array($value$array2)) {
  3858.                 return $value;
  3859.             }
  3860.         }
  3861.         return false;
  3862.     }
  3863.     /**
  3864.      * Returns all errors
  3865.      *
  3866.      * @return string[]
  3867.      * @access public
  3868.      */
  3869.     public function getErrors()
  3870.     {
  3871.         return $this->errors;
  3872.     }
  3873.     /**
  3874.      * Returns the last error
  3875.      *
  3876.      * @return string
  3877.      * @access public
  3878.      */
  3879.     public function getLastError()
  3880.     {
  3881.         $count count($this->errors);
  3882.         if ($count 0) {
  3883.             return $this->errors[$count 1];
  3884.         }
  3885.     }
  3886.     /**
  3887.      * Return the server identification.
  3888.      *
  3889.      * @return string
  3890.      * @access public
  3891.      */
  3892.     public function getServerIdentification()
  3893.     {
  3894.         $this->connect();
  3895.         return $this->server_identifier;
  3896.     }
  3897.     /**
  3898.      * Returns a list of algorithms the server supports
  3899.      *
  3900.      * @return array
  3901.      * @access public
  3902.      */
  3903.     public function getServerAlgorithms()
  3904.     {
  3905.         $this->connect();
  3906.         return [
  3907.             'kex' => $this->kex_algorithms,
  3908.             'hostkey' => $this->server_host_key_algorithms,
  3909.             'client_to_server' => [
  3910.                 'crypt' => $this->encryption_algorithms_client_to_server,
  3911.                 'mac' => $this->mac_algorithms_client_to_server,
  3912.                 'comp' => $this->compression_algorithms_client_to_server,
  3913.                 'lang' => $this->languages_client_to_server
  3914.             ],
  3915.             'server_to_client' => [
  3916.                 'crypt' => $this->encryption_algorithms_server_to_client,
  3917.                 'mac' => $this->mac_algorithms_server_to_client,
  3918.                 'comp' => $this->compression_algorithms_server_to_client,
  3919.                 'lang' => $this->languages_server_to_client
  3920.             ]
  3921.         ];
  3922.     }
  3923.     /**
  3924.      * Returns a list of KEX algorithms that phpseclib supports
  3925.      *
  3926.      * @return array
  3927.      * @access public
  3928.      */
  3929.     public static function getSupportedKEXAlgorithms()
  3930.     {
  3931.         $kex_algorithms = [
  3932.             // Elliptic Curve Diffie-Hellman Key Agreement (ECDH) using
  3933.             // Curve25519. See doc/curve25519-sha256@libssh.org.txt in the
  3934.             // libssh repository for more information.
  3935.             'curve25519-sha256',
  3936.             'curve25519-sha256@libssh.org',
  3937.             'ecdh-sha2-nistp256'// RFC 5656
  3938.             'ecdh-sha2-nistp384'// RFC 5656
  3939.             'ecdh-sha2-nistp521'// RFC 5656
  3940.             'diffie-hellman-group-exchange-sha256',// RFC 4419
  3941.             'diffie-hellman-group-exchange-sha1',  // RFC 4419
  3942.             // Diffie-Hellman Key Agreement (DH) using integer modulo prime
  3943.             // groups.
  3944.             'diffie-hellman-group14-sha256',
  3945.             'diffie-hellman-group14-sha1'// REQUIRED
  3946.             'diffie-hellman-group15-sha512',
  3947.             'diffie-hellman-group16-sha512',
  3948.             'diffie-hellman-group17-sha512',
  3949.             'diffie-hellman-group18-sha512',
  3950.             'diffie-hellman-group1-sha1'// REQUIRED
  3951.         ];
  3952.         return $kex_algorithms;
  3953.     }
  3954.     /**
  3955.      * Returns a list of host key algorithms that phpseclib supports
  3956.      *
  3957.      * @return array
  3958.      * @access public
  3959.      */
  3960.     public static function getSupportedHostKeyAlgorithms()
  3961.     {
  3962.         return [
  3963.             'ssh-ed25519'// https://tools.ietf.org/html/draft-ietf-curdle-ssh-ed25519-02
  3964.             'ecdsa-sha2-nistp256'// RFC 5656
  3965.             'ecdsa-sha2-nistp384'// RFC 5656
  3966.             'ecdsa-sha2-nistp521'// RFC 5656
  3967.             'rsa-sha2-256'// RFC 8332
  3968.             'rsa-sha2-512'// RFC 8332
  3969.             'ssh-rsa'// RECOMMENDED  sign   Raw RSA Key
  3970.             'ssh-dss'  // REQUIRED     sign   Raw DSS Key
  3971.         ];
  3972.     }
  3973.     /**
  3974.      * Returns a list of symmetric key algorithms that phpseclib supports
  3975.      *
  3976.      * @return array
  3977.      * @access public
  3978.      */
  3979.     public static function getSupportedEncryptionAlgorithms()
  3980.     {
  3981.         $algos = [
  3982.             // from <https://tools.ietf.org/html/rfc5647>:
  3983.             'aes128-gcm@openssh.com',
  3984.             'aes256-gcm@openssh.com',
  3985.             // from <http://tools.ietf.org/html/rfc4345#section-4>:
  3986.             'arcfour256',
  3987.             'arcfour128',
  3988.             //'arcfour',      // OPTIONAL          the ARCFOUR stream cipher with a 128-bit key
  3989.             // CTR modes from <http://tools.ietf.org/html/rfc4344#section-4>:
  3990.             'aes128-ctr',     // RECOMMENDED       AES (Rijndael) in SDCTR mode, with 128-bit key
  3991.             'aes192-ctr',     // RECOMMENDED       AES with 192-bit key
  3992.             'aes256-ctr',     // RECOMMENDED       AES with 256-bit key
  3993.             // from <https://git.io/fhxOl>:
  3994.             // one of the big benefits of chacha20-poly1305 is speed. the problem is...
  3995.             // libsodium doesn't generate the poly1305 keys in the way ssh does and openssl's PHP bindings don't even
  3996.             // seem to support poly1305 currently. so even if libsodium or openssl are being used for the chacha20
  3997.             // part, pure-PHP has to be used for the poly1305 part and that's gonna cause a big slow down.
  3998.             // speed-wise it winds up being faster to use AES (when openssl or mcrypt are available) and some HMAC
  3999.             // (which is always gonna be super fast to compute thanks to the hash extension, which
  4000.             // "is bundled and compiled into PHP by default")
  4001.             'chacha20-poly1305@openssh.com',
  4002.             'twofish128-ctr'// OPTIONAL          Twofish in SDCTR mode, with 128-bit key
  4003.             'twofish192-ctr'// OPTIONAL          Twofish with 192-bit key
  4004.             'twofish256-ctr'// OPTIONAL          Twofish with 256-bit key
  4005.             'aes128-cbc',     // RECOMMENDED       AES with a 128-bit key
  4006.             'aes192-cbc',     // OPTIONAL          AES with a 192-bit key
  4007.             'aes256-cbc',     // OPTIONAL          AES in CBC mode, with a 256-bit key
  4008.             'twofish128-cbc'// OPTIONAL          Twofish with a 128-bit key
  4009.             'twofish192-cbc'// OPTIONAL          Twofish with a 192-bit key
  4010.             'twofish256-cbc',
  4011.             'twofish-cbc',    // OPTIONAL          alias for "twofish256-cbc"
  4012.                               //                   (this is being retained for historical reasons)
  4013.             'blowfish-ctr',   // OPTIONAL          Blowfish in SDCTR mode
  4014.             'blowfish-cbc',   // OPTIONAL          Blowfish in CBC mode
  4015.             '3des-ctr',       // RECOMMENDED       Three-key 3DES in SDCTR mode
  4016.             '3des-cbc',       // REQUIRED          three-key 3DES in CBC mode
  4017.              //'none'           // OPTIONAL          no encryption; NOT RECOMMENDED
  4018.         ];
  4019.         if (self::$crypto_engine) {
  4020.             $engines = [self::$crypto_engine];
  4021.         } else {
  4022.             $engines = [
  4023.                 'libsodium',
  4024.                 'OpenSSL (GCM)',
  4025.                 'OpenSSL',
  4026.                 'mcrypt',
  4027.                 'Eval',
  4028.                 'PHP'
  4029.                 ];
  4030.         }
  4031.         $ciphers = [];
  4032.         foreach ($engines as $engine) {
  4033.             foreach ($algos as $algo) {
  4034.                 $obj self::encryption_algorithm_to_crypt_instance($algo);
  4035.                 if ($obj instanceof Rijndael ) {
  4036.                     $obj->setKeyLength(preg_replace('#[^\d]#'''$algo));
  4037.                 }
  4038.                 switch ($algo) {
  4039.                     case 'chacha20-poly1305@openssh.com':
  4040.                     case 'arcfour128':
  4041.                     case 'arcfour256':
  4042.                         if ($engine != 'Eval') {
  4043.                             continue 2;
  4044.                         }
  4045.                         break;
  4046.                     case 'aes128-gcm@openssh.com':
  4047.                     case 'aes256-gcm@openssh.com':
  4048.                         if ($engine == 'OpenSSL') {
  4049.                             continue 2;
  4050.                         }
  4051.                         $obj->setNonce('dummydummydu');
  4052.                 }
  4053.                 if ($obj->isValidEngine($engine)) {
  4054.                     $algos array_diff($algos, [$algo]);
  4055.                     $ciphers[] = $algo;
  4056.                 }
  4057.             }
  4058.         }
  4059.         return $ciphers;
  4060.     }
  4061.     /**
  4062.      * Returns a list of MAC algorithms that phpseclib supports
  4063.      *
  4064.      * @return array
  4065.      * @access public
  4066.      */
  4067.     public static function getSupportedMACAlgorithms()
  4068.     {
  4069.         return [
  4070.             'hmac-sha2-256-etm@openssh.com',
  4071.             'hmac-sha2-512-etm@openssh.com',
  4072.             'umac-64-etm@openssh.com',
  4073.             'umac-128-etm@openssh.com',
  4074.             'hmac-sha1-etm@openssh.com',
  4075.             // from <http://www.ietf.org/rfc/rfc6668.txt>:
  4076.             'hmac-sha2-256',// RECOMMENDED     HMAC-SHA256 (digest length = key length = 32)
  4077.             'hmac-sha2-512',// OPTIONAL        HMAC-SHA512 (digest length = key length = 64)
  4078.             // from <https://tools.ietf.org/html/draft-miller-secsh-umac-01>:
  4079.             'umac-64@openssh.com',
  4080.             'umac-128@openssh.com',
  4081.             'hmac-sha1-96'// RECOMMENDED     first 96 bits of HMAC-SHA1 (digest length = 12, key length = 20)
  4082.             'hmac-sha1',    // REQUIRED        HMAC-SHA1 (digest length = key length = 20)
  4083.             'hmac-md5-96',  // OPTIONAL        first 96 bits of HMAC-MD5 (digest length = 12, key length = 16)
  4084.             'hmac-md5',     // OPTIONAL        HMAC-MD5 (digest length = key length = 16)
  4085.             //'none'          // OPTIONAL        no MAC; NOT RECOMMENDED
  4086.         ];
  4087.     }
  4088.     /**
  4089.      * Returns a list of compression algorithms that phpseclib supports
  4090.      *
  4091.      * @return array
  4092.      * @access public
  4093.      */
  4094.     public static function getSupportedCompressionAlgorithms()
  4095.     {
  4096.         return [
  4097.             'none'   // REQUIRED        no compression
  4098.             //'zlib' // OPTIONAL        ZLIB (LZ77) compression
  4099.         ];
  4100.     }
  4101.     /**
  4102.      * Return list of negotiated algorithms
  4103.      *
  4104.      * Uses the same format as https://www.php.net/ssh2-methods-negotiated
  4105.      *
  4106.      * @return array
  4107.      * @access public
  4108.      */
  4109.     public function getAlgorithmsNegotiated()
  4110.     {
  4111.         $this->connect();
  4112.         return [
  4113.             'kex' => $this->kex_algorithm,
  4114.             'hostkey' => $this->signature_format,
  4115.             'client_to_server' => [
  4116.                 'crypt' => $this->encrypt->name,
  4117.                 'mac' => $this->hmac_create->name,
  4118.                 'comp' => 'none',
  4119.             ],
  4120.             'server_to_client' => [
  4121.                 'crypt' => $this->decrypt->name,
  4122.                 'mac' => $this->hmac_check->name,
  4123.                 'comp' => 'none',
  4124.             ]
  4125.         ];
  4126.     }
  4127.     /**
  4128.      * Accepts an associative array with up to four parameters as described at
  4129.      * <https://www.php.net/manual/en/function.ssh2-connect.php>
  4130.      *
  4131.      * @param array $methods
  4132.      * @access public
  4133.      */
  4134.     public function setPreferredAlgorithms(array $methods)
  4135.     {
  4136.         $preferred $methods;
  4137.         if (isset($preferred['kex'])) {
  4138.             $preferred['kex'] = array_intersect(
  4139.                 $preferred['kex'],
  4140.                 static::getSupportedKEXAlgorithms()
  4141.             );
  4142.         }
  4143.         if (isset($preferred['hostkey'])) {
  4144.             $preferred['hostkey'] = array_intersect(
  4145.                 $preferred['hostkey'],
  4146.                 static::getSupportedHostKeyAlgorithms()
  4147.             );
  4148.         }
  4149.         $keys = ['client_to_server''server_to_client'];
  4150.         foreach ($keys as $key) {
  4151.             if (isset($preferred[$key])) {
  4152.                 $a = &$preferred[$key];
  4153.                 if (isset($a['crypt'])) {
  4154.                     $a['crypt'] = array_intersect(
  4155.                         $a['crypt'],
  4156.                         static::getSupportedEncryptionAlgorithms()
  4157.                     );
  4158.                 }
  4159.                 if (isset($a['comp'])) {
  4160.                     $a['comp'] = array_intersect(
  4161.                         $a['comp'],
  4162.                         static::getSupportedCompressionAlgorithms()
  4163.                     );
  4164.                 }
  4165.                 if (isset($a['mac'])) {
  4166.                     $a['mac'] = array_intersect(
  4167.                         $a['mac'],
  4168.                         static::getSupportedMACAlgorithms()
  4169.                     );
  4170.                 }
  4171.             }
  4172.         }
  4173.         $keys = [
  4174.             'kex',
  4175.             'hostkey',
  4176.             'client_to_server/crypt',
  4177.             'client_to_server/comp',
  4178.             'client_to_server/mac',
  4179.             'server_to_client/crypt',
  4180.             'server_to_client/comp',
  4181.             'server_to_client/mac',
  4182.         ];
  4183.         foreach ($keys as $key) {
  4184.             $p $preferred;
  4185.             $m $methods;
  4186.             $subkeys explode('/'$key);
  4187.             foreach ($subkeys as $subkey) {
  4188.                 if (!isset($p[$subkey])) {
  4189.                     continue 2;
  4190.                 }
  4191.                 $p $p[$subkey];
  4192.                 $m $m[$subkey];
  4193.             }
  4194.             if (count($p) != count($m)) {
  4195.                 $diff array_diff($m$p);
  4196.                 $msg count($diff) == ?
  4197.                     ' is not a supported algorithm' :
  4198.                     ' are not supported algorithms';
  4199.                 throw new UnsupportedAlgorithmException(implode(', '$diff) . $msg);
  4200.             }
  4201.         }
  4202.         $this->preferred $preferred;
  4203.     }
  4204.     /**
  4205.      * Returns the banner message.
  4206.      *
  4207.      * Quoting from the RFC, "in some jurisdictions, sending a warning message before
  4208.      * authentication may be relevant for getting legal protection."
  4209.      *
  4210.      * @return string
  4211.      * @access public
  4212.      */
  4213.     public function getBannerMessage()
  4214.     {
  4215.         return $this->banner_message;
  4216.     }
  4217.     /**
  4218.      * Returns the server public host key.
  4219.      *
  4220.      * Caching this the first time you connect to a server and checking the result on subsequent connections
  4221.      * is recommended.  Returns false if the server signature is not signed correctly with the public host key.
  4222.      *
  4223.      * @return mixed
  4224.      * @throws \RuntimeException on badly formatted keys
  4225.      * @throws \phpseclib3\Exception\NoSupportedAlgorithmsException when the key isn't in a supported format
  4226.      * @access public
  4227.      */
  4228.     public function getServerPublicHostKey()
  4229.     {
  4230.         if (!($this->bitmap self::MASK_CONSTRUCTOR)) {
  4231.             if (!$this->connect()) {
  4232.                 return false;
  4233.             }
  4234.         }
  4235.         $signature $this->signature;
  4236.         $server_public_host_key base64_encode($this->server_public_host_key);
  4237.         if ($this->signature_validated) {
  4238.             return $this->bitmap ?
  4239.                 $this->signature_format ' ' $server_public_host_key :
  4240.                 false;
  4241.         }
  4242.         $this->signature_validated true;
  4243.         switch ($this->signature_format) {
  4244.             case 'ssh-ed25519':
  4245.             case 'ecdsa-sha2-nistp256':
  4246.             case 'ecdsa-sha2-nistp384':
  4247.             case 'ecdsa-sha2-nistp521':
  4248.                 $key EC::loadFormat('OpenSSH'$server_public_host_key)
  4249.                     ->withSignatureFormat('SSH2');
  4250.                 switch ($this->signature_format) {
  4251.                     case 'ssh-ed25519':
  4252.                         $hash 'sha512';
  4253.                         break;
  4254.                     case 'ecdsa-sha2-nistp256':
  4255.                         $hash 'sha256';
  4256.                         break;
  4257.                     case 'ecdsa-sha2-nistp384':
  4258.                         $hash 'sha384';
  4259.                         break;
  4260.                     case 'ecdsa-sha2-nistp521':
  4261.                         $hash 'sha512';
  4262.                 }
  4263.                 $key $key->withHash($hash);
  4264.                 break;
  4265.             case 'ssh-dss':
  4266.                 $key DSA::loadFormat('OpenSSH'$server_public_host_key)
  4267.                     ->withSignatureFormat('SSH2')
  4268.                     ->withHash('sha1');
  4269.                 break;
  4270.             case 'ssh-rsa':
  4271.             case 'rsa-sha2-256':
  4272.             case 'rsa-sha2-512':
  4273.                 if (strlen($signature) < 15) {
  4274.                     return false;
  4275.                 }
  4276.                 Strings::shift($signature11);
  4277.                 $temp unpack('Nlength'Strings::shift($signature4));
  4278.                 $signature Strings::shift($signature$temp['length']);
  4279.                 $key RSA::loadFormat('OpenSSH'$server_public_host_key)
  4280.                     ->withPadding(RSA::SIGNATURE_PKCS1);
  4281.                 switch ($this->signature_format) {
  4282.                     case 'rsa-sha2-512':
  4283.                         $hash 'sha512';
  4284.                         break;
  4285.                     case 'rsa-sha2-256':
  4286.                         $hash 'sha256';
  4287.                         break;
  4288.                     //case 'ssh-rsa':
  4289.                     default:
  4290.                         $hash 'sha1';
  4291.                 }
  4292.                 $key $key->withHash($hash);
  4293.                 break;
  4294.             default:
  4295.                 $this->disconnect_helper(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
  4296.                 throw new NoSupportedAlgorithmsException('Unsupported signature format');
  4297.         }
  4298.         if (!$key->verify($this->exchange_hash$signature)) {
  4299.             return $this->disconnect_helper(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
  4300.         };
  4301.         return $this->signature_format ' ' $server_public_host_key;
  4302.     }
  4303.     /**
  4304.      * Returns the exit status of an SSH command or false.
  4305.      *
  4306.      * @return false|int
  4307.      * @access public
  4308.      */
  4309.     public function getExitStatus()
  4310.     {
  4311.         if (is_null($this->exit_status)) {
  4312.             return false;
  4313.         }
  4314.         return $this->exit_status;
  4315.     }
  4316.     /**
  4317.      * Returns the number of columns for the terminal window size.
  4318.      *
  4319.      * @return int
  4320.      * @access public
  4321.      */
  4322.     public function getWindowColumns()
  4323.     {
  4324.         return $this->windowColumns;
  4325.     }
  4326.     /**
  4327.      * Returns the number of rows for the terminal window size.
  4328.      *
  4329.      * @return int
  4330.      * @access public
  4331.      */
  4332.     public function getWindowRows()
  4333.     {
  4334.         return $this->windowRows;
  4335.     }
  4336.     /**
  4337.      * Sets the number of columns for the terminal window size.
  4338.      *
  4339.      * @param int $value
  4340.      * @access public
  4341.      */
  4342.     public function setWindowColumns($value)
  4343.     {
  4344.         $this->windowColumns $value;
  4345.     }
  4346.     /**
  4347.      * Sets the number of rows for the terminal window size.
  4348.      *
  4349.      * @param int $value
  4350.      * @access public
  4351.      */
  4352.     public function setWindowRows($value)
  4353.     {
  4354.         $this->windowRows $value;
  4355.     }
  4356.     /**
  4357.      * Sets the number of columns and rows for the terminal window size.
  4358.      *
  4359.      * @param int $columns
  4360.      * @param int $rows
  4361.      * @access public
  4362.      */
  4363.     public function setWindowSize($columns 80$rows 24)
  4364.     {
  4365.         $this->windowColumns $columns;
  4366.         $this->windowRows $rows;
  4367.     }
  4368.     /**
  4369.      * To String Magic Method
  4370.      *
  4371.      * @return string
  4372.      * @access public
  4373.      */
  4374.     public function __toString()
  4375.     {
  4376.         return $this->getResourceId();
  4377.     }
  4378.     /**
  4379.      * Get Resource ID
  4380.      *
  4381.      * We use {} because that symbols should not be in URL according to
  4382.      * {@link http://tools.ietf.org/html/rfc3986#section-2 RFC}.
  4383.      * It will safe us from any conflicts, because otherwise regexp will
  4384.      * match all alphanumeric domains.
  4385.      *
  4386.      * @return string
  4387.      */
  4388.     public function getResourceId()
  4389.     {
  4390.         return '{' spl_object_hash($this) . '}';
  4391.     }
  4392.     /**
  4393.      * Return existing connection
  4394.      *
  4395.      * @param string $id
  4396.      *
  4397.      * @return bool|SSH2 will return false if no such connection
  4398.      */
  4399.     public static function getConnectionByResourceId($id)
  4400.     {
  4401.         return isset(self::$connections[$id]) ? self::$connections[$id] : false;
  4402.     }
  4403.     /**
  4404.      * Return all excising connections
  4405.      *
  4406.      * @return SSH2[]
  4407.      */
  4408.     public static function getConnections()
  4409.     {
  4410.         return self::$connections;
  4411.     }
  4412.     /*
  4413.      * Update packet types in log history
  4414.      *
  4415.      * @param string $old
  4416.      * @param string $new
  4417.      * @access private
  4418.      */
  4419.     private function updateLogHistory($old$new)
  4420.     {
  4421.         if (defined('NET_SSH2_LOGGING') && NET_SSH2_LOGGING == self::LOG_COMPLEX) {
  4422.             $this->message_number_log[count($this->message_number_log) - 1] = str_replace(
  4423.                 $old,
  4424.                 $new,
  4425.                 $this->message_number_log[count($this->message_number_log) - 1]
  4426.             );
  4427.         }
  4428.     }
  4429. }