PageRenderTime 146ms CodeModel.GetById 110ms app.highlight 28ms RepoModel.GetById 1ms app.codeStats 0ms

/phpseclib/Net/SSH1.php

https://github.com/kea/phpseclib
PHP | 1334 lines | 570 code | 151 blank | 613 comment | 83 complexity | 2c942eecce5e2668a9bc8734176b462f MD5 | raw file
   1<?php
   2/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
   3
   4/**
   5 * Pure-PHP implementation of SSHv1.
   6 *
   7 * PHP versions 4 and 5
   8 *
   9 * Here's a short example of how to use this library:
  10 * <code>
  11 * <?php
  12 *    include('Net/SSH1.php');
  13 *
  14 *    $ssh = new Net_SSH1('www.domain.tld');
  15 *    if (!$ssh->login('username', 'password')) {
  16 *        exit('Login Failed');
  17 *    }
  18 *
  19 *    echo $ssh->exec('ls -la');
  20 * ?>
  21 * </code>
  22 *
  23 * Here's another short example:
  24 * <code>
  25 * <?php
  26 *    include('Net/SSH1.php');
  27 *
  28 *    $ssh = new Net_SSH1('www.domain.tld');
  29 *    if (!$ssh->login('username', 'password')) {
  30 *        exit('Login Failed');
  31 *    }
  32 *
  33 *    echo $ssh->read('username@username:~$');
  34 *    $ssh->write("ls -la\n");
  35 *    echo $ssh->read('username@username:~$');
  36 * ?>
  37 * </code>
  38 *
  39 * More information on the SSHv1 specification can be found by reading
  40 * {@link http://www.snailbook.com/docs/protocol-1.5.txt protocol-1.5.txt}.
  41 *
  42 * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
  43 * of this software and associated documentation files (the "Software"), to deal
  44 * in the Software without restriction, including without limitation the rights
  45 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  46 * copies of the Software, and to permit persons to whom the Software is
  47 * furnished to do so, subject to the following conditions:
  48 *
  49 * The above copyright notice and this permission notice shall be included in
  50 * all copies or substantial portions of the Software.
  51 *
  52 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  53 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  54 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  55 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  56 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  57 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  58 * THE SOFTWARE.
  59 *
  60 * @category   Net
  61 * @package    Net_SSH1
  62 * @author     Jim Wigginton <terrafrost@php.net>
  63 * @copyright  MMVII Jim Wigginton
  64 * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
  65 * @version    $Id: SSH1.php,v 1.15 2010/03/22 22:01:38 terrafrost Exp $
  66 * @link       http://phpseclib.sourceforge.net
  67 */
  68
  69namespace phpseclib;
  70
  71/**
  72 * Pure-PHP implementation of SSHv1.
  73 *
  74 * @author  Jim Wigginton <terrafrost@php.net>
  75 * @version 0.1.0
  76 * @access  public
  77 * @package Net_SSH1
  78 */
  79class Net_SSH1 {
  80    /**#@+
  81     * Encryption Methods
  82     *
  83     * @see Net_SSH1::getSupportedCiphers()
  84     * @access public
  85     */
  86    /**
  87     * No encryption
  88     *
  89     * Not supported.
  90     */
  91    const CIPHER_NONE = 0;
  92
  93    /**
  94     * IDEA in CFB mode
  95     *
  96     * Not supported.
  97     */
  98    const CIPHER_IDEA = 1;
  99
 100    /**
 101     * DES in CBC mode
 102     */
 103    const CIPHER_DES = 2;
 104
 105    /**
 106     * Triple-DES in CBC mode
 107     *
 108     * All implementations are required to support this
 109     */
 110    const CIPHER_3DES = 3;
 111
 112    /**
 113     * TRI's Simple Stream encryption CBC
 114     *
 115     * Not supported nor is it defined in the official SSH1 specs.  OpenSSH, however, does define it (see cipher.h),
 116     * although it doesn't use it (see cipher.c)
 117     */
 118    const CIPHER_BROKEN_TSS = 4;
 119
 120    /**
 121     * RC4
 122     *
 123     * Not supported.
 124     *
 125     * @internal According to the SSH1 specs:
 126     *
 127     *        "The first 16 bytes of the session key are used as the key for
 128     *         the server to client direction.  The remaining 16 bytes are used
 129     *         as the key for the client to server direction.  This gives
 130     *         independent 128-bit keys for each direction."
 131     *
 132     *     This library currently only supports encryption when the same key is being used for both directions.  This is
 133     *     because there's only one $crypto object.  Two could be added ($encrypt and $decrypt, perhaps).
 134     */
 135    const CIPHER_RC4 = 5;
 136
 137    /**
 138     * Blowfish
 139     *
 140     * Not supported nor is it defined in the official SSH1 specs.  OpenSSH, however, defines it (see cipher.h) and
 141     * uses it (see cipher.c)
 142     */
 143    const CIPHER_BLOWFISH = 6;
 144    /**#@-*/
 145    
 146    /**#@+
 147     * Authentication Methods
 148     *
 149     * @see Net_SSH1::getSupportedAuthentications()
 150     * @access public
 151     */
 152    /**
 153     * .rhosts or /etc/hosts.equiv
 154     */
 155    const AUTH_RHOSTS = 1;
 156
 157    /**
 158     * pure RSA authentication
 159     */
 160    const AUTH_RSA = 2;
 161
 162    /**
 163     * password authentication
 164     *
 165     * This is the only method that is supported by this library.
 166     */
 167    const AUTH_PASSWORD = 3;
 168    
 169    /**
 170     * .rhosts with RSA host authentication
 171     */
 172    const AUTH_RHOSTS_RSA = 4;
 173    /**#@-*/
 174    
 175    /**#@+
 176     * Terminal Modes
 177     *
 178     * @link http://3sp.com/content/developer/maverick-net/docs/Maverick.SSH.PseudoTerminalModesMembers.html
 179     * @access private
 180     */
 181    const TTY_OP_END = 0;
 182    /**#@-*/
 183    
 184    /**
 185     * The Response Type
 186     *
 187     * @see Net_SSH1::_get_binary_packet()
 188     * @access private
 189     */
 190    const RESPONSE_TYPE = 1;
 191    
 192    /**
 193     * The Response Data
 194     *
 195     * @see Net_SSH1::_get_binary_packet()
 196     * @access private
 197     */
 198    const RESPONSE_DATA = 2;
 199    
 200    /**#@+
 201     * Execution Bitmap Masks
 202     *
 203     * @see Net_SSH1::bitmap
 204     * @access private
 205     */
 206    const MASK_CONSTRUCTOR = 1;
 207    const MASK_LOGIN = 2;
 208    const MASK_SHELL = 4;
 209    /**#@-*/
 210    
 211    /**#@+
 212     * @access public
 213     * @see Net_SSH1::getLog()
 214     */
 215    /**
 216     * Returns the message numbers
 217     */
 218    const LOG_SIMPLE = 1;
 219
 220    /**
 221     * Returns the message content
 222     */
 223    const LOG_COMPLEX = 2;
 224    /**#@-*/
 225    
 226    /**#@+
 227     * @access public
 228     * @see Net_SSH1::read()
 229     */
 230    /**
 231     * Returns when a string matching $expect exactly is found
 232     */
 233    const READ_SIMPLE = 1;
 234
 235    /**
 236     * Returns when a string matching the regular expression $expect is found
 237     */
 238    const READ_REGEX = 2;
 239    /**#@-*/
 240
 241    /**
 242     * Protocol Flags Constants
 243     */
 244    const MSG_DISCONNECT = 1;
 245    const SMSG_PUBLIC_KEY = 2;
 246    const CMSG_SESSION_KEY = 3;
 247    const CMSG_USER = 4;
 248    const CMSG_AUTH_PASSWORD = 9;
 249    const CMSG_REQUEST_PTY = 10;
 250    const CMSG_EXEC_SHELL = 12;
 251    const CMSG_EXEC_CMD = 13;
 252    const SMSG_SUCCESS = 14;
 253    const SMSG_FAILURE = 15;
 254    const CMSG_STDIN_DATA = 16;
 255    const SMSG_STDOUT_DATA = 17;
 256    const SMSG_STDERR_DATA = 18;
 257    const CMSG_EOF = 19;
 258    const SMSG_EXITSTATUS = 20;
 259    const CMSG_EXIT_CONFIRMATION = 33;
 260    /**
 261     * The SSH identifier
 262     *
 263     * @var String
 264     * @access private
 265     */
 266    var $identifier = 'SSH-1.5-phpseclib';
 267
 268    /**
 269     * The Socket Object
 270     *
 271     * @var Object
 272     * @access private
 273     */
 274    var $fsock;
 275
 276    /**
 277     * The cryptography object
 278     *
 279     * @var Object
 280     * @access private
 281     */
 282    var $crypto = false;
 283
 284    /**
 285     * Execution Bitmap
 286     *
 287     * The bits that are set represent functions that have been called already.  This is used to determine
 288     * if a requisite function has been successfully executed.  If not, an error should be thrown.
 289     *
 290     * @var Integer
 291     * @access private
 292     */
 293    var $bitmap = 0;
 294
 295    /**
 296     * The Server Key Public Exponent
 297     *
 298     * Logged for debug purposes
 299     *
 300     * @see Net_SSH1::getServerKeyPublicExponent()
 301     * @var String
 302     * @access private
 303     */
 304    var $server_key_public_exponent;
 305
 306    /**
 307     * The Server Key Public Modulus
 308     *
 309     * Logged for debug purposes
 310     *
 311     * @see Net_SSH1::getServerKeyPublicModulus()
 312     * @var String
 313     * @access private
 314     */
 315    var $server_key_public_modulus;
 316
 317    /**
 318     * The Host Key Public Exponent
 319     *
 320     * Logged for debug purposes
 321     *
 322     * @see Net_SSH1::getHostKeyPublicExponent()
 323     * @var String
 324     * @access private
 325     */
 326    var $host_key_public_exponent;
 327
 328    /**
 329     * The Host Key Public Modulus
 330     *
 331     * Logged for debug purposes
 332     *
 333     * @see Net_SSH1::getHostKeyPublicModulus()
 334     * @var String
 335     * @access private
 336     */
 337    var $host_key_public_modulus;
 338
 339    /**
 340     * Supported Ciphers
 341     *
 342     * Logged for debug purposes
 343     *
 344     * @see Net_SSH1::getSupportedCiphers()
 345     * @var Array
 346     * @access private
 347     */
 348    var $supported_ciphers = array(
 349        self::CIPHER_NONE       => 'No encryption',
 350        self::CIPHER_IDEA       => 'IDEA in CFB mode',
 351        self::CIPHER_DES        => 'DES in CBC mode',
 352        self::CIPHER_3DES       => 'Triple-DES in CBC mode',
 353        self::CIPHER_BROKEN_TSS => 'TRI\'s Simple Stream encryption CBC',
 354        self::CIPHER_RC4        => 'RC4',
 355        self::CIPHER_BLOWFISH   => 'Blowfish'
 356    );
 357
 358    /**
 359     * Supported Authentications
 360     *
 361     * Logged for debug purposes
 362     *
 363     * @see Net_SSH1::getSupportedAuthentications()
 364     * @var Array
 365     * @access private
 366     */
 367    var $supported_authentications = array(
 368        self::AUTH_RHOSTS     => '.rhosts or /etc/hosts.equiv',
 369        self::AUTH_RSA        => 'pure RSA authentication',
 370        self::AUTH_PASSWORD   => 'password authentication',
 371        self::AUTH_RHOSTS_RSA => '.rhosts with RSA host authentication'
 372    );
 373
 374    /**
 375     * Server Identification
 376     *
 377     * @see Net_SSH1::getServerIdentification()
 378     * @var String
 379     * @access private
 380     */
 381    var $server_identification = '';
 382
 383    /**
 384     * Protocol Flags
 385     *
 386     * @see Net_SSH1::Net_SSH1()
 387     * @var Array
 388     * @access private
 389     */
 390    var $protocol_flags = array();
 391
 392    /**
 393     * Protocol Flag Log
 394     *
 395     * @see Net_SSH1::getLog()
 396     * @var Array
 397     * @access private
 398     */
 399    var $protocol_flag_log = array();
 400
 401    /**
 402     * Message Log
 403     *
 404     * @see Net_SSH1::getLog()
 405     * @var Array
 406     * @access private
 407     */
 408    var $message_log = array();
 409
 410    /**
 411     * Interactive Buffer
 412     *
 413     * @see Net_SSH1::read()
 414     * @var Array
 415     * @access private
 416     */
 417    var $interactive_buffer = '';
 418
 419    /**
 420     * Default Constructor.
 421     *
 422     * Connects to an SSHv1 server
 423     *
 424     * @param String $host
 425     * @param optional Integer $port
 426     * @param optional Integer $timeout
 427     * @param optional Integer $cipher
 428     * @return Net_SSH1
 429     * @access public
 430     */
 431    function __construct($host, $port = 22, $timeout = 10, $cipher = self::CIPHER_3DES)
 432    {
 433        $this->fsock = @fsockopen($host, $port, $errno, $errstr, $timeout);
 434        if (!$this->fsock) {
 435            throw new \Exception(rtrim("Cannot connect to $host. Error $errno. $errstr"), E_USER_NOTICE);
 436        }
 437
 438        $this->server_identification = $init_line = fgets($this->fsock, 255);
 439
 440        if (defined('NET_SSH1_LOGGING')) {
 441            $this->protocol_flags_log[] = '<-';
 442            $this->protocol_flags_log[] = '->';
 443
 444            if (NET_SSH1_LOGGING == self::LOG_COMPLEX) {
 445                $this->message_log[] = $this->server_identification;
 446                $this->message_log[] = $this->identifier . "\r\n";
 447            }
 448        }
 449
 450        if (!preg_match('#SSH-([0-9\.]+)-(.+)#', $init_line, $parts)) {
 451            throw new \Exception('Can only connect to SSH servers', E_USER_NOTICE);
 452        }
 453        if ($parts[1][0] != 1) {
 454            throw new \Exception("Cannot connect to SSH $parts[1] servers", E_USER_NOTICE);
 455        }
 456
 457        fputs($this->fsock, $this->identifier."\r\n");
 458
 459        $response = $this->_get_binary_packet();
 460        if ($response[self::RESPONSE_TYPE] != self::SMSG_PUBLIC_KEY) {
 461            throw new \Exception('Expected SSH_SMSG_PUBLIC_KEY', E_USER_NOTICE);
 462        }
 463
 464        $anti_spoofing_cookie = $this->_string_shift($response[self::RESPONSE_DATA], 8);
 465
 466        $this->_string_shift($response[self::RESPONSE_DATA], 4);
 467
 468        $temp = unpack('nlen', $this->_string_shift($response[self::RESPONSE_DATA], 2));
 469        $server_key_public_exponent = new Math_BigInteger($this->_string_shift($response[self::RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
 470        $this->server_key_public_exponent = $server_key_public_exponent;
 471
 472        $temp = unpack('nlen', $this->_string_shift($response[self::RESPONSE_DATA], 2));
 473        $server_key_public_modulus = new Math_BigInteger($this->_string_shift($response[self::RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
 474        $this->server_key_public_modulus = $server_key_public_modulus;
 475
 476        $this->_string_shift($response[self::RESPONSE_DATA], 4);
 477
 478        $temp = unpack('nlen', $this->_string_shift($response[self::RESPONSE_DATA], 2));
 479        $host_key_public_exponent = new Math_BigInteger($this->_string_shift($response[self::RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
 480        $this->host_key_public_exponent = $host_key_public_exponent;
 481
 482        $temp = unpack('nlen', $this->_string_shift($response[self::RESPONSE_DATA], 2));
 483        $host_key_public_modulus = new Math_BigInteger($this->_string_shift($response[self::RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
 484        $this->host_key_public_modulus = $host_key_public_modulus;
 485
 486        $this->_string_shift($response[self::RESPONSE_DATA], 4);
 487
 488        // get a list of the supported ciphers
 489        extract(unpack('Nsupported_ciphers_mask', $this->_string_shift($response[self::RESPONSE_DATA], 4)));
 490        foreach ($this->supported_ciphers as $mask=>$name) {
 491            if (($supported_ciphers_mask & (1 << $mask)) == 0) {
 492                unset($this->supported_ciphers[$mask]);
 493            }
 494        }
 495
 496        // get a list of the supported authentications
 497        extract(unpack('Nsupported_authentications_mask', $this->_string_shift($response[self::RESPONSE_DATA], 4)));
 498        foreach ($this->supported_authentications as $mask=>$name) {
 499            if (($supported_authentications_mask & (1 << $mask)) == 0) {
 500                unset($this->supported_authentications[$mask]);
 501            }
 502        }
 503
 504        $session_id = pack('H*', md5($host_key_public_modulus->toBytes() . $server_key_public_modulus->toBytes() . $anti_spoofing_cookie));
 505
 506        $session_key = '';
 507        for ($i = 0; $i < 32; $i++) {
 508            $session_key.= chr(Crypt_Random::generateRandom(0, 255));
 509        }
 510        $double_encrypted_session_key = $session_key ^ str_pad($session_id, 32, chr(0));
 511
 512        if ($server_key_public_modulus->compare($host_key_public_modulus) < 0) {
 513            $double_encrypted_session_key = $this->_rsa_crypt(
 514                $double_encrypted_session_key,
 515                array(
 516                    $server_key_public_exponent,
 517                    $server_key_public_modulus
 518                )
 519            );
 520            $double_encrypted_session_key = $this->_rsa_crypt(
 521                $double_encrypted_session_key,
 522                array(
 523                    $host_key_public_exponent,
 524                    $host_key_public_modulus
 525                )
 526            );
 527        } else {
 528            $double_encrypted_session_key = $this->_rsa_crypt(
 529                $double_encrypted_session_key,
 530                array(
 531                    $host_key_public_exponent,
 532                    $host_key_public_modulus
 533                )
 534            );
 535            $double_encrypted_session_key = $this->_rsa_crypt(
 536                $double_encrypted_session_key,
 537                array(
 538                    $server_key_public_exponent,
 539                    $server_key_public_modulus
 540                )
 541            );
 542        }
 543
 544        $cipher = isset($this->supported_ciphers[$cipher]) ? $cipher : self::CIPHER_3DES;
 545        $data = pack('C2a*na*N', self::CMSG_SESSION_KEY, $cipher, $anti_spoofing_cookie, 8 * strlen($double_encrypted_session_key), $double_encrypted_session_key, 0);
 546
 547        if (!$this->_send_binary_packet($data)) {
 548            throw new \Exception('Error sending SSH_CMSG_SESSION_KEY', E_USER_NOTICE);
 549        }
 550
 551        switch ($cipher) {
 552            //case self::CIPHER_NONE:
 553            //    $this->crypto = new Crypt_Null();
 554            //    break;
 555            case self::CIPHER_DES:
 556                $this->crypto = new Crypt_DES();
 557                $this->crypto->disablePadding();
 558                $this->crypto->enableContinuousBuffer();
 559                $this->crypto->setKey(substr($session_key, 0,  8));
 560                break;
 561            case self::CIPHER_3DES:
 562                $this->crypto = new Crypt_TripleDES(CRYPT_DES_MODE_3CBC);
 563                $this->crypto->disablePadding();
 564                $this->crypto->enableContinuousBuffer();
 565                $this->crypto->setKey(substr($session_key, 0, 24));
 566                break;
 567            //case self::CIPHER_RC4:
 568            //    $this->crypto = new Crypt_RC4();
 569            //    $this->crypto->enableContinuousBuffer();
 570            //    $this->crypto->setKey(substr($session_key, 0,  16));
 571            //    break;
 572        }
 573
 574        $response = $this->_get_binary_packet();
 575
 576        if ($response[self::RESPONSE_TYPE] != self::SMSG_SUCCESS) {
 577            throw new \Exception('Expected SSH_SMSG_SUCCESS', E_USER_NOTICE);
 578        }
 579
 580        $this->bitmap = self::MASK_CONSTRUCTOR;
 581    }
 582
 583    /**
 584     * Login
 585     *
 586     * @param String $username
 587     * @param optional String $password
 588     * @return Boolean
 589     * @access public
 590     */
 591    function login($username, $password = '')
 592    {
 593        if (!($this->bitmap & self::MASK_CONSTRUCTOR)) {
 594            return false;
 595        }
 596
 597        $data = pack('CNa*', self::CMSG_USER, strlen($username), $username);
 598
 599        if (!$this->_send_binary_packet($data)) {
 600            throw new \Exception('Error sending SSH_CMSG_USER', E_USER_NOTICE);
 601        }
 602
 603        $response = $this->_get_binary_packet();
 604
 605        if ($response[self::RESPONSE_TYPE] == self::SMSG_SUCCESS) {
 606            $this->bitmap |= self::MASK_LOGIN;
 607            return true;
 608        } else if ($response[self::RESPONSE_TYPE] != self::SMSG_FAILURE) {
 609            throw new \Exception('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE', E_USER_NOTICE);
 610        }
 611
 612        $data = pack('CNa*', self::CMSG_AUTH_PASSWORD, strlen($password), $password);
 613
 614        if (!$this->_send_binary_packet($data)) {
 615            throw new \Exception('Error sending SSH_CMSG_AUTH_PASSWORD', E_USER_NOTICE);
 616        }
 617
 618        // remove the username and password from the last logged packet
 619        if (defined('NET_SSH1_LOGGING') && NET_SSH1_LOGGING == self::LOG_COMPLEX) {
 620            $data = pack('CNa*', self::CMSG_AUTH_PASSWORD, strlen('password'), 'password');
 621            $this->message_log[count($this->message_log) - 1] = $data; // zzzzz
 622        }
 623
 624        $response = $this->_get_binary_packet();
 625
 626        if ($response[self::RESPONSE_TYPE] == self::SMSG_SUCCESS) {
 627            $this->bitmap |= self::MASK_LOGIN;
 628            return true;
 629        } else if ($response[self::RESPONSE_TYPE] == self::SMSG_FAILURE) {
 630            return false;
 631        } else {
 632            throw new \Exception('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE', E_USER_NOTICE);
 633        }
 634    }
 635
 636    /**
 637     * Executes a command on a non-interactive shell, returns the output, and quits.
 638     *
 639     * An SSH1 server will close the connection after a command has been executed on a non-interactive shell.  SSH2
 640     * servers don't, however, this isn't an SSH2 client.  The way this works, on the server, is by initiating a
 641     * shell with the -s option, as discussed in the following links:
 642     *
 643     * {@link http://www.faqs.org/docs/bashman/bashref_65.html http://www.faqs.org/docs/bashman/bashref_65.html}
 644     * {@link http://www.faqs.org/docs/bashman/bashref_62.html http://www.faqs.org/docs/bashman/bashref_62.html}
 645     *
 646     * To execute further commands, a new Net_SSH1 object will need to be created.
 647     *
 648     * Returns false on failure and the output, otherwise.
 649     *
 650     * @see Net_SSH1::interactiveRead()
 651     * @see Net_SSH1::interactiveWrite()
 652     * @param String $cmd
 653     * @return mixed
 654     * @access public
 655     */
 656    function exec($cmd, $block = true)
 657    {
 658        if (!($this->bitmap & self::MASK_LOGIN)) {
 659            throw new \Exception('Operation disallowed prior to login()', E_USER_NOTICE);
 660        }
 661
 662        $data = pack('CNa*', self::CMSG_EXEC_CMD, strlen($cmd), $cmd);
 663
 664        if (!$this->_send_binary_packet($data)) {
 665            throw new \Exception('Error sending SSH_CMSG_EXEC_CMD', E_USER_NOTICE);
 666        }
 667
 668        if (!$block) {
 669            return true;
 670        }
 671
 672        $output = '';
 673        $response = $this->_get_binary_packet();
 674
 675        do {
 676            $output.= substr($response[self::RESPONSE_DATA], 4);
 677            $response = $this->_get_binary_packet();
 678        } while ($response[self::RESPONSE_TYPE] != self::SMSG_EXITSTATUS);
 679
 680        $data = pack('C', self::CMSG_EXIT_CONFIRMATION);
 681
 682        // i don't think it's really all that important if this packet gets sent or not.
 683        $this->_send_binary_packet($data);
 684
 685        fclose($this->fsock);
 686
 687        // reset the execution bitmap - a new Net_SSH1 object needs to be created.
 688        $this->bitmap = 0;
 689
 690        return $output;
 691    }
 692
 693    /**
 694     * Creates an interactive shell
 695     *
 696     * @see Net_SSH1::interactiveRead()
 697     * @see Net_SSH1::interactiveWrite()
 698     * @return Boolean
 699     * @access private
 700     */
 701    function _initShell()
 702    {
 703        // connect using the sample parameters in protocol-1.5.txt.
 704        // according to wikipedia.org's entry on text terminals, "the fundamental type of application running on a text
 705        // terminal is a command line interpreter or shell".  thus, opening a terminal session to run the shell.
 706        $data = pack('CNa*N4C', self::CMSG_REQUEST_PTY, strlen('vt100'), 'vt100', 24, 80, 0, 0, self::TTY_OP_END);
 707
 708        if (!$this->_send_binary_packet($data)) {
 709            throw new \Exception('Error sending SSH_CMSG_REQUEST_PTY', E_USER_NOTICE);
 710        }
 711
 712        $response = $this->_get_binary_packet();
 713
 714        if ($response[self::RESPONSE_TYPE] != self::SMSG_SUCCESS) {
 715            throw new \Exception('Expected SSH_SMSG_SUCCESS', E_USER_NOTICE);
 716        }
 717
 718        $data = pack('C', self::CMSG_EXEC_SHELL);
 719
 720        if (!$this->_send_binary_packet($data)) {
 721            throw new \Exception('Error sending SSH_CMSG_EXEC_SHELL', E_USER_NOTICE);
 722        }
 723
 724        $this->bitmap |= self::MASK_SHELL;
 725
 726        //stream_set_blocking($this->fsock, 0);
 727
 728        return true;
 729    }
 730
 731    /**
 732     * Inputs a command into an interactive shell.
 733     *
 734     * @see Net_SSH1::interactiveWrite()
 735     * @param String $cmd
 736     * @return Boolean
 737     * @access public
 738     */
 739    function write($cmd)
 740    {
 741        return $this->interactiveWrite($cmd);
 742    }
 743
 744    /**
 745     * Returns the output of an interactive shell when there's a match for $expect
 746     *
 747     * $expect can take the form of a string literal or, if $mode == self::READ_REGEX,
 748     * a regular expression.
 749     *
 750     * @see Net_SSH1::write()
 751     * @param String $expect
 752     * @param Integer $mode
 753     * @return Boolean
 754     * @access public
 755     */
 756    function read($expect, $mode = self::READ_SIMPLE)
 757    {
 758        if (!($this->bitmap & self::MASK_LOGIN)) {
 759            throw new \Exception('Operation disallowed prior to login()', E_USER_NOTICE);
 760        }
 761
 762        if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
 763            throw new \Exception('Unable to initiate an interactive shell session', E_USER_NOTICE);
 764        }
 765
 766        $match = $expect;
 767        while (true) {
 768            if ($mode == self::READ_REGEX) {
 769                preg_match($expect, $this->interactiveBuffer, $matches);
 770                $match = $matches[0];
 771            }
 772            $pos = strpos($this->interactiveBuffer, $match);
 773            if ($pos !== false) {
 774                return $this->_string_shift($this->interactiveBuffer, $pos + strlen($match));
 775            }
 776            $response = $this->_get_binary_packet();
 777            $this->interactiveBuffer.= substr($response[self::RESPONSE_DATA], 4);
 778        }
 779    }
 780
 781    /**
 782     * Inputs a command into an interactive shell.
 783     *
 784     * @see Net_SSH1::interactiveRead()
 785     * @param String $cmd
 786     * @return Boolean
 787     * @access public
 788     */
 789    function interactiveWrite($cmd)
 790    {
 791        if (!($this->bitmap & self::MASK_LOGIN)) {
 792            throw new \Exception('Operation disallowed prior to login()', E_USER_NOTICE);
 793        }
 794
 795        if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
 796            throw new \Exception('Unable to initiate an interactive shell session', E_USER_NOTICE);
 797        }
 798
 799        $data = pack('CNa*', self::CMSG_STDIN_DATA, strlen($cmd), $cmd);
 800
 801        if (!$this->_send_binary_packet($data)) {
 802            throw new \Exception('Error sending SSH_CMSG_STDIN', E_USER_NOTICE);
 803        }
 804
 805        return true;
 806    }
 807
 808    /**
 809     * Returns the output of an interactive shell when no more output is available.
 810     *
 811     * Requires PHP 4.3.0 or later due to the use of the stream_select() function.  If you see stuff like
 812     * "", you're seeing ANSI escape codes.  According to
 813     * {@link http://support.microsoft.com/kb/101875 How to Enable ANSI.SYS in a Command Window}, "Windows NT
 814     * does not support ANSI escape sequences in Win32 Console applications", so if you're a Windows user,
 815     * there's not going to be much recourse.
 816     *
 817     * @see Net_SSH1::interactiveRead()
 818     * @return String
 819     * @access public
 820     */
 821    function interactiveRead()
 822    {
 823        if (!($this->bitmap & self::MASK_LOGIN)) {
 824            throw new \Exception('Operation disallowed prior to login()', E_USER_NOTICE);
 825        }
 826
 827        if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
 828            throw new \Exception('Unable to initiate an interactive shell session', E_USER_NOTICE);
 829        }
 830
 831        $read = array($this->fsock);
 832        $write = $except = null;
 833        if (stream_select($read, $write, $except, 0)) {
 834            $response = $this->_get_binary_packet();
 835            return substr($response[self::RESPONSE_DATA], 4);
 836        } else {
 837            return '';
 838        }
 839    }
 840
 841    /**
 842     * Disconnect
 843     *
 844     * @access public
 845     */
 846    function disconnect()
 847    {
 848        $this->_disconnect();
 849    }
 850
 851    /**
 852     * Destructor.
 853     *
 854     * Will be called, automatically, if you're supporting just PHP5.  If you're supporting PHP4, you'll need to call
 855     * disconnect().
 856     *
 857     * @access public
 858     */
 859    function __destruct()
 860    {
 861        $this->_disconnect();
 862    }
 863
 864    /**
 865     * Disconnect
 866     *
 867     * @param String $msg
 868     * @access private
 869     */
 870    function _disconnect($msg = 'Client Quit')
 871    {
 872        if ($this->bitmap) {
 873            $data = pack('C', self::CMSG_EOF);
 874            $this->_send_binary_packet($data);
 875
 876            $response = $this->_get_binary_packet();
 877            switch ($response[self::RESPONSE_TYPE]) {
 878                case self::SMSG_EXITSTATUS:
 879                    $data = pack('C', self::CMSG_EXIT_CONFIRMATION);
 880                    break;
 881                default:
 882                    $data = pack('CNa*', self::MSG_DISCONNECT, strlen($msg), $msg);
 883            }
 884
 885            $this->_send_binary_packet($data);
 886            fclose($this->fsock);
 887            $this->bitmap = 0;
 888        }
 889    }
 890
 891    /**
 892     * Gets Binary Packets
 893     *
 894     * See 'The Binary Packet Protocol' of protocol-1.5.txt for more info.
 895     *
 896     * Also, this function could be improved upon by adding detection for the following exploit:
 897     * http://www.securiteam.com/securitynews/5LP042K3FY.html
 898     *
 899     * @see Net_SSH1::_send_binary_packet()
 900     * @return Array
 901     * @access private
 902     */
 903    function _get_binary_packet()
 904    {
 905        if (feof($this->fsock)) {
 906            throw new \Exception('Connection closed prematurely', E_USER_NOTICE);
 907        }
 908
 909        $temp = unpack('Nlength', fread($this->fsock, 4));
 910
 911        $padding_length = 8 - ($temp['length'] & 7);
 912        $length = $temp['length'] + $padding_length;
 913
 914        $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
 915        $raw = fread($this->fsock, $length);
 916        $stop = strtok(microtime(), ' ') + strtok('');
 917
 918        if ($this->crypto !== false) {
 919            $raw = $this->crypto->decrypt($raw);
 920        }
 921
 922        $padding = substr($raw, 0, $padding_length);
 923        $type = $raw[$padding_length];
 924        $data = substr($raw, $padding_length + 1, -4);
 925
 926        $temp = unpack('Ncrc', substr($raw, -4));
 927
 928        //if ( $temp['crc'] != $this->_crc($padding . $type . $data) ) {
 929        //    throw new \Exception('Bad CRC in packet from server', E_USER_NOTICE);
 930        //    return false;
 931        //}
 932
 933        $type = ord($type);
 934
 935        if (defined('NET_SSH1_LOGGING')) {
 936            $temp = isset($this->protocol_flags[$type]) ? $this->protocol_flags[$type] : 'UNKNOWN';
 937            $this->protocol_flags_log[] = '<- ' . $temp .
 938                                          ' (' . round($stop - $start, 4) . 's)';
 939            if (NET_SSH1_LOGGING == self::LOG_COMPLEX) {
 940                $this->message_log[] = $data;
 941            }
 942        }
 943
 944        return array(
 945            self::RESPONSE_TYPE => $type,
 946            self::RESPONSE_DATA => $data
 947        );
 948    }
 949
 950    /**
 951     * Sends Binary Packets
 952     *
 953     * Returns true on success, false on failure.
 954     *
 955     * @see Net_SSH1::_get_binary_packet()
 956     * @param String $data
 957     * @return Boolean
 958     * @access private
 959     */
 960    function _send_binary_packet($data) {
 961        if (feof($this->fsock)) {
 962            throw new \Exception('Connection closed prematurely', E_USER_NOTICE);
 963        }
 964
 965        if (defined('NET_SSH1_LOGGING')) {
 966            $temp = isset($this->protocol_flags[ord($data[0])]) ? $this->protocol_flags[ord($data[0])] : 'UNKNOWN';
 967            $this->protocol_flags_log[] = '-> ' . $temp .
 968                                          ' (' . round($stop - $start, 4) . 's)';
 969            if (NET_SSH1_LOGGING == self::LOG_COMPLEX) {
 970                $this->message_log[] = substr($data, 1);
 971            }
 972        }
 973
 974        $length = strlen($data) + 4;
 975
 976        $padding_length = 8 - ($length & 7);
 977        $padding = '';
 978        for ($i = 0; $i < $padding_length; $i++) {
 979            $padding.= chr(Crypt_Random::generateRandom(0, 255));
 980        }
 981
 982        $data = $padding . $data;
 983        $data.= pack('N', $this->_crc($data));
 984
 985        if ($this->crypto !== false) {
 986            $data = $this->crypto->encrypt($data);
 987        }
 988
 989        $packet = pack('Na*', $length, $data);
 990
 991        $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
 992        $result = strlen($packet) == fputs($this->fsock, $packet);
 993        $stop = strtok(microtime(), ' ') + strtok('');
 994
 995        return $result;
 996    }
 997
 998    /**
 999     * Cyclic Redundancy Check (CRC)
1000     *
1001     * PHP's crc32 function is implemented slightly differently than the one that SSH v1 uses, so
1002     * we've reimplemented it. A more detailed discussion of the differences can be found after
1003     * $crc_lookup_table's initialization.
1004     *
1005     * @see Net_SSH1::_get_binary_packet()
1006     * @see Net_SSH1::_send_binary_packet()
1007     * @param String $data
1008     * @return Integer
1009     * @access private
1010     */
1011    function _crc($data)
1012    {
1013        static $crc_lookup_table = array(
1014            0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
1015            0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
1016            0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
1017            0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
1018            0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
1019            0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
1020            0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
1021            0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
1022            0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
1023            0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
1024            0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
1025            0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
1026            0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
1027            0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
1028            0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
1029            0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
1030            0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
1031            0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
1032            0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
1033            0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
1034            0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
1035            0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
1036            0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
1037            0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
1038            0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
1039            0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
1040            0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
1041            0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
1042            0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
1043            0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
1044            0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
1045            0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
1046            0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
1047            0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
1048            0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
1049            0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
1050            0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
1051            0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
1052            0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
1053            0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
1054            0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
1055            0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
1056            0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
1057            0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
1058            0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
1059            0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
1060            0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
1061            0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
1062            0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
1063            0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
1064            0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
1065            0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
1066            0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
1067            0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
1068            0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
1069            0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
1070            0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
1071            0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
1072            0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
1073            0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
1074            0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
1075            0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
1076            0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
1077            0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
1078        );
1079
1080        // For this function to yield the same output as PHP's crc32 function, $crc would have to be
1081        // set to 0xFFFFFFFF, initially - not 0x00000000 as it currently is.
1082        $crc = 0x00000000;
1083        $length = strlen($data);
1084
1085        for ($i=0;$i<$length;$i++) {
1086            // We AND $crc >> 8 with 0x00FFFFFF because we want the eight newly added bits to all
1087            // be zero.  PHP, unfortunately, doesn't always do this.  0x80000000 >> 8, as an example,
1088            // yields 0xFF800000 - not 0x00800000.  The following link elaborates:
1089            // http://www.php.net/manual/en/language.operators.bitwise.php#57281
1090            $crc = (($crc >> 8) & 0x00FFFFFF) ^ $crc_lookup_table[($crc & 0xFF) ^ ord($data[$i])];
1091        }
1092
1093        // In addition to having to set $crc to 0xFFFFFFFF, initially, the return value must be XOR'd with
1094        // 0xFFFFFFFF for this function to return the same thing that PHP's crc32 function would.
1095        return $crc;
1096    }
1097
1098    /**
1099     * String Shift
1100     *
1101     * Inspired by array_shift
1102     *
1103     * @param String $string
1104     * @param optional Integer $index
1105     * @return String
1106     * @access private
1107     */
1108    function _string_shift(&$string, $index = 1)
1109    {
1110        $substr = substr($string, 0, $index);
1111        $string = substr($string, $index);
1112        return $substr;
1113    }
1114
1115    /**
1116     * RSA Encrypt
1117     *
1118     * Returns mod(pow($m, $e), $n), where $n should be the product of two (large) primes $p and $q and where $e
1119     * should be a number with the property that gcd($e, ($p - 1) * ($q - 1)) == 1.  Could just make anything that
1120     * calls this call modexp, instead, but I think this makes things clearer, maybe...
1121     *
1122     * @see Net_SSH1::Net_SSH1()
1123     * @param Math_BigInteger $m
1124     * @param Array $key
1125     * @return Math_BigInteger
1126     * @access private
1127     */
1128    function _rsa_crypt($m, $key)
1129    {
1130        /*
1131        $rsa = new Crypt_RSA();
1132        $rsa->loadKey($key, CRYPT_RSA_PUBLIC_FORMAT_RAW);
1133        $rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
1134        return $rsa->encrypt($m);
1135        */
1136
1137        // To quote from protocol-1.5.txt:
1138        // The most significant byte (which is only partial as the value must be
1139        // less than the public modulus, which is never a power of two) is zero.
1140        //
1141        // The next byte contains the value 2 (which stands for public-key
1142        // encrypted data in the PKCS standard [PKCS#1]).  Then, there are non-
1143        // zero random bytes to fill any unused space, a zero byte, and the data
1144        // to be encrypted in the least significant bytes, the last byte of the
1145        // data in the least significant byte.
1146
1147        // Presumably the part of PKCS#1 they're refering to is "Section 7.2.1 Encryption Operation",
1148        // under "7.2 RSAES-PKCS1-v1.5" and "7 Encryption schemes" of the following URL:
1149        // ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.pdf
1150        $temp = chr(0) . chr(2);
1151        $modulus = $key[1]->toBytes();
1152        $length = strlen($modulus) - strlen($m) - 3;
1153        for ($i = 0; $i < $length; $i++) {
1154            $temp.= chr(Crypt_Random::generateRandom(1, 255));
1155        }
1156        $temp.= chr(0) . $m;
1157
1158        $m = new Math_BigInteger($temp, 256);
1159        $m = $m->modPow($key[0], $key[1]);
1160
1161        return $m->toBytes();
1162    }
1163
1164    /**
1165     * Returns a log of the packets that have been sent and received.
1166     *
1167     * Returns a string if NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX, an array if NET_SSH2_LOGGING == NET_SSH2_LOG_SIMPLE and false if !defined('NET_SSH2_LOGGING')
1168     *
1169     * @access public
1170     * @return String or Array
1171     */
1172    function getLog()
1173    {
1174        if (!defined('NET_SSH1_LOGGING')) {
1175            return false;
1176        }
1177
1178        switch (NET_SSH1_LOGGING) {
1179            case self::LOG_SIMPLE:
1180                return $this->message_number_log;
1181                break;
1182            case self::LOG_COMPLEX:
1183                return $this->_format_log($this->message_log, $this->protocol_flags_log);
1184                break;
1185            default:
1186                return false;
1187        }
1188    }
1189
1190    /**
1191     * Formats a log for printing
1192     *
1193     * @param Array $message_log
1194     * @param Array $message_number_log
1195     * @access private
1196     * @return String
1197     */
1198    function _format_log($message_log, $message_number_log)
1199    {
1200        static $boundary = ':', $long_width = 65, $short_width = 16;
1201
1202        $output = '';
1203        for ($i = 0; $i < count($message_log); $i++) {
1204            $output.= $message_number_log[$i] . "\r\n";
1205            $current_log = $message_log[$i];
1206            $j = 0;
1207            do {
1208                if (!empty($current_log)) {
1209                    $output.= str_pad(dechex($j), 7, '0', STR_PAD_LEFT) . '0  ';
1210                }
1211                $fragment = $this->_string_shift($current_log, $short_width);
1212                $hex = substr(
1213                           preg_replace(
1214                               '#(.)#es',
1215                               '"' . $boundary . '" . str_pad(dechex(ord(substr("\\1", -1))), 2, "0", STR_PAD_LEFT)',
1216                               $fragment),
1217                           strlen($boundary)
1218                       );
1219                // replace non ASCII printable characters with dots
1220                // http://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters
1221                // also replace < with a . since < messes up the output on web browsers
1222                $raw = preg_replace('#[^\x20-\x7E]|<#', '.', $fragment);
1223                $output.= str_pad($hex, $long_width - $short_width, ' ') . $raw . "\r\n";
1224                $j++;
1225            } while (!empty($current_log));
1226            $output.= "\r\n";
1227        }
1228
1229        return $output;
1230    }
1231
1232    /**
1233     * Return the server key public exponent
1234     *
1235     * Returns, by default, the base-10 representation.  If $raw_output is set to true, returns, instead,
1236     * the raw bytes.  This behavior is similar to PHP's md5() function.
1237     *
1238     * @param optional Boolean $raw_output
1239     * @return String
1240     * @access public
1241     */
1242    function getServerKeyPublicExponent($raw_output = false)
1243    {
1244        return $raw_output ? $this->server_key_public_exponent->toBytes() : $this->server_key_public_exponent->toString();
1245    }
1246
1247    /**
1248     * Return the server key public modulus
1249     *
1250     * Returns, by default, the base-10 representation.  If $raw_output is set to true, returns, instead,
1251     * the raw bytes.  This behavior is similar to PHP's md5() function.
1252     *
1253     * @param optional Boolean $raw_output
1254     * @return String
1255     * @access public
1256     */
1257    function getServerKeyPublicModulus($raw_output = false)
1258    {
1259        return $raw_output ? $this->server_key_public_modulus->toBytes() : $this->server_key_public_modulus->toString();
1260    }
1261
1262    /**
1263     * Return the host key public exponent
1264     *
1265     * Returns, by default, the base-10 representation.  If $raw_output is set to true, returns, instead,
1266     * the raw bytes.  This behavior is similar to PHP's md5() function.
1267     *
1268     * @param optional Boolean $raw_output
1269     * @return String
1270     * @access public
1271     */
1272    function getHostKeyPublicExponent($raw_output = false)
1273    {
1274        return $raw_output ? $this->host_key_public_exponent->toBytes() : $this->host_key_public_exponent->toString();
1275    }
1276
1277    /**
1278     * Return the host key public modulus
1279     *
1280     * Returns, by default, the base-10 representation.  If $raw_output is set to true, returns, instead,
1281     * the raw bytes.  This behavior is similar to PHP's md5() function.
1282     *
1283     * @param optional Boolean $raw_output
1284     * @return String
1285     * @access public
1286     */
1287    function getHostKeyPublicModulus($raw_output = false)
1288    {
1289        return $raw_output ? $this->host_key_public_modulus->toBytes() : $this->host_key_public_modulus->toString();
1290    }
1291
1292    /**
1293     * Return a list of ciphers supported by SSH1 server.
1294     *
1295     * Just because a cipher is supported by an SSH1 server doesn't mean it's supported by this library. If $raw_output
1296     * is set to true, returns, instead, an array of constants.  ie. instead of array('Triple-DES in CBC mode'), you'll
1297     * get array(self::CIPHER_3DES).
1298     *
1299     * @param optional Boolean $raw_output
1300     * @return Array
1301     * @access public
1302     */
1303    function getSupportedCiphers($raw_output = false)
1304    {
1305        return $raw_output ? array_keys($this->supported_ciphers) : array_values($this->supported_ciphers);
1306    }
1307
1308    /**
1309     * Return a list of authentications supported by SSH1 server.
1310     *
1311     * Just because a cipher is supported by an SSH1 server doesn't mean it's supported by this library. If $raw_output
1312     * is set to true, returns, instead, an array of constants.  ie. instead of array('password authentication'), you'll
1313     * get array(self::AUTH_PASSWORD).
1314     *
1315     * @param optional Boolean $raw_output
1316     * @return Array
1317     * @access public
1318     */
1319    function getSupportedAuthentications($raw_output = false)
1320    {
1321        return $raw_output ? array_keys($this->supported_authentications) : array_values($this->supported_authentications);
1322    }
1323
1324    /**
1325     * Return the server identification.
1326     *
1327     * @return String
1328     * @access public
1329     */
1330    function getServerIdentification()
1331    {
1332        return rtrim($this->server_identification);
1333    }
1334}