PageRenderTime 50ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/s3db3.5.10/pearlib/phpseclib/Net/SSH2.php

https://code.google.com/p/s3db/
PHP | 1677 lines | 903 code | 219 blank | 555 comment | 141 complexity | a36f6831e57357bc40dac241b84c0f97 MD5 | raw file

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->exec('pwd');
  38. * echo $ssh->exec('ls -la');
  39. * ?>
  40. * </code>
  41. *
  42. * LICENSE: This library is free software; you can redistribute it and/or
  43. * modify it under the terms of the GNU Lesser General Public
  44. * License as published by the Free Software Foundation; either
  45. * version 2.1 of the License, or (at your option) any later version.
  46. *
  47. * This library is distributed in the hope that it will be useful,
  48. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  49. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  50. * Lesser General Public License for more details.
  51. *
  52. * You should have received a copy of the GNU Lesser General Public
  53. * License along with this library; if not, write to the Free Software
  54. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  55. * MA 02111-1307 USA
  56. *
  57. * @category Net
  58. * @package Net_SSH2
  59. * @author Jim Wigginton <terrafrost@php.net>
  60. * @copyright MMVII Jim Wigginton
  61. * @license http://www.gnu.org/licenses/lgpl.txt
  62. * @version $Id: SSH2.php,v 1.29 2009/12/03 19:04:10 terrafrost Exp $
  63. * @link http://phpseclib.sourceforge.net
  64. */
  65. /**
  66. * Include Math_BigInteger
  67. *
  68. * Used to do Diffie-Hellman key exchange and DSA/RSA signature verification.
  69. */
  70. require_once('Math/BigInteger.php');
  71. /**
  72. * Include Crypt_Random
  73. */
  74. require_once('Crypt/Random.php');
  75. /**
  76. * Include Crypt_Hash
  77. */
  78. require_once('Crypt/Hash.php');
  79. /**
  80. * Include Crypt_TripleDES
  81. */
  82. require_once('Crypt/TripleDES.php');
  83. /**
  84. * Include Crypt_RC4
  85. */
  86. require_once('Crypt/RC4.php');
  87. /**
  88. * Include Crypt_AES
  89. */
  90. require_once('Crypt/AES.php');
  91. /**#@+
  92. * Execution Bitmap Masks
  93. *
  94. * @see Net_SSH2::bitmap
  95. * @access private
  96. */
  97. define('NET_SSH2_MASK_CONSTRUCTOR', 0x00000001);
  98. define('NET_SSH2_MASK_LOGIN', 0x00000002);
  99. /**#@-*/
  100. /**#@+
  101. * @access public
  102. * @see Net_SSH2::getLog()
  103. */
  104. /**
  105. * Returns the message numbers
  106. */
  107. define('NET_SSH2_LOG_SIMPLE', 1);
  108. /**
  109. * Returns the message content
  110. */
  111. define('NET_SSH2_LOG_COMPLEX', 2);
  112. /**#@-*/
  113. /**
  114. * Pure-PHP implementation of SSHv2.
  115. *
  116. * @author Jim Wigginton <terrafrost@php.net>
  117. * @version 0.1.0
  118. * @access public
  119. * @package Net_SSH2
  120. */
  121. class Net_SSH2 {
  122. /**
  123. * The SSH identifier
  124. *
  125. * @var String
  126. * @access private
  127. */
  128. var $identifier = 'SSH-2.0-phpseclib_0.1';
  129. /**
  130. * The Socket Object
  131. *
  132. * @var Object
  133. * @access private
  134. */
  135. var $fsock;
  136. /**
  137. * Execution Bitmap
  138. *
  139. * The bits that are set reprsent functions that have been called already. This is used to determine
  140. * if a requisite function has been successfully executed. If not, an error should be thrown.
  141. *
  142. * @var Integer
  143. * @access private
  144. */
  145. var $bitmap = 0;
  146. /**
  147. * Debug Info
  148. *
  149. * @see Net_SSH2::getDebugInfo()
  150. * @var String
  151. * @access private
  152. */
  153. var $debug_info = '';
  154. /**
  155. * Server Identifier
  156. *
  157. * @see Net_SSH2::getServerIdentification()
  158. * @var String
  159. * @access private
  160. */
  161. var $server_identifier = '';
  162. /**
  163. * Key Exchange Algorithms
  164. *
  165. * @see Net_SSH2::getKexAlgorithims()
  166. * @var Array
  167. * @access private
  168. */
  169. var $kex_algorithms;
  170. /**
  171. * Server Host Key Algorithms
  172. *
  173. * @see Net_SSH2::getServerHostKeyAlgorithms()
  174. * @var Array
  175. * @access private
  176. */
  177. var $server_host_key_algorithms;
  178. /**
  179. * Encryption Algorithms: Client to Server
  180. *
  181. * @see Net_SSH2::getEncryptionAlgorithmsClient2Server()
  182. * @var Array
  183. * @access private
  184. */
  185. var $encryption_algorithms_client_to_server;
  186. /**
  187. * Encryption Algorithms: Server to Client
  188. *
  189. * @see Net_SSH2::getEncryptionAlgorithmsServer2Client()
  190. * @var Array
  191. * @access private
  192. */
  193. var $encryption_algorithms_server_to_client;
  194. /**
  195. * MAC Algorithms: Client to Server
  196. *
  197. * @see Net_SSH2::getMACAlgorithmsClient2Server()
  198. * @var Array
  199. * @access private
  200. */
  201. var $mac_algorithms_client_to_server;
  202. /**
  203. * MAC Algorithms: Server to Client
  204. *
  205. * @see Net_SSH2::getMACAlgorithmsServer2Client()
  206. * @var Array
  207. * @access private
  208. */
  209. var $mac_algorithms_server_to_client;
  210. /**
  211. * Compression Algorithms: Client to Server
  212. *
  213. * @see Net_SSH2::getCompressionAlgorithmsClient2Server()
  214. * @var Array
  215. * @access private
  216. */
  217. var $compression_algorithms_client_to_server;
  218. /**
  219. * Compression Algorithms: Server to Client
  220. *
  221. * @see Net_SSH2::getCompressionAlgorithmsServer2Client()
  222. * @var Array
  223. * @access private
  224. */
  225. var $compression_algorithms_server_to_client;
  226. /**
  227. * Languages: Server to Client
  228. *
  229. * @see Net_SSH2::getLanguagesServer2Client()
  230. * @var Array
  231. * @access private
  232. */
  233. var $languages_server_to_client;
  234. /**
  235. * Languages: Client to Server
  236. *
  237. * @see Net_SSH2::getLanguagesClient2Server()
  238. * @var Array
  239. * @access private
  240. */
  241. var $languages_client_to_server;
  242. /**
  243. * Block Size for Server to Client Encryption
  244. *
  245. * "Note that the length of the concatenation of 'packet_length',
  246. * 'padding_length', 'payload', and 'random padding' MUST be a multiple
  247. * of the cipher block size or 8, whichever is larger. This constraint
  248. * MUST be enforced, even when using stream ciphers."
  249. *
  250. * -- http://tools.ietf.org/html/rfc4253#section-6
  251. *
  252. * @see Net_SSH2::Net_SSH2()
  253. * @see Net_SSH2::_send_binary_packet()
  254. * @var Integer
  255. * @access private
  256. */
  257. var $encrypt_block_size = 8;
  258. /**
  259. * Block Size for Client to Server Encryption
  260. *
  261. * @see Net_SSH2::Net_SSH2()
  262. * @see Net_SSH2::_get_binary_packet()
  263. * @var Integer
  264. * @access private
  265. */
  266. var $decrypt_block_size = 8;
  267. /**
  268. * Server to Client Encryption Object
  269. *
  270. * @see Net_SSH2::_get_binary_packet()
  271. * @var Object
  272. * @access private
  273. */
  274. var $decrypt = false;
  275. /**
  276. * Client to Server Encryption Object
  277. *
  278. * @see Net_SSH2::_send_binary_packet()
  279. * @var Object
  280. * @access private
  281. */
  282. var $encrypt = false;
  283. /**
  284. * Client to Server HMAC Object
  285. *
  286. * @see Net_SSH2::_send_binary_packet()
  287. * @var Object
  288. * @access private
  289. */
  290. var $hmac_create = false;
  291. /**
  292. * Server to Client HMAC Object
  293. *
  294. * @see Net_SSH2::_get_binary_packet()
  295. * @var Object
  296. * @access private
  297. */
  298. var $hmac_check = false;
  299. /**
  300. * Size of server to client HMAC
  301. *
  302. * 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.
  303. * 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
  304. * append it.
  305. *
  306. * @see Net_SSH2::_get_binary_packet()
  307. * @var Integer
  308. * @access private
  309. */
  310. var $hmac_size = false;
  311. /**
  312. * Server Public Host Key
  313. *
  314. * @see Net_SSH2::getServerPublicHostKey()
  315. * @var String
  316. * @access private
  317. */
  318. var $server_public_host_key;
  319. /**
  320. * Session identifer
  321. *
  322. * "The exchange hash H from the first key exchange is additionally
  323. * used as the session identifier, which is a unique identifier for
  324. * this connection."
  325. *
  326. * -- http://tools.ietf.org/html/rfc4253#section-7.2
  327. *
  328. * @see Net_SSH2::_key_exchange()
  329. * @var String
  330. * @access private
  331. */
  332. var $session_id = false;
  333. /**
  334. * Message Numbers
  335. *
  336. * @see Net_SSH2::Net_SSH2()
  337. * @var Array
  338. * @access private
  339. */
  340. var $message_numbers = array();
  341. /**
  342. * Disconnection Message 'reason codes' defined in RFC4253
  343. *
  344. * @see Net_SSH2::Net_SSH2()
  345. * @var Array
  346. * @access private
  347. */
  348. var $disconnect_reasons = array();
  349. /**
  350. * SSH_MSG_CHANNEL_OPEN_FAILURE 'reason codes', defined in RFC4254
  351. *
  352. * @see Net_SSH2::Net_SSH2()
  353. * @var Array
  354. * @access private
  355. */
  356. var $channel_open_failure_reasons = array();
  357. /**
  358. * Terminal Modes
  359. *
  360. * @link http://tools.ietf.org/html/rfc4254#section-8
  361. * @see Net_SSH2::Net_SSH2()
  362. * @var Array
  363. * @access private
  364. */
  365. var $terminal_modes = array();
  366. /**
  367. * SSH_MSG_CHANNEL_EXTENDED_DATA's data_type_codes
  368. *
  369. * @link http://tools.ietf.org/html/rfc4254#section-5.2
  370. * @see Net_SSH2::Net_SSH2()
  371. * @var Array
  372. * @access private
  373. */
  374. var $channel_extended_data_type_codes = array();
  375. /**
  376. * Send Sequence Number
  377. *
  378. * See 'Section 6.4. Data Integrity' of rfc4253 for more info.
  379. *
  380. * @see Net_SSH2::_send_binary_packet()
  381. * @var Integer
  382. * @access private
  383. */
  384. var $send_seq_no = 0;
  385. /**
  386. * Get Sequence Number
  387. *
  388. * See 'Section 6.4. Data Integrity' of rfc4253 for more info.
  389. *
  390. * @see Net_SSH2::_get_binary_packet()
  391. * @var Integer
  392. * @access private
  393. */
  394. var $get_seq_no = 0;
  395. /**
  396. * The Client Channel
  397. *
  398. * Net_SSH2::exec() uses 0, although since Net_SSH2::exec() doesn't send NET_SSH2_CHANNEL_DATA packets,
  399. * Net_SSH2::_send_channel_packet() isn't actually called by any function in Net/SSH2.php. Classes that
  400. * extend Net_SSH2, however, might call that function, hence it's existence.
  401. *
  402. * @var Integer
  403. * @see Net_SSH2::_send_channel_packet
  404. * @access private
  405. */
  406. var $client_channel = 1;
  407. /**
  408. * Server Channels
  409. *
  410. * Maps client channels to server channels
  411. *
  412. * @see Net_SSH2::_get_channel_packet()
  413. * @see Net_SSH2::exec()
  414. * @var Array
  415. * @access private
  416. */
  417. var $server_channels = array();
  418. /**
  419. * Packet Size
  420. *
  421. * Maximum packet size
  422. *
  423. * @see Net_SSH2::_send_channel_packet()
  424. * @see Net_SSH2::exec()
  425. * @var Integer
  426. * @access private
  427. */
  428. var $packet_size_client_to_server = 0;
  429. /**
  430. * Message Number Log
  431. *
  432. * @see Net_SSH2::getLog()
  433. * @var Array
  434. * @access private
  435. */
  436. var $message_number_log = array();
  437. /**
  438. * Message Log
  439. *
  440. * @see Net_SSH2::getLog()
  441. * @var Array
  442. * @access private
  443. */
  444. var $message_log = array();
  445. /**
  446. * Default Constructor.
  447. *
  448. * Connects to an SSHv2 server
  449. *
  450. * @param String $host
  451. * @param optional Integer $port
  452. * @param optional Integer $timeout
  453. * @return Net_SSH2
  454. * @access public
  455. */
  456. function Net_SSH2($host, $port = 22, $timeout = 10)
  457. {
  458. $this->message_numbers = array(
  459. 1 => 'NET_SSH2_MSG_DISCONNECT',
  460. 2 => 'NET_SSH2_MSG_IGNORE',
  461. 3 => 'NET_SSH2_MSG_UNIMPLEMENTED',
  462. 4 => 'NET_SSH2_MSG_DEBUG',
  463. 5 => 'NET_SSH2_MSG_SERVICE_REQUEST',
  464. 6 => 'NET_SSH2_MSG_SERVICE_ACCEPT',
  465. 20 => 'NET_SSH2_MSG_KEXINIT',
  466. 21 => 'NET_SSH2_MSG_NEWKEYS',
  467. 30 => 'NET_SSH2_MSG_KEXDH_INIT',
  468. 31 => 'NET_SSH2_MSG_KEXDH_REPLY',
  469. 50 => 'NET_SSH2_MSG_USERAUTH_REQUEST',
  470. 51 => 'NET_SSH2_MSG_USERAUTH_FAILURE',
  471. 52 => 'NET_SSH2_MSG_USERAUTH_SUCCESS',
  472. 53 => 'NET_SSH2_MSG_USERAUTH_BANNER',
  473. 80 => 'NET_SSH2_MSG_GLOBAL_REQUEST',
  474. 81 => 'NET_SSH2_MSG_REQUEST_SUCCESS',
  475. 82 => 'NET_SSH2_MSG_REQUEST_FAILURE',
  476. 90 => 'NET_SSH2_MSG_CHANNEL_OPEN',
  477. 91 => 'NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION',
  478. 92 => 'NET_SSH2_MSG_CHANNEL_OPEN_FAILURE',
  479. 93 => 'NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST',
  480. 94 => 'NET_SSH2_MSG_CHANNEL_DATA',
  481. 95 => 'NET_SSH2_MSG_CHANNEL_EXTENDED_DATA',
  482. 96 => 'NET_SSH2_MSG_CHANNEL_EOF',
  483. 97 => 'NET_SSH2_MSG_CHANNEL_CLOSE',
  484. 98 => 'NET_SSH2_MSG_CHANNEL_REQUEST',
  485. 99 => 'NET_SSH2_MSG_CHANNEL_SUCCESS',
  486. 100 => 'NET_SSH2_MSG_CHANNEL_FAILURE'
  487. );
  488. $this->disconnect_reasons = array(
  489. 1 => 'NET_SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT',
  490. 2 => 'NET_SSH2_DISCONNECT_PROTOCOL_ERROR',
  491. 3 => 'NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED',
  492. 4 => 'NET_SSH2_DISCONNECT_RESERVED',
  493. 5 => 'NET_SSH2_DISCONNECT_MAC_ERROR',
  494. 6 => 'NET_SSH2_DISCONNECT_COMPRESSION_ERROR',
  495. 7 => 'NET_SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE',
  496. 8 => 'NET_SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED',
  497. 9 => 'NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE',
  498. 10 => 'NET_SSH2_DISCONNECT_CONNECTION_LOST',
  499. 11 => 'NET_SSH2_DISCONNECT_BY_APPLICATION',
  500. 12 => 'NET_SSH2_DISCONNECT_TOO_MANY_CONNECTIONS',
  501. 13 => 'NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER',
  502. 14 => 'NET_SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE',
  503. 15 => 'NET_SSH2_DISCONNECT_ILLEGAL_USER_NAME'
  504. );
  505. $this->channel_open_failure_reasons = array(
  506. 1 => 'NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED'
  507. );
  508. $this->terminal_modes = array(
  509. 0 => 'NET_SSH2_TTY_OP_END'
  510. );
  511. $this->channel_extended_data_type_codes = array(
  512. 1 => 'NET_SSH2_EXTENDED_DATA_STDERR'
  513. );
  514. $this->_define_array(
  515. $this->message_numbers,
  516. $this->disconnect_reasons,
  517. $this->channel_open_failure_reasons,
  518. $this->terminal_modes,
  519. $this->channel_extended_data_type_codes,
  520. array(60 => 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ'),
  521. array(60 => 'NET_SSH2_MSG_USERAUTH_PK_OK')
  522. );
  523. $this->fsock = @fsockopen($host, $port, $errno, $errstr, $timeout);
  524. if (!$this->fsock) {
  525. user_error(rtrim("Cannot connect to $host. Error $errno. $errstr"), E_USER_NOTICE);
  526. return;
  527. }
  528. /* According to the SSH2 specs,
  529. "The server MAY send other lines of data before sending the version
  530. string. Each line SHOULD be terminated by a Carriage Return and Line
  531. Feed. Such lines MUST NOT begin with "SSH-", and SHOULD be encoded
  532. in ISO-10646 UTF-8 [RFC3629] (language is not specified). Clients
  533. MUST be able to process such lines." */
  534. $temp = '';
  535. while (!feof($this->fsock) && !preg_match('#^SSH-(\d\.\d+)#', $temp, $matches)) {
  536. if (substr($temp, -2) == "\r\n") {
  537. $this->debug_info.= $temp;
  538. $temp = '';
  539. }
  540. $temp.= fgets($this->fsock, 255);
  541. }
  542. if (defined('NET_SSH2_LOGGING')) {
  543. $this->message_number_log[] = '<-';
  544. $this->message_log[] = $temp;
  545. $this->message_number_log[] = '->';
  546. $this->message_log[] = $this->identifier . "\r\n";
  547. }
  548. $this->server_identifier = trim($temp);
  549. $this->debug_info = utf8_decode($this->debug_info);
  550. if ($matches[1] != '1.99' && $matches[1] != '2.0') {
  551. user_error("Cannot connect to SSH $matches[1] servers", E_USER_NOTICE);
  552. return;
  553. }
  554. fputs($this->fsock, $this->identifier . "\r\n");
  555. $response = $this->_get_binary_packet();
  556. if ($response === false) {
  557. user_error('Connection closed by server', E_USER_NOTICE);
  558. return;
  559. }
  560. if (ord($response[0]) != NET_SSH2_MSG_KEXINIT) {
  561. user_error('Expected SSH_MSG_KEXINIT', E_USER_NOTICE);
  562. return;
  563. }
  564. if (!$this->_key_exchange($response)) {
  565. return;
  566. }
  567. $this->bitmap = NET_SSH2_MASK_CONSTRUCTOR;
  568. }
  569. /**
  570. * Key Exchange
  571. *
  572. * @param String $kexinit_payload_server
  573. * @access private
  574. */
  575. function _key_exchange($kexinit_payload_server)
  576. {
  577. static $kex_algorithms = array(
  578. 'diffie-hellman-group1-sha1', // REQUIRED
  579. 'diffie-hellman-group14-sha1' // REQUIRED
  580. );
  581. static $server_host_key_algorithms = array(
  582. 'ssh-rsa', // RECOMMENDED sign Raw RSA Key
  583. 'ssh-dss' // REQUIRED sign Raw DSS Key
  584. );
  585. static $encryption_algorithms = array(
  586. 'arcfour', // OPTIONAL the ARCFOUR stream cipher with a 128-bit key
  587. 'aes128-cbc', // RECOMMENDED AES with a 128-bit key
  588. 'aes192-cbc', // OPTIONAL AES with a 192-bit key
  589. 'aes256-cbc', // OPTIONAL AES in CBC mode, with a 256-bit key
  590. '3des-cbc', // REQUIRED three-key 3DES in CBC mode
  591. 'none' // OPTIONAL no encryption; NOT RECOMMENDED
  592. );
  593. static $mac_algorithms = array(
  594. 'hmac-sha1-96', // RECOMMENDED first 96 bits of HMAC-SHA1 (digest length = 12, key length = 20)
  595. 'hmac-sha1', // REQUIRED HMAC-SHA1 (digest length = key length = 20)
  596. 'hmac-md5-96', // OPTIONAL first 96 bits of HMAC-MD5 (digest length = 12, key length = 16)
  597. 'hmac-md5', // OPTIONAL HMAC-MD5 (digest length = key length = 16)
  598. 'none' // OPTIONAL no MAC; NOT RECOMMENDED
  599. );
  600. static $compression_algorithms = array(
  601. 'none' // REQUIRED no compression
  602. //'zlib' // OPTIONAL ZLIB (LZ77) compression
  603. );
  604. static $str_kex_algorithms, $str_server_host_key_algorithms,
  605. $encryption_algorithms_server_to_client, $mac_algorithms_server_to_client, $compression_algorithms_server_to_client,
  606. $encryption_algorithms_client_to_server, $mac_algorithms_client_to_server, $compression_algorithms_client_to_server;
  607. if (empty($str_kex_algorithms)) {
  608. $str_kex_algorithms = implode(',', $kex_algorithms);
  609. $str_server_host_key_algorithms = implode(',', $server_host_key_algorithms);
  610. $encryption_algorithms_server_to_client = $encryption_algorithms_client_to_server = implode(',', $encryption_algorithms);
  611. $mac_algorithms_server_to_client = $mac_algorithms_client_to_server = implode(',', $mac_algorithms);
  612. $compression_algorithms_server_to_client = $compression_algorithms_client_to_server = implode(',', $compression_algorithms);
  613. }
  614. $client_cookie = '';
  615. for ($i = 0; $i < 16; $i++) {
  616. $client_cookie.= chr(crypt_random(0, 255));
  617. }
  618. $response = $kexinit_payload_server;
  619. $this->_string_shift($response, 1); // skip past the message number (it should be SSH_MSG_KEXINIT)
  620. $server_cookie = $this->_string_shift($response, 16);
  621. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  622. $this->kex_algorithms = explode(',', $this->_string_shift($response, $temp['length']));
  623. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  624. $this->server_host_key_algorithms = explode(',', $this->_string_shift($response, $temp['length']));
  625. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  626. $this->encryption_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
  627. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  628. $this->encryption_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
  629. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  630. $this->mac_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
  631. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  632. $this->mac_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
  633. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  634. $this->compression_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
  635. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  636. $this->compression_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
  637. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  638. $this->languages_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
  639. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  640. $this->languages_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
  641. extract(unpack('Cfirst_kex_packet_follows', $this->_string_shift($response, 1)));
  642. $first_kex_packet_follows = $first_kex_packet_follows != 0;
  643. // the sending of SSH2_MSG_KEXINIT could go in one of two places. this is the second place.
  644. $kexinit_payload_client = pack('Ca*Na*Na*Na*Na*Na*Na*Na*Na*Na*Na*CN',
  645. NET_SSH2_MSG_KEXINIT, $client_cookie, strlen($str_kex_algorithms), $str_kex_algorithms,
  646. strlen($str_server_host_key_algorithms), $str_server_host_key_algorithms, strlen($encryption_algorithms_client_to_server),
  647. $encryption_algorithms_client_to_server, strlen($encryption_algorithms_server_to_client), $encryption_algorithms_server_to_client,
  648. strlen($mac_algorithms_client_to_server), $mac_algorithms_client_to_server, strlen($mac_algorithms_server_to_client),
  649. $mac_algorithms_server_to_client, strlen($compression_algorithms_client_to_server), $compression_algorithms_client_to_server,
  650. strlen($compression_algorithms_server_to_client), $compression_algorithms_server_to_client, 0, '', 0, '',
  651. 0, 0
  652. );
  653. if (!$this->_send_binary_packet($kexinit_payload_client)) {
  654. return false;
  655. }
  656. // here ends the second place.
  657. // we need to decide upon the symmetric encryption algorithms before we do the diffie-hellman key exchange
  658. for ($i = 0; $i < count($encryption_algorithms) && !in_array($encryption_algorithms[$i], $this->encryption_algorithms_server_to_client); $i++);
  659. if ($i == count($encryption_algorithms)) {
  660. user_error('No compatible server to client encryption algorithms found', E_USER_NOTICE);
  661. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  662. }
  663. // we don't initialize any crypto-objects, yet - we do that, later. for now, we need the lengths to make the
  664. // diffie-hellman key exchange as fast as possible
  665. $decrypt = $encryption_algorithms[$i];
  666. switch ($decrypt) {
  667. case '3des-cbc':
  668. $decryptKeyLength = 24; // eg. 192 / 8
  669. break;
  670. case 'aes256-cbc':
  671. $decryptKeyLength = 32; // eg. 256 / 8
  672. break;
  673. case 'aes192-cbc':
  674. $decryptKeyLength = 24; // eg. 192 / 8
  675. break;
  676. case 'aes128-cbc':
  677. $decryptKeyLength = 16; // eg. 128 / 8
  678. break;
  679. case 'arcfour':
  680. $decryptKeyLength = 16; // eg. 128 / 8
  681. break;
  682. case 'none';
  683. $decryptKeyLength = 0;
  684. }
  685. for ($i = 0; $i < count($encryption_algorithms) && !in_array($encryption_algorithms[$i], $this->encryption_algorithms_client_to_server); $i++);
  686. if ($i == count($encryption_algorithms)) {
  687. user_error('No compatible client to server encryption algorithms found', E_USER_NOTICE);
  688. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  689. }
  690. $encrypt = $encryption_algorithms[$i];
  691. switch ($encrypt) {
  692. case '3des-cbc':
  693. $encryptKeyLength = 24;
  694. break;
  695. case 'aes256-cbc':
  696. $encryptKeyLength = 32;
  697. break;
  698. case 'aes192-cbc':
  699. $encryptKeyLength = 24;
  700. break;
  701. case 'aes128-cbc':
  702. $encryptKeyLength = 16;
  703. break;
  704. case 'arcfour':
  705. $encryptKeyLength = 16;
  706. break;
  707. case 'none';
  708. $encryptKeyLength = 0;
  709. }
  710. $keyLength = $decryptKeyLength > $encryptKeyLength ? $decryptKeyLength : $encryptKeyLength;
  711. // through diffie-hellman key exchange a symmetric key is obtained
  712. for ($i = 0; $i < count($kex_algorithms) && !in_array($kex_algorithms[$i], $this->kex_algorithms); $i++);
  713. if ($i == count($kex_algorithms)) {
  714. user_error('No compatible key exchange algorithms found', E_USER_NOTICE);
  715. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  716. }
  717. switch ($kex_algorithms[$i]) {
  718. // see http://tools.ietf.org/html/rfc2409#section-6.2 and
  719. // http://tools.ietf.org/html/rfc2412, appendex E
  720. case 'diffie-hellman-group1-sha1':
  721. $p = pack('H256', 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' .
  722. '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' .
  723. '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
  724. 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF');
  725. $keyLength = $keyLength < 160 ? $keyLength : 160;
  726. $hash = 'sha1';
  727. break;
  728. // see http://tools.ietf.org/html/rfc3526#section-3
  729. case 'diffie-hellman-group14-sha1':
  730. $p = pack('H512', 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' .
  731. '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' .
  732. '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
  733. 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' .
  734. '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' .
  735. '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' .
  736. 'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' .
  737. '3995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF');
  738. $keyLength = $keyLength < 160 ? $keyLength : 160;
  739. $hash = 'sha1';
  740. }
  741. $p = new Math_BigInteger($p, 256);
  742. //$q = $p->bitwise_rightShift(1);
  743. /* To increase the speed of the key exchange, both client and server may
  744. reduce the size of their private exponents. It should be at least
  745. twice as long as the key material that is generated from the shared
  746. secret. For more details, see the paper by van Oorschot and Wiener
  747. [VAN-OORSCHOT].
  748. -- http://tools.ietf.org/html/rfc4419#section-6.2 */
  749. $q = new Math_BigInteger(1);
  750. $q = $q->bitwise_leftShift(2 * $keyLength);
  751. $q = $q->subtract(new Math_BigInteger(1));
  752. $g = new Math_BigInteger(2);
  753. $x = new Math_BigInteger();
  754. $x->setRandomGenerator('crypt_random');
  755. $x = $x->random(new Math_BigInteger(1), $q);
  756. $e = $g->modPow($x, $p);
  757. $eBytes = $e->toBytes(true);
  758. $data = pack('CNa*', NET_SSH2_MSG_KEXDH_INIT, strlen($eBytes), $eBytes);
  759. if (!$this->_send_binary_packet($data)) {
  760. user_error('Connection closed by server', E_USER_NOTICE);
  761. return false;
  762. }
  763. $response = $this->_get_binary_packet();
  764. if ($response === false) {
  765. user_error('Connection closed by server', E_USER_NOTICE);
  766. return false;
  767. }
  768. extract(unpack('Ctype', $this->_string_shift($response, 1)));
  769. if ($type != NET_SSH2_MSG_KEXDH_REPLY) {
  770. user_error('Expected SSH_MSG_KEXDH_REPLY', E_USER_NOTICE);
  771. return false;
  772. }
  773. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  774. $this->server_public_host_key = $server_public_host_key = $this->_string_shift($response, $temp['length']);
  775. $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
  776. $public_key_format = $this->_string_shift($server_public_host_key, $temp['length']);
  777. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  778. $fBytes = $this->_string_shift($response, $temp['length']);
  779. $f = new Math_BigInteger($fBytes, -256);
  780. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  781. $signature = $this->_string_shift($response, $temp['length']);
  782. $temp = unpack('Nlength', $this->_string_shift($signature, 4));
  783. $signature_format = $this->_string_shift($signature, $temp['length']);
  784. $key = $f->modPow($x, $p);
  785. $keyBytes = $key->toBytes(true);
  786. $source = pack('Na*Na*Na*Na*Na*Na*Na*Na*',
  787. strlen($this->identifier), $this->identifier, strlen($this->server_identifier), $this->server_identifier,
  788. strlen($kexinit_payload_client), $kexinit_payload_client, strlen($kexinit_payload_server),
  789. $kexinit_payload_server, strlen($this->server_public_host_key), $this->server_public_host_key, strlen($eBytes),
  790. $eBytes, strlen($fBytes), $fBytes, strlen($keyBytes), $keyBytes
  791. );
  792. $source = pack('H*', $hash($source));
  793. if ($this->session_id === false) {
  794. $this->session_id = $source;
  795. }
  796. // if you the server's assymetric key matches the one you have on file, then you should be able to decrypt the
  797. // "signature" and get something that should equal the "exchange hash", as defined in the SSH-2 specs.
  798. // here, we just check to see if the "signature" is good. you can verify whether or not the assymetric key is good,
  799. // later, with the getServerHostKeyAlgorithm() function
  800. for ($i = 0; $i < count($server_host_key_algorithms) && !in_array($server_host_key_algorithms[$i], $this->server_host_key_algorithms); $i++);
  801. if ($i == count($server_host_key_algorithms)) {
  802. user_error('No compatible server host key algorithms found', E_USER_NOTICE);
  803. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  804. }
  805. if ($public_key_format != $server_host_key_algorithms[$i] || $signature_format != $server_host_key_algorithms[$i]) {
  806. user_error('Sever Host Key Algorithm Mismatch', E_USER_NOTICE);
  807. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  808. }
  809. switch ($server_host_key_algorithms[$i]) {
  810. case 'ssh-dss':
  811. $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
  812. $p = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
  813. $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
  814. $q = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
  815. $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
  816. $g = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
  817. $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
  818. $y = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
  819. /* The value for 'dss_signature_blob' is encoded as a string containing
  820. r, followed by s (which are 160-bit integers, without lengths or
  821. padding, unsigned, and in network byte order). */
  822. $temp = unpack('Nlength', $this->_string_shift($signature, 4));
  823. if ($temp['length'] != 40) {
  824. user_error('Invalid signature', E_USER_NOTICE);
  825. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  826. }
  827. $r = new Math_BigInteger($this->_string_shift($signature, 20), 256);
  828. $s = new Math_BigInteger($this->_string_shift($signature, 20), 256);
  829. if ($r->compare($q) >= 0 || $s->compare($q) >= 0) {
  830. user_error('Invalid signature', E_USER_NOTICE);
  831. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  832. }
  833. $w = $s->modInverse($q);
  834. $u1 = $w->multiply(new Math_BigInteger(sha1($source), 16));
  835. list(, $u1) = $u1->divide($q);
  836. $u2 = $w->multiply($r);
  837. list(, $u2) = $u2->divide($q);
  838. $g = $g->modPow($u1, $p);
  839. $y = $y->modPow($u2, $p);
  840. $v = $g->multiply($y);
  841. list(, $v) = $v->divide($p);
  842. list(, $v) = $v->divide($q);
  843. if (!$v->equals($r)) {
  844. user_error('Invalid signature', E_USER_NOTICE);
  845. return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
  846. }
  847. break;
  848. case 'ssh-rsa':
  849. $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
  850. $e = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
  851. $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
  852. $n = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
  853. $nLength = $temp['length'];
  854. /*
  855. $temp = unpack('Nlength', $this->_string_shift($signature, 4));
  856. $signature = $this->_string_shift($signature, $temp['length']);
  857. if (!class_exists('Crypt_RSA')) {
  858. require_once('Crypt/RSA.php');
  859. }
  860. $rsa = new Crypt_RSA();
  861. $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
  862. $rsa->loadKey(array('e' => $e, 'n' => $n), CRYPT_RSA_PUBLIC_FORMAT_RAW);
  863. if (!$rsa->verify($source, $signature)) {
  864. user_error('Bad server signature', E_USER_NOTICE);
  865. return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
  866. }
  867. */
  868. $temp = unpack('Nlength', $this->_string_shift($signature, 4));
  869. $s = new Math_BigInteger($this->_string_shift($signature, $temp['length']), 256);
  870. // validate an RSA signature per "8.2 RSASSA-PKCS1-v1_5", "5.2.2 RSAVP1", and "9.1 EMSA-PSS" in the
  871. // following URL:
  872. // ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.pdf
  873. // also, see SSHRSA.c (rsa2_verifysig) in PuTTy's source.
  874. if ($s->compare(new Math_BigInteger()) < 0 || $s->compare($n->subtract(new Math_BigInteger(1))) > 0) {
  875. user_error('Invalid signature', E_USER_NOTICE);
  876. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  877. }
  878. $s = $s->modPow($e, $n);
  879. $s = $s->toBytes();
  880. $h = pack('N4H*', 0x00302130, 0x0906052B, 0x0E03021A, 0x05000414, sha1($source));
  881. $h = chr(0x01) . str_repeat(chr(0xFF), $nLength - 3 - strlen($h)) . $h;
  882. if ($s != $h) {
  883. user_error('Bad server signature', E_USER_NOTICE);
  884. return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
  885. }
  886. }
  887. $packet = pack('C',
  888. NET_SSH2_MSG_NEWKEYS
  889. );
  890. if (!$this->_send_binary_packet($packet)) {
  891. return false;
  892. }
  893. $response = $this->_get_binary_packet();
  894. if ($response === false) {
  895. user_error('Connection closed by server', E_USER_NOTICE);
  896. return false;
  897. }
  898. extract(unpack('Ctype', $this->_string_shift($response, 1)));
  899. if ($type != NET_SSH2_MSG_NEWKEYS) {
  900. user_error('Expected SSH_MSG_NEWKEYS', E_USER_NOTICE);
  901. return false;
  902. }
  903. switch ($encrypt) {
  904. case '3des-cbc':
  905. $this->encrypt = new Crypt_TripleDES();
  906. // $this->encrypt_block_size = 64 / 8 == the default
  907. break;
  908. case 'aes256-cbc':
  909. $this->encrypt = new Crypt_AES();
  910. $this->encrypt_block_size = 16; // eg. 128 / 8
  911. break;
  912. case 'aes192-cbc':
  913. $this->encrypt = new Crypt_AES();
  914. $this->encrypt_block_size = 16;
  915. break;
  916. case 'aes128-cbc':
  917. $this->encrypt = new Crypt_AES();
  918. $this->encrypt_block_size = 16;
  919. break;
  920. case 'arcfour':
  921. $this->encrypt = new Crypt_RC4();
  922. break;
  923. case 'none';
  924. //$this->encrypt = new Crypt_Null();
  925. }
  926. switch ($decrypt) {
  927. case '3des-cbc':
  928. $this->decrypt = new Crypt_TripleDES();
  929. break;
  930. case 'aes256-cbc':
  931. $this->decrypt = new Crypt_AES();
  932. $this->decrypt_block_size = 16;
  933. break;
  934. case 'aes192-cbc':
  935. $this->decrypt = new Crypt_AES();
  936. $this->decrypt_block_size = 16;
  937. break;
  938. case 'aes128-cbc':
  939. $this->decrypt = new Crypt_AES();
  940. $this->decrypt_block_size = 16;
  941. break;
  942. case 'arcfour':
  943. $this->decrypt = new Crypt_RC4();
  944. break;
  945. case 'none';
  946. //$this->decrypt = new Crypt_Null();
  947. }
  948. $keyBytes = pack('Na*', strlen($keyBytes), $keyBytes);
  949. if ($this->encrypt) {
  950. $this->encrypt->enableContinuousBuffer();
  951. $this->encrypt->disablePadding();
  952. $iv = pack('H*', $hash($keyBytes . $source . 'A' . $this->session_id));
  953. while ($this->encrypt_block_size > strlen($iv)) {
  954. $iv.= pack('H*', $hash($keyBytes . $source . $iv));
  955. }
  956. $this->encrypt->setIV(substr($iv, 0, $this->encrypt_block_size));
  957. $key = pack('H*', $hash($keyBytes . $source . 'C' . $this->session_id));
  958. while ($encryptKeyLength > strlen($key)) {
  959. $key.= pack('H*', $hash($keyBytes . $source . $key));
  960. }
  961. $this->encrypt->setKey(substr($key, 0, $encryptKeyLength));
  962. }
  963. if ($this->decrypt) {
  964. $this->decrypt->enableContinuousBuffer();
  965. $this->decrypt->disablePadding();
  966. $iv = pack('H*', $hash($keyBytes . $source . 'B' . $this->session_id));
  967. while ($this->decrypt_block_size > strlen($iv)) {
  968. $iv.= pack('H*', $hash($keyBytes . $source . $iv));
  969. }
  970. $this->decrypt->setIV(substr($iv, 0, $this->decrypt_block_size));
  971. $key = pack('H*', $hash($keyBytes . $source . 'D' . $this->session_id));
  972. while ($decryptKeyLength > strlen($key)) {
  973. $key.= pack('H*', $hash($keyBytes . $source . $key));
  974. }
  975. $this->decrypt->setKey(substr($key, 0, $decryptKeyLength));
  976. }
  977. for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_client_to_server); $i++);
  978. if ($i == count($mac_algorithms)) {
  979. user_error('No compatible client to server message authentication algorithms found', E_USER_NOTICE);
  980. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  981. }
  982. $createKeyLength = 0; // ie. $mac_algorithms[$i] == 'none'
  983. switch ($mac_algorithms[$i]) {
  984. case 'hmac-sha1':
  985. $this->hmac_create = new Crypt_Hash('sha1');
  986. $createKeyLength = 20;
  987. break;
  988. case 'hmac-sha1-96':
  989. $this->hmac_create = new Crypt_Hash('sha1-96');
  990. $createKeyLength = 20;
  991. break;
  992. case 'hmac-md5':
  993. $this->hmac_create = new Crypt_Hash('md5');
  994. $createKeyLength = 16;
  995. break;
  996. case 'hmac-md5-96':
  997. $this->hmac_create = new Crypt_Hash('md5-96');
  998. $createKeyLength = 16;
  999. }
  1000. for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_server_to_client); $i++);
  1001. if ($i == count($mac_algorithms)) {
  1002. user_error('No compatible server to client message authentication algorithms found', E_USER_NOTICE);
  1003. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  1004. }
  1005. $checkKeyLength = 0;
  1006. $this->hmac_size = 0;
  1007. switch ($mac_algorithms[$i]) {
  1008. case 'hmac-sha1':
  1009. $this->hmac_check = new Crypt_Hash('sha1');
  1010. $checkKeyLength = 20;
  1011. $this->hmac_size = 20;
  1012. break;
  1013. case 'hmac-sha1-96':
  1014. $this->hmac_check = new Crypt_Hash('sha1-96');
  1015. $checkKeyLength = 20;
  1016. $this->hmac_size = 12;
  1017. break;
  1018. case 'hmac-md5':
  1019. $this->hmac_check = new Crypt_Hash('md5');
  1020. $checkKeyLength = 16;
  1021. $this->hmac_size = 16;
  1022. break;
  1023. case 'hmac-md5-96':
  1024. $this->hmac_check = new Crypt_Hash('md5-96');
  1025. $checkKeyLength = 16;
  1026. $this->hmac_size = 12;
  1027. }
  1028. $key = pack('H*', $hash($keyBytes . $source . 'E' . $this->session_id));
  1029. while ($createKeyLength > strlen($key)) {
  1030. $key.= pack('H*', $hash($keyBytes . $source . $key));
  1031. }
  1032. $this->hmac_create->setKey(substr($key, 0, $createKeyLength));
  1033. $key = pack('H*', $hash($keyBytes . $source . 'F' . $this->session_id));
  1034. while ($checkKeyLength > strlen($key)) {
  1035. $key.= pack('H*', $hash($keyBytes . $source . $key));
  1036. }
  1037. $this->hmac_check->setKey(substr($key, 0, $checkKeyLength));
  1038. for ($i = 0; $i < count($compression_algorithms) && !in_array($compression_algorithms[$i], $this->compression_algorithms_server_to_client); $i++);
  1039. if ($i == count($compression_algorithms)) {
  1040. user_error('No compatible server to client compression algorithms found', E_USER_NOTICE);
  1041. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  1042. }
  1043. $this->decompress = $compression_algorithms[$i] == 'zlib';
  1044. for ($i = 0; $i < count($compression_algorithms) && !in_array($compression_algorithms[$i], $this->compression_algorithms_client_to_server); $i++);
  1045. if ($i == count($compression_algorithms)) {
  1046. user_error('No compatible client to server compression algorithms found', E_USER_NOTICE);
  1047. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  1048. }
  1049. $this->compress = $compression_algorithms[$i] == 'zlib';
  1050. return true;
  1051. }
  1052. /**
  1053. * Login
  1054. *
  1055. * @param String $username
  1056. * @param optional String $password
  1057. * @return Boolean
  1058. * @access public
  1059. * @internal It might be worthwhile, at some point, to protect against {@link http://tools.ietf.org/html/rfc4251#section-9.3.9 traffic analysis}
  1060. * by sending dummy SSH_MSG_IGNORE messages.
  1061. */
  1062. function login($username, $password = '')
  1063. {
  1064. if (!($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR)) {
  1065. return false;
  1066. }
  1067. $packet = pack('CNa*',
  1068. NET_SSH2_MSG_SERVICE_REQUEST, strlen('ssh-userauth'), 'ssh-userauth'
  1069. );
  1070. if (!$this->_send_binary_packet($packet)) {
  1071. return false;
  1072. }
  1073. $response = $this->_get_binary_packet();
  1074. if ($response === false) {
  1075. user_error('Connection closed by server', E_USER_NOTICE);
  1076. return false;
  1077. }
  1078. extract(unpack('Ctype', $this->_string_shift($response, 1)));
  1079. if ($type != NET_SSH2_MSG_SERVICE_ACCEPT) {
  1080. user_error('Expected SSH_MSG_SERVICE_ACCEPT', E_USER_NOTICE);
  1081. return false;
  1082. }
  1083. // although PHP5's get_class() preserves the case, PHP4's does not
  1084. if (strtolower(get_class($password)) == 'crypt_rsa') {
  1085. return $this->_privatekey_login($username, $password);
  1086. }
  1087. $utf8_password = utf8_encode($password);
  1088. $packet = pack('CNa*Na*Na*CNa*',
  1089. NET_SSH2_MSG_USERAUTH_REQUEST, strlen($username), $username, strlen('ssh-connection'), 'ssh-connection',
  1090. strlen('password'), 'password', 0, strlen($utf8_password), $utf8_password
  1091. );
  1092. if (!$this->_send_binary_packet($packet)) {
  1093. return false;
  1094. }
  1095. // remove the username and password from the last logged packet
  1096. if (defined('NET_SSH2_LOGGING')) {
  1097. $packet = pack('CNa*Na*Na*CNa*',
  1098. NET_SSH2_MSG_USERAUTH_REQUEST, strlen('username'), 'username', strlen('ssh-connection'), 'ssh-connection',
  1099. strlen('password'), 'password', 0, strlen('password'), 'password'
  1100. );
  1101. $this->message_log[count($this->message_log) - 1] = $packet;
  1102. }
  1103. $response = $this->_get_binary_packet();
  1104. if ($response === false) {
  1105. user_error('Connection closed by server', E_USER_NOTICE);
  1106. return false;
  1107. }
  1108. extract(unpack('Ctype', $this->_string_shift($response, 1)));
  1109. switch ($type) {
  1110. case NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ: // in theory, the password can be changed
  1111. if (defined('NET_SSH2_LOGGING')) {
  1112. $this->message_number_log[count($this->message_number_log) - 1] = 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ';
  1113. }
  1114. extract(unpack('Nlength', $this->_string_shift($response, 4)));
  1115. $this->debug_info.= "\r\n\r\nSSH_MSG_USERAUTH_PASSWD_CHANGEREQ:\r\n" . utf8_decode($this->_string_shift($response, $length));
  1116. return $this->_disconnect(NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER);
  1117. case NET_SSH2_MSG_USERAUTH_FAILURE:
  1118. // either the login is bad or the server employees multi-factor authentication
  1119. return false;
  1120. case NET_SSH2_MSG_USERAUTH_SUCCESS:
  1121. $this->bitmap |= NET_SSH2_MASK_LOGIN;
  1122. return true;
  1123. }
  1124. return false;
  1125. }
  1126. /**
  1127. * Login with an RSA private key
  1128. *
  1129. * @param String $username
  1130. * @param Crypt_RSA $password
  1131. * @return Boolean
  1132. * @access private
  1133. * @internal It might be worthwhile, at some point, to protect against {@link http://tools.ietf.org/html/rfc4251#section-9.3.9 traffic analysis}
  1134. * by sending dummy SSH_MSG_IGNORE messages.
  1135. */
  1136. function _privatekey_login($username, $privatekey)
  1137. {
  1138. // see http://tools.ietf.org/html/rfc4253#page-15
  1139. $publickey = $privatekey->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_RAW);
  1140. $publickey = array(
  1141. 'e' => $publickey['e']->toBytes(true),
  1142. 'n' => $publickey['n']->toBytes(true)
  1143. );
  1144. $publickey = pack('Na*Na*Na*',
  1145. strlen('ssh-rsa'), 'ssh-rsa', strlen($publickey['e']), $publickey['e'], strlen($publickey['n']), $

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