[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/vendor/phpseclib/phpseclib/phpseclib/Net/ -> SSH1.php (source)

   1  <?php
   2  
   3  /**
   4   * Pure-PHP implementation of SSHv1.
   5   *
   6   * PHP version 5
   7   *
   8   * Here's a short example of how to use this library:
   9   * <code>
  10   * <?php
  11   *    include 'vendor/autoload.php';
  12   *
  13   *    $ssh = new \phpseclib\Net\SSH1('www.domain.tld');
  14   *    if (!$ssh->login('username', 'password')) {
  15   *        exit('Login Failed');
  16   *    }
  17   *
  18   *    echo $ssh->exec('ls -la');
  19   * ?>
  20   * </code>
  21   *
  22   * Here's another short example:
  23   * <code>
  24   * <?php
  25   *    include 'vendor/autoload.php';
  26   *
  27   *    $ssh = new \phpseclib\Net\SSH1('www.domain.tld');
  28   *    if (!$ssh->login('username', 'password')) {
  29   *        exit('Login Failed');
  30   *    }
  31   *
  32   *    echo $ssh->read('username@username:~$');
  33   *    $ssh->write("ls -la\n");
  34   *    echo $ssh->read('username@username:~$');
  35   * ?>
  36   * </code>
  37   *
  38   * More information on the SSHv1 specification can be found by reading
  39   * {@link http://www.snailbook.com/docs/protocol-1.5.txt protocol-1.5.txt}.
  40   *
  41   * @category  Net
  42   * @package   SSH1
  43   * @author    Jim Wigginton <terrafrost@php.net>
  44   * @copyright 2007 Jim Wigginton
  45   * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
  46   * @link      http://phpseclib.sourceforge.net
  47   */
  48  
  49  namespace phpseclib\Net;
  50  
  51  use phpseclib\Crypt\DES;
  52  use phpseclib\Crypt\Random;
  53  use phpseclib\Crypt\TripleDES;
  54  use phpseclib\Math\BigInteger;
  55  
  56  /**
  57   * Pure-PHP implementation of SSHv1.
  58   *
  59   * @package SSH1
  60   * @author  Jim Wigginton <terrafrost@php.net>
  61   * @access  public
  62   */
  63  class SSH1
  64  {
  65      /**#@+
  66       * Encryption Methods
  67       *
  68       * @see \phpseclib\Net\SSH1::getSupportedCiphers()
  69       * @access public
  70       */
  71      /**
  72       * No encryption
  73       *
  74       * Not supported.
  75       */
  76      const CIPHER_NONE = 0;
  77      /**
  78       * IDEA in CFB mode
  79       *
  80       * Not supported.
  81       */
  82      const CIPHER_IDEA = 1;
  83      /**
  84       * DES in CBC mode
  85       */
  86      const CIPHER_DES = 2;
  87      /**
  88       * Triple-DES in CBC mode
  89       *
  90       * All implementations are required to support this
  91       */
  92      const CIPHER_3DES = 3;
  93      /**
  94       * TRI's Simple Stream encryption CBC
  95       *
  96       * Not supported nor is it defined in the official SSH1 specs.  OpenSSH, however, does define it (see cipher.h),
  97       * although it doesn't use it (see cipher.c)
  98       */
  99      const CIPHER_BROKEN_TSS = 4;
 100      /**
 101       * RC4
 102       *
 103       * Not supported.
 104       *
 105       * @internal According to the SSH1 specs:
 106       *
 107       *        "The first 16 bytes of the session key are used as the key for
 108       *         the server to client direction.  The remaining 16 bytes are used
 109       *         as the key for the client to server direction.  This gives
 110       *         independent 128-bit keys for each direction."
 111       *
 112       *     This library currently only supports encryption when the same key is being used for both directions.  This is
 113       *     because there's only one $crypto object.  Two could be added ($encrypt and $decrypt, perhaps).
 114       */
 115      const CIPHER_RC4 = 5;
 116      /**
 117       * Blowfish
 118       *
 119       * Not supported nor is it defined in the official SSH1 specs.  OpenSSH, however, defines it (see cipher.h) and
 120       * uses it (see cipher.c)
 121       */
 122      const CIPHER_BLOWFISH = 6;
 123      /**#@-*/
 124  
 125      /**#@+
 126       * Authentication Methods
 127       *
 128       * @see \phpseclib\Net\SSH1::getSupportedAuthentications()
 129       * @access public
 130      */
 131      /**
 132       * .rhosts or /etc/hosts.equiv
 133       */
 134      const AUTH_RHOSTS = 1;
 135      /**
 136       * pure RSA authentication
 137       */
 138      const AUTH_RSA = 2;
 139      /**
 140       * password authentication
 141       *
 142       * This is the only method that is supported by this library.
 143       */
 144      const AUTH_PASSWORD = 3;
 145      /**
 146       * .rhosts with RSA host authentication
 147       */
 148      const AUTH_RHOSTS_RSA = 4;
 149      /**#@-*/
 150  
 151      /**#@+
 152       * Terminal Modes
 153       *
 154       * @link http://3sp.com/content/developer/maverick-net/docs/Maverick.SSH.PseudoTerminalModesMembers.html
 155       * @access private
 156      */
 157      const TTY_OP_END = 0;
 158      /**#@-*/
 159  
 160      /**
 161       * The Response Type
 162       *
 163       * @see \phpseclib\Net\SSH1::_get_binary_packet()
 164       * @access private
 165       */
 166      const RESPONSE_TYPE = 1;
 167  
 168      /**
 169       * The Response Data
 170       *
 171       * @see \phpseclib\Net\SSH1::_get_binary_packet()
 172       * @access private
 173       */
 174      const RESPONSE_DATA = 2;
 175  
 176      /**#@+
 177       * Execution Bitmap Masks
 178       *
 179       * @see \phpseclib\Net\SSH1::bitmap
 180       * @access private
 181      */
 182      const MASK_CONSTRUCTOR = 0x00000001;
 183      const MASK_CONNECTED   = 0x00000002;
 184      const MASK_LOGIN       = 0x00000004;
 185      const MASK_SHELL       = 0x00000008;
 186      /**#@-*/
 187  
 188      /**#@+
 189       * @access public
 190       * @see \phpseclib\Net\SSH1::getLog()
 191      */
 192      /**
 193       * Returns the message numbers
 194       */
 195      const LOG_SIMPLE = 1;
 196      /**
 197       * Returns the message content
 198       */
 199      const LOG_COMPLEX = 2;
 200      /**
 201       * Outputs the content real-time
 202       */
 203      const LOG_REALTIME = 3;
 204      /**
 205       * Dumps the content real-time to a file
 206       */
 207      const LOG_REALTIME_FILE = 4;
 208      /**#@-*/
 209  
 210      /**#@+
 211       * @access public
 212       * @see \phpseclib\Net\SSH1::read()
 213      */
 214      /**
 215       * Returns when a string matching $expect exactly is found
 216       */
 217      const READ_SIMPLE = 1;
 218      /**
 219       * Returns when a string matching the regular expression $expect is found
 220       */
 221      const READ_REGEX = 2;
 222      /**#@-*/
 223  
 224      /**
 225       * The SSH identifier
 226       *
 227       * @var string
 228       * @access private
 229       */
 230      var $identifier = 'SSH-1.5-phpseclib';
 231  
 232      /**
 233       * The Socket Object
 234       *
 235       * @var object
 236       * @access private
 237       */
 238      var $fsock;
 239  
 240      /**
 241       * The cryptography object
 242       *
 243       * @var object
 244       * @access private
 245       */
 246      var $crypto = false;
 247  
 248      /**
 249       * Execution Bitmap
 250       *
 251       * The bits that are set represent functions that have been called already.  This is used to determine
 252       * if a requisite function has been successfully executed.  If not, an error should be thrown.
 253       *
 254       * @var int
 255       * @access private
 256       */
 257      var $bitmap = 0;
 258  
 259      /**
 260       * The Server Key Public Exponent
 261       *
 262       * Logged for debug purposes
 263       *
 264       * @see self::getServerKeyPublicExponent()
 265       * @var string
 266       * @access private
 267       */
 268      var $server_key_public_exponent;
 269  
 270      /**
 271       * The Server Key Public Modulus
 272       *
 273       * Logged for debug purposes
 274       *
 275       * @see self::getServerKeyPublicModulus()
 276       * @var string
 277       * @access private
 278       */
 279      var $server_key_public_modulus;
 280  
 281      /**
 282       * The Host Key Public Exponent
 283       *
 284       * Logged for debug purposes
 285       *
 286       * @see self::getHostKeyPublicExponent()
 287       * @var string
 288       * @access private
 289       */
 290      var $host_key_public_exponent;
 291  
 292      /**
 293       * The Host Key Public Modulus
 294       *
 295       * Logged for debug purposes
 296       *
 297       * @see self::getHostKeyPublicModulus()
 298       * @var string
 299       * @access private
 300       */
 301      var $host_key_public_modulus;
 302  
 303      /**
 304       * Supported Ciphers
 305       *
 306       * Logged for debug purposes
 307       *
 308       * @see self::getSupportedCiphers()
 309       * @var array
 310       * @access private
 311       */
 312      var $supported_ciphers = array(
 313          self::CIPHER_NONE       => 'No encryption',
 314          self::CIPHER_IDEA       => 'IDEA in CFB mode',
 315          self::CIPHER_DES        => 'DES in CBC mode',
 316          self::CIPHER_3DES       => 'Triple-DES in CBC mode',
 317          self::CIPHER_BROKEN_TSS => 'TRI\'s Simple Stream encryption CBC',
 318          self::CIPHER_RC4        => 'RC4',
 319          self::CIPHER_BLOWFISH   => 'Blowfish'
 320      );
 321  
 322      /**
 323       * Supported Authentications
 324       *
 325       * Logged for debug purposes
 326       *
 327       * @see self::getSupportedAuthentications()
 328       * @var array
 329       * @access private
 330       */
 331      var $supported_authentications = array(
 332          self::AUTH_RHOSTS     => '.rhosts or /etc/hosts.equiv',
 333          self::AUTH_RSA        => 'pure RSA authentication',
 334          self::AUTH_PASSWORD   => 'password authentication',
 335          self::AUTH_RHOSTS_RSA => '.rhosts with RSA host authentication'
 336      );
 337  
 338      /**
 339       * Server Identification
 340       *
 341       * @see self::getServerIdentification()
 342       * @var string
 343       * @access private
 344       */
 345      var $server_identification = '';
 346  
 347      /**
 348       * Protocol Flags
 349       *
 350       * @see self::__construct()
 351       * @var array
 352       * @access private
 353       */
 354      var $protocol_flags = array();
 355  
 356      /**
 357       * Protocol Flag Log
 358       *
 359       * @see self::getLog()
 360       * @var array
 361       * @access private
 362       */
 363      var $protocol_flag_log = array();
 364  
 365      /**
 366       * Message Log
 367       *
 368       * @see self::getLog()
 369       * @var array
 370       * @access private
 371       */
 372      var $message_log = array();
 373  
 374      /**
 375       * Real-time log file pointer
 376       *
 377       * @see self::_append_log()
 378       * @var resource
 379       * @access private
 380       */
 381      var $realtime_log_file;
 382  
 383      /**
 384       * Real-time log file size
 385       *
 386       * @see self::_append_log()
 387       * @var int
 388       * @access private
 389       */
 390      var $realtime_log_size;
 391  
 392      /**
 393       * Real-time log file wrap boolean
 394       *
 395       * @see self::_append_log()
 396       * @var bool
 397       * @access private
 398       */
 399      var $realtime_log_wrap;
 400  
 401      /**
 402       * Interactive Buffer
 403       *
 404       * @see self::read()
 405       * @var array
 406       * @access private
 407       */
 408      var $interactiveBuffer = '';
 409  
 410      /**
 411       * Timeout
 412       *
 413       * @see self::setTimeout()
 414       * @access private
 415       */
 416      var $timeout;
 417  
 418      /**
 419       * Current Timeout
 420       *
 421       * @see self::_get_channel_packet()
 422       * @access private
 423       */
 424      var $curTimeout;
 425  
 426      /**
 427       * Log Boundary
 428       *
 429       * @see self::_format_log()
 430       * @access private
 431       */
 432      var $log_boundary = ':';
 433  
 434      /**
 435       * Log Long Width
 436       *
 437       * @see self::_format_log()
 438       * @access private
 439       */
 440      var $log_long_width = 65;
 441  
 442      /**
 443       * Log Short Width
 444       *
 445       * @see self::_format_log()
 446       * @access private
 447       */
 448      var $log_short_width = 16;
 449  
 450      /**
 451       * Hostname
 452       *
 453       * @see self::__construct()
 454       * @see self::_connect()
 455       * @var string
 456       * @access private
 457       */
 458      var $host;
 459  
 460      /**
 461       * Port Number
 462       *
 463       * @see self::__construct()
 464       * @see self::_connect()
 465       * @var int
 466       * @access private
 467       */
 468      var $port;
 469  
 470      /**
 471       * Timeout for initial connection
 472       *
 473       * Set by the constructor call. Calling setTimeout() is optional. If it's not called functions like
 474       * exec() won't timeout unless some PHP setting forces it too. The timeout specified in the constructor,
 475       * however, is non-optional. There will be a timeout, whether or not you set it. If you don't it'll be
 476       * 10 seconds. It is used by fsockopen() in that function.
 477       *
 478       * @see self::__construct()
 479       * @see self::_connect()
 480       * @var int
 481       * @access private
 482       */
 483      var $connectionTimeout;
 484  
 485      /**
 486       * Default cipher
 487       *
 488       * @see self::__construct()
 489       * @see self::_connect()
 490       * @var int
 491       * @access private
 492       */
 493      var $cipher;
 494  
 495      /**
 496       * Default Constructor.
 497       *
 498       * Connects to an SSHv1 server
 499       *
 500       * @param string $host
 501       * @param int $port
 502       * @param int $timeout
 503       * @param int $cipher
 504       * @return \phpseclib\Net\SSH1
 505       * @access public
 506       */
 507      function __construct($host, $port = 22, $timeout = 10, $cipher = self::CIPHER_3DES)
 508      {
 509          $this->protocol_flags = array(
 510              1  => 'NET_SSH1_MSG_DISCONNECT',
 511              2  => 'NET_SSH1_SMSG_PUBLIC_KEY',
 512              3  => 'NET_SSH1_CMSG_SESSION_KEY',
 513              4  => 'NET_SSH1_CMSG_USER',
 514              9  => 'NET_SSH1_CMSG_AUTH_PASSWORD',
 515              10 => 'NET_SSH1_CMSG_REQUEST_PTY',
 516              12 => 'NET_SSH1_CMSG_EXEC_SHELL',
 517              13 => 'NET_SSH1_CMSG_EXEC_CMD',
 518              14 => 'NET_SSH1_SMSG_SUCCESS',
 519              15 => 'NET_SSH1_SMSG_FAILURE',
 520              16 => 'NET_SSH1_CMSG_STDIN_DATA',
 521              17 => 'NET_SSH1_SMSG_STDOUT_DATA',
 522              18 => 'NET_SSH1_SMSG_STDERR_DATA',
 523              19 => 'NET_SSH1_CMSG_EOF',
 524              20 => 'NET_SSH1_SMSG_EXITSTATUS',
 525              33 => 'NET_SSH1_CMSG_EXIT_CONFIRMATION'
 526          );
 527  
 528          $this->_define_array($this->protocol_flags);
 529  
 530          $this->host = $host;
 531          $this->port = $port;
 532          $this->connectionTimeout = $timeout;
 533          $this->cipher = $cipher;
 534      }
 535  
 536      /**
 537       * Connect to an SSHv1 server
 538       *
 539       * @return bool
 540       * @access private
 541       */
 542      function _connect()
 543      {
 544          $this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $this->connectionTimeout);
 545          if (!$this->fsock) {
 546              user_error(rtrim("Cannot connect to {$this->host}:{$this->port}. Error $errno. $errstr"));
 547              return false;
 548          }
 549  
 550          $this->server_identification = $init_line = fgets($this->fsock, 255);
 551  
 552          if (defined('NET_SSH1_LOGGING')) {
 553              $this->_append_log('<-', $this->server_identification);
 554              $this->_append_log('->', $this->identifier . "\r\n");
 555          }
 556  
 557          if (!preg_match('#SSH-([0-9\.]+)-(.+)#', $init_line, $parts)) {
 558              user_error('Can only connect to SSH servers');
 559              return false;
 560          }
 561          if ($parts[1][0] != 1) {
 562              user_error("Cannot connect to SSH $parts[1] servers");
 563              return false;
 564          }
 565  
 566          fputs($this->fsock, $this->identifier."\r\n");
 567  
 568          $response = $this->_get_binary_packet();
 569          if ($response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_PUBLIC_KEY) {
 570              user_error('Expected SSH_SMSG_PUBLIC_KEY');
 571              return false;
 572          }
 573  
 574          $anti_spoofing_cookie = $this->_string_shift($response[self::RESPONSE_DATA], 8);
 575  
 576          $this->_string_shift($response[self::RESPONSE_DATA], 4);
 577  
 578          if (strlen($response[self::RESPONSE_DATA]) < 2) {
 579              return false;
 580          }
 581          $temp = unpack('nlen', $this->_string_shift($response[self::RESPONSE_DATA], 2));
 582          $server_key_public_exponent = new BigInteger($this->_string_shift($response[self::RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
 583          $this->server_key_public_exponent = $server_key_public_exponent;
 584  
 585          if (strlen($response[self::RESPONSE_DATA]) < 2) {
 586              return false;
 587          }
 588          $temp = unpack('nlen', $this->_string_shift($response[self::RESPONSE_DATA], 2));
 589          $server_key_public_modulus = new BigInteger($this->_string_shift($response[self::RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
 590  
 591          $this->server_key_public_modulus = $server_key_public_modulus;
 592  
 593          $this->_string_shift($response[self::RESPONSE_DATA], 4);
 594  
 595          if (strlen($response[self::RESPONSE_DATA]) < 2) {
 596              return false;
 597          }
 598          $temp = unpack('nlen', $this->_string_shift($response[self::RESPONSE_DATA], 2));
 599          $host_key_public_exponent = new BigInteger($this->_string_shift($response[self::RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
 600          $this->host_key_public_exponent = $host_key_public_exponent;
 601  
 602          if (strlen($response[self::RESPONSE_DATA]) < 2) {
 603              return false;
 604          }
 605          $temp = unpack('nlen', $this->_string_shift($response[self::RESPONSE_DATA], 2));
 606          $host_key_public_modulus = new BigInteger($this->_string_shift($response[self::RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
 607  
 608          $this->host_key_public_modulus = $host_key_public_modulus;
 609  
 610          $this->_string_shift($response[self::RESPONSE_DATA], 4);
 611  
 612          // get a list of the supported ciphers
 613          if (strlen($response[self::RESPONSE_DATA]) < 4) {
 614              return false;
 615          }
 616          extract(unpack('Nsupported_ciphers_mask', $this->_string_shift($response[self::RESPONSE_DATA], 4)));
 617  
 618          foreach ($this->supported_ciphers as $mask => $name) {
 619              if (($supported_ciphers_mask & (1 << $mask)) == 0) {
 620                  unset($this->supported_ciphers[$mask]);
 621              }
 622          }
 623  
 624          // get a list of the supported authentications
 625          if (strlen($response[self::RESPONSE_DATA]) < 4) {
 626              return false;
 627          }
 628          extract(unpack('Nsupported_authentications_mask', $this->_string_shift($response[self::RESPONSE_DATA], 4)));
 629          foreach ($this->supported_authentications as $mask => $name) {
 630              if (($supported_authentications_mask & (1 << $mask)) == 0) {
 631                  unset($this->supported_authentications[$mask]);
 632              }
 633          }
 634  
 635          $session_id = pack('H*', md5($host_key_public_modulus->toBytes() . $server_key_public_modulus->toBytes() . $anti_spoofing_cookie));
 636  
 637          $session_key = Random::string(32);
 638          $double_encrypted_session_key = $session_key ^ str_pad($session_id, 32, chr(0));
 639  
 640          if ($server_key_public_modulus->compare($host_key_public_modulus) < 0) {
 641              $double_encrypted_session_key = $this->_rsa_crypt(
 642                  $double_encrypted_session_key,
 643                  array(
 644                      $server_key_public_exponent,
 645                      $server_key_public_modulus
 646                  )
 647              );
 648              $double_encrypted_session_key = $this->_rsa_crypt(
 649                  $double_encrypted_session_key,
 650                  array(
 651                      $host_key_public_exponent,
 652                      $host_key_public_modulus
 653                  )
 654              );
 655          } else {
 656              $double_encrypted_session_key = $this->_rsa_crypt(
 657                  $double_encrypted_session_key,
 658                  array(
 659                      $host_key_public_exponent,
 660                      $host_key_public_modulus
 661                  )
 662              );
 663              $double_encrypted_session_key = $this->_rsa_crypt(
 664                  $double_encrypted_session_key,
 665                  array(
 666                      $server_key_public_exponent,
 667                      $server_key_public_modulus
 668                  )
 669              );
 670          }
 671  
 672          $cipher = isset($this->supported_ciphers[$this->cipher]) ? $this->cipher : self::CIPHER_3DES;
 673          $data = pack('C2a*na*N', NET_SSH1_CMSG_SESSION_KEY, $cipher, $anti_spoofing_cookie, 8 * strlen($double_encrypted_session_key), $double_encrypted_session_key, 0);
 674  
 675          if (!$this->_send_binary_packet($data)) {
 676              user_error('Error sending SSH_CMSG_SESSION_KEY');
 677              return false;
 678          }
 679  
 680          switch ($cipher) {
 681              //case self::CIPHER_NONE:
 682              //    $this->crypto = new \phpseclib\Crypt\Null();
 683              //    break;
 684              case self::CIPHER_DES:
 685                  $this->crypto = new DES();
 686                  $this->crypto->disablePadding();
 687                  $this->crypto->enableContinuousBuffer();
 688                  $this->crypto->setKey(substr($session_key, 0,  8));
 689                  break;
 690              case self::CIPHER_3DES:
 691                  $this->crypto = new TripleDES(TripleDES::MODE_3CBC);
 692                  $this->crypto->disablePadding();
 693                  $this->crypto->enableContinuousBuffer();
 694                  $this->crypto->setKey(substr($session_key, 0, 24));
 695                  break;
 696              //case self::CIPHER_RC4:
 697              //    $this->crypto = new RC4();
 698              //    $this->crypto->enableContinuousBuffer();
 699              //    $this->crypto->setKey(substr($session_key, 0,  16));
 700              //    break;
 701          }
 702  
 703          $response = $this->_get_binary_packet();
 704  
 705          if ($response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) {
 706              user_error('Expected SSH_SMSG_SUCCESS');
 707              return false;
 708          }
 709  
 710          $this->bitmap = self::MASK_CONNECTED;
 711  
 712          return true;
 713      }
 714  
 715      /**
 716       * Login
 717       *
 718       * @param string $username
 719       * @param string $password
 720       * @return bool
 721       * @access public
 722       */
 723      function login($username, $password = '')
 724      {
 725          if (!($this->bitmap & self::MASK_CONSTRUCTOR)) {
 726              $this->bitmap |= self::MASK_CONSTRUCTOR;
 727              if (!$this->_connect()) {
 728                  return false;
 729              }
 730          }
 731  
 732          if (!($this->bitmap & self::MASK_CONNECTED)) {
 733              return false;
 734          }
 735  
 736          $data = pack('CNa*', NET_SSH1_CMSG_USER, strlen($username), $username);
 737  
 738          if (!$this->_send_binary_packet($data)) {
 739              user_error('Error sending SSH_CMSG_USER');
 740              return false;
 741          }
 742  
 743          $response = $this->_get_binary_packet();
 744  
 745          if ($response === true) {
 746              return false;
 747          }
 748          if ($response[self::RESPONSE_TYPE] == NET_SSH1_SMSG_SUCCESS) {
 749              $this->bitmap |= self::MASK_LOGIN;
 750              return true;
 751          } elseif ($response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_FAILURE) {
 752              user_error('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE');
 753              return false;
 754          }
 755  
 756          $data = pack('CNa*', NET_SSH1_CMSG_AUTH_PASSWORD, strlen($password), $password);
 757  
 758          if (!$this->_send_binary_packet($data)) {
 759              user_error('Error sending SSH_CMSG_AUTH_PASSWORD');
 760              return false;
 761          }
 762  
 763          // remove the username and password from the last logged packet
 764          if (defined('NET_SSH1_LOGGING') && NET_SSH1_LOGGING == self::LOG_COMPLEX) {
 765              $data = pack('CNa*', NET_SSH1_CMSG_AUTH_PASSWORD, strlen('password'), 'password');
 766              $this->message_log[count($this->message_log) - 1] = $data;
 767          }
 768  
 769          $response = $this->_get_binary_packet();
 770  
 771          if ($response === true) {
 772              return false;
 773          }
 774          if ($response[self::RESPONSE_TYPE] == NET_SSH1_SMSG_SUCCESS) {
 775              $this->bitmap |= self::MASK_LOGIN;
 776              return true;
 777          } elseif ($response[self::RESPONSE_TYPE] == NET_SSH1_SMSG_FAILURE) {
 778              return false;
 779          } else {
 780              user_error('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE');
 781              return false;
 782          }
 783      }
 784  
 785      /**
 786       * Set Timeout
 787       *
 788       * $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.
 789       * Setting $timeout to false or 0 will mean there is no timeout.
 790       *
 791       * @param mixed $timeout
 792       */
 793      function setTimeout($timeout)
 794      {
 795          $this->timeout = $this->curTimeout = $timeout;
 796      }
 797  
 798      /**
 799       * Executes a command on a non-interactive shell, returns the output, and quits.
 800       *
 801       * An SSH1 server will close the connection after a command has been executed on a non-interactive shell.  SSH2
 802       * servers don't, however, this isn't an SSH2 client.  The way this works, on the server, is by initiating a
 803       * shell with the -s option, as discussed in the following links:
 804       *
 805       * {@link http://www.faqs.org/docs/bashman/bashref_65.html http://www.faqs.org/docs/bashman/bashref_65.html}
 806       * {@link http://www.faqs.org/docs/bashman/bashref_62.html http://www.faqs.org/docs/bashman/bashref_62.html}
 807       *
 808       * To execute further commands, a new \phpseclib\Net\SSH1 object will need to be created.
 809       *
 810       * Returns false on failure and the output, otherwise.
 811       *
 812       * @see self::interactiveRead()
 813       * @see self::interactiveWrite()
 814       * @param string $cmd
 815       * @param bool $block
 816       * @return mixed
 817       * @access public
 818       */
 819      function exec($cmd, $block = true)
 820      {
 821          if (!($this->bitmap & self::MASK_LOGIN)) {
 822              user_error('Operation disallowed prior to login()');
 823              return false;
 824          }
 825  
 826          $data = pack('CNa*', NET_SSH1_CMSG_EXEC_CMD, strlen($cmd), $cmd);
 827  
 828          if (!$this->_send_binary_packet($data)) {
 829              user_error('Error sending SSH_CMSG_EXEC_CMD');
 830              return false;
 831          }
 832  
 833          if (!$block) {
 834              return true;
 835          }
 836  
 837          $output = '';
 838          $response = $this->_get_binary_packet();
 839  
 840          if ($response !== false) {
 841              do {
 842                  $output.= substr($response[self::RESPONSE_DATA], 4);
 843                  $response = $this->_get_binary_packet();
 844              } while (is_array($response) && $response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_EXITSTATUS);
 845          }
 846  
 847          $data = pack('C', NET_SSH1_CMSG_EXIT_CONFIRMATION);
 848  
 849          // i don't think it's really all that important if this packet gets sent or not.
 850          $this->_send_binary_packet($data);
 851  
 852          fclose($this->fsock);
 853  
 854          // reset the execution bitmap - a new \phpseclib\Net\SSH1 object needs to be created.
 855          $this->bitmap = 0;
 856  
 857          return $output;
 858      }
 859  
 860      /**
 861       * Creates an interactive shell
 862       *
 863       * @see self::interactiveRead()
 864       * @see self::interactiveWrite()
 865       * @return bool
 866       * @access private
 867       */
 868      function _initShell()
 869      {
 870          // connect using the sample parameters in protocol-1.5.txt.
 871          // according to wikipedia.org's entry on text terminals, "the fundamental type of application running on a text
 872          // terminal is a command line interpreter or shell".  thus, opening a terminal session to run the shell.
 873          $data = pack('CNa*N4C', NET_SSH1_CMSG_REQUEST_PTY, strlen('vt100'), 'vt100', 24, 80, 0, 0, self::TTY_OP_END);
 874  
 875          if (!$this->_send_binary_packet($data)) {
 876              user_error('Error sending SSH_CMSG_REQUEST_PTY');
 877              return false;
 878          }
 879  
 880          $response = $this->_get_binary_packet();
 881  
 882          if ($response === true) {
 883              return false;
 884          }
 885          if ($response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) {
 886              user_error('Expected SSH_SMSG_SUCCESS');
 887              return false;
 888          }
 889  
 890          $data = pack('C', NET_SSH1_CMSG_EXEC_SHELL);
 891  
 892          if (!$this->_send_binary_packet($data)) {
 893              user_error('Error sending SSH_CMSG_EXEC_SHELL');
 894              return false;
 895          }
 896  
 897          $this->bitmap |= self::MASK_SHELL;
 898  
 899          //stream_set_blocking($this->fsock, 0);
 900  
 901          return true;
 902      }
 903  
 904      /**
 905       * Inputs a command into an interactive shell.
 906       *
 907       * @see self::interactiveWrite()
 908       * @param string $cmd
 909       * @return bool
 910       * @access public
 911       */
 912      function write($cmd)
 913      {
 914          return $this->interactiveWrite($cmd);
 915      }
 916  
 917      /**
 918       * Returns the output of an interactive shell when there's a match for $expect
 919       *
 920       * $expect can take the form of a string literal or, if $mode == self::READ_REGEX,
 921       * a regular expression.
 922       *
 923       * @see self::write()
 924       * @param string $expect
 925       * @param int $mode
 926       * @return bool
 927       * @access public
 928       */
 929      function read($expect, $mode = self::READ_SIMPLE)
 930      {
 931          if (!($this->bitmap & self::MASK_LOGIN)) {
 932              user_error('Operation disallowed prior to login()');
 933              return false;
 934          }
 935  
 936          if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
 937              user_error('Unable to initiate an interactive shell session');
 938              return false;
 939          }
 940  
 941          $match = $expect;
 942          while (true) {
 943              if ($mode == self::READ_REGEX) {
 944                  preg_match($expect, $this->interactiveBuffer, $matches);
 945                  $match = isset($matches[0]) ? $matches[0] : '';
 946              }
 947              $pos = strlen($match) ? strpos($this->interactiveBuffer, $match) : false;
 948              if ($pos !== false) {
 949                  return $this->_string_shift($this->interactiveBuffer, $pos + strlen($match));
 950              }
 951              $response = $this->_get_binary_packet();
 952  
 953              if ($response === true) {
 954                  return $this->_string_shift($this->interactiveBuffer, strlen($this->interactiveBuffer));
 955              }
 956              $this->interactiveBuffer.= substr($response[self::RESPONSE_DATA], 4);
 957          }
 958      }
 959  
 960      /**
 961       * Inputs a command into an interactive shell.
 962       *
 963       * @see self::interactiveRead()
 964       * @param string $cmd
 965       * @return bool
 966       * @access public
 967       */
 968      function interactiveWrite($cmd)
 969      {
 970          if (!($this->bitmap & self::MASK_LOGIN)) {
 971              user_error('Operation disallowed prior to login()');
 972              return false;
 973          }
 974  
 975          if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
 976              user_error('Unable to initiate an interactive shell session');
 977              return false;
 978          }
 979  
 980          $data = pack('CNa*', NET_SSH1_CMSG_STDIN_DATA, strlen($cmd), $cmd);
 981  
 982          if (!$this->_send_binary_packet($data)) {
 983              user_error('Error sending SSH_CMSG_STDIN');
 984              return false;
 985          }
 986  
 987          return true;
 988      }
 989  
 990      /**
 991       * Returns the output of an interactive shell when no more output is available.
 992       *
 993       * Requires PHP 4.3.0 or later due to the use of the stream_select() function.  If you see stuff like
 994       * "^[[00m", you're seeing ANSI escape codes.  According to
 995       * {@link http://support.microsoft.com/kb/101875 How to Enable ANSI.SYS in a Command Window}, "Windows NT
 996       * does not support ANSI escape sequences in Win32 Console applications", so if you're a Windows user,
 997       * there's not going to be much recourse.
 998       *
 999       * @see self::interactiveRead()
1000       * @return string
1001       * @access public
1002       */
1003      function interactiveRead()
1004      {
1005          if (!($this->bitmap & self::MASK_LOGIN)) {
1006              user_error('Operation disallowed prior to login()');
1007              return false;
1008          }
1009  
1010          if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
1011              user_error('Unable to initiate an interactive shell session');
1012              return false;
1013          }
1014  
1015          $read = array($this->fsock);
1016          $write = $except = null;
1017          if (stream_select($read, $write, $except, 0)) {
1018              $response = $this->_get_binary_packet();
1019              return substr($response[self::RESPONSE_DATA], 4);
1020          } else {
1021              return '';
1022          }
1023      }
1024  
1025      /**
1026       * Disconnect
1027       *
1028       * @access public
1029       */
1030      function disconnect()
1031      {
1032          $this->_disconnect();
1033      }
1034  
1035      /**
1036       * Destructor.
1037       *
1038       * Will be called, automatically, if you're supporting just PHP5.  If you're supporting PHP4, you'll need to call
1039       * disconnect().
1040       *
1041       * @access public
1042       */
1043      function __destruct()
1044      {
1045          $this->_disconnect();
1046      }
1047  
1048      /**
1049       * Disconnect
1050       *
1051       * @param string $msg
1052       * @access private
1053       */
1054      function _disconnect($msg = 'Client Quit')
1055      {
1056          if ($this->bitmap) {
1057              $data = pack('C', NET_SSH1_CMSG_EOF);
1058              $this->_send_binary_packet($data);
1059              /*
1060              $response = $this->_get_binary_packet();
1061              if ($response === true) {
1062                  $response = array(self::RESPONSE_TYPE => -1);
1063              }
1064              switch ($response[self::RESPONSE_TYPE]) {
1065                  case NET_SSH1_SMSG_EXITSTATUS:
1066                      $data = pack('C', NET_SSH1_CMSG_EXIT_CONFIRMATION);
1067                      break;
1068                  default:
1069                      $data = pack('CNa*', NET_SSH1_MSG_DISCONNECT, strlen($msg), $msg);
1070              }
1071              */
1072              $data = pack('CNa*', NET_SSH1_MSG_DISCONNECT, strlen($msg), $msg);
1073  
1074              $this->_send_binary_packet($data);
1075              fclose($this->fsock);
1076              $this->bitmap = 0;
1077          }
1078      }
1079  
1080      /**
1081       * Gets Binary Packets
1082       *
1083       * See 'The Binary Packet Protocol' of protocol-1.5.txt for more info.
1084       *
1085       * Also, this function could be improved upon by adding detection for the following exploit:
1086       * http://www.securiteam.com/securitynews/5LP042K3FY.html
1087       *
1088       * @see self::_send_binary_packet()
1089       * @return array
1090       * @access private
1091       */
1092      function _get_binary_packet()
1093      {
1094          if (feof($this->fsock)) {
1095              //user_error('connection closed prematurely');
1096              return false;
1097          }
1098  
1099          if ($this->curTimeout) {
1100              $read = array($this->fsock);
1101              $write = $except = null;
1102  
1103              $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
1104              $sec = floor($this->curTimeout);
1105              $usec = 1000000 * ($this->curTimeout - $sec);
1106              // on windows this returns a "Warning: Invalid CRT parameters detected" error
1107              if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {
1108                  //$this->_disconnect('Timeout');
1109                  return true;
1110              }
1111              $elapsed = strtok(microtime(), ' ') + strtok('') - $start;
1112              $this->curTimeout-= $elapsed;
1113          }
1114  
1115          $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
1116          $data = fread($this->fsock, 4);
1117          if (strlen($data) < 4) {
1118              return false;
1119          }
1120          $temp = unpack('Nlength', $data);
1121  
1122          $padding_length = 8 - ($temp['length'] & 7);
1123          $length = $temp['length'] + $padding_length;
1124          $raw = '';
1125  
1126          while ($length > 0) {
1127              $temp = fread($this->fsock, $length);
1128              if (strlen($temp) != $length) {
1129                  return false;
1130              }
1131              $raw.= $temp;
1132              $length-= strlen($temp);
1133          }
1134          $stop = strtok(microtime(), ' ') + strtok('');
1135  
1136          if (strlen($raw) && $this->crypto !== false) {
1137              $raw = $this->crypto->decrypt($raw);
1138          }
1139  
1140          $padding = substr($raw, 0, $padding_length);
1141          $type = $raw[$padding_length];
1142          $data = substr($raw, $padding_length + 1, -4);
1143  
1144          if (strlen($raw) < 4) {
1145              return false;
1146          }
1147          $temp = unpack('Ncrc', substr($raw, -4));
1148  
1149          //if ( $temp['crc'] != $this->_crc($padding . $type . $data) ) {
1150          //    user_error('Bad CRC in packet from server');
1151          //    return false;
1152          //}
1153  
1154          $type = ord($type);
1155  
1156          if (defined('NET_SSH1_LOGGING')) {
1157              $temp = isset($this->protocol_flags[$type]) ? $this->protocol_flags[$type] : 'UNKNOWN';
1158              $temp = '<- ' . $temp .
1159                      ' (' . round($stop - $start, 4) . 's)';
1160              $this->_append_log($temp, $data);
1161          }
1162  
1163          return array(
1164              self::RESPONSE_TYPE => $type,
1165              self::RESPONSE_DATA => $data
1166          );
1167      }
1168  
1169      /**
1170       * Sends Binary Packets
1171       *
1172       * Returns true on success, false on failure.
1173       *
1174       * @see self::_get_binary_packet()
1175       * @param string $data
1176       * @return bool
1177       * @access private
1178       */
1179      function _send_binary_packet($data)
1180      {
1181          if (feof($this->fsock)) {
1182              //user_error('connection closed prematurely');
1183              return false;
1184          }
1185  
1186          $length = strlen($data) + 4;
1187  
1188          $padding = Random::string(8 - ($length & 7));
1189  
1190          $orig = $data;
1191          $data = $padding . $data;
1192          $data.= pack('N', $this->_crc($data));
1193  
1194          if ($this->crypto !== false) {
1195              $data = $this->crypto->encrypt($data);
1196          }
1197  
1198          $packet = pack('Na*', $length, $data);
1199  
1200          $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
1201          $result = strlen($packet) == fputs($this->fsock, $packet);
1202          $stop = strtok(microtime(), ' ') + strtok('');
1203  
1204          if (defined('NET_SSH1_LOGGING')) {
1205              $temp = isset($this->protocol_flags[ord($orig[0])]) ? $this->protocol_flags[ord($orig[0])] : 'UNKNOWN';
1206              $temp = '-> ' . $temp .
1207                      ' (' . round($stop - $start, 4) . 's)';
1208              $this->_append_log($temp, $orig);
1209          }
1210  
1211          return $result;
1212      }
1213  
1214      /**
1215       * Cyclic Redundancy Check (CRC)
1216       *
1217       * PHP's crc32 function is implemented slightly differently than the one that SSH v1 uses, so
1218       * we've reimplemented it. A more detailed discussion of the differences can be found after
1219       * $crc_lookup_table's initialization.
1220       *
1221       * @see self::_get_binary_packet()
1222       * @see self::_send_binary_packet()
1223       * @param string $data
1224       * @return int
1225       * @access private
1226       */
1227      function _crc($data)
1228      {
1229          static $crc_lookup_table = array(
1230              0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
1231              0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
1232              0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
1233              0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
1234              0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
1235              0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
1236              0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
1237              0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
1238              0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
1239              0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
1240              0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
1241              0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
1242              0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
1243              0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
1244              0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
1245              0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
1246              0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
1247              0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
1248              0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
1249              0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
1250              0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
1251              0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
1252              0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
1253              0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
1254              0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
1255              0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
1256              0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
1257              0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
1258              0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
1259              0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
1260              0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
1261              0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
1262              0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
1263              0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
1264              0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
1265              0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
1266              0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
1267              0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
1268              0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
1269              0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
1270              0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
1271              0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
1272              0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
1273              0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
1274              0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
1275              0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
1276              0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
1277              0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
1278              0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
1279              0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
1280              0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
1281              0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
1282              0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
1283              0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
1284              0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
1285              0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
1286              0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
1287              0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
1288              0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
1289              0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
1290              0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
1291              0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
1292              0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
1293              0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
1294          );
1295  
1296          // For this function to yield the same output as PHP's crc32 function, $crc would have to be
1297          // set to 0xFFFFFFFF, initially - not 0x00000000 as it currently is.
1298          $crc = 0x00000000;
1299          $length = strlen($data);
1300  
1301          for ($i=0; $i<$length; $i++) {
1302              // We AND $crc >> 8 with 0x00FFFFFF because we want the eight newly added bits to all
1303              // be zero.  PHP, unfortunately, doesn't always do this.  0x80000000 >> 8, as an example,
1304              // yields 0xFF800000 - not 0x00800000.  The following link elaborates:
1305              // http://www.php.net/manual/en/language.operators.bitwise.php#57281
1306              $crc = (($crc >> 8) & 0x00FFFFFF) ^ $crc_lookup_table[($crc & 0xFF) ^ ord($data[$i])];
1307          }
1308  
1309          // In addition to having to set $crc to 0xFFFFFFFF, initially, the return value must be XOR'd with
1310          // 0xFFFFFFFF for this function to return the same thing that PHP's crc32 function would.
1311          return $crc;
1312      }
1313  
1314      /**
1315       * String Shift
1316       *
1317       * Inspired by array_shift
1318       *
1319       * @param string $string
1320       * @param int $index
1321       * @return string
1322       * @access private
1323       */
1324      function _string_shift(&$string, $index = 1)
1325      {
1326          $substr = substr($string, 0, $index);
1327          $string = substr($string, $index);
1328          return $substr;
1329      }
1330  
1331      /**
1332       * RSA Encrypt
1333       *
1334       * Returns mod(pow($m, $e), $n), where $n should be the product of two (large) primes $p and $q and where $e
1335       * should be a number with the property that gcd($e, ($p - 1) * ($q - 1)) == 1.  Could just make anything that
1336       * calls this call modexp, instead, but I think this makes things clearer, maybe...
1337       *
1338       * @see self::__construct()
1339       * @param BigInteger $m
1340       * @param array $key
1341       * @return BigInteger
1342       * @access private
1343       */
1344      function _rsa_crypt($m, $key)
1345      {
1346          /*
1347          $rsa = new RSA();
1348          $rsa->loadKey($key, RSA::PUBLIC_FORMAT_RAW);
1349          $rsa->setEncryptionMode(RSA::ENCRYPTION_PKCS1);
1350          return $rsa->encrypt($m);
1351          */
1352  
1353          // To quote from protocol-1.5.txt:
1354          // The most significant byte (which is only partial as the value must be
1355          // less than the public modulus, which is never a power of two) is zero.
1356          //
1357          // The next byte contains the value 2 (which stands for public-key
1358          // encrypted data in the PKCS standard [PKCS#1]).  Then, there are non-
1359          // zero random bytes to fill any unused space, a zero byte, and the data
1360          // to be encrypted in the least significant bytes, the last byte of the
1361          // data in the least significant byte.
1362  
1363          // Presumably the part of PKCS#1 they're refering to is "Section 7.2.1 Encryption Operation",
1364          // under "7.2 RSAES-PKCS1-v1.5" and "7 Encryption schemes" of the following URL:
1365          // ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.pdf
1366          $modulus = $key[1]->toBytes();
1367          $length = strlen($modulus) - strlen($m) - 3;
1368          $random = '';
1369          while (strlen($random) != $length) {
1370              $block = Random::string($length - strlen($random));
1371              $block = str_replace("\x00", '', $block);
1372              $random.= $block;
1373          }
1374          $temp = chr(0) . chr(2) . $random . chr(0) . $m;
1375  
1376          $m = new BigInteger($temp, 256);
1377          $m = $m->modPow($key[0], $key[1]);
1378  
1379          return $m->toBytes();
1380      }
1381  
1382      /**
1383       * Define Array
1384       *
1385       * Takes any number of arrays whose indices are integers and whose values are strings and defines a bunch of
1386       * named constants from it, using the value as the name of the constant and the index as the value of the constant.
1387       * If any of the constants that would be defined already exists, none of the constants will be defined.
1388       *
1389       * @access private
1390       */
1391      function _define_array()
1392      {
1393          $args = func_get_args();
1394          foreach ($args as $arg) {
1395              foreach ($arg as $key => $value) {
1396                  if (!defined($value)) {
1397                      define($value, $key);
1398                  } else {
1399                      break 2;
1400                  }
1401              }
1402          }
1403      }
1404  
1405      /**
1406       * Returns a log of the packets that have been sent and received.
1407       *
1408       * Returns a string if NET_SSH1_LOGGING == self::LOG_COMPLEX, an array if NET_SSH1_LOGGING == self::LOG_SIMPLE and false if !defined('NET_SSH1_LOGGING')
1409       *
1410       * @access public
1411       * @return array|false|string
1412       */
1413      function getLog()
1414      {
1415          if (!defined('NET_SSH1_LOGGING')) {
1416              return false;
1417          }
1418  
1419          switch (NET_SSH1_LOGGING) {
1420              case self::LOG_SIMPLE:
1421                  return $this->message_number_log;
1422                  break;
1423              case self::LOG_COMPLEX:
1424                  return $this->_format_log($this->message_log, $this->protocol_flags_log);
1425                  break;
1426              default:
1427                  return false;
1428          }
1429      }
1430  
1431      /**
1432       * Formats a log for printing
1433       *
1434       * @param array $message_log
1435       * @param array $message_number_log
1436       * @access private
1437       * @return string
1438       */
1439      function _format_log($message_log, $message_number_log)
1440      {
1441          $output = '';
1442          for ($i = 0; $i < count($message_log); $i++) {
1443              $output.= $message_number_log[$i] . "\r\n";
1444              $current_log = $message_log[$i];
1445              $j = 0;
1446              do {
1447                  if (strlen($current_log)) {
1448                      $output.= str_pad(dechex($j), 7, '0', STR_PAD_LEFT) . '0  ';
1449                  }
1450                  $fragment = $this->_string_shift($current_log, $this->log_short_width);
1451                  $hex = substr(preg_replace_callback('#.#s', array($this, '_format_log_helper'), $fragment), strlen($this->log_boundary));
1452                  // replace non ASCII printable characters with dots
1453                  // http://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters
1454                  // also replace < with a . since < messes up the output on web browsers
1455                  $raw = preg_replace('#[^\x20-\x7E]|<#', '.', $fragment);
1456                  $output.= str_pad($hex, $this->log_long_width - $this->log_short_width, ' ') . $raw . "\r\n";
1457                  $j++;
1458              } while (strlen($current_log));
1459              $output.= "\r\n";
1460          }
1461  
1462          return $output;
1463      }
1464  
1465      /**
1466       * Helper function for _format_log
1467       *
1468       * For use with preg_replace_callback()
1469       *
1470       * @param array $matches
1471       * @access private
1472       * @return string
1473       */
1474      function _format_log_helper($matches)
1475      {
1476          return $this->log_boundary . str_pad(dechex(ord($matches[0])), 2, '0', STR_PAD_LEFT);
1477      }
1478  
1479      /**
1480       * Return the server key public exponent
1481       *
1482       * Returns, by default, the base-10 representation.  If $raw_output is set to true, returns, instead,
1483       * the raw bytes.  This behavior is similar to PHP's md5() function.
1484       *
1485       * @param bool $raw_output
1486       * @return string
1487       * @access public
1488       */
1489      function getServerKeyPublicExponent($raw_output = false)
1490      {
1491          return $raw_output ? $this->server_key_public_exponent->toBytes() : $this->server_key_public_exponent->toString();
1492      }
1493  
1494      /**
1495       * Return the server key public modulus
1496       *
1497       * Returns, by default, the base-10 representation.  If $raw_output is set to true, returns, instead,
1498       * the raw bytes.  This behavior is similar to PHP's md5() function.
1499       *
1500       * @param bool $raw_output
1501       * @return string
1502       * @access public
1503       */
1504      function getServerKeyPublicModulus($raw_output = false)
1505      {
1506          return $raw_output ? $this->server_key_public_modulus->toBytes() : $this->server_key_public_modulus->toString();
1507      }
1508  
1509      /**
1510       * Return the host key public exponent
1511       *
1512       * Returns, by default, the base-10 representation.  If $raw_output is set to true, returns, instead,
1513       * the raw bytes.  This behavior is similar to PHP's md5() function.
1514       *
1515       * @param bool $raw_output
1516       * @return string
1517       * @access public
1518       */
1519      function getHostKeyPublicExponent($raw_output = false)
1520      {
1521          return $raw_output ? $this->host_key_public_exponent->toBytes() : $this->host_key_public_exponent->toString();
1522      }
1523  
1524      /**
1525       * Return the host key public modulus
1526       *
1527       * Returns, by default, the base-10 representation.  If $raw_output is set to true, returns, instead,
1528       * the raw bytes.  This behavior is similar to PHP's md5() function.
1529       *
1530       * @param bool $raw_output
1531       * @return string
1532       * @access public
1533       */
1534      function getHostKeyPublicModulus($raw_output = false)
1535      {
1536          return $raw_output ? $this->host_key_public_modulus->toBytes() : $this->host_key_public_modulus->toString();
1537      }
1538  
1539      /**
1540       * Return a list of ciphers supported by SSH1 server.
1541       *
1542       * Just because a cipher is supported by an SSH1 server doesn't mean it's supported by this library. If $raw_output
1543       * is set to true, returns, instead, an array of constants.  ie. instead of array('Triple-DES in CBC mode'), you'll
1544       * get array(self::CIPHER_3DES).
1545       *
1546       * @param bool $raw_output
1547       * @return array
1548       * @access public
1549       */
1550      function getSupportedCiphers($raw_output = false)
1551      {
1552          return $raw_output ? array_keys($this->supported_ciphers) : array_values($this->supported_ciphers);
1553      }
1554  
1555      /**
1556       * Return a list of authentications supported by SSH1 server.
1557       *
1558       * Just because a cipher is supported by an SSH1 server doesn't mean it's supported by this library. If $raw_output
1559       * is set to true, returns, instead, an array of constants.  ie. instead of array('password authentication'), you'll
1560       * get array(self::AUTH_PASSWORD).
1561       *
1562       * @param bool $raw_output
1563       * @return array
1564       * @access public
1565       */
1566      function getSupportedAuthentications($raw_output = false)
1567      {
1568          return $raw_output ? array_keys($this->supported_authentications) : array_values($this->supported_authentications);
1569      }
1570  
1571      /**
1572       * Return the server identification.
1573       *
1574       * @return string
1575       * @access public
1576       */
1577      function getServerIdentification()
1578      {
1579          return rtrim($this->server_identification);
1580      }
1581  
1582      /**
1583       * Logs data packets
1584       *
1585       * Makes sure that only the last 1MB worth of packets will be logged
1586       *
1587       * @param int $protocol_flags
1588       * @param string $message
1589       * @access private
1590       */
1591      function _append_log($protocol_flags, $message)
1592      {
1593          switch (NET_SSH1_LOGGING) {
1594              // useful for benchmarks
1595              case self::LOG_SIMPLE:
1596                  $this->protocol_flags_log[] = $protocol_flags;
1597                  break;
1598              // the most useful log for SSH1
1599              case self::LOG_COMPLEX:
1600                  $this->protocol_flags_log[] = $protocol_flags;
1601                  $this->_string_shift($message);
1602                  $this->log_size+= strlen($message);
1603                  $this->message_log[] = $message;
1604                  while ($this->log_size > self::LOG_MAX_SIZE) {
1605                      $this->log_size-= strlen(array_shift($this->message_log));
1606                      array_shift($this->protocol_flags_log);
1607                  }
1608                  break;
1609              // dump the output out realtime; packets may be interspersed with non packets,
1610              // passwords won't be filtered out and select other packets may not be correctly
1611              // identified
1612              case self::LOG_REALTIME:
1613                  echo "<pre>\r\n" . $this->_format_log(array($message), array($protocol_flags)) . "\r\n</pre>\r\n";
1614                  @flush();
1615                  @ob_flush();
1616                  break;
1617              // basically the same thing as self::LOG_REALTIME with the caveat that self::LOG_REALTIME_FILE
1618              // needs to be defined and that the resultant log file will be capped out at self::LOG_MAX_SIZE.
1619              // the earliest part of the log file is denoted by the first <<< START >>> and is not going to necessarily
1620              // at the beginning of the file
1621              case self::LOG_REALTIME_FILE:
1622                  if (!isset($this->realtime_log_file)) {
1623                      // PHP doesn't seem to like using constants in fopen()
1624                      $filename = self::LOG_REALTIME_FILE;
1625                      $fp = fopen($filename, 'w');
1626                      $this->realtime_log_file = $fp;
1627                  }
1628                  if (!is_resource($this->realtime_log_file)) {
1629                      break;
1630                  }
1631                  $entry = $this->_format_log(array($message), array($protocol_flags));
1632                  if ($this->realtime_log_wrap) {
1633                      $temp = "<<< START >>>\r\n";
1634                      $entry.= $temp;
1635                      fseek($this->realtime_log_file, ftell($this->realtime_log_file) - strlen($temp));
1636                  }
1637                  $this->realtime_log_size+= strlen($entry);
1638                  if ($this->realtime_log_size > self::LOG_MAX_SIZE) {
1639                      fseek($this->realtime_log_file, 0);
1640                      $this->realtime_log_size = strlen($entry);
1641                      $this->realtime_log_wrap = true;
1642                  }
1643                  fputs($this->realtime_log_file, $entry);
1644          }
1645      }
1646  }