[ 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       * @return mixed
 816       * @access public
 817       */
 818      function exec($cmd, $block = true)
 819      {
 820          if (!($this->bitmap & self::MASK_LOGIN)) {
 821              user_error('Operation disallowed prior to login()');
 822              return false;
 823          }
 824  
 825          $data = pack('CNa*', NET_SSH1_CMSG_EXEC_CMD, strlen($cmd), $cmd);
 826  
 827          if (!$this->_send_binary_packet($data)) {
 828              user_error('Error sending SSH_CMSG_EXEC_CMD');
 829              return false;
 830          }
 831  
 832          if (!$block) {
 833              return true;
 834          }
 835  
 836          $output = '';
 837          $response = $this->_get_binary_packet();
 838  
 839          if ($response !== false) {
 840              do {
 841                  $output.= substr($response[self::RESPONSE_DATA], 4);
 842                  $response = $this->_get_binary_packet();
 843              } while (is_array($response) && $response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_EXITSTATUS);
 844          }
 845  
 846          $data = pack('C', NET_SSH1_CMSG_EXIT_CONFIRMATION);
 847  
 848          // i don't think it's really all that important if this packet gets sent or not.
 849          $this->_send_binary_packet($data);
 850  
 851          fclose($this->fsock);
 852  
 853          // reset the execution bitmap - a new \phpseclib\Net\SSH1 object needs to be created.
 854          $this->bitmap = 0;
 855  
 856          return $output;
 857      }
 858  
 859      /**
 860       * Creates an interactive shell
 861       *
 862       * @see self::interactiveRead()
 863       * @see self::interactiveWrite()
 864       * @return bool
 865       * @access private
 866       */
 867      function _initShell()
 868      {
 869          // connect using the sample parameters in protocol-1.5.txt.
 870          // according to wikipedia.org's entry on text terminals, "the fundamental type of application running on a text
 871          // terminal is a command line interpreter or shell".  thus, opening a terminal session to run the shell.
 872          $data = pack('CNa*N4C', NET_SSH1_CMSG_REQUEST_PTY, strlen('vt100'), 'vt100', 24, 80, 0, 0, self::TTY_OP_END);
 873  
 874          if (!$this->_send_binary_packet($data)) {
 875              user_error('Error sending SSH_CMSG_REQUEST_PTY');
 876              return false;
 877          }
 878  
 879          $response = $this->_get_binary_packet();
 880  
 881          if ($response === true) {
 882              return false;
 883          }
 884          if ($response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) {
 885              user_error('Expected SSH_SMSG_SUCCESS');
 886              return false;
 887          }
 888  
 889          $data = pack('C', NET_SSH1_CMSG_EXEC_SHELL);
 890  
 891          if (!$this->_send_binary_packet($data)) {
 892              user_error('Error sending SSH_CMSG_EXEC_SHELL');
 893              return false;
 894          }
 895  
 896          $this->bitmap |= self::MASK_SHELL;
 897  
 898          //stream_set_blocking($this->fsock, 0);
 899  
 900          return true;
 901      }
 902  
 903      /**
 904       * Inputs a command into an interactive shell.
 905       *
 906       * @see self::interactiveWrite()
 907       * @param string $cmd
 908       * @return bool
 909       * @access public
 910       */
 911      function write($cmd)
 912      {
 913          return $this->interactiveWrite($cmd);
 914      }
 915  
 916      /**
 917       * Returns the output of an interactive shell when there's a match for $expect
 918       *
 919       * $expect can take the form of a string literal or, if $mode == self::READ_REGEX,
 920       * a regular expression.
 921       *
 922       * @see self::write()
 923       * @param string $expect
 924       * @param int $mode
 925       * @return bool
 926       * @access public
 927       */
 928      function read($expect, $mode = self::READ_SIMPLE)
 929      {
 930          if (!($this->bitmap & self::MASK_LOGIN)) {
 931              user_error('Operation disallowed prior to login()');
 932              return false;
 933          }
 934  
 935          if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
 936              user_error('Unable to initiate an interactive shell session');
 937              return false;
 938          }
 939  
 940          $match = $expect;
 941          while (true) {
 942              if ($mode == self::READ_REGEX) {
 943                  preg_match($expect, $this->interactiveBuffer, $matches);
 944                  $match = isset($matches[0]) ? $matches[0] : '';
 945              }
 946              $pos = strlen($match) ? strpos($this->interactiveBuffer, $match) : false;
 947              if ($pos !== false) {
 948                  return $this->_string_shift($this->interactiveBuffer, $pos + strlen($match));
 949              }
 950              $response = $this->_get_binary_packet();
 951  
 952              if ($response === true) {
 953                  return $this->_string_shift($this->interactiveBuffer, strlen($this->interactiveBuffer));
 954              }
 955              $this->interactiveBuffer.= substr($response[self::RESPONSE_DATA], 4);
 956          }
 957      }
 958  
 959      /**
 960       * Inputs a command into an interactive shell.
 961       *
 962       * @see self::interactiveRead()
 963       * @param string $cmd
 964       * @return bool
 965       * @access public
 966       */
 967      function interactiveWrite($cmd)
 968      {
 969          if (!($this->bitmap & self::MASK_LOGIN)) {
 970              user_error('Operation disallowed prior to login()');
 971              return false;
 972          }
 973  
 974          if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
 975              user_error('Unable to initiate an interactive shell session');
 976              return false;
 977          }
 978  
 979          $data = pack('CNa*', NET_SSH1_CMSG_STDIN_DATA, strlen($cmd), $cmd);
 980  
 981          if (!$this->_send_binary_packet($data)) {
 982              user_error('Error sending SSH_CMSG_STDIN');
 983              return false;
 984          }
 985  
 986          return true;
 987      }
 988  
 989      /**
 990       * Returns the output of an interactive shell when no more output is available.
 991       *
 992       * Requires PHP 4.3.0 or later due to the use of the stream_select() function.  If you see stuff like
 993       * "^[[00m", you're seeing ANSI escape codes.  According to
 994       * {@link http://support.microsoft.com/kb/101875 How to Enable ANSI.SYS in a Command Window}, "Windows NT
 995       * does not support ANSI escape sequences in Win32 Console applications", so if you're a Windows user,
 996       * there's not going to be much recourse.
 997       *
 998       * @see self::interactiveRead()
 999       * @return string
1000       * @access public
1001       */
1002      function interactiveRead()
1003      {
1004          if (!($this->bitmap & self::MASK_LOGIN)) {
1005              user_error('Operation disallowed prior to login()');
1006              return false;
1007          }
1008  
1009          if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
1010              user_error('Unable to initiate an interactive shell session');
1011              return false;
1012          }
1013  
1014          $read = array($this->fsock);
1015          $write = $except = null;
1016          if (stream_select($read, $write, $except, 0)) {
1017              $response = $this->_get_binary_packet();
1018              return substr($response[self::RESPONSE_DATA], 4);
1019          } else {
1020              return '';
1021          }
1022      }
1023  
1024      /**
1025       * Disconnect
1026       *
1027       * @access public
1028       */
1029      function disconnect()
1030      {
1031          $this->_disconnect();
1032      }
1033  
1034      /**
1035       * Destructor.
1036       *
1037       * Will be called, automatically, if you're supporting just PHP5.  If you're supporting PHP4, you'll need to call
1038       * disconnect().
1039       *
1040       * @access public
1041       */
1042      function __destruct()
1043      {
1044          $this->_disconnect();
1045      }
1046  
1047      /**
1048       * Disconnect
1049       *
1050       * @param string $msg
1051       * @access private
1052       */
1053      function _disconnect($msg = 'Client Quit')
1054      {
1055          if ($this->bitmap) {
1056              $data = pack('C', NET_SSH1_CMSG_EOF);
1057              $this->_send_binary_packet($data);
1058              /*
1059              $response = $this->_get_binary_packet();
1060              if ($response === true) {
1061                  $response = array(self::RESPONSE_TYPE => -1);
1062              }
1063              switch ($response[self::RESPONSE_TYPE]) {
1064                  case NET_SSH1_SMSG_EXITSTATUS:
1065                      $data = pack('C', NET_SSH1_CMSG_EXIT_CONFIRMATION);
1066                      break;
1067                  default:
1068                      $data = pack('CNa*', NET_SSH1_MSG_DISCONNECT, strlen($msg), $msg);
1069              }
1070              */
1071              $data = pack('CNa*', NET_SSH1_MSG_DISCONNECT, strlen($msg), $msg);
1072  
1073              $this->_send_binary_packet($data);
1074              fclose($this->fsock);
1075              $this->bitmap = 0;
1076          }
1077      }
1078  
1079      /**
1080       * Gets Binary Packets
1081       *
1082       * See 'The Binary Packet Protocol' of protocol-1.5.txt for more info.
1083       *
1084       * Also, this function could be improved upon by adding detection for the following exploit:
1085       * http://www.securiteam.com/securitynews/5LP042K3FY.html
1086       *
1087       * @see self::_send_binary_packet()
1088       * @return array
1089       * @access private
1090       */
1091      function _get_binary_packet()
1092      {
1093          if (feof($this->fsock)) {
1094              //user_error('connection closed prematurely');
1095              return false;
1096          }
1097  
1098          if ($this->curTimeout) {
1099              $read = array($this->fsock);
1100              $write = $except = null;
1101  
1102              $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
1103              $sec = floor($this->curTimeout);
1104              $usec = 1000000 * ($this->curTimeout - $sec);
1105              // on windows this returns a "Warning: Invalid CRT parameters detected" error
1106              if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {
1107                  //$this->_disconnect('Timeout');
1108                  return true;
1109              }
1110              $elapsed = strtok(microtime(), ' ') + strtok('') - $start;
1111              $this->curTimeout-= $elapsed;
1112          }
1113  
1114          $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
1115          $data = fread($this->fsock, 4);
1116          if (strlen($data) < 4) {
1117              return false;
1118          }
1119          $temp = unpack('Nlength', $data);
1120  
1121          $padding_length = 8 - ($temp['length'] & 7);
1122          $length = $temp['length'] + $padding_length;
1123          $raw = '';
1124  
1125          while ($length > 0) {
1126              $temp = fread($this->fsock, $length);
1127              if (strlen($temp) != $length) {
1128                  return false;
1129              }
1130              $raw.= $temp;
1131              $length-= strlen($temp);
1132          }
1133          $stop = strtok(microtime(), ' ') + strtok('');
1134  
1135          if (strlen($raw) && $this->crypto !== false) {
1136              $raw = $this->crypto->decrypt($raw);
1137          }
1138  
1139          $padding = substr($raw, 0, $padding_length);
1140          $type = $raw[$padding_length];
1141          $data = substr($raw, $padding_length + 1, -4);
1142  
1143          if (strlen($raw) < 4) {
1144              return false;
1145          }
1146          $temp = unpack('Ncrc', substr($raw, -4));
1147  
1148          //if ( $temp['crc'] != $this->_crc($padding . $type . $data) ) {
1149          //    user_error('Bad CRC in packet from server');
1150          //    return false;
1151          //}
1152  
1153          $type = ord($type);
1154  
1155          if (defined('NET_SSH1_LOGGING')) {
1156              $temp = isset($this->protocol_flags[$type]) ? $this->protocol_flags[$type] : 'UNKNOWN';
1157              $temp = '<- ' . $temp .
1158                      ' (' . round($stop - $start, 4) . 's)';
1159              $this->_append_log($temp, $data);
1160          }
1161  
1162          return array(
1163              self::RESPONSE_TYPE => $type,
1164              self::RESPONSE_DATA => $data
1165          );
1166      }
1167  
1168      /**
1169       * Sends Binary Packets
1170       *
1171       * Returns true on success, false on failure.
1172       *
1173       * @see self::_get_binary_packet()
1174       * @param string $data
1175       * @return bool
1176       * @access private
1177       */
1178      function _send_binary_packet($data)
1179      {
1180          if (feof($this->fsock)) {
1181              //user_error('connection closed prematurely');
1182              return false;
1183          }
1184  
1185          $length = strlen($data) + 4;
1186  
1187          $padding = Random::string(8 - ($length & 7));
1188  
1189          $orig = $data;
1190          $data = $padding . $data;
1191          $data.= pack('N', $this->_crc($data));
1192  
1193          if ($this->crypto !== false) {
1194              $data = $this->crypto->encrypt($data);
1195          }
1196  
1197          $packet = pack('Na*', $length, $data);
1198  
1199          $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
1200          $result = strlen($packet) == fputs($this->fsock, $packet);
1201          $stop = strtok(microtime(), ' ') + strtok('');
1202  
1203          if (defined('NET_SSH1_LOGGING')) {
1204              $temp = isset($this->protocol_flags[ord($orig[0])]) ? $this->protocol_flags[ord($orig[0])] : 'UNKNOWN';
1205              $temp = '-> ' . $temp .
1206                      ' (' . round($stop - $start, 4) . 's)';
1207              $this->_append_log($temp, $orig);
1208          }
1209  
1210          return $result;
1211      }
1212  
1213      /**
1214       * Cyclic Redundancy Check (CRC)
1215       *
1216       * PHP's crc32 function is implemented slightly differently than the one that SSH v1 uses, so
1217       * we've reimplemented it. A more detailed discussion of the differences can be found after
1218       * $crc_lookup_table's initialization.
1219       *
1220       * @see self::_get_binary_packet()
1221       * @see self::_send_binary_packet()
1222       * @param string $data
1223       * @return int
1224       * @access private
1225       */
1226      function _crc($data)
1227      {
1228          static $crc_lookup_table = array(
1229              0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
1230              0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
1231              0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
1232              0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
1233              0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
1234              0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
1235              0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
1236              0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
1237              0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
1238              0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
1239              0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
1240              0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
1241              0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
1242              0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
1243              0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
1244              0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
1245              0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
1246              0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
1247              0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
1248              0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
1249              0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
1250              0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
1251              0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
1252              0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
1253              0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
1254              0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
1255              0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
1256              0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
1257              0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
1258              0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
1259              0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
1260              0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
1261              0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
1262              0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
1263              0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
1264              0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
1265              0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
1266              0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
1267              0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
1268              0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
1269              0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
1270              0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
1271              0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
1272              0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
1273              0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
1274              0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
1275              0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
1276              0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
1277              0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
1278              0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
1279              0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
1280              0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
1281              0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
1282              0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
1283              0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
1284              0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
1285              0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
1286              0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
1287              0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
1288              0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
1289              0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
1290              0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
1291              0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
1292              0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
1293          );
1294  
1295          // For this function to yield the same output as PHP's crc32 function, $crc would have to be
1296          // set to 0xFFFFFFFF, initially - not 0x00000000 as it currently is.
1297          $crc = 0x00000000;
1298          $length = strlen($data);
1299  
1300          for ($i=0; $i<$length; $i++) {
1301              // We AND $crc >> 8 with 0x00FFFFFF because we want the eight newly added bits to all
1302              // be zero.  PHP, unfortunately, doesn't always do this.  0x80000000 >> 8, as an example,
1303              // yields 0xFF800000 - not 0x00800000.  The following link elaborates:
1304              // http://www.php.net/manual/en/language.operators.bitwise.php#57281
1305              $crc = (($crc >> 8) & 0x00FFFFFF) ^ $crc_lookup_table[($crc & 0xFF) ^ ord($data[$i])];
1306          }
1307  
1308          // In addition to having to set $crc to 0xFFFFFFFF, initially, the return value must be XOR'd with
1309          // 0xFFFFFFFF for this function to return the same thing that PHP's crc32 function would.
1310          return $crc;
1311      }
1312  
1313      /**
1314       * String Shift
1315       *
1316       * Inspired by array_shift
1317       *
1318       * @param string $string
1319       * @param int $index
1320       * @return string
1321       * @access private
1322       */
1323      function _string_shift(&$string, $index = 1)
1324      {
1325          $substr = substr($string, 0, $index);
1326          $string = substr($string, $index);
1327          return $substr;
1328      }
1329  
1330      /**
1331       * RSA Encrypt
1332       *
1333       * Returns mod(pow($m, $e), $n), where $n should be the product of two (large) primes $p and $q and where $e
1334       * should be a number with the property that gcd($e, ($p - 1) * ($q - 1)) == 1.  Could just make anything that
1335       * calls this call modexp, instead, but I think this makes things clearer, maybe...
1336       *
1337       * @see self::__construct()
1338       * @param BigInteger $m
1339       * @param array $key
1340       * @return BigInteger
1341       * @access private
1342       */
1343      function _rsa_crypt($m, $key)
1344      {
1345          /*
1346          $rsa = new RSA();
1347          $rsa->loadKey($key, RSA::PUBLIC_FORMAT_RAW);
1348          $rsa->setEncryptionMode(RSA::ENCRYPTION_PKCS1);
1349          return $rsa->encrypt($m);
1350          */
1351  
1352          // To quote from protocol-1.5.txt:
1353          // The most significant byte (which is only partial as the value must be
1354          // less than the public modulus, which is never a power of two) is zero.
1355          //
1356          // The next byte contains the value 2 (which stands for public-key
1357          // encrypted data in the PKCS standard [PKCS#1]).  Then, there are non-
1358          // zero random bytes to fill any unused space, a zero byte, and the data
1359          // to be encrypted in the least significant bytes, the last byte of the
1360          // data in the least significant byte.
1361  
1362          // Presumably the part of PKCS#1 they're refering to is "Section 7.2.1 Encryption Operation",
1363          // under "7.2 RSAES-PKCS1-v1.5" and "7 Encryption schemes" of the following URL:
1364          // ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.pdf
1365          $modulus = $key[1]->toBytes();
1366          $length = strlen($modulus) - strlen($m) - 3;
1367          $random = '';
1368          while (strlen($random) != $length) {
1369              $block = Random::string($length - strlen($random));
1370              $block = str_replace("\x00", '', $block);
1371              $random.= $block;
1372          }
1373          $temp = chr(0) . chr(2) . $random . chr(0) . $m;
1374  
1375          $m = new BigInteger($temp, 256);
1376          $m = $m->modPow($key[0], $key[1]);
1377  
1378          return $m->toBytes();
1379      }
1380  
1381      /**
1382       * Define Array
1383       *
1384       * Takes any number of arrays whose indices are integers and whose values are strings and defines a bunch of
1385       * named constants from it, using the value as the name of the constant and the index as the value of the constant.
1386       * If any of the constants that would be defined already exists, none of the constants will be defined.
1387       *
1388       * @param array $array
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 string $data
1588       * @access private
1589       */
1590      function _append_log($protocol_flags, $message)
1591      {
1592          switch (NET_SSH1_LOGGING) {
1593              // useful for benchmarks
1594              case self::LOG_SIMPLE:
1595                  $this->protocol_flags_log[] = $protocol_flags;
1596                  break;
1597              // the most useful log for SSH1
1598              case self::LOG_COMPLEX:
1599                  $this->protocol_flags_log[] = $protocol_flags;
1600                  $this->_string_shift($message);
1601                  $this->log_size+= strlen($message);
1602                  $this->message_log[] = $message;
1603                  while ($this->log_size > self::LOG_MAX_SIZE) {
1604                      $this->log_size-= strlen(array_shift($this->message_log));
1605                      array_shift($this->protocol_flags_log);
1606                  }
1607                  break;
1608              // dump the output out realtime; packets may be interspersed with non packets,
1609              // passwords won't be filtered out and select other packets may not be correctly
1610              // identified
1611              case self::LOG_REALTIME:
1612                  echo "<pre>\r\n" . $this->_format_log(array($message), array($protocol_flags)) . "\r\n</pre>\r\n";
1613                  @flush();
1614                  @ob_flush();
1615                  break;
1616              // basically the same thing as self::LOG_REALTIME with the caveat that self::LOG_REALTIME_FILE
1617              // needs to be defined and that the resultant log file will be capped out at self::LOG_MAX_SIZE.
1618              // the earliest part of the log file is denoted by the first <<< START >>> and is not going to necessarily
1619              // at the beginning of the file
1620              case self::LOG_REALTIME_FILE:
1621                  if (!isset($this->realtime_log_file)) {
1622                      // PHP doesn't seem to like using constants in fopen()
1623                      $filename = self::LOG_REALTIME_FILE;
1624                      $fp = fopen($filename, 'w');
1625                      $this->realtime_log_file = $fp;
1626                  }
1627                  if (!is_resource($this->realtime_log_file)) {
1628                      break;
1629                  }
1630                  $entry = $this->_format_log(array($message), array($protocol_flags));
1631                  if ($this->realtime_log_wrap) {
1632                      $temp = "<<< START >>>\r\n";
1633                      $entry.= $temp;
1634                      fseek($this->realtime_log_file, ftell($this->realtime_log_file) - strlen($temp));
1635                  }
1636                  $this->realtime_log_size+= strlen($entry);
1637                  if ($this->realtime_log_size > self::LOG_MAX_SIZE) {
1638                      fseek($this->realtime_log_file, 0);
1639                      $this->realtime_log_size = strlen($entry);
1640                      $this->realtime_log_wrap = true;
1641                  }
1642                  fputs($this->realtime_log_file, $entry);
1643          }
1644      }
1645  }