PageRenderTime 61ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/library/phpseclib/Net/SSH2.php

http://openemr.codeplex.com
PHP | 2945 lines | 1555 code | 350 blank | 1040 comment | 257 complexity | 9292afc32c880027d46631a31c23c517 MD5 | raw file
Possible License(s): LGPL-2.1, AGPL-1.0, LGPL-3.0, BSD-3-Clause, GPL-2.0, MPL-2.0, GPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3. /**
  4. * Pure-PHP implementation of SSHv2.
  5. *
  6. * PHP versions 4 and 5
  7. *
  8. * Here are some examples of how to use this library:
  9. * <code>
  10. * <?php
  11. * include('Net/SSH2.php');
  12. *
  13. * $ssh = new Net_SSH2('www.domain.tld');
  14. * if (!$ssh->login('username', 'password')) {
  15. * exit('Login Failed');
  16. * }
  17. *
  18. * echo $ssh->exec('pwd');
  19. * echo $ssh->exec('ls -la');
  20. * ?>
  21. * </code>
  22. *
  23. * <code>
  24. * <?php
  25. * include('Crypt/RSA.php');
  26. * include('Net/SSH2.php');
  27. *
  28. * $key = new Crypt_RSA();
  29. * //$key->setPassword('whatever');
  30. * $key->loadKey(file_get_contents('privatekey'));
  31. *
  32. * $ssh = new Net_SSH2('www.domain.tld');
  33. * if (!$ssh->login('username', $key)) {
  34. * exit('Login Failed');
  35. * }
  36. *
  37. * echo $ssh->read('username@username:~$');
  38. * $ssh->write("ls -la\n");
  39. * echo $ssh->read('username@username:~$');
  40. * ?>
  41. * </code>
  42. *
  43. * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
  44. * of this software and associated documentation files (the "Software"), to deal
  45. * in the Software without restriction, including without limitation the rights
  46. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  47. * copies of the Software, and to permit persons to whom the Software is
  48. * furnished to do so, subject to the following conditions:
  49. *
  50. * The above copyright notice and this permission notice shall be included in
  51. * all copies or substantial portions of the Software.
  52. *
  53. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  54. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  55. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  56. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  57. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  58. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  59. * THE SOFTWARE.
  60. *
  61. * @category Net
  62. * @package Net_SSH2
  63. * @author Jim Wigginton <terrafrost@php.net>
  64. * @copyright MMVII Jim Wigginton
  65. * @license http://www.opensource.org/licenses/mit-license.html MIT License
  66. * @version $Id: SSH2.php,v 1.53 2010-10-24 01:24:30 terrafrost Exp $
  67. * @link http://phpseclib.sourceforge.net
  68. */
  69. /**
  70. * Include Math_BigInteger
  71. *
  72. * Used to do Diffie-Hellman key exchange and DSA/RSA signature verification.
  73. */
  74. if (!class_exists('Math_BigInteger')) {
  75. require_once('Math/BigInteger.php');
  76. }
  77. /**
  78. * Include Crypt_Random
  79. */
  80. // the class_exists() will only be called if the crypt_random function hasn't been defined and
  81. // will trigger a call to __autoload() if you're wanting to auto-load classes
  82. // call function_exists() a second time to stop the require_once from being called outside
  83. // of the auto loader
  84. if (!function_exists('crypt_random') && !class_exists('Crypt_Random') && !function_exists('crypt_random')) {
  85. require_once('Crypt/Random.php');
  86. }
  87. /**
  88. * Include Crypt_Hash
  89. */
  90. if (!class_exists('Crypt_Hash')) {
  91. require_once('Crypt/Hash.php');
  92. }
  93. /**
  94. * Include Crypt_TripleDES
  95. */
  96. if (!class_exists('Crypt_TripleDES')) {
  97. require_once('Crypt/TripleDES.php');
  98. }
  99. /**
  100. * Include Crypt_RC4
  101. */
  102. if (!class_exists('Crypt_RC4')) {
  103. require_once('Crypt/RC4.php');
  104. }
  105. /**
  106. * Include Crypt_AES
  107. */
  108. if (!class_exists('Crypt_AES')) {
  109. require_once('Crypt/AES.php');
  110. }
  111. /**#@+
  112. * Execution Bitmap Masks
  113. *
  114. * @see Net_SSH2::bitmap
  115. * @access private
  116. */
  117. define('NET_SSH2_MASK_CONSTRUCTOR', 0x00000001);
  118. define('NET_SSH2_MASK_LOGIN', 0x00000002);
  119. define('NET_SSH2_MASK_SHELL', 0x00000004);
  120. /**#@-*/
  121. /**#@+
  122. * Channel constants
  123. *
  124. * RFC4254 refers not to client and server channels but rather to sender and recipient channels. we don't refer
  125. * to them in that way because RFC4254 toggles the meaning. the client sends a SSH_MSG_CHANNEL_OPEN message with
  126. * a sender channel and the server sends a SSH_MSG_CHANNEL_OPEN_CONFIRMATION in response, with a sender and a
  127. * recepient channel. at first glance, you might conclude that SSH_MSG_CHANNEL_OPEN_CONFIRMATION's sender channel
  128. * would be the same thing as SSH_MSG_CHANNEL_OPEN's sender channel, but it's not, per this snipet:
  129. * The 'recipient channel' is the channel number given in the original
  130. * open request, and 'sender channel' is the channel number allocated by
  131. * the other side.
  132. *
  133. * @see Net_SSH2::_send_channel_packet()
  134. * @see Net_SSH2::_get_channel_packet()
  135. * @access private
  136. */
  137. define('NET_SSH2_CHANNEL_EXEC', 0); // PuTTy uses 0x100
  138. define('NET_SSH2_CHANNEL_SHELL',1);
  139. /**#@-*/
  140. /**#@+
  141. * @access public
  142. * @see Net_SSH2::getLog()
  143. */
  144. /**
  145. * Returns the message numbers
  146. */
  147. define('NET_SSH2_LOG_SIMPLE', 1);
  148. /**
  149. * Returns the message content
  150. */
  151. define('NET_SSH2_LOG_COMPLEX', 2);
  152. /**
  153. * Outputs the content real-time
  154. */
  155. define('NET_SSH2_LOG_REALTIME', 3);
  156. /**
  157. * Dumps the content real-time to a file
  158. */
  159. define('NET_SSH2_LOG_REALTIME_FILE', 4);
  160. /**#@-*/
  161. /**#@+
  162. * @access public
  163. * @see Net_SSH2::read()
  164. */
  165. /**
  166. * Returns when a string matching $expect exactly is found
  167. */
  168. define('NET_SSH2_READ_SIMPLE', 1);
  169. /**
  170. * Returns when a string matching the regular expression $expect is found
  171. */
  172. define('NET_SSH2_READ_REGEX', 2);
  173. /**
  174. * Make sure that the log never gets larger than this
  175. */
  176. define('NET_SSH2_LOG_MAX_SIZE', 1024 * 1024);
  177. /**#@-*/
  178. /**
  179. * Pure-PHP implementation of SSHv2.
  180. *
  181. * @author Jim Wigginton <terrafrost@php.net>
  182. * @version 0.1.0
  183. * @access public
  184. * @package Net_SSH2
  185. */
  186. class Net_SSH2 {
  187. /**
  188. * The SSH identifier
  189. *
  190. * @var String
  191. * @access private
  192. */
  193. var $identifier = 'SSH-2.0-phpseclib_0.3';
  194. /**
  195. * The Socket Object
  196. *
  197. * @var Object
  198. * @access private
  199. */
  200. var $fsock;
  201. /**
  202. * Execution Bitmap
  203. *
  204. * The bits that are set represent functions that have been called already. This is used to determine
  205. * if a requisite function has been successfully executed. If not, an error should be thrown.
  206. *
  207. * @var Integer
  208. * @access private
  209. */
  210. var $bitmap = 0;
  211. /**
  212. * Error information
  213. *
  214. * @see Net_SSH2::getErrors()
  215. * @see Net_SSH2::getLastError()
  216. * @var String
  217. * @access private
  218. */
  219. var $errors = array();
  220. /**
  221. * Server Identifier
  222. *
  223. * @see Net_SSH2::getServerIdentification()
  224. * @var String
  225. * @access private
  226. */
  227. var $server_identifier = '';
  228. /**
  229. * Key Exchange Algorithms
  230. *
  231. * @see Net_SSH2::getKexAlgorithims()
  232. * @var Array
  233. * @access private
  234. */
  235. var $kex_algorithms;
  236. /**
  237. * Server Host Key Algorithms
  238. *
  239. * @see Net_SSH2::getServerHostKeyAlgorithms()
  240. * @var Array
  241. * @access private
  242. */
  243. var $server_host_key_algorithms;
  244. /**
  245. * Encryption Algorithms: Client to Server
  246. *
  247. * @see Net_SSH2::getEncryptionAlgorithmsClient2Server()
  248. * @var Array
  249. * @access private
  250. */
  251. var $encryption_algorithms_client_to_server;
  252. /**
  253. * Encryption Algorithms: Server to Client
  254. *
  255. * @see Net_SSH2::getEncryptionAlgorithmsServer2Client()
  256. * @var Array
  257. * @access private
  258. */
  259. var $encryption_algorithms_server_to_client;
  260. /**
  261. * MAC Algorithms: Client to Server
  262. *
  263. * @see Net_SSH2::getMACAlgorithmsClient2Server()
  264. * @var Array
  265. * @access private
  266. */
  267. var $mac_algorithms_client_to_server;
  268. /**
  269. * MAC Algorithms: Server to Client
  270. *
  271. * @see Net_SSH2::getMACAlgorithmsServer2Client()
  272. * @var Array
  273. * @access private
  274. */
  275. var $mac_algorithms_server_to_client;
  276. /**
  277. * Compression Algorithms: Client to Server
  278. *
  279. * @see Net_SSH2::getCompressionAlgorithmsClient2Server()
  280. * @var Array
  281. * @access private
  282. */
  283. var $compression_algorithms_client_to_server;
  284. /**
  285. * Compression Algorithms: Server to Client
  286. *
  287. * @see Net_SSH2::getCompressionAlgorithmsServer2Client()
  288. * @var Array
  289. * @access private
  290. */
  291. var $compression_algorithms_server_to_client;
  292. /**
  293. * Languages: Server to Client
  294. *
  295. * @see Net_SSH2::getLanguagesServer2Client()
  296. * @var Array
  297. * @access private
  298. */
  299. var $languages_server_to_client;
  300. /**
  301. * Languages: Client to Server
  302. *
  303. * @see Net_SSH2::getLanguagesClient2Server()
  304. * @var Array
  305. * @access private
  306. */
  307. var $languages_client_to_server;
  308. /**
  309. * Block Size for Server to Client Encryption
  310. *
  311. * "Note that the length of the concatenation of 'packet_length',
  312. * 'padding_length', 'payload', and 'random padding' MUST be a multiple
  313. * of the cipher block size or 8, whichever is larger. This constraint
  314. * MUST be enforced, even when using stream ciphers."
  315. *
  316. * -- http://tools.ietf.org/html/rfc4253#section-6
  317. *
  318. * @see Net_SSH2::Net_SSH2()
  319. * @see Net_SSH2::_send_binary_packet()
  320. * @var Integer
  321. * @access private
  322. */
  323. var $encrypt_block_size = 8;
  324. /**
  325. * Block Size for Client to Server Encryption
  326. *
  327. * @see Net_SSH2::Net_SSH2()
  328. * @see Net_SSH2::_get_binary_packet()
  329. * @var Integer
  330. * @access private
  331. */
  332. var $decrypt_block_size = 8;
  333. /**
  334. * Server to Client Encryption Object
  335. *
  336. * @see Net_SSH2::_get_binary_packet()
  337. * @var Object
  338. * @access private
  339. */
  340. var $decrypt = false;
  341. /**
  342. * Client to Server Encryption Object
  343. *
  344. * @see Net_SSH2::_send_binary_packet()
  345. * @var Object
  346. * @access private
  347. */
  348. var $encrypt = false;
  349. /**
  350. * Client to Server HMAC Object
  351. *
  352. * @see Net_SSH2::_send_binary_packet()
  353. * @var Object
  354. * @access private
  355. */
  356. var $hmac_create = false;
  357. /**
  358. * Server to Client HMAC Object
  359. *
  360. * @see Net_SSH2::_get_binary_packet()
  361. * @var Object
  362. * @access private
  363. */
  364. var $hmac_check = false;
  365. /**
  366. * Size of server to client HMAC
  367. *
  368. * We need to know how big the HMAC will be for the server to client direction so that we know how many bytes to read.
  369. * For the client to server side, the HMAC object will make the HMAC as long as it needs to be. All we need to do is
  370. * append it.
  371. *
  372. * @see Net_SSH2::_get_binary_packet()
  373. * @var Integer
  374. * @access private
  375. */
  376. var $hmac_size = false;
  377. /**
  378. * Server Public Host Key
  379. *
  380. * @see Net_SSH2::getServerPublicHostKey()
  381. * @var String
  382. * @access private
  383. */
  384. var $server_public_host_key;
  385. /**
  386. * Session identifer
  387. *
  388. * "The exchange hash H from the first key exchange is additionally
  389. * used as the session identifier, which is a unique identifier for
  390. * this connection."
  391. *
  392. * -- http://tools.ietf.org/html/rfc4253#section-7.2
  393. *
  394. * @see Net_SSH2::_key_exchange()
  395. * @var String
  396. * @access private
  397. */
  398. var $session_id = false;
  399. /**
  400. * Exchange hash
  401. *
  402. * The current exchange hash
  403. *
  404. * @see Net_SSH2::_key_exchange()
  405. * @var String
  406. * @access private
  407. */
  408. var $exchange_hash = false;
  409. /**
  410. * Message Numbers
  411. *
  412. * @see Net_SSH2::Net_SSH2()
  413. * @var Array
  414. * @access private
  415. */
  416. var $message_numbers = array();
  417. /**
  418. * Disconnection Message 'reason codes' defined in RFC4253
  419. *
  420. * @see Net_SSH2::Net_SSH2()
  421. * @var Array
  422. * @access private
  423. */
  424. var $disconnect_reasons = array();
  425. /**
  426. * SSH_MSG_CHANNEL_OPEN_FAILURE 'reason codes', defined in RFC4254
  427. *
  428. * @see Net_SSH2::Net_SSH2()
  429. * @var Array
  430. * @access private
  431. */
  432. var $channel_open_failure_reasons = array();
  433. /**
  434. * Terminal Modes
  435. *
  436. * @link http://tools.ietf.org/html/rfc4254#section-8
  437. * @see Net_SSH2::Net_SSH2()
  438. * @var Array
  439. * @access private
  440. */
  441. var $terminal_modes = array();
  442. /**
  443. * SSH_MSG_CHANNEL_EXTENDED_DATA's data_type_codes
  444. *
  445. * @link http://tools.ietf.org/html/rfc4254#section-5.2
  446. * @see Net_SSH2::Net_SSH2()
  447. * @var Array
  448. * @access private
  449. */
  450. var $channel_extended_data_type_codes = array();
  451. /**
  452. * Send Sequence Number
  453. *
  454. * See 'Section 6.4. Data Integrity' of rfc4253 for more info.
  455. *
  456. * @see Net_SSH2::_send_binary_packet()
  457. * @var Integer
  458. * @access private
  459. */
  460. var $send_seq_no = 0;
  461. /**
  462. * Get Sequence Number
  463. *
  464. * See 'Section 6.4. Data Integrity' of rfc4253 for more info.
  465. *
  466. * @see Net_SSH2::_get_binary_packet()
  467. * @var Integer
  468. * @access private
  469. */
  470. var $get_seq_no = 0;
  471. /**
  472. * Server Channels
  473. *
  474. * Maps client channels to server channels
  475. *
  476. * @see Net_SSH2::_get_channel_packet()
  477. * @see Net_SSH2::exec()
  478. * @var Array
  479. * @access private
  480. */
  481. var $server_channels = array();
  482. /**
  483. * Channel Buffers
  484. *
  485. * If a client requests a packet from one channel but receives two packets from another those packets should
  486. * be placed in a buffer
  487. *
  488. * @see Net_SSH2::_get_channel_packet()
  489. * @see Net_SSH2::exec()
  490. * @var Array
  491. * @access private
  492. */
  493. var $channel_buffers = array();
  494. /**
  495. * Channel Status
  496. *
  497. * Contains the type of the last sent message
  498. *
  499. * @see Net_SSH2::_get_channel_packet()
  500. * @var Array
  501. * @access private
  502. */
  503. var $channel_status = array();
  504. /**
  505. * Packet Size
  506. *
  507. * Maximum packet size indexed by channel
  508. *
  509. * @see Net_SSH2::_send_channel_packet()
  510. * @var Array
  511. * @access private
  512. */
  513. var $packet_size_client_to_server = array();
  514. /**
  515. * Message Number Log
  516. *
  517. * @see Net_SSH2::getLog()
  518. * @var Array
  519. * @access private
  520. */
  521. var $message_number_log = array();
  522. /**
  523. * Message Log
  524. *
  525. * @see Net_SSH2::getLog()
  526. * @var Array
  527. * @access private
  528. */
  529. var $message_log = array();
  530. /**
  531. * The Window Size
  532. *
  533. * Bytes the other party can send before it must wait for the window to be adjusted (0x7FFFFFFF = 4GB)
  534. *
  535. * @var Integer
  536. * @see Net_SSH2::_send_channel_packet()
  537. * @see Net_SSH2::exec()
  538. * @access private
  539. */
  540. var $window_size = 0x7FFFFFFF;
  541. /**
  542. * Window size
  543. *
  544. * Window size indexed by channel
  545. *
  546. * @see Net_SSH2::_send_channel_packet()
  547. * @var Array
  548. * @access private
  549. */
  550. var $window_size_client_to_server = array();
  551. /**
  552. * Server signature
  553. *
  554. * Verified against $this->session_id
  555. *
  556. * @see Net_SSH2::getServerPublicHostKey()
  557. * @var String
  558. * @access private
  559. */
  560. var $signature = '';
  561. /**
  562. * Server signature format
  563. *
  564. * ssh-rsa or ssh-dss.
  565. *
  566. * @see Net_SSH2::getServerPublicHostKey()
  567. * @var String
  568. * @access private
  569. */
  570. var $signature_format = '';
  571. /**
  572. * Interactive Buffer
  573. *
  574. * @see Net_SSH2::read()
  575. * @var Array
  576. * @access private
  577. */
  578. var $interactiveBuffer = '';
  579. /**
  580. * Current log size
  581. *
  582. * Should never exceed NET_SSH2_LOG_MAX_SIZE
  583. *
  584. * @see Net_SSH2::_send_binary_packet()
  585. * @see Net_SSH2::_get_binary_packet()
  586. * @var Integer
  587. * @access private
  588. */
  589. var $log_size;
  590. /**
  591. * Timeout
  592. *
  593. * @see Net_SSH2::setTimeout()
  594. * @access private
  595. */
  596. var $timeout;
  597. /**
  598. * Current Timeout
  599. *
  600. * @see Net_SSH2::_get_channel_packet()
  601. * @access private
  602. */
  603. var $curTimeout;
  604. /**
  605. * Real-time log file pointer
  606. *
  607. * @see Net_SSH2::_append_log()
  608. * @access private
  609. */
  610. var $realtime_log_file;
  611. /**
  612. * Real-time log file size
  613. *
  614. * @see Net_SSH2::_append_log()
  615. * @access private
  616. */
  617. var $realtime_log_size;
  618. /**
  619. * Has the signature been validated?
  620. *
  621. * @see Net_SSH2::getServerPublicHostKey()
  622. * @access private
  623. */
  624. var $signature_validated = false;
  625. /**
  626. * Real-time log file wrap boolean
  627. *
  628. * @see Net_SSH2::_append_log()
  629. * @access private
  630. */
  631. var $realtime_log_wrap;
  632. /**
  633. * Flag to suppress stderr from output
  634. *
  635. * @see Net_SSH2::enableQuietMode()
  636. * @access private
  637. */
  638. var $quiet_mode = false;
  639. /**
  640. * Default Constructor.
  641. *
  642. * Connects to an SSHv2 server
  643. *
  644. * @param String $host
  645. * @param optional Integer $port
  646. * @param optional Integer $timeout
  647. * @return Net_SSH2
  648. * @access public
  649. */
  650. function Net_SSH2($host, $port = 22, $timeout = 10)
  651. {
  652. $this->message_numbers = array(
  653. 1 => 'NET_SSH2_MSG_DISCONNECT',
  654. 2 => 'NET_SSH2_MSG_IGNORE',
  655. 3 => 'NET_SSH2_MSG_UNIMPLEMENTED',
  656. 4 => 'NET_SSH2_MSG_DEBUG',
  657. 5 => 'NET_SSH2_MSG_SERVICE_REQUEST',
  658. 6 => 'NET_SSH2_MSG_SERVICE_ACCEPT',
  659. 20 => 'NET_SSH2_MSG_KEXINIT',
  660. 21 => 'NET_SSH2_MSG_NEWKEYS',
  661. 30 => 'NET_SSH2_MSG_KEXDH_INIT',
  662. 31 => 'NET_SSH2_MSG_KEXDH_REPLY',
  663. 50 => 'NET_SSH2_MSG_USERAUTH_REQUEST',
  664. 51 => 'NET_SSH2_MSG_USERAUTH_FAILURE',
  665. 52 => 'NET_SSH2_MSG_USERAUTH_SUCCESS',
  666. 53 => 'NET_SSH2_MSG_USERAUTH_BANNER',
  667. 80 => 'NET_SSH2_MSG_GLOBAL_REQUEST',
  668. 81 => 'NET_SSH2_MSG_REQUEST_SUCCESS',
  669. 82 => 'NET_SSH2_MSG_REQUEST_FAILURE',
  670. 90 => 'NET_SSH2_MSG_CHANNEL_OPEN',
  671. 91 => 'NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION',
  672. 92 => 'NET_SSH2_MSG_CHANNEL_OPEN_FAILURE',
  673. 93 => 'NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST',
  674. 94 => 'NET_SSH2_MSG_CHANNEL_DATA',
  675. 95 => 'NET_SSH2_MSG_CHANNEL_EXTENDED_DATA',
  676. 96 => 'NET_SSH2_MSG_CHANNEL_EOF',
  677. 97 => 'NET_SSH2_MSG_CHANNEL_CLOSE',
  678. 98 => 'NET_SSH2_MSG_CHANNEL_REQUEST',
  679. 99 => 'NET_SSH2_MSG_CHANNEL_SUCCESS',
  680. 100 => 'NET_SSH2_MSG_CHANNEL_FAILURE'
  681. );
  682. $this->disconnect_reasons = array(
  683. 1 => 'NET_SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT',
  684. 2 => 'NET_SSH2_DISCONNECT_PROTOCOL_ERROR',
  685. 3 => 'NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED',
  686. 4 => 'NET_SSH2_DISCONNECT_RESERVED',
  687. 5 => 'NET_SSH2_DISCONNECT_MAC_ERROR',
  688. 6 => 'NET_SSH2_DISCONNECT_COMPRESSION_ERROR',
  689. 7 => 'NET_SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE',
  690. 8 => 'NET_SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED',
  691. 9 => 'NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE',
  692. 10 => 'NET_SSH2_DISCONNECT_CONNECTION_LOST',
  693. 11 => 'NET_SSH2_DISCONNECT_BY_APPLICATION',
  694. 12 => 'NET_SSH2_DISCONNECT_TOO_MANY_CONNECTIONS',
  695. 13 => 'NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER',
  696. 14 => 'NET_SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE',
  697. 15 => 'NET_SSH2_DISCONNECT_ILLEGAL_USER_NAME'
  698. );
  699. $this->channel_open_failure_reasons = array(
  700. 1 => 'NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED'
  701. );
  702. $this->terminal_modes = array(
  703. 0 => 'NET_SSH2_TTY_OP_END'
  704. );
  705. $this->channel_extended_data_type_codes = array(
  706. 1 => 'NET_SSH2_EXTENDED_DATA_STDERR'
  707. );
  708. $this->_define_array(
  709. $this->message_numbers,
  710. $this->disconnect_reasons,
  711. $this->channel_open_failure_reasons,
  712. $this->terminal_modes,
  713. $this->channel_extended_data_type_codes,
  714. array(60 => 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ'),
  715. array(60 => 'NET_SSH2_MSG_USERAUTH_PK_OK'),
  716. array(60 => 'NET_SSH2_MSG_USERAUTH_INFO_REQUEST',
  717. 61 => 'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE')
  718. );
  719. $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
  720. $this->fsock = @fsockopen($host, $port, $errno, $errstr, $timeout);
  721. if (!$this->fsock) {
  722. user_error(rtrim("Cannot connect to $host. Error $errno. $errstr"), E_USER_NOTICE);
  723. return;
  724. }
  725. $elapsed = strtok(microtime(), ' ') + strtok('') - $start;
  726. $timeout-= $elapsed;
  727. if ($timeout <= 0) {
  728. user_error(rtrim("Cannot connect to $host. Timeout error"), E_USER_NOTICE);
  729. return;
  730. }
  731. $read = array($this->fsock);
  732. $write = $except = NULL;
  733. $sec = floor($timeout);
  734. $usec = 1000000 * ($timeout - $sec);
  735. // on windows this returns a "Warning: Invalid CRT parameters detected" error
  736. // the !count() is done as a workaround for <https://bugs.php.net/42682>
  737. if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {
  738. user_error(rtrim("Cannot connect to $host. Banner timeout"), E_USER_NOTICE);
  739. return;
  740. }
  741. /* According to the SSH2 specs,
  742. "The server MAY send other lines of data before sending the version
  743. string. Each line SHOULD be terminated by a Carriage Return and Line
  744. Feed. Such lines MUST NOT begin with "SSH-", and SHOULD be encoded
  745. in ISO-10646 UTF-8 [RFC3629] (language is not specified). Clients
  746. MUST be able to process such lines." */
  747. $temp = '';
  748. $extra = '';
  749. while (!feof($this->fsock) && !preg_match('#^SSH-(\d\.\d+)#', $temp, $matches)) {
  750. if (substr($temp, -2) == "\r\n") {
  751. $extra.= $temp;
  752. $temp = '';
  753. }
  754. $temp.= fgets($this->fsock, 255);
  755. }
  756. if (feof($this->fsock)) {
  757. user_error('Connection closed by server', E_USER_NOTICE);
  758. return false;
  759. }
  760. $ext = array();
  761. if (extension_loaded('mcrypt')) {
  762. $ext[] = 'mcrypt';
  763. }
  764. if (extension_loaded('gmp')) {
  765. $ext[] = 'gmp';
  766. } else if (extension_loaded('bcmath')) {
  767. $ext[] = 'bcmath';
  768. }
  769. if (!empty($ext)) {
  770. $this->identifier.= ' (' . implode(', ', $ext) . ')';
  771. }
  772. if (defined('NET_SSH2_LOGGING')) {
  773. $this->message_number_log[] = '<-';
  774. $this->message_number_log[] = '->';
  775. if (NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) {
  776. $this->message_log[] = $extra . $temp;
  777. $this->message_log[] = $this->identifier . "\r\n";
  778. }
  779. }
  780. $this->server_identifier = trim($temp, "\r\n");
  781. if (!empty($extra)) {
  782. $this->errors[] = utf8_decode($extra);
  783. }
  784. if ($matches[1] != '1.99' && $matches[1] != '2.0') {
  785. user_error("Cannot connect to SSH $matches[1] servers", E_USER_NOTICE);
  786. return;
  787. }
  788. fputs($this->fsock, $this->identifier . "\r\n");
  789. $response = $this->_get_binary_packet();
  790. if ($response === false) {
  791. user_error('Connection closed by server', E_USER_NOTICE);
  792. return;
  793. }
  794. if (ord($response[0]) != NET_SSH2_MSG_KEXINIT) {
  795. user_error('Expected SSH_MSG_KEXINIT', E_USER_NOTICE);
  796. return;
  797. }
  798. if (!$this->_key_exchange($response)) {
  799. return;
  800. }
  801. $this->bitmap = NET_SSH2_MASK_CONSTRUCTOR;
  802. }
  803. /**
  804. * Key Exchange
  805. *
  806. * @param String $kexinit_payload_server
  807. * @access private
  808. */
  809. function _key_exchange($kexinit_payload_server)
  810. {
  811. static $kex_algorithms = array(
  812. 'diffie-hellman-group1-sha1', // REQUIRED
  813. 'diffie-hellman-group14-sha1' // REQUIRED
  814. );
  815. static $server_host_key_algorithms = array(
  816. 'ssh-rsa', // RECOMMENDED sign Raw RSA Key
  817. 'ssh-dss' // REQUIRED sign Raw DSS Key
  818. );
  819. static $encryption_algorithms = array(
  820. // from <http://tools.ietf.org/html/rfc4345#section-4>:
  821. 'arcfour256',
  822. 'arcfour128',
  823. 'arcfour', // OPTIONAL the ARCFOUR stream cipher with a 128-bit key
  824. 'aes128-cbc', // RECOMMENDED AES with a 128-bit key
  825. 'aes192-cbc', // OPTIONAL AES with a 192-bit key
  826. 'aes256-cbc', // OPTIONAL AES in CBC mode, with a 256-bit key
  827. // from <http://tools.ietf.org/html/rfc4344#section-4>:
  828. 'aes128-ctr', // RECOMMENDED AES (Rijndael) in SDCTR mode, with 128-bit key
  829. 'aes192-ctr', // RECOMMENDED AES with 192-bit key
  830. 'aes256-ctr', // RECOMMENDED AES with 256-bit key
  831. '3des-ctr', // RECOMMENDED Three-key 3DES in SDCTR mode
  832. '3des-cbc', // REQUIRED three-key 3DES in CBC mode
  833. 'none' // OPTIONAL no encryption; NOT RECOMMENDED
  834. );
  835. static $mac_algorithms = array(
  836. 'hmac-sha1-96', // RECOMMENDED first 96 bits of HMAC-SHA1 (digest length = 12, key length = 20)
  837. 'hmac-sha1', // REQUIRED HMAC-SHA1 (digest length = key length = 20)
  838. 'hmac-md5-96', // OPTIONAL first 96 bits of HMAC-MD5 (digest length = 12, key length = 16)
  839. 'hmac-md5', // OPTIONAL HMAC-MD5 (digest length = key length = 16)
  840. 'none' // OPTIONAL no MAC; NOT RECOMMENDED
  841. );
  842. static $compression_algorithms = array(
  843. 'none' // REQUIRED no compression
  844. //'zlib' // OPTIONAL ZLIB (LZ77) compression
  845. );
  846. // some SSH servers have buggy implementations of some of the above algorithms
  847. switch ($this->server_identifier) {
  848. case 'SSH-2.0-SSHD':
  849. $mac_algorithms = array_values(array_diff(
  850. $mac_algorithms,
  851. array('hmac-sha1-96', 'hmac-md5-96')
  852. ));
  853. }
  854. static $str_kex_algorithms, $str_server_host_key_algorithms,
  855. $encryption_algorithms_server_to_client, $mac_algorithms_server_to_client, $compression_algorithms_server_to_client,
  856. $encryption_algorithms_client_to_server, $mac_algorithms_client_to_server, $compression_algorithms_client_to_server;
  857. if (empty($str_kex_algorithms)) {
  858. $str_kex_algorithms = implode(',', $kex_algorithms);
  859. $str_server_host_key_algorithms = implode(',', $server_host_key_algorithms);
  860. $encryption_algorithms_server_to_client = $encryption_algorithms_client_to_server = implode(',', $encryption_algorithms);
  861. $mac_algorithms_server_to_client = $mac_algorithms_client_to_server = implode(',', $mac_algorithms);
  862. $compression_algorithms_server_to_client = $compression_algorithms_client_to_server = implode(',', $compression_algorithms);
  863. }
  864. $client_cookie = '';
  865. for ($i = 0; $i < 16; $i++) {
  866. $client_cookie.= chr(crypt_random(0, 255));
  867. }
  868. $response = $kexinit_payload_server;
  869. $this->_string_shift($response, 1); // skip past the message number (it should be SSH_MSG_KEXINIT)
  870. $server_cookie = $this->_string_shift($response, 16);
  871. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  872. $this->kex_algorithms = explode(',', $this->_string_shift($response, $temp['length']));
  873. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  874. $this->server_host_key_algorithms = explode(',', $this->_string_shift($response, $temp['length']));
  875. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  876. $this->encryption_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
  877. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  878. $this->encryption_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
  879. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  880. $this->mac_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
  881. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  882. $this->mac_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
  883. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  884. $this->compression_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
  885. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  886. $this->compression_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
  887. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  888. $this->languages_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
  889. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  890. $this->languages_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
  891. extract(unpack('Cfirst_kex_packet_follows', $this->_string_shift($response, 1)));
  892. $first_kex_packet_follows = $first_kex_packet_follows != 0;
  893. // the sending of SSH2_MSG_KEXINIT could go in one of two places. this is the second place.
  894. $kexinit_payload_client = pack('Ca*Na*Na*Na*Na*Na*Na*Na*Na*Na*Na*CN',
  895. NET_SSH2_MSG_KEXINIT, $client_cookie, strlen($str_kex_algorithms), $str_kex_algorithms,
  896. strlen($str_server_host_key_algorithms), $str_server_host_key_algorithms, strlen($encryption_algorithms_client_to_server),
  897. $encryption_algorithms_client_to_server, strlen($encryption_algorithms_server_to_client), $encryption_algorithms_server_to_client,
  898. strlen($mac_algorithms_client_to_server), $mac_algorithms_client_to_server, strlen($mac_algorithms_server_to_client),
  899. $mac_algorithms_server_to_client, strlen($compression_algorithms_client_to_server), $compression_algorithms_client_to_server,
  900. strlen($compression_algorithms_server_to_client), $compression_algorithms_server_to_client, 0, '', 0, '',
  901. 0, 0
  902. );
  903. if (!$this->_send_binary_packet($kexinit_payload_client)) {
  904. return false;
  905. }
  906. // here ends the second place.
  907. // we need to decide upon the symmetric encryption algorithms before we do the diffie-hellman key exchange
  908. for ($i = 0; $i < count($encryption_algorithms) && !in_array($encryption_algorithms[$i], $this->encryption_algorithms_server_to_client); $i++);
  909. if ($i == count($encryption_algorithms)) {
  910. user_error('No compatible server to client encryption algorithms found', E_USER_NOTICE);
  911. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  912. }
  913. // we don't initialize any crypto-objects, yet - we do that, later. for now, we need the lengths to make the
  914. // diffie-hellman key exchange as fast as possible
  915. $decrypt = $encryption_algorithms[$i];
  916. switch ($decrypt) {
  917. case '3des-cbc':
  918. case '3des-ctr':
  919. $decryptKeyLength = 24; // eg. 192 / 8
  920. break;
  921. case 'aes256-cbc':
  922. case 'aes256-ctr':
  923. $decryptKeyLength = 32; // eg. 256 / 8
  924. break;
  925. case 'aes192-cbc':
  926. case 'aes192-ctr':
  927. $decryptKeyLength = 24; // eg. 192 / 8
  928. break;
  929. case 'aes128-cbc':
  930. case 'aes128-ctr':
  931. $decryptKeyLength = 16; // eg. 128 / 8
  932. break;
  933. case 'arcfour':
  934. case 'arcfour128':
  935. $decryptKeyLength = 16; // eg. 128 / 8
  936. break;
  937. case 'arcfour256':
  938. $decryptKeyLength = 32; // eg. 128 / 8
  939. break;
  940. case 'none';
  941. $decryptKeyLength = 0;
  942. }
  943. for ($i = 0; $i < count($encryption_algorithms) && !in_array($encryption_algorithms[$i], $this->encryption_algorithms_client_to_server); $i++);
  944. if ($i == count($encryption_algorithms)) {
  945. user_error('No compatible client to server encryption algorithms found', E_USER_NOTICE);
  946. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  947. }
  948. $encrypt = $encryption_algorithms[$i];
  949. switch ($encrypt) {
  950. case '3des-cbc':
  951. case '3des-ctr':
  952. $encryptKeyLength = 24;
  953. break;
  954. case 'aes256-cbc':
  955. case 'aes256-ctr':
  956. $encryptKeyLength = 32;
  957. break;
  958. case 'aes192-cbc':
  959. case 'aes192-ctr':
  960. $encryptKeyLength = 24;
  961. break;
  962. case 'aes128-cbc':
  963. case 'aes128-ctr':
  964. $encryptKeyLength = 16;
  965. break;
  966. case 'arcfour':
  967. case 'arcfour128':
  968. $encryptKeyLength = 16;
  969. break;
  970. case 'arcfour256':
  971. $encryptKeyLength = 32;
  972. break;
  973. case 'none';
  974. $encryptKeyLength = 0;
  975. }
  976. $keyLength = $decryptKeyLength > $encryptKeyLength ? $decryptKeyLength : $encryptKeyLength;
  977. // through diffie-hellman key exchange a symmetric key is obtained
  978. for ($i = 0; $i < count($kex_algorithms) && !in_array($kex_algorithms[$i], $this->kex_algorithms); $i++);
  979. if ($i == count($kex_algorithms)) {
  980. user_error('No compatible key exchange algorithms found', E_USER_NOTICE);
  981. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  982. }
  983. switch ($kex_algorithms[$i]) {
  984. // see http://tools.ietf.org/html/rfc2409#section-6.2 and
  985. // http://tools.ietf.org/html/rfc2412, appendex E
  986. case 'diffie-hellman-group1-sha1':
  987. $p = pack('H256', 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' .
  988. '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' .
  989. '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
  990. 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF');
  991. $keyLength = $keyLength < 160 ? $keyLength : 160;
  992. $hash = 'sha1';
  993. break;
  994. // see http://tools.ietf.org/html/rfc3526#section-3
  995. case 'diffie-hellman-group14-sha1':
  996. $p = pack('H512', 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' .
  997. '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' .
  998. '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
  999. 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' .
  1000. '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' .
  1001. '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' .
  1002. 'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' .
  1003. '3995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF');
  1004. $keyLength = $keyLength < 160 ? $keyLength : 160;
  1005. $hash = 'sha1';
  1006. }
  1007. $p = new Math_BigInteger($p, 256);
  1008. //$q = $p->bitwise_rightShift(1);
  1009. /* To increase the speed of the key exchange, both client and server may
  1010. reduce the size of their private exponents. It should be at least
  1011. twice as long as the key material that is generated from the shared
  1012. secret. For more details, see the paper by van Oorschot and Wiener
  1013. [VAN-OORSCHOT].
  1014. -- http://tools.ietf.org/html/rfc4419#section-6.2 */
  1015. $q = new Math_BigInteger(1);
  1016. $q = $q->bitwise_leftShift(2 * $keyLength);
  1017. $q = $q->subtract(new Math_BigInteger(1));
  1018. $g = new Math_BigInteger(2);
  1019. $x = new Math_BigInteger();
  1020. $x->setRandomGenerator('crypt_random');
  1021. $x = $x->random(new Math_BigInteger(1), $q);
  1022. $e = $g->modPow($x, $p);
  1023. $eBytes = $e->toBytes(true);
  1024. $data = pack('CNa*', NET_SSH2_MSG_KEXDH_INIT, strlen($eBytes), $eBytes);
  1025. if (!$this->_send_binary_packet($data)) {
  1026. user_error('Connection closed by server', E_USER_NOTICE);
  1027. return false;
  1028. }
  1029. $response = $this->_get_binary_packet();
  1030. if ($response === false) {
  1031. user_error('Connection closed by server', E_USER_NOTICE);
  1032. return false;
  1033. }
  1034. extract(unpack('Ctype', $this->_string_shift($response, 1)));
  1035. if ($type != NET_SSH2_MSG_KEXDH_REPLY) {
  1036. user_error('Expected SSH_MSG_KEXDH_REPLY', E_USER_NOTICE);
  1037. return false;
  1038. }
  1039. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  1040. $this->server_public_host_key = $server_public_host_key = $this->_string_shift($response, $temp['length']);
  1041. $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
  1042. $public_key_format = $this->_string_shift($server_public_host_key, $temp['length']);
  1043. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  1044. $fBytes = $this->_string_shift($response, $temp['length']);
  1045. $f = new Math_BigInteger($fBytes, -256);
  1046. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  1047. $this->signature = $this->_string_shift($response, $temp['length']);
  1048. $temp = unpack('Nlength', $this->_string_shift($this->signature, 4));
  1049. $this->signature_format = $this->_string_shift($this->signature, $temp['length']);
  1050. $key = $f->modPow($x, $p);
  1051. $keyBytes = $key->toBytes(true);
  1052. $this->exchange_hash = pack('Na*Na*Na*Na*Na*Na*Na*Na*',
  1053. strlen($this->identifier), $this->identifier, strlen($this->server_identifier), $this->server_identifier,
  1054. strlen($kexinit_payload_client), $kexinit_payload_client, strlen($kexinit_payload_server),
  1055. $kexinit_payload_server, strlen($this->server_public_host_key), $this->server_public_host_key, strlen($eBytes),
  1056. $eBytes, strlen($fBytes), $fBytes, strlen($keyBytes), $keyBytes
  1057. );
  1058. $this->exchange_hash = pack('H*', $hash($this->exchange_hash));
  1059. if ($this->session_id === false) {
  1060. $this->session_id = $this->exchange_hash;
  1061. }
  1062. for ($i = 0; $i < count($server_host_key_algorithms) && !in_array($server_host_key_algorithms[$i], $this->server_host_key_algorithms); $i++);
  1063. if ($i == count($server_host_key_algorithms)) {
  1064. user_error('No compatible server host key algorithms found', E_USER_NOTICE);
  1065. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  1066. }
  1067. if ($public_key_format != $server_host_key_algorithms[$i] || $this->signature_format != $server_host_key_algorithms[$i]) {
  1068. user_error('Sever Host Key Algorithm Mismatch', E_USER_NOTICE);
  1069. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  1070. }
  1071. $packet = pack('C',
  1072. NET_SSH2_MSG_NEWKEYS
  1073. );
  1074. if (!$this->_send_binary_packet($packet)) {
  1075. return false;
  1076. }
  1077. $response = $this->_get_binary_packet();
  1078. if ($response === false) {
  1079. user_error('Connection closed by server', E_USER_NOTICE);
  1080. return false;
  1081. }
  1082. extract(unpack('Ctype', $this->_string_shift($response, 1)));
  1083. if ($type != NET_SSH2_MSG_NEWKEYS) {
  1084. user_error('Expected SSH_MSG_NEWKEYS', E_USER_NOTICE);
  1085. return false;
  1086. }
  1087. switch ($encrypt) {
  1088. case '3des-cbc':
  1089. $this->encrypt = new Crypt_TripleDES();
  1090. // $this->encrypt_block_size = 64 / 8 == the default
  1091. break;
  1092. case '3des-ctr':
  1093. $this->encrypt = new Crypt_TripleDES(CRYPT_DES_MODE_CTR);
  1094. // $this->encrypt_block_size = 64 / 8 == the default
  1095. break;
  1096. case 'aes256-cbc':
  1097. case 'aes192-cbc':
  1098. case 'aes128-cbc':
  1099. $this->encrypt = new Crypt_AES();
  1100. $this->encrypt_block_size = 16; // eg. 128 / 8
  1101. break;
  1102. case 'aes256-ctr':
  1103. case 'aes192-ctr':
  1104. case 'aes128-ctr':
  1105. $this->encrypt = new Crypt_AES(CRYPT_AES_MODE_CTR);
  1106. $this->encrypt_block_size = 16; // eg. 128 / 8
  1107. break;
  1108. case 'arcfour':
  1109. case 'arcfour128':
  1110. case 'arcfour256':
  1111. $this->encrypt = new Crypt_RC4();
  1112. break;
  1113. case 'none';
  1114. //$this->encrypt = new Crypt_Null();
  1115. }
  1116. switch ($decrypt) {
  1117. case '3des-cbc':
  1118. $this->decrypt = new Crypt_TripleDES();
  1119. break;
  1120. case '3des-ctr':
  1121. $this->decrypt = new Crypt_TripleDES(CRYPT_DES_MODE_CTR);
  1122. break;
  1123. case 'aes256-cbc':
  1124. case 'aes192-cbc':
  1125. case 'aes128-cbc':
  1126. $this->decrypt = new Crypt_AES();
  1127. $this->decrypt_block_size = 16;
  1128. break;
  1129. case 'aes256-ctr':
  1130. case 'aes192-ctr':
  1131. case 'aes128-ctr':
  1132. $this->decrypt = new Crypt_AES(CRYPT_AES_MODE_CTR);
  1133. $this->decrypt_block_size = 16;
  1134. break;
  1135. case 'arcfour':
  1136. case 'arcfour128':
  1137. case 'arcfour256':
  1138. $this->decrypt = new Crypt_RC4();
  1139. break;
  1140. case 'none';
  1141. //$this->decrypt = new Crypt_Null();
  1142. }
  1143. $keyBytes = pack('Na*', strlen($keyBytes), $keyBytes);
  1144. if ($this->encrypt) {
  1145. $this->encrypt->enableContinuousBuffer();
  1146. $this->encrypt->disablePadding();
  1147. $iv = pack('H*', $hash($keyBytes . $this->exchange_hash . 'A' . $this->session_id));
  1148. while ($this->encrypt_block_size > strlen($iv)) {
  1149. $iv.= pack('H*', $hash($keyBytes . $this->exchange_hash . $iv));
  1150. }
  1151. $this->encrypt->setIV(substr($iv, 0, $this->encrypt_block_size));
  1152. $key = pack('H*', $hash($keyBytes . $this->exchange_hash . 'C' . $this->session_id));
  1153. while ($encryptKeyLength > strlen($key)) {
  1154. $key.= pack('H*', $hash($keyBytes . $this->exchange_hash . $key));
  1155. }
  1156. $this->encrypt->setKey(substr($key, 0, $encryptKeyLength));
  1157. }
  1158. if ($this->decrypt) {
  1159. $this->decrypt->enableContinuousBuffer();
  1160. $this->decrypt->disablePadding();
  1161. $iv = pack('H*', $hash($keyBytes . $this->exchange_hash . 'B' . $this->session_id));
  1162. while ($this->decrypt_block_size > strlen($iv)) {
  1163. $iv.= pack('H*', $hash($keyBytes . $this->exchange_hash . $iv));
  1164. }
  1165. $this->decrypt->setIV(substr($iv, 0, $this->decrypt_block_size));
  1166. $key = pack('H*', $hash($keyBytes . $this->exchange_hash . 'D' . $this->session_id));
  1167. while ($decryptKeyLength > strlen($key)) {
  1168. $key.= pack('H*', $hash($keyBytes . $this->exchange_hash . $key));
  1169. }
  1170. $this->decrypt->setKey(substr($key, 0, $decryptKeyLength));
  1171. }
  1172. /* The "arcfour128" algorithm is the RC4 cipher, as described in
  1173. [SCHNEIER], using a 128-bit key. The first 1536 bytes of keystream
  1174. generated by the cipher MUST be discarded, and the first byte of the
  1175. first encrypted packet MUST be encrypted using the 1537th byte of
  1176. keystream.
  1177. -- http://tools.ietf.org/html/rfc4345#section-4 */
  1178. if ($encrypt == 'arcfour128' || $encrypt == 'arcfour256') {
  1179. $this->encrypt->encrypt(str_repeat("\0", 1536));
  1180. }
  1181. if ($decrypt == 'arcfour128' || $decrypt == 'arcfour256') {
  1182. $this->decrypt->decrypt(str_repeat("\0", 1536));
  1183. }
  1184. for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_client_to_server); $i++);
  1185. if ($i == count($mac_algorithms)) {
  1186. user_error('No compatible client to server message authentication algorithms found', E_USER_NOTICE);
  1187. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  1188. }
  1189. $createKeyLength = 0; // ie. $mac_algorithms[$i] == 'none'
  1190. switch ($mac_algorithms[$i]) {
  1191. case 'hmac-sha1':
  1192. $this->hmac_create = new Crypt_Hash('sha1');
  1193. $createKeyLength = 20;
  1194. break;
  1195. case 'hmac-sha1-96':
  1196. $this->hmac_create = new Crypt_Hash('sha1-96');
  1197. $createKeyLength = 20;
  1198. break;
  1199. case 'hmac-md5':
  1200. $this->hmac_create = new Crypt_Hash('md5');
  1201. $createKeyLength = 16;
  1202. break;
  1203. case 'hmac-md5-96':
  1204. $this->hmac_create = new Crypt_Hash('md5-96');
  1205. $createKeyLength = 16;
  1206. }
  1207. for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_server_to_client); $i++);
  1208. if ($i == count($mac_algorithms)) {
  1209. user_error('No compatible server to client message authentication algorithms found', E_USER_NOTICE);
  1210. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  1211. }
  1212. $checkKeyLength = 0;
  1213. $this->hmac_size = 0;
  1214. switch ($mac_algorithms[$i]) {
  1215. case 'hmac-sha1':
  1216. $this->hmac_check = new Crypt_Hash('sha1');
  1217. $checkKeyLength = 20;
  1218. $this->hmac_size = 20;
  1219. break;
  1220. case 'hmac-sha1-96':
  1221. $this->hmac_check = new Crypt_Hash('sha1-96');
  1222. $checkKeyLength = 20;
  1223. $this->hmac_size = 12;
  1224. break;
  1225. case 'hmac-md5':
  1226. $this->hmac_check = new Crypt_Hash('md5');
  1227. $checkKeyLength = 16;
  1228. $this->hmac_size = 16;
  1229. break;
  1230. case 'hmac-md5-96':
  1231. $this->hmac_check = new Crypt_Hash('md5-96');
  1232. $checkKeyLength = 16;
  1233. $this->hmac_size = 12;
  1234. }
  1235. $key = pack('H*', $hash($keyBytes . $this->exchange_hash . 'E' . $this->session_id));
  1236. while ($createKeyLength > strlen($key)) {
  1237. $key.= pack('H*', $hash($keyBytes . $this->exchange_hash . $key));
  1238. }
  1239. $this->hmac_create->setKey(substr($key, 0, $createKeyLength));
  1240. $key = pack('H*', $hash($keyBytes . $this->exchange_hash . 'F' . $this->session_id));
  1241. while ($checkKeyLength > strlen($key)) {
  1242. $key.= pack('H*', $hash($keyBytes . $this->exchange_hash . $key));
  1243. }
  1244. $this->hmac_check->setKey(substr($key, 0, $checkKeyLength));
  1245. for ($i = 0; $i < count($compression_algorithms) && !in_array($compression_algorithms[$i], $this->compression_algorithms_server_to_client); $i++);
  1246. if ($i == count($compression_algorithms)) {
  1247. user_error('No compatible server to client compression algorithms found', E_USER_NOTICE);
  1248. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  1249. }
  1250. $this->decompress = $compression_algorithms[$i] == 'zlib';
  1251. for ($i = 0; $i < count($compression_algorithms) && !in_array($compression_algorithms[$i], $this->compression_algorithms_client_to_server); $i++);
  1252. if ($i == count($compression_algorithms)) {
  1253. user_error('No compatible client to server compression algorithms found', E_USER_NOTICE);
  1254. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  1255. }
  1256. $this->compress = $compression_algorithms[$i] == 'zlib';
  1257. return true;
  1258. }
  1259. /**
  1260. * Login
  1261. *
  1262. * The $password parameter can be a plaintext password or a Crypt_RSA object.
  1263. *
  1264. * @param String $username
  1265. * @param optional String $password
  1266. * @return Boolean
  1267. * @access public
  1268. * @internal It might be worthwhile, at some point, to protect against {@link http://tools.ietf.org/html/rfc4251#section-9.3.9 traffic analysis}
  1269. * by sending dummy SSH_MSG_IGNORE messages.
  1270. */
  1271. function login($username, $password = '')
  1272. {
  1273. if (!($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR)) {
  1274. return false;
  1275. }
  1276. $packet = pack('CNa*',
  1277. NET_SSH2_MSG_SERVICE_REQUEST, strlen('ssh-userauth'), 'ssh-userauth'
  1278. );
  1279. if (!$this->_send_binary_packet($packet)) {
  1280. return false;
  1281. }
  1282. $response = $this->_get_binary_packet();
  1283. if ($response === false) {
  1284. user_error('Connection closed by server', E_USER_NOTICE);
  1285. return false;
  1286. }
  1287. extract(unpack('Ctype', $this->_string_shift($response, 1)));
  1288. if ($type != NET_SSH2_MSG_SERVICE_ACCEPT) {
  1289. user_error('Expected SSH_MSG_SERVICE_ACCEPT', E_USER_NOTICE);
  1290. return false;
  1291. }
  1292. // although PHP5's get_class() preserves the case, PHP4's does not
  1293. if (is_object($password) && strtolower(get_class($password)) == 'crypt_rsa') {
  1294. return $this->_privatekey_login($username, $passwo

Large files files are truncated, but you can click here to view the full file