/**
  * Raise an arbitrary precision number to another, reduced by a specified modulus
  *
  * @param string $base The left operand, as a string.
  * @param string $exp The right operand, as a string.
  * @param string $mod The modulus, as a string.
  * @access public
  * @return string|null Returns the result as a string, or <b>NULL</b> if modulus is 0.
  */
 public function powmod($base, $exp, $mod)
 {
     //FIXME
     $base = new Math_BigInteger($base);
     $exp = new Math_BigInteger($exp);
     $mod = new Math_BigInteger($mod);
     $mod = $base->modPow($exp, $mod);
     return $mod->toString();
 }
 /**
  * Key Exchange
  *
  * @param String $kexinit_payload_server
  * @access private
  */
 function _key_exchange($kexinit_payload_server)
 {
     static $kex_algorithms = array('diffie-hellman-group1-sha1', 'diffie-hellman-group14-sha1');
     static $server_host_key_algorithms = array('ssh-rsa', 'ssh-dss');
     static $encryption_algorithms = false;
     if ($encryption_algorithms === false) {
         $encryption_algorithms = array('arcfour256', 'arcfour128', 'arcfour', 'aes128-ctr', 'aes192-ctr', 'aes256-ctr', 'twofish128-ctr', 'twofish192-ctr', 'twofish256-ctr', 'aes128-cbc', 'aes192-cbc', 'aes256-cbc', 'twofish128-cbc', 'twofish192-cbc', 'twofish256-cbc', 'twofish-cbc', 'blowfish-ctr', 'blowfish-cbc', '3des-ctr', '3des-cbc', 'none');
         if (phpseclib_resolve_include_path('Crypt/RC4.php') === false) {
             $encryption_algorithms = array_diff($encryption_algorithms, array('arcfour256', 'arcfour128', 'arcfour'));
         }
         if (phpseclib_resolve_include_path('Crypt/Rijndael.php') === false) {
             $encryption_algorithms = array_diff($encryption_algorithms, array('aes128-ctr', 'aes192-ctr', 'aes256-ctr', 'aes128-cbc', 'aes192-cbc', 'aes256-cbc'));
         }
         if (phpseclib_resolve_include_path('Crypt/Twofish.php') === false) {
             $encryption_algorithms = array_diff($encryption_algorithms, array('twofish128-ctr', 'twofish192-ctr', 'twofish256-ctr', 'twofish128-cbc', 'twofish192-cbc', 'twofish256-cbc', 'twofish-cbc'));
         }
         if (phpseclib_resolve_include_path('Crypt/Blowfish.php') === false) {
             $encryption_algorithms = array_diff($encryption_algorithms, array('blowfish-ctr', 'blowfish-cbc'));
         }
         if (phpseclib_resolve_include_path('Crypt/TripleDES.php') === false) {
             $encryption_algorithms = array_diff($encryption_algorithms, array('3des-ctr', '3des-cbc'));
         }
         $encryption_algorithms = array_values($encryption_algorithms);
     }
     $mac_algorithms = array('hmac-sha1-96', 'hmac-sha1', 'hmac-md5-96', 'hmac-md5', 'none');
     static $compression_algorithms = array('none');
     // some SSH servers have buggy implementations of some of the above algorithms
     switch ($this->server_identifier) {
         case 'SSH-2.0-SSHD':
             $mac_algorithms = array_values(array_diff($mac_algorithms, array('hmac-sha1-96', 'hmac-md5-96')));
     }
     static $str_kex_algorithms, $str_server_host_key_algorithms, $encryption_algorithms_server_to_client, $mac_algorithms_server_to_client, $compression_algorithms_server_to_client, $encryption_algorithms_client_to_server, $mac_algorithms_client_to_server, $compression_algorithms_client_to_server;
     if (empty($str_kex_algorithms)) {
         $str_kex_algorithms = implode(',', $kex_algorithms);
         $str_server_host_key_algorithms = implode(',', $server_host_key_algorithms);
         $encryption_algorithms_server_to_client = $encryption_algorithms_client_to_server = implode(',', $encryption_algorithms);
         $mac_algorithms_server_to_client = $mac_algorithms_client_to_server = implode(',', $mac_algorithms);
         $compression_algorithms_server_to_client = $compression_algorithms_client_to_server = implode(',', $compression_algorithms);
     }
     $client_cookie = crypt_random_string(16);
     $response = $kexinit_payload_server;
     $this->_string_shift($response, 1);
     // skip past the message number (it should be SSH_MSG_KEXINIT)
     $server_cookie = $this->_string_shift($response, 16);
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->kex_algorithms = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->server_host_key_algorithms = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->encryption_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->encryption_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->mac_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->mac_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->compression_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->compression_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->languages_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->languages_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
     extract(unpack('Cfirst_kex_packet_follows', $this->_string_shift($response, 1)));
     $first_kex_packet_follows = $first_kex_packet_follows != 0;
     // the sending of SSH2_MSG_KEXINIT could go in one of two places.  this is the second place.
     $kexinit_payload_client = pack('Ca*Na*Na*Na*Na*Na*Na*Na*Na*Na*Na*CN', NET_SSH2_MSG_KEXINIT, $client_cookie, strlen($str_kex_algorithms), $str_kex_algorithms, strlen($str_server_host_key_algorithms), $str_server_host_key_algorithms, strlen($encryption_algorithms_client_to_server), $encryption_algorithms_client_to_server, strlen($encryption_algorithms_server_to_client), $encryption_algorithms_server_to_client, strlen($mac_algorithms_client_to_server), $mac_algorithms_client_to_server, strlen($mac_algorithms_server_to_client), $mac_algorithms_server_to_client, strlen($compression_algorithms_client_to_server), $compression_algorithms_client_to_server, strlen($compression_algorithms_server_to_client), $compression_algorithms_server_to_client, 0, '', 0, '', 0, 0);
     if (!$this->_send_binary_packet($kexinit_payload_client)) {
         return false;
     }
     // here ends the second place.
     // we need to decide upon the symmetric encryption algorithms before we do the diffie-hellman key exchange
     for ($i = 0; $i < count($encryption_algorithms) && !in_array($encryption_algorithms[$i], $this->encryption_algorithms_server_to_client); $i++) {
     }
     if ($i == count($encryption_algorithms)) {
         user_error('No compatible server to client encryption algorithms found');
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     // we don't initialize any crypto-objects, yet - we do that, later. for now, we need the lengths to make the
     // diffie-hellman key exchange as fast as possible
     $decrypt = $encryption_algorithms[$i];
     switch ($decrypt) {
         case '3des-cbc':
         case '3des-ctr':
             $decryptKeyLength = 24;
             // eg. 192 / 8
             break;
         case 'aes256-cbc':
         case 'aes256-ctr':
         case 'twofish-cbc':
         case 'twofish256-cbc':
         case 'twofish256-ctr':
             $decryptKeyLength = 32;
             // eg. 256 / 8
             break;
         case 'aes192-cbc':
         case 'aes192-ctr':
         case 'twofish192-cbc':
         case 'twofish192-ctr':
             $decryptKeyLength = 24;
             // eg. 192 / 8
             break;
         case 'aes128-cbc':
         case 'aes128-ctr':
         case 'twofish128-cbc':
         case 'twofish128-ctr':
         case 'blowfish-cbc':
         case 'blowfish-ctr':
             $decryptKeyLength = 16;
             // eg. 128 / 8
             break;
         case 'arcfour':
         case 'arcfour128':
             $decryptKeyLength = 16;
             // eg. 128 / 8
             break;
         case 'arcfour256':
             $decryptKeyLength = 32;
             // eg. 128 / 8
             break;
         case 'none':
             $decryptKeyLength = 0;
     }
     for ($i = 0; $i < count($encryption_algorithms) && !in_array($encryption_algorithms[$i], $this->encryption_algorithms_client_to_server); $i++) {
     }
     if ($i == count($encryption_algorithms)) {
         user_error('No compatible client to server encryption algorithms found');
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     $encrypt = $encryption_algorithms[$i];
     switch ($encrypt) {
         case '3des-cbc':
         case '3des-ctr':
             $encryptKeyLength = 24;
             break;
         case 'aes256-cbc':
         case 'aes256-ctr':
         case 'twofish-cbc':
         case 'twofish256-cbc':
         case 'twofish256-ctr':
             $encryptKeyLength = 32;
             break;
         case 'aes192-cbc':
         case 'aes192-ctr':
         case 'twofish192-cbc':
         case 'twofish192-ctr':
             $encryptKeyLength = 24;
             break;
         case 'aes128-cbc':
         case 'aes128-ctr':
         case 'twofish128-cbc':
         case 'twofish128-ctr':
         case 'blowfish-cbc':
         case 'blowfish-ctr':
             $encryptKeyLength = 16;
             break;
         case 'arcfour':
         case 'arcfour128':
             $encryptKeyLength = 16;
             break;
         case 'arcfour256':
             $encryptKeyLength = 32;
             break;
         case 'none':
             $encryptKeyLength = 0;
     }
     $keyLength = $decryptKeyLength > $encryptKeyLength ? $decryptKeyLength : $encryptKeyLength;
     // through diffie-hellman key exchange a symmetric key is obtained
     for ($i = 0; $i < count($kex_algorithms) && !in_array($kex_algorithms[$i], $this->kex_algorithms); $i++) {
     }
     if ($i == count($kex_algorithms)) {
         user_error('No compatible key exchange algorithms found');
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     switch ($kex_algorithms[$i]) {
         // see http://tools.ietf.org/html/rfc2409#section-6.2 and
         // http://tools.ietf.org/html/rfc2412, appendex E
         case 'diffie-hellman-group1-sha1':
             $prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF';
             break;
             // see http://tools.ietf.org/html/rfc3526#section-3
         // see http://tools.ietf.org/html/rfc3526#section-3
         case 'diffie-hellman-group14-sha1':
             $prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' . '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' . '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' . 'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' . '3995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF';
             break;
     }
     // For both diffie-hellman-group1-sha1 and diffie-hellman-group14-sha1
     // the generator field element is 2 (decimal) and the hash function is sha1.
     $g = new Math_BigInteger(2);
     $prime = new Math_BigInteger($prime, 16);
     $kexHash = new Crypt_Hash('sha1');
     //$q = $p->bitwise_rightShift(1);
     /* To increase the speed of the key exchange, both client and server may
                reduce the size of their private exponents.  It should be at least
                twice as long as the key material that is generated from the shared
                secret.  For more details, see the paper by van Oorschot and Wiener
                [VAN-OORSCHOT].
     
                -- http://tools.ietf.org/html/rfc4419#section-6.2 */
     $one = new Math_BigInteger(1);
     $keyLength = min($keyLength, $kexHash->getLength());
     $max = $one->bitwise_leftShift(16 * $keyLength);
     // 2 * 8 * $keyLength
     $max = $max->subtract($one);
     $x = $one->random($one, $max);
     $e = $g->modPow($x, $prime);
     $eBytes = $e->toBytes(true);
     $data = pack('CNa*', NET_SSH2_MSG_KEXDH_INIT, strlen($eBytes), $eBytes);
     if (!$this->_send_binary_packet($data)) {
         user_error('Connection closed by server');
         return false;
     }
     $response = $this->_get_binary_packet();
     if ($response === false) {
         user_error('Connection closed by server');
         return false;
     }
     extract(unpack('Ctype', $this->_string_shift($response, 1)));
     if ($type != NET_SSH2_MSG_KEXDH_REPLY) {
         user_error('Expected SSH_MSG_KEXDH_REPLY');
         return false;
     }
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->server_public_host_key = $server_public_host_key = $this->_string_shift($response, $temp['length']);
     $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
     $public_key_format = $this->_string_shift($server_public_host_key, $temp['length']);
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $fBytes = $this->_string_shift($response, $temp['length']);
     $f = new Math_BigInteger($fBytes, -256);
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->signature = $this->_string_shift($response, $temp['length']);
     $temp = unpack('Nlength', $this->_string_shift($this->signature, 4));
     $this->signature_format = $this->_string_shift($this->signature, $temp['length']);
     $key = $f->modPow($x, $prime);
     $keyBytes = $key->toBytes(true);
     $this->exchange_hash = pack('Na*Na*Na*Na*Na*Na*Na*Na*', strlen($this->identifier), $this->identifier, strlen($this->server_identifier), $this->server_identifier, strlen($kexinit_payload_client), $kexinit_payload_client, strlen($kexinit_payload_server), $kexinit_payload_server, strlen($this->server_public_host_key), $this->server_public_host_key, strlen($eBytes), $eBytes, strlen($fBytes), $fBytes, strlen($keyBytes), $keyBytes);
     $this->exchange_hash = $kexHash->hash($this->exchange_hash);
     if ($this->session_id === false) {
         $this->session_id = $this->exchange_hash;
     }
     for ($i = 0; $i < count($server_host_key_algorithms) && !in_array($server_host_key_algorithms[$i], $this->server_host_key_algorithms); $i++) {
     }
     if ($i == count($server_host_key_algorithms)) {
         user_error('No compatible server host key algorithms found');
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     if ($public_key_format != $server_host_key_algorithms[$i] || $this->signature_format != $server_host_key_algorithms[$i]) {
         user_error('Server Host Key Algorithm Mismatch');
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     $packet = pack('C', NET_SSH2_MSG_NEWKEYS);
     if (!$this->_send_binary_packet($packet)) {
         return false;
     }
     $response = $this->_get_binary_packet();
     if ($response === false) {
         user_error('Connection closed by server');
         return false;
     }
     extract(unpack('Ctype', $this->_string_shift($response, 1)));
     if ($type != NET_SSH2_MSG_NEWKEYS) {
         user_error('Expected SSH_MSG_NEWKEYS');
         return false;
     }
     switch ($encrypt) {
         case '3des-cbc':
             if (!class_exists('Crypt_TripleDES')) {
                 include_once 'Crypt/TripleDES.php';
             }
             $this->encrypt = new Crypt_TripleDES();
             // $this->encrypt_block_size = 64 / 8 == the default
             break;
         case '3des-ctr':
             if (!class_exists('Crypt_TripleDES')) {
                 include_once 'Crypt/TripleDES.php';
             }
             $this->encrypt = new Crypt_TripleDES(CRYPT_DES_MODE_CTR);
             // $this->encrypt_block_size = 64 / 8 == the default
             break;
         case 'aes256-cbc':
         case 'aes192-cbc':
         case 'aes128-cbc':
             if (!class_exists('Crypt_Rijndael')) {
                 include_once 'Crypt/Rijndael.php';
             }
             $this->encrypt = new Crypt_Rijndael();
             $this->encrypt_block_size = 16;
             // eg. 128 / 8
             break;
         case 'aes256-ctr':
         case 'aes192-ctr':
         case 'aes128-ctr':
             if (!class_exists('Crypt_Rijndael')) {
                 include_once 'Crypt/Rijndael.php';
             }
             $this->encrypt = new Crypt_Rijndael(CRYPT_RIJNDAEL_MODE_CTR);
             $this->encrypt_block_size = 16;
             // eg. 128 / 8
             break;
         case 'blowfish-cbc':
             if (!class_exists('Crypt_Blowfish')) {
                 include_once 'Crypt/Blowfish.php';
             }
             $this->encrypt = new Crypt_Blowfish();
             $this->encrypt_block_size = 8;
             break;
         case 'blowfish-ctr':
             if (!class_exists('Crypt_Blowfish')) {
                 include_once 'Crypt/Blowfish.php';
             }
             $this->encrypt = new Crypt_Blowfish(CRYPT_BLOWFISH_MODE_CTR);
             $this->encrypt_block_size = 8;
             break;
         case 'twofish128-cbc':
         case 'twofish192-cbc':
         case 'twofish256-cbc':
         case 'twofish-cbc':
             if (!class_exists('Crypt_Twofish')) {
                 include_once 'Crypt/Twofish.php';
             }
             $this->encrypt = new Crypt_Twofish();
             $this->encrypt_block_size = 16;
             break;
         case 'twofish128-ctr':
         case 'twofish192-ctr':
         case 'twofish256-ctr':
             if (!class_exists('Crypt_Twofish')) {
                 include_once 'Crypt/Twofish.php';
             }
             $this->encrypt = new Crypt_Twofish(CRYPT_TWOFISH_MODE_CTR);
             $this->encrypt_block_size = 16;
             break;
         case 'arcfour':
         case 'arcfour128':
         case 'arcfour256':
             if (!class_exists('Crypt_RC4')) {
                 include_once 'Crypt/RC4.php';
             }
             $this->encrypt = new Crypt_RC4();
             break;
         case 'none':
             //$this->encrypt = new Crypt_Null();
     }
     switch ($decrypt) {
         case '3des-cbc':
             if (!class_exists('Crypt_TripleDES')) {
                 include_once 'Crypt/TripleDES.php';
             }
             $this->decrypt = new Crypt_TripleDES();
             break;
         case '3des-ctr':
             if (!class_exists('Crypt_TripleDES')) {
                 include_once 'Crypt/TripleDES.php';
             }
             $this->decrypt = new Crypt_TripleDES(CRYPT_DES_MODE_CTR);
             break;
         case 'aes256-cbc':
         case 'aes192-cbc':
         case 'aes128-cbc':
             if (!class_exists('Crypt_Rijndael')) {
                 include_once 'Crypt/Rijndael.php';
             }
             $this->decrypt = new Crypt_Rijndael();
             $this->decrypt_block_size = 16;
             break;
         case 'aes256-ctr':
         case 'aes192-ctr':
         case 'aes128-ctr':
             if (!class_exists('Crypt_Rijndael')) {
                 include_once 'Crypt/Rijndael.php';
             }
             $this->decrypt = new Crypt_Rijndael(CRYPT_RIJNDAEL_MODE_CTR);
             $this->decrypt_block_size = 16;
             break;
         case 'blowfish-cbc':
             if (!class_exists('Crypt_Blowfish')) {
                 include_once 'Crypt/Blowfish.php';
             }
             $this->decrypt = new Crypt_Blowfish();
             $this->decrypt_block_size = 8;
             break;
         case 'blowfish-ctr':
             if (!class_exists('Crypt_Blowfish')) {
                 include_once 'Crypt/Blowfish.php';
             }
             $this->decrypt = new Crypt_Blowfish(CRYPT_BLOWFISH_MODE_CTR);
             $this->decrypt_block_size = 8;
             break;
         case 'twofish128-cbc':
         case 'twofish192-cbc':
         case 'twofish256-cbc':
         case 'twofish-cbc':
             if (!class_exists('Crypt_Twofish')) {
                 include_once 'Crypt/Twofish.php';
             }
             $this->decrypt = new Crypt_Twofish();
             $this->decrypt_block_size = 16;
             break;
         case 'twofish128-ctr':
         case 'twofish192-ctr':
         case 'twofish256-ctr':
             if (!class_exists('Crypt_Twofish')) {
                 include_once 'Crypt/Twofish.php';
             }
             $this->decrypt = new Crypt_Twofish(CRYPT_TWOFISH_MODE_CTR);
             $this->decrypt_block_size = 16;
             break;
         case 'arcfour':
         case 'arcfour128':
         case 'arcfour256':
             if (!class_exists('Crypt_RC4')) {
                 include_once 'Crypt/RC4.php';
             }
             $this->decrypt = new Crypt_RC4();
             break;
         case 'none':
             //$this->decrypt = new Crypt_Null();
     }
     $keyBytes = pack('Na*', strlen($keyBytes), $keyBytes);
     if ($this->encrypt) {
         $this->encrypt->enableContinuousBuffer();
         $this->encrypt->disablePadding();
         $iv = $kexHash->hash($keyBytes . $this->exchange_hash . 'A' . $this->session_id);
         while ($this->encrypt_block_size > strlen($iv)) {
             $iv .= $kexHash->hash($keyBytes . $this->exchange_hash . $iv);
         }
         $this->encrypt->setIV(substr($iv, 0, $this->encrypt_block_size));
         $key = $kexHash->hash($keyBytes . $this->exchange_hash . 'C' . $this->session_id);
         while ($encryptKeyLength > strlen($key)) {
             $key .= $kexHash->hash($keyBytes . $this->exchange_hash . $key);
         }
         $this->encrypt->setKey(substr($key, 0, $encryptKeyLength));
     }
     if ($this->decrypt) {
         $this->decrypt->enableContinuousBuffer();
         $this->decrypt->disablePadding();
         $iv = $kexHash->hash($keyBytes . $this->exchange_hash . 'B' . $this->session_id);
         while ($this->decrypt_block_size > strlen($iv)) {
             $iv .= $kexHash->hash($keyBytes . $this->exchange_hash . $iv);
         }
         $this->decrypt->setIV(substr($iv, 0, $this->decrypt_block_size));
         $key = $kexHash->hash($keyBytes . $this->exchange_hash . 'D' . $this->session_id);
         while ($decryptKeyLength > strlen($key)) {
             $key .= $kexHash->hash($keyBytes . $this->exchange_hash . $key);
         }
         $this->decrypt->setKey(substr($key, 0, $decryptKeyLength));
     }
     /* The "arcfour128" algorithm is the RC4 cipher, as described in
                [SCHNEIER], using a 128-bit key.  The first 1536 bytes of keystream
                generated by the cipher MUST be discarded, and the first byte of the
                first encrypted packet MUST be encrypted using the 1537th byte of
                keystream.
     
                -- http://tools.ietf.org/html/rfc4345#section-4 */
     if ($encrypt == 'arcfour128' || $encrypt == 'arcfour256') {
         $this->encrypt->encrypt(str_repeat("", 1536));
     }
     if ($decrypt == 'arcfour128' || $decrypt == 'arcfour256') {
         $this->decrypt->decrypt(str_repeat("", 1536));
     }
     for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_client_to_server); $i++) {
     }
     if ($i == count($mac_algorithms)) {
         user_error('No compatible client to server message authentication algorithms found');
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     $createKeyLength = 0;
     // ie. $mac_algorithms[$i] == 'none'
     switch ($mac_algorithms[$i]) {
         case 'hmac-sha1':
             $this->hmac_create = new Crypt_Hash('sha1');
             $createKeyLength = 20;
             break;
         case 'hmac-sha1-96':
             $this->hmac_create = new Crypt_Hash('sha1-96');
             $createKeyLength = 20;
             break;
         case 'hmac-md5':
             $this->hmac_create = new Crypt_Hash('md5');
             $createKeyLength = 16;
             break;
         case 'hmac-md5-96':
             $this->hmac_create = new Crypt_Hash('md5-96');
             $createKeyLength = 16;
     }
     for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_server_to_client); $i++) {
     }
     if ($i == count($mac_algorithms)) {
         user_error('No compatible server to client message authentication algorithms found');
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     $checkKeyLength = 0;
     $this->hmac_size = 0;
     switch ($mac_algorithms[$i]) {
         case 'hmac-sha1':
             $this->hmac_check = new Crypt_Hash('sha1');
             $checkKeyLength = 20;
             $this->hmac_size = 20;
             break;
         case 'hmac-sha1-96':
             $this->hmac_check = new Crypt_Hash('sha1-96');
             $checkKeyLength = 20;
             $this->hmac_size = 12;
             break;
         case 'hmac-md5':
             $this->hmac_check = new Crypt_Hash('md5');
             $checkKeyLength = 16;
             $this->hmac_size = 16;
             break;
         case 'hmac-md5-96':
             $this->hmac_check = new Crypt_Hash('md5-96');
             $checkKeyLength = 16;
             $this->hmac_size = 12;
     }
     $key = $kexHash->hash($keyBytes . $this->exchange_hash . 'E' . $this->session_id);
     while ($createKeyLength > strlen($key)) {
         $key .= $kexHash->hash($keyBytes . $this->exchange_hash . $key);
     }
     $this->hmac_create->setKey(substr($key, 0, $createKeyLength));
     $key = $kexHash->hash($keyBytes . $this->exchange_hash . 'F' . $this->session_id);
     while ($checkKeyLength > strlen($key)) {
         $key .= $kexHash->hash($keyBytes . $this->exchange_hash . $key);
     }
     $this->hmac_check->setKey(substr($key, 0, $checkKeyLength));
     for ($i = 0; $i < count($compression_algorithms) && !in_array($compression_algorithms[$i], $this->compression_algorithms_server_to_client); $i++) {
     }
     if ($i == count($compression_algorithms)) {
         user_error('No compatible server to client compression algorithms found');
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     $this->decompress = $compression_algorithms[$i] == 'zlib';
     for ($i = 0; $i < count($compression_algorithms) && !in_array($compression_algorithms[$i], $this->compression_algorithms_client_to_server); $i++) {
     }
     if ($i == count($compression_algorithms)) {
         user_error('No compatible client to server compression algorithms found');
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     $this->compress = $compression_algorithms[$i] == 'zlib';
     return true;
 }
Exemple #3
0
 /**
  * Performs RSA Blinding
  *
  * Protects against timing attacks by employing RSA Blinding.
  * Returns $x->modPow($this->exponents[$i], $this->primes[$i])
  *
  * @access private
  * @param Math_BigInteger $x
  * @param Math_BigInteger $r
  * @param Integer $i
  * @return Math_BigInteger
  */
 function _blind($x, $r, $i)
 {
     $x = $x->multiply($r->modPow($this->publicExponent, $this->primes[$i]));
     $x = $x->modPow($this->exponents[$i], $this->primes[$i]);
     $r = $r->modInverse($this->primes[$i]);
     $x = $x->multiply($r);
     list(, $x) = $x->divide($this->primes[$i]);
     return $x;
 }
Exemple #4
0
 /**
  * DSA verify.
  *
  * @param string $message     Message.
  * @param string $hash_alg    Hash algorithm.
  * @param Math_BigInteger $r  r.
  * @param Math_BigInteger $s  s.
  *
  * @return bool  True if verified.
  */
 public function verify($message, $hash_alg, $r, $s)
 {
     $hash = new Crypt_Hash($hash_alg);
     $hash_m = new Math_BigInteger($hash->hash($message), 256);
     $g = new Math_BigInteger($this->_key->key['g'], 256);
     $p = new Math_BigInteger($this->_key->key['p'], 256);
     $q = new Math_BigInteger($this->_key->key['q'], 256);
     $y = new Math_BigInteger($this->_key->key['y'], 256);
     $w = $s->modInverse($q);
     $hash_m_mul = $hash_m->multiply($w);
     $u1_base = $hash_m_mul->divide($q);
     $u1 = $u1_base[1];
     $r_mul = $r->multiply($w);
     $u2_base = $r_mul->divide($q);
     $u2 = $u2_base[1];
     $g_pow = $g->modPow($u1, $p);
     $y_pow = $y->modPow($u2, $p);
     $g_pow_mul = $g_pow->multiply($y_pow);
     $g_pow_mul_mod_base = $g_pow_mul->divide($p);
     $g_pow_mul_mod = $g_pow_mul_mod_base[1];
     $v_base = $g_pow_mul_mod->divide($q);
     $v = $v_base[1];
     return $v->compare($r) == 0;
 }
Exemple #5
0
$result = bcsub($result, $y);
$_result = $_result->subtract($_y);
echo "\$result = \$result-\$y;\r\n";
echo "{$result}\r\n";
echo $_result->toString();
echo "\r\n\r\n";
$result = bcdiv($x, $y);
list($_result, ) = $_x->divide($_y);
echo "\$result = \$x/\$y;\r\n";
echo "{$result}\r\n";
echo $_result->toString();
echo "\r\n\r\n";
$result = bcmod($y, $z);
list(, $_result) = $_y->divide($_z);
echo "\$result = \$x%\$y;\r\n";
echo "{$result}\r\n";
echo $_result->toString();
echo "\r\n\r\n";
$result = bcmul($x, $z);
$_result = $_x->multiply($_z);
echo "\$result = \$x*\$z;\r\n";
echo "{$result}\r\n";
echo $_result->toString();
echo "\r\n\r\n";
$result = bcpowmod($x, $y, $result);
$_result = $_x->modPow($_y, $_result);
echo "\$result = (\$x**\$y)%\$result;\r\n";
echo "{$result}\r\n";
echo $_result->toString();
echo "\r\n\r\n";
// modInverse isn't demo'd because no equivalent to it exists in BCMath.
Exemple #6
0
 /**
  * Key Exchange
  *
  * @param String $kexinit_payload_server
  * @access private
  */
 function _key_exchange($kexinit_payload_server)
 {
     static $kex_algorithms = array('diffie-hellman-group1-sha1', 'diffie-hellman-group14-sha1');
     static $server_host_key_algorithms = array('ssh-rsa', 'ssh-dss');
     static $encryption_algorithms = array('arcfour', 'aes128-cbc', 'aes192-cbc', 'aes256-cbc', '3des-cbc', 'none');
     static $mac_algorithms = array('hmac-sha1-96', 'hmac-sha1', 'hmac-md5-96', 'hmac-md5', 'none');
     static $compression_algorithms = array('none');
     static $str_kex_algorithms, $str_server_host_key_algorithms, $encryption_algorithms_server_to_client, $mac_algorithms_server_to_client, $compression_algorithms_server_to_client, $encryption_algorithms_client_to_server, $mac_algorithms_client_to_server, $compression_algorithms_client_to_server;
     if (empty($str_kex_algorithms)) {
         $str_kex_algorithms = implode(',', $kex_algorithms);
         $str_server_host_key_algorithms = implode(',', $server_host_key_algorithms);
         $encryption_algorithms_server_to_client = $encryption_algorithms_client_to_server = implode(',', $encryption_algorithms);
         $mac_algorithms_server_to_client = $mac_algorithms_client_to_server = implode(',', $mac_algorithms);
         $compression_algorithms_server_to_client = $compression_algorithms_client_to_server = implode(',', $compression_algorithms);
     }
     $client_cookie = '';
     for ($i = 0; $i < 16; $i++) {
         $client_cookie .= chr(crypt_random(0, 255));
     }
     $response = $kexinit_payload_server;
     $this->_string_shift($response, 1);
     // skip past the message number (it should be SSH_MSG_KEXINIT)
     $server_cookie = $this->_string_shift($response, 16);
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->kex_algorithms = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->server_host_key_algorithms = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->encryption_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->encryption_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->mac_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->mac_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->compression_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->compression_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->languages_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->languages_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
     extract(unpack('Cfirst_kex_packet_follows', $this->_string_shift($response, 1)));
     $first_kex_packet_follows = $first_kex_packet_follows != 0;
     // the sending of SSH2_MSG_KEXINIT could go in one of two places.  this is the second place.
     $kexinit_payload_client = pack('Ca*Na*Na*Na*Na*Na*Na*Na*Na*Na*Na*CN', NET_SSH2_MSG_KEXINIT, $client_cookie, strlen($str_kex_algorithms), $str_kex_algorithms, strlen($str_server_host_key_algorithms), $str_server_host_key_algorithms, strlen($encryption_algorithms_client_to_server), $encryption_algorithms_client_to_server, strlen($encryption_algorithms_server_to_client), $encryption_algorithms_server_to_client, strlen($mac_algorithms_client_to_server), $mac_algorithms_client_to_server, strlen($mac_algorithms_server_to_client), $mac_algorithms_server_to_client, strlen($compression_algorithms_client_to_server), $compression_algorithms_client_to_server, strlen($compression_algorithms_server_to_client), $compression_algorithms_server_to_client, 0, '', 0, '', 0, 0);
     if (!$this->_send_binary_packet($kexinit_payload_client)) {
         return false;
     }
     // here ends the second place.
     // we need to decide upon the symmetric encryption algorithms before we do the diffie-hellman key exchange
     for ($i = 0; $i < count($encryption_algorithms) && !in_array($encryption_algorithms[$i], $this->encryption_algorithms_server_to_client); $i++) {
     }
     if ($i == count($encryption_algorithms)) {
         user_error('No compatible server to client encryption algorithms found', E_USER_NOTICE);
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     // we don't initialize any crypto-objects, yet - we do that, later. for now, we need the lengths to make the
     // diffie-hellman key exchange as fast as possible
     $decrypt = $encryption_algorithms[$i];
     switch ($decrypt) {
         case '3des-cbc':
             $decryptKeyLength = 24;
             // eg. 192 / 8
             break;
         case 'aes256-cbc':
             $decryptKeyLength = 32;
             // eg. 256 / 8
             break;
         case 'aes192-cbc':
             $decryptKeyLength = 24;
             // eg. 192 / 8
             break;
         case 'aes128-cbc':
             $decryptKeyLength = 16;
             // eg. 128 / 8
             break;
         case 'arcfour':
             $decryptKeyLength = 16;
             // eg. 128 / 8
             break;
         case 'none':
             $decryptKeyLength = 0;
     }
     for ($i = 0; $i < count($encryption_algorithms) && !in_array($encryption_algorithms[$i], $this->encryption_algorithms_client_to_server); $i++) {
     }
     if ($i == count($encryption_algorithms)) {
         user_error('No compatible client to server encryption algorithms found', E_USER_NOTICE);
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     $encrypt = $encryption_algorithms[$i];
     switch ($encrypt) {
         case '3des-cbc':
             $encryptKeyLength = 24;
             break;
         case 'aes256-cbc':
             $encryptKeyLength = 32;
             break;
         case 'aes192-cbc':
             $encryptKeyLength = 24;
             break;
         case 'aes128-cbc':
             $encryptKeyLength = 16;
             break;
         case 'arcfour':
             $encryptKeyLength = 16;
             break;
         case 'none':
             $encryptKeyLength = 0;
     }
     $keyLength = $decryptKeyLength > $encryptKeyLength ? $decryptKeyLength : $encryptKeyLength;
     // through diffie-hellman key exchange a symmetric key is obtained
     for ($i = 0; $i < count($kex_algorithms) && !in_array($kex_algorithms[$i], $this->kex_algorithms); $i++) {
     }
     if ($i == count($kex_algorithms)) {
         user_error('No compatible key exchange algorithms found', E_USER_NOTICE);
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     switch ($kex_algorithms[$i]) {
         // see http://tools.ietf.org/html/rfc2409#section-6.2 and
         // http://tools.ietf.org/html/rfc2412, appendex E
         case 'diffie-hellman-group1-sha1':
             $p = pack('H256', 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF');
             $keyLength = $keyLength < 160 ? $keyLength : 160;
             $hash = 'sha1';
             break;
             // see http://tools.ietf.org/html/rfc3526#section-3
         // see http://tools.ietf.org/html/rfc3526#section-3
         case 'diffie-hellman-group14-sha1':
             $p = pack('H512', 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' . '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' . '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' . 'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' . '3995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF');
             $keyLength = $keyLength < 160 ? $keyLength : 160;
             $hash = 'sha1';
     }
     $p = new Math_BigInteger($p, 256);
     //$q = $p->bitwise_rightShift(1);
     /* To increase the speed of the key exchange, both client and server may
                reduce the size of their private exponents.  It should be at least
                twice as long as the key material that is generated from the shared
                secret.  For more details, see the paper by van Oorschot and Wiener
                [VAN-OORSCHOT].
     
                -- http://tools.ietf.org/html/rfc4419#section-6.2 */
     $q = new Math_BigInteger(1);
     $q = $q->bitwise_leftShift(2 * $keyLength);
     $q = $q->subtract(new Math_BigInteger(1));
     $g = new Math_BigInteger(2);
     $x = new Math_BigInteger();
     $x->setRandomGenerator('crypt_random');
     $x = $x->random(new Math_BigInteger(1), $q);
     $e = $g->modPow($x, $p);
     $eBytes = $e->toBytes(true);
     $data = pack('CNa*', NET_SSH2_MSG_KEXDH_INIT, strlen($eBytes), $eBytes);
     if (!$this->_send_binary_packet($data)) {
         user_error('Connection closed by server', E_USER_NOTICE);
         return false;
     }
     $response = $this->_get_binary_packet();
     if ($response === false) {
         user_error('Connection closed by server', E_USER_NOTICE);
         return false;
     }
     extract(unpack('Ctype', $this->_string_shift($response, 1)));
     if ($type != NET_SSH2_MSG_KEXDH_REPLY) {
         user_error('Expected SSH_MSG_KEXDH_REPLY', E_USER_NOTICE);
         return false;
     }
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->server_public_host_key = $server_public_host_key = $this->_string_shift($response, $temp['length']);
     $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
     $public_key_format = $this->_string_shift($server_public_host_key, $temp['length']);
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $fBytes = $this->_string_shift($response, $temp['length']);
     $f = new Math_BigInteger($fBytes, -256);
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $signature = $this->_string_shift($response, $temp['length']);
     $temp = unpack('Nlength', $this->_string_shift($signature, 4));
     $signature_format = $this->_string_shift($signature, $temp['length']);
     $key = $f->modPow($x, $p);
     $keyBytes = $key->toBytes(true);
     $source = pack('Na*Na*Na*Na*Na*Na*Na*Na*', strlen($this->identifier), $this->identifier, strlen($this->server_identifier), $this->server_identifier, strlen($kexinit_payload_client), $kexinit_payload_client, strlen($kexinit_payload_server), $kexinit_payload_server, strlen($this->server_public_host_key), $this->server_public_host_key, strlen($eBytes), $eBytes, strlen($fBytes), $fBytes, strlen($keyBytes), $keyBytes);
     $source = pack('H*', $hash($source));
     if ($this->session_id === false) {
         $this->session_id = $source;
     }
     // if you the server's assymetric key matches the one you have on file, then you should be able to decrypt the
     // "signature" and get something that should equal the "exchange hash", as defined in the SSH-2 specs.
     // here, we just check to see if the "signature" is good.  you can verify whether or not the assymetric key is good,
     // later, with the getServerHostKeyAlgorithm() function
     for ($i = 0; $i < count($server_host_key_algorithms) && !in_array($server_host_key_algorithms[$i], $this->server_host_key_algorithms); $i++) {
     }
     if ($i == count($server_host_key_algorithms)) {
         user_error('No compatible server host key algorithms found', E_USER_NOTICE);
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     if ($public_key_format != $server_host_key_algorithms[$i] || $signature_format != $server_host_key_algorithms[$i]) {
         user_error('Sever Host Key Algorithm Mismatch', E_USER_NOTICE);
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     switch ($server_host_key_algorithms[$i]) {
         case 'ssh-dss':
             $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
             $p = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
             $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
             $q = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
             $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
             $g = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
             $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
             $y = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
             /* The value for 'dss_signature_blob' is encoded as a string containing
                r, followed by s (which are 160-bit integers, without lengths or
                padding, unsigned, and in network byte order). */
             $temp = unpack('Nlength', $this->_string_shift($signature, 4));
             if ($temp['length'] != 40) {
                 user_error('Invalid signature', E_USER_NOTICE);
                 return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
             }
             $r = new Math_BigInteger($this->_string_shift($signature, 20), 256);
             $s = new Math_BigInteger($this->_string_shift($signature, 20), 256);
             if ($r->compare($q) >= 0 || $s->compare($q) >= 0) {
                 user_error('Invalid signature', E_USER_NOTICE);
                 return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
             }
             $w = $s->modInverse($q);
             $u1 = $w->multiply(new Math_BigInteger(sha1($source), 16));
             list(, $u1) = $u1->divide($q);
             $u2 = $w->multiply($r);
             list(, $u2) = $u2->divide($q);
             $g = $g->modPow($u1, $p);
             $y = $y->modPow($u2, $p);
             $v = $g->multiply($y);
             list(, $v) = $v->divide($p);
             list(, $v) = $v->divide($q);
             if (!$v->equals($r)) {
                 user_error('Invalid signature', E_USER_NOTICE);
                 return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
             }
             break;
         case 'ssh-rsa':
             $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
             $e = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
             $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
             $n = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
             $nLength = $temp['length'];
             /*
             $temp = unpack('Nlength', $this->_string_shift($signature, 4));
             $signature = $this->_string_shift($signature, $temp['length']);
             
             if (!class_exists('Crypt_RSA')) {
                 require_once('Crypt/RSA.php');
             }
             
             $rsa = new Crypt_RSA();
             $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
             $rsa->loadKey(array('e' => $e, 'n' => $n), CRYPT_RSA_PUBLIC_FORMAT_RAW);
             if (!$rsa->verify($source, $signature)) {
                 user_error('Bad server signature', E_USER_NOTICE);
                 return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
             }
             */
             $temp = unpack('Nlength', $this->_string_shift($signature, 4));
             $s = new Math_BigInteger($this->_string_shift($signature, $temp['length']), 256);
             // validate an RSA signature per "8.2 RSASSA-PKCS1-v1_5", "5.2.2 RSAVP1", and "9.1 EMSA-PSS" in the
             // following URL:
             // ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.pdf
             // also, see SSHRSA.c (rsa2_verifysig) in PuTTy's source.
             if ($s->compare(new Math_BigInteger()) < 0 || $s->compare($n->subtract(new Math_BigInteger(1))) > 0) {
                 user_error('Invalid signature', E_USER_NOTICE);
                 return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
             }
             $s = $s->modPow($e, $n);
             $s = $s->toBytes();
             $h = pack('N4H*', 0x302130, 0x906052b, 0xe03021a, 0x5000414, sha1($source));
             $h = chr(0x1) . str_repeat(chr(0xff), $nLength - 3 - strlen($h)) . $h;
             if ($s != $h) {
                 user_error('Bad server signature', E_USER_NOTICE);
                 return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
             }
     }
     $packet = pack('C', NET_SSH2_MSG_NEWKEYS);
     if (!$this->_send_binary_packet($packet)) {
         return false;
     }
     $response = $this->_get_binary_packet();
     if ($response === false) {
         user_error('Connection closed by server', E_USER_NOTICE);
         return false;
     }
     extract(unpack('Ctype', $this->_string_shift($response, 1)));
     if ($type != NET_SSH2_MSG_NEWKEYS) {
         user_error('Expected SSH_MSG_NEWKEYS', E_USER_NOTICE);
         return false;
     }
     switch ($encrypt) {
         case '3des-cbc':
             $this->encrypt = new Crypt_TripleDES();
             // $this->encrypt_block_size = 64 / 8 == the default
             break;
         case 'aes256-cbc':
             $this->encrypt = new Crypt_AES();
             $this->encrypt_block_size = 16;
             // eg. 128 / 8
             break;
         case 'aes192-cbc':
             $this->encrypt = new Crypt_AES();
             $this->encrypt_block_size = 16;
             break;
         case 'aes128-cbc':
             $this->encrypt = new Crypt_AES();
             $this->encrypt_block_size = 16;
             break;
         case 'arcfour':
             $this->encrypt = new Crypt_RC4();
             break;
         case 'none':
             //$this->encrypt = new Crypt_Null();
     }
     switch ($decrypt) {
         case '3des-cbc':
             $this->decrypt = new Crypt_TripleDES();
             break;
         case 'aes256-cbc':
             $this->decrypt = new Crypt_AES();
             $this->decrypt_block_size = 16;
             break;
         case 'aes192-cbc':
             $this->decrypt = new Crypt_AES();
             $this->decrypt_block_size = 16;
             break;
         case 'aes128-cbc':
             $this->decrypt = new Crypt_AES();
             $this->decrypt_block_size = 16;
             break;
         case 'arcfour':
             $this->decrypt = new Crypt_RC4();
             break;
         case 'none':
             //$this->decrypt = new Crypt_Null();
     }
     $keyBytes = pack('Na*', strlen($keyBytes), $keyBytes);
     if ($this->encrypt) {
         $this->encrypt->enableContinuousBuffer();
         $this->encrypt->disablePadding();
         $iv = pack('H*', $hash($keyBytes . $source . 'A' . $this->session_id));
         while ($this->encrypt_block_size > strlen($iv)) {
             $iv .= pack('H*', $hash($keyBytes . $source . $iv));
         }
         $this->encrypt->setIV(substr($iv, 0, $this->encrypt_block_size));
         $key = pack('H*', $hash($keyBytes . $source . 'C' . $this->session_id));
         while ($encryptKeyLength > strlen($key)) {
             $key .= pack('H*', $hash($keyBytes . $source . $key));
         }
         $this->encrypt->setKey(substr($key, 0, $encryptKeyLength));
     }
     if ($this->decrypt) {
         $this->decrypt->enableContinuousBuffer();
         $this->decrypt->disablePadding();
         $iv = pack('H*', $hash($keyBytes . $source . 'B' . $this->session_id));
         while ($this->decrypt_block_size > strlen($iv)) {
             $iv .= pack('H*', $hash($keyBytes . $source . $iv));
         }
         $this->decrypt->setIV(substr($iv, 0, $this->decrypt_block_size));
         $key = pack('H*', $hash($keyBytes . $source . 'D' . $this->session_id));
         while ($decryptKeyLength > strlen($key)) {
             $key .= pack('H*', $hash($keyBytes . $source . $key));
         }
         $this->decrypt->setKey(substr($key, 0, $decryptKeyLength));
     }
     for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_client_to_server); $i++) {
     }
     if ($i == count($mac_algorithms)) {
         user_error('No compatible client to server message authentication algorithms found', E_USER_NOTICE);
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     $createKeyLength = 0;
     // ie. $mac_algorithms[$i] == 'none'
     switch ($mac_algorithms[$i]) {
         case 'hmac-sha1':
             $this->hmac_create = new Crypt_Hash('sha1');
             $createKeyLength = 20;
             break;
         case 'hmac-sha1-96':
             $this->hmac_create = new Crypt_Hash('sha1-96');
             $createKeyLength = 20;
             break;
         case 'hmac-md5':
             $this->hmac_create = new Crypt_Hash('md5');
             $createKeyLength = 16;
             break;
         case 'hmac-md5-96':
             $this->hmac_create = new Crypt_Hash('md5-96');
             $createKeyLength = 16;
     }
     for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_server_to_client); $i++) {
     }
     if ($i == count($mac_algorithms)) {
         user_error('No compatible server to client message authentication algorithms found', E_USER_NOTICE);
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     $checkKeyLength = 0;
     $this->hmac_size = 0;
     switch ($mac_algorithms[$i]) {
         case 'hmac-sha1':
             $this->hmac_check = new Crypt_Hash('sha1');
             $checkKeyLength = 20;
             $this->hmac_size = 20;
             break;
         case 'hmac-sha1-96':
             $this->hmac_check = new Crypt_Hash('sha1-96');
             $checkKeyLength = 20;
             $this->hmac_size = 12;
             break;
         case 'hmac-md5':
             $this->hmac_check = new Crypt_Hash('md5');
             $checkKeyLength = 16;
             $this->hmac_size = 16;
             break;
         case 'hmac-md5-96':
             $this->hmac_check = new Crypt_Hash('md5-96');
             $checkKeyLength = 16;
             $this->hmac_size = 12;
     }
     $key = pack('H*', $hash($keyBytes . $source . 'E' . $this->session_id));
     while ($createKeyLength > strlen($key)) {
         $key .= pack('H*', $hash($keyBytes . $source . $key));
     }
     $this->hmac_create->setKey(substr($key, 0, $createKeyLength));
     $key = pack('H*', $hash($keyBytes . $source . 'F' . $this->session_id));
     while ($checkKeyLength > strlen($key)) {
         $key .= pack('H*', $hash($keyBytes . $source . $key));
     }
     $this->hmac_check->setKey(substr($key, 0, $checkKeyLength));
     for ($i = 0; $i < count($compression_algorithms) && !in_array($compression_algorithms[$i], $this->compression_algorithms_server_to_client); $i++) {
     }
     if ($i == count($compression_algorithms)) {
         user_error('No compatible server to client compression algorithms found', E_USER_NOTICE);
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     $this->decompress = $compression_algorithms[$i] == 'zlib';
     for ($i = 0; $i < count($compression_algorithms) && !in_array($compression_algorithms[$i], $this->compression_algorithms_client_to_server); $i++) {
     }
     if ($i == count($compression_algorithms)) {
         user_error('No compatible client to server compression algorithms found', E_USER_NOTICE);
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     $this->compress = $compression_algorithms[$i] == 'zlib';
     return true;
 }
Exemple #7
0
 /**
  * Key Exchange
  *
  * @param String $kexinit_payload_server
  * @access private
  */
 function _key_exchange($kexinit_payload_server)
 {
     static $kex_algorithms = array('diffie-hellman-group1-sha1', 'diffie-hellman-group14-sha1');
     static $server_host_key_algorithms = array('ssh-rsa', 'ssh-dss');
     static $encryption_algorithms = array('arcfour', 'aes128-cbc', 'aes192-cbc', 'aes256-cbc', '3des-cbc', 'none');
     static $mac_algorithms = array('hmac-sha1-96', 'hmac-sha1', 'hmac-md5-96', 'hmac-md5', 'none');
     static $compression_algorithms = array('none');
     static $str_kex_algorithms, $str_server_host_key_algorithms, $encryption_algorithms_server_to_client, $mac_algorithms_server_to_client, $compression_algorithms_server_to_client, $encryption_algorithms_client_to_server, $mac_algorithms_client_to_server, $compression_algorithms_client_to_server;
     if (empty($str_kex_algorithms)) {
         $str_kex_algorithms = implode(',', $kex_algorithms);
         $str_server_host_key_algorithms = implode(',', $server_host_key_algorithms);
         $encryption_algorithms_server_to_client = $encryption_algorithms_client_to_server = implode(',', $encryption_algorithms);
         $mac_algorithms_server_to_client = $mac_algorithms_client_to_server = implode(',', $mac_algorithms);
         $compression_algorithms_server_to_client = $compression_algorithms_client_to_server = implode(',', $compression_algorithms);
     }
     $client_cookie = '';
     for ($i = 0; $i < 16; $i++) {
         $client_cookie .= chr(crypt_random(0, 255));
     }
     $response = $kexinit_payload_server;
     $this->_string_shift($response, 1);
     // skip past the message number (it should be SSH_MSG_KEXINIT)
     list(, $server_cookie) = unpack('a16', $this->_string_shift($response, 16));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->kex_algorithms = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->server_host_key_algorithms = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->encryption_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->encryption_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->mac_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->mac_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->compression_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->compression_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->languages_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->languages_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
     list(, $first_kex_packet_follows) = unpack('C', $this->_string_shift($response, 1));
     $first_kex_packet_follows = $first_kex_packet_follows != 0;
     // the sending of SSH2_MSG_KEXINIT could go in one of two places.  this is the second place.
     $kexinit_payload_client = pack('Ca*Na*Na*Na*Na*Na*Na*Na*Na*Na*Na*CN', NET_SSH2_MSG_KEXINIT, $client_cookie, strlen($str_kex_algorithms), $str_kex_algorithms, strlen($str_server_host_key_algorithms), $str_server_host_key_algorithms, strlen($encryption_algorithms_client_to_server), $encryption_algorithms_client_to_server, strlen($encryption_algorithms_server_to_client), $encryption_algorithms_server_to_client, strlen($mac_algorithms_client_to_server), $mac_algorithms_client_to_server, strlen($mac_algorithms_server_to_client), $mac_algorithms_server_to_client, strlen($compression_algorithms_client_to_server), $compression_algorithms_client_to_server, strlen($compression_algorithms_server_to_client), $compression_algorithms_server_to_client, 0, '', 0, '', 0, 0);
     if (!$this->_send_binary_packet($kexinit_payload_client)) {
         return false;
     }
     // here ends the second place.
     // we need to decide upon the symmetric encryption algorithms before we do the diffie-hellman key exchange
     for ($i = 0; $i < count($encryption_algorithms) && !in_array($encryption_algorithms[$i], $this->encryption_algorithms_server_to_client); $i++) {
     }
     if ($i == count($encryption_algorithms)) {
         user_error('No compatible server to client encryption algorithms found', E_USER_NOTICE);
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     // we don't initialize any crypto-objects, yet - we do that, later. for now, we need the lengths to make the
     // diffie-hellman key exchange as fast as possible
     $decrypt = $encryption_algorithms[$i];
     switch ($decrypt) {
         case '3des-cbc':
             $decryptKeyLength = 24;
             // eg. 192 / 8
             break;
         case 'aes256-cbc':
             $decryptKeyLength = 32;
             // eg. 256 / 8
             break;
         case 'aes192-cbc':
             $decryptKeyLength = 24;
             // eg. 192 / 8
             break;
         case 'aes128-cbc':
             $decryptKeyLength = 16;
             // eg. 128 / 8
             break;
         case 'arcfour':
             $decryptKeyLength = 16;
             // eg. 128 / 8
             break;
         case 'none':
             $decryptKeyLength = 0;
     }
     for ($i = 0; $i < count($encryption_algorithms) && !in_array($encryption_algorithms[$i], $this->encryption_algorithms_client_to_server); $i++) {
     }
     if ($i == count($encryption_algorithms)) {
         user_error('No compatible client to server encryption algorithms found', E_USER_NOTICE);
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     $encrypt = $encryption_algorithms[$i];
     switch ($encrypt) {
         case '3des-cbc':
             $encryptKeyLength = 24;
             break;
         case 'aes256-cbc':
             $encryptKeyLength = 32;
             break;
         case 'aes192-cbc':
             $encryptKeyLength = 24;
             break;
         case 'aes128-cbc':
             $encryptKeyLength = 16;
             break;
         case 'arcfour':
             $encryptKeyLength = 16;
             break;
         case 'none':
             $encryptKeyLength = 0;
     }
     $keyLength = $decryptKeyLength > $encryptKeyLength ? $decryptKeyLength : $encryptKeyLength;
     // through diffie-hellman key exchange a symmetric key is obtained
     for ($i = 0; $i < count($kex_algorithms) && !in_array($kex_algorithms[$i], $this->kex_algorithms); $i++) {
     }
     if ($i == count($kex_algorithms)) {
         user_error('No compatible key exchange algorithms found', E_USER_NOTICE);
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     switch ($kex_algorithms[$i]) {
         // see http://tools.ietf.org/html/rfc2409#section-6.2 and
         // http://tools.ietf.org/html/rfc2412, appendex E
         case 'diffie-hellman-group1-sha1':
             $p = pack('N32', 4294967295.0, 4294967295.0, 3373259426.0, 0x2168c234, 3301335691.0, 2161908945.0, 0x29024e08, 2322058356.0, 0x20bbea6, 0x3b139b22, 0x514a0879, 0.0, 0.0, 3443147547.0, 0x302b0a6d, 4066317367.0, 0x4fe1356d, 0x6d51c245, 0.0, 0x625e7ec6, 0.0, 0.0, 0xbff5cb6, 0.0, 0.0, 0x5a899fa5, 0.0, 0x7c4b1fe6, 0x49286651, 0.0, 4294967295.0, 4294967295.0);
             $keyLength = $keyLength < 160 ? $keyLength : 160;
             $hash = 'sha1';
             break;
             // see http://tools.ietf.org/html/rfc3526#section-3
         // see http://tools.ietf.org/html/rfc3526#section-3
         case 'diffie-hellman-group14-sha1':
             $p = pack('N64', 4294967295.0, 4294967295.0, 3373259426.0, 0x2168c234, 3301335691.0, 2161908945.0, 0x29024e08, 2322058356.0, 0x20bbea6, 0x3b139b22, 0x514a0879, 0.0, 0.0, 3443147547.0, 0x302b0a6d, 4066317367.0, 0x4fe1356d, 0x6d51c245, 0.0, 0x625e7ec6, 0.0, 0.0, 0xbff5cb6, 0.0, 0.0, 0x5a899fa5, 0.0, 0x7c4b1fe6, 0x49286651, 0.0, 3254811832.0, 2707668741.0, 2564442166.0, 0x1c55d39a, 0x69163fa8, 4247048031.0, 2204458275.0, 3701714326.0, 0x1c62f356, 0x208552bb, 0.0, 0x7096966d, 0x670c354e, 0x4abc9804, 4050938888.0, 3390579068.0, 0x32905e46, 0x2e36ce3b, 0.0, 0x180e8603, 2603058082.0, 0.0, 3049610736.0, 0x6f4c52c9, 0.0, 2505578264.0, 0x3995497c, 0.0, 0x15d22618, 2566522128.0, 0x15728e5a, 2326571624.0, 4294967295.0, 4294967295.0);
             $keyLength = $keyLength < 160 ? $keyLength : 160;
             $hash = 'sha1';
     }
     $p = new Math_BigInteger($p, 256);
     //$q = $p->bitwise_rightShift(1);
     /* To increase the speed of the key exchange, both client and server may
                reduce the size of their private exponents.  It should be at least
                twice as long as the key material that is generated from the shared
                secret.  For more details, see the paper by van Oorschot and Wiener
                [VAN-OORSCHOT].
     
                -- http://tools.ietf.org/html/rfc4419#section-6.2 */
     $q = new Math_BigInteger(1);
     $q = $q->bitwise_leftShift(2 * $keyLength);
     $q = $q->subtract(new Math_BigInteger(1));
     $g = new Math_BigInteger(2);
     $x = new Math_BigInteger();
     $x = $x->random(new Math_BigInteger(1), $q, 'crypt_random');
     $e = $g->modPow($x, $p);
     $eBytes = $e->toBytes(true);
     $data = pack('CNa*', NET_SSH2_MSG_KEXDH_INIT, strlen($eBytes), $eBytes);
     if (!$this->_send_binary_packet($data)) {
         user_error('Connection closed by server', E_USER_NOTICE);
         return false;
     }
     $response = $this->_get_binary_packet();
     if ($response === false) {
         user_error('Connection closed by server', E_USER_NOTICE);
         return false;
     }
     list(, $type) = unpack('C', $this->_string_shift($response, 1));
     if ($type != NET_SSH2_MSG_KEXDH_REPLY) {
         user_error('Expected SSH_MSG_KEXDH_REPLY', E_USER_NOTICE);
         return false;
     }
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $this->server_public_host_key = $server_public_host_key = $this->_string_shift($response, $temp['length']);
     $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
     $public_key_format = $this->_string_shift($server_public_host_key, $temp['length']);
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $fBytes = $this->_string_shift($response, $temp['length']);
     $f = new Math_BigInteger($fBytes, -256);
     $temp = unpack('Nlength', $this->_string_shift($response, 4));
     $signature = $this->_string_shift($response, $temp['length']);
     $temp = unpack('Nlength', $this->_string_shift($signature, 4));
     $signature_format = $this->_string_shift($signature, $temp['length']);
     $key = $f->modPow($x, $p);
     $keyBytes = $key->toBytes(true);
     $source = pack('Na*Na*Na*Na*Na*Na*Na*Na*', strlen($this->identifier), $this->identifier, strlen($this->server_identifier), $this->server_identifier, strlen($kexinit_payload_client), $kexinit_payload_client, strlen($kexinit_payload_server), $kexinit_payload_server, strlen($this->server_public_host_key), $this->server_public_host_key, strlen($eBytes), $eBytes, strlen($fBytes), $fBytes, strlen($keyBytes), $keyBytes);
     $source = pack('H*', $hash($source));
     if ($this->session_id === false) {
         $this->session_id = $source;
     }
     // if you the server's assymetric key matches the one you have on file, then you should be able to decrypt the
     // "signature" and get something that should equal the "exchange hash", as defined in the SSH-2 specs.
     // here, we just check to see if the "signature" is good.  you can verify whether or not the assymetric key is good,
     // later, with the getServerHostKeyAlgorithm() function
     for ($i = 0; $i < count($server_host_key_algorithms) && !in_array($server_host_key_algorithms[$i], $this->server_host_key_algorithms); $i++) {
     }
     if ($i == count($server_host_key_algorithms)) {
         user_error('No compatible server host key algorithms found', E_USER_NOTICE);
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     if ($public_key_format != $server_host_key_algorithms[$i] || $signature_format != $server_host_key_algorithms[$i]) {
         user_error('Sever Host Key Algorithm Mismatch', E_USER_NOTICE);
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     switch ($server_host_key_algorithms[$i]) {
         case 'ssh-dss':
             $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
             $p = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
             $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
             $q = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
             $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
             $g = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
             $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
             $y = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
             /* The value for 'dss_signature_blob' is encoded as a string containing
                r, followed by s (which are 160-bit integers, without lengths or
                padding, unsigned, and in network byte order). */
             $temp = unpack('Nlength', $this->_string_shift($signature, 4));
             if ($temp['length'] != 40) {
                 user_error('Invalid signature', E_USER_NOTICE);
                 return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
             }
             $r = new Math_BigInteger($this->_string_shift($signature, 20), 256);
             $s = new Math_BigInteger($this->_string_shift($signature, 20), 256);
             if ($r->compare($q) >= 0 || $s->compare($q) >= 0) {
                 user_error('Invalid signature', E_USER_NOTICE);
                 return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
             }
             $w = $s->modInverse($q);
             $u1 = $w->multiply(new Math_BigInteger(sha1($source), 16));
             list(, $u1) = $u1->divide($q);
             $u2 = $w->multiply($r);
             list(, $u2) = $u2->divide($q);
             $g = $g->modPow($u1, $p);
             $y = $y->modPow($u2, $p);
             $v = $g->multiply($y);
             list(, $v) = $v->divide($p);
             list(, $v) = $v->divide($q);
             if ($v->compare($r) != 0) {
                 user_error('Invalid signature', E_USER_NOTICE);
                 return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
             }
             break;
         case 'ssh-rsa':
             $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
             $e = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
             $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
             $n = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
             $nLength = $temp['length'];
             $temp = unpack('Nlength', $this->_string_shift($signature, 4));
             $s = new Math_BigInteger($this->_string_shift($signature, $temp['length']), 256);
             // validate an RSA signature per "8.2 RSASSA-PKCS1-v1_5", "5.2.2 RSAVP1", and "9.1 EMSA-PSS" in the
             // following URL:
             // ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.pdf
             // also, see SSHRSA.c (rsa2_verifysig) in PuTTy's source.
             if ($s->compare(new Math_BigInteger()) < 0 || $s->compare($n->subtract(new Math_BigInteger(1))) > 0) {
                 user_error('Invalid signature', E_USER_NOTICE);
                 return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
             }
             $s = $s->modPow($e, $n);
             $s = $s->toBytes();
             $h = pack('N4H*', 0x302130, 0x906052b, 0xe03021a, 0x5000414, sha1($source));
             $h = chr(0x1) . str_repeat(chr(0xff), $nLength - 3 - strlen($h)) . $h;
             if ($s != $h) {
                 user_error('Bad server signature', E_USER_NOTICE);
                 return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
             }
     }
     $packet = pack('C', NET_SSH2_MSG_NEWKEYS);
     if (!$this->_send_binary_packet($packet)) {
         return false;
     }
     $response = $this->_get_binary_packet();
     if ($response === false) {
         user_error('Connection closed by server', E_USER_NOTICE);
         return false;
     }
     list(, $type) = unpack('C', $this->_string_shift($response, 1));
     if ($type != NET_SSH2_MSG_NEWKEYS) {
         user_error('Expected SSH_MSG_NEWKEYS', E_USER_NOTICE);
         return false;
     }
     switch ($encrypt) {
         case '3des-cbc':
             $this->encrypt = new Crypt_TripleDES();
             // $this->encrypt_block_size = 64 / 8 == the default
             break;
         case 'aes256-cbc':
             $this->encrypt = new Crypt_AES();
             $this->encrypt_block_size = 16;
             // eg. 128 / 8
             break;
         case 'aes192-cbc':
             $this->encrypt = new Crypt_AES();
             $this->encrypt_block_size = 16;
             break;
         case 'aes128-cbc':
             $this->encrypt = new Crypt_AES();
             $this->encrypt_block_size = 16;
             break;
         case 'arcfour':
             $this->encrypt = new Crypt_RC4();
             break;
         case 'none':
             //$this->encrypt = new Crypt_Null();
     }
     switch ($decrypt) {
         case '3des-cbc':
             $this->decrypt = new Crypt_TripleDES();
             break;
         case 'aes256-cbc':
             $this->decrypt = new Crypt_AES();
             $this->decrypt_block_size = 16;
             break;
         case 'aes192-cbc':
             $this->decrypt = new Crypt_AES();
             $this->decrypt_block_size = 16;
             break;
         case 'aes128-cbc':
             $this->decrypt = new Crypt_AES();
             $this->decrypt_block_size = 16;
             break;
         case 'arcfour':
             $this->decrypt = new Crypt_RC4();
             break;
         case 'none':
             //$this->decrypt = new Crypt_Null();
     }
     $keyBytes = pack('Na*', strlen($keyBytes), $keyBytes);
     if ($this->encrypt) {
         $this->encrypt->enableContinuousBuffer();
         $this->encrypt->disablePadding();
         $iv = pack('H*', $hash($keyBytes . $source . 'A' . $this->session_id));
         while ($this->encrypt_block_size > strlen($iv)) {
             $iv .= pack('H*', $hash($keyBytes . $source . $iv));
         }
         $this->encrypt->setIV(substr($iv, 0, $this->encrypt_block_size));
         $key = pack('H*', $hash($keyBytes . $source . 'C' . $this->session_id));
         while ($encryptKeyLength > strlen($key)) {
             $key .= pack('H*', $hash($keyBytes . $source . $key));
         }
         $this->encrypt->setKey(substr($key, 0, $encryptKeyLength));
     }
     if ($this->decrypt) {
         $this->decrypt->enableContinuousBuffer();
         $this->decrypt->disablePadding();
         $iv = pack('H*', $hash($keyBytes . $source . 'B' . $this->session_id));
         while ($this->decrypt_block_size > strlen($iv)) {
             $iv .= pack('H*', $hash($keyBytes . $source . $iv));
         }
         $this->decrypt->setIV(substr($iv, 0, $this->decrypt_block_size));
         $key = pack('H*', $hash($keyBytes . $source . 'D' . $this->session_id));
         while ($decryptKeyLength > strlen($key)) {
             $key .= pack('H*', $hash($keyBytes . $source . $key));
         }
         $this->decrypt->setKey(substr($key, 0, $decryptKeyLength));
     }
     for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_client_to_server); $i++) {
     }
     if ($i == count($mac_algorithms)) {
         user_error('No compatible client to server message authentication algorithms found', E_USER_NOTICE);
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     $createKeyLength = 0;
     // ie. $mac_algorithms[$i] == 'none'
     switch ($mac_algorithms[$i]) {
         case 'hmac-sha1':
             $this->hmac_create = new Crypt_Hash('sha1');
             $createKeyLength = 20;
             break;
         case 'hmac-sha1-96':
             $this->hmac_create = new Crypt_Hash('sha1-96');
             $createKeyLength = 20;
             break;
         case 'hmac-md5':
             $this->hmac_create = new Crypt_Hash('md5');
             $createKeyLength = 16;
             break;
         case 'hmac-md5-96':
             $this->hmac_create = new Crypt_Hash('md5-96');
             $createKeyLength = 16;
     }
     for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_server_to_client); $i++) {
     }
     if ($i == count($mac_algorithms)) {
         user_error('No compatible server to client message authentication algorithms found', E_USER_NOTICE);
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     $checkKeyLength = 0;
     $this->hmac_size = 0;
     switch ($mac_algorithms[$i]) {
         case 'hmac-sha1':
             $this->hmac_check = new Crypt_Hash('sha1');
             $checkKeyLength = 20;
             $this->hmac_size = 20;
             break;
         case 'hmac-sha1-96':
             $this->hmac_check = new Crypt_Hash('sha1-96');
             $checkKeyLength = 20;
             $this->hmac_size = 12;
             break;
         case 'hmac-md5':
             $this->hmac_check = new Crypt_Hash('md5');
             $checkKeyLength = 16;
             $this->hmac_size = 16;
             break;
         case 'hmac-md5-96':
             $this->hmac_check = new Crypt_Hash('md5-96');
             $checkKeyLength = 16;
             $this->hmac_size = 12;
     }
     $key = pack('H*', $hash($keyBytes . $source . 'E' . $this->session_id));
     while ($createKeyLength > strlen($key)) {
         $key .= pack('H*', $hash($keyBytes . $source . $key));
     }
     $this->hmac_create->setKey(substr($key, 0, $createKeyLength));
     $key = pack('H*', $hash($keyBytes . $source . 'F' . $this->session_id));
     while ($checkKeyLength > strlen($key)) {
         $key .= pack('H*', $hash($keyBytes . $source . $key));
     }
     $this->hmac_check->setKey(substr($key, 0, $checkKeyLength));
     for ($i = 0; $i < count($compression_algorithms) && !in_array($compression_algorithms[$i], $this->compression_algorithms_server_to_client); $i++) {
     }
     if ($i == count($compression_algorithms)) {
         user_error('No compatible server to client compression algorithms found', E_USER_NOTICE);
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     $this->decompress = $compression_algorithms[$i] == 'zlib';
     for ($i = 0; $i < count($compression_algorithms) && !in_array($compression_algorithms[$i], $this->compression_algorithms_client_to_server); $i++) {
     }
     if ($i == count($compression_algorithms)) {
         user_error('No compatible client to server compression algorithms found', E_USER_NOTICE);
         return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
     }
     $this->compress = $compression_algorithms[$i] == 'zlib';
     return true;
 }
Exemple #8
0
<?php

/*
On a 1.6GHz Pentium M, the following takes about 1.33 seconds with the pure-PHP implementation,
0.66 seconds with BCmath, and 0.001 seconds with GMP.
*/
include '../Math/BigInteger.php';
//define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_INTERNAL);
//define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_BCMATH);
$a = '0b078d385e9d05d9e029dc9732e75f94f59fdcfb989fe25e81edcb4f93c1dc53a9bb6ba09b5799bd' . 'aa9e35cd4e00a8200b720d9c6034da9819a5c84e3c7106fcdf5e64c975221bfd9b606bf924bc2971' . 'de66c470b88221b419ad32e0bff8fb234cbfa0f99e0909d46855a6751b7660b7178f0a661265ad23' . '8433331edb99e0ff';
$b = 'a6b9ac382a5f8d394ee83d9e6e21e993c8d240e1';
$c = 'aebbcd9a69b5116ce60400b4126c9e84173635abde4bfa56da904e75d752a51a47d3f088f13299a0' . '3b6bf66bf77a6accddeb16fc46a8a32164d7fad2ce4bb159e5caeddb40c25ae02c19e7426bd26398' . '14d36ead09509031fc423852c33ff0e6d402b2af825acc03ad6ad234eb5d269c17a026bd37c1b6e2' . '4c8c7248d09e12ef';
$a = new Math_BigInteger($a, 16);
$b = new Math_BigInteger($b, 16);
$c = new Math_BigInteger($c, 16);
$start = microtime(true);
$d = $a->modPow($b, $c);
$elapsed = microtime(true) - $start;
echo "took {$elapsed} seconds\r\n";
echo md5($d->toString());
// should equal aab326a2511ee857e16ce0cdd3243779
Exemple #9
0
 /**
  * Decrypt data.
  *
  * @param string $text  PKCS1-v1_5 encoded text.
  *
  * @return string  Plaintext.
  */
 public function decrypt($text)
 {
     $out = '';
     $p_len = strlen($this->_key->key['p']);
     $text = str_split($text, $p_len);
     $text[count($text) - 1] = str_pad($text[count($text) - 1], $p_len, chr(0), STR_PAD_LEFT);
     $p = new Math_BigInteger($this->_key->key['p'], 256);
     $x = new Math_BigInteger($this->_key->key['x'], 256);
     for ($i = 0, $j = count($text); $i < $j; $i += 2) {
         $c1 = new Math_BigInteger($text[$i], 256);
         $c2 = new Math_BigInteger($text[$i + 1], 256);
         $s = $c1->modPow($x, $p);
         $m_prime = $s->modInverse($p)->multiply($c2)->divide($p);
         $em = str_pad($m_prime[1]->toBytes(), $p_len, chr(0), STR_PAD_LEFT);
         // EME-PKCS1-v1_5 decoding
         if (ord($em[0]) !== 0 || ord($em[1]) !== 2) {
             throw new RuntimeException();
         }
         $out .= substr($em, strpos($em, chr(0), 2) + 1);
     }
     return $out;
 }
 /**
  * Calculates pow($num, $pow) (mod $mod)
  *
  * @param string $num
  * @param string $pow
  * @param string $mod
  * @return string
  * @access public
  */
 function powmod($num, $pow, $mod)
 {
     $num = new Math_BigInteger($num, 10);
     $pow = new Math_BigInteger($pow, 10);
     $mod = new Math_BigInteger($mod, 10);
     $res = $num->modPow($pow, $mod);
     return $res->toString();
     /*        if (function_exists('bcpowmod')) {
                 // bcpowmod is only available under PHP5
                 return bcpowmod($num, $pow, $mod);
             }
     
             // emulate bcpowmod
             $result = '1';
             do {
                 if (!bccomp(bcmod($pow, '2'), '1')) {
                     $result = bcmod(bcmul($result, $num), $mod);
                 }
                 $num = bcmod(bcpow($num, '2'), $mod);
                 $pow = bcdiv($pow, '2');
             } while (bccomp($pow, '0'));
             return $result;*/
 }
Exemple #11
0
 /**
  * Exponentiate with or without Chinese Remainder Theorem
  *
  * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.2}.
  *
  * @access private
  * @param Math_BigInteger $x
  * @return Math_BigInteger
  */
 function _exponentiate($x)
 {
     if (empty($this->primes) || empty($this->coefficients) || empty($this->exponents)) {
         return $x->modPow($this->exponent, $this->modulus);
     }
     $num_primes = count($this->primes);
     $m_i = array(1 => $x->modPow($this->exponents[1], $this->primes[1]), 2 => $x->modPow($this->exponents[2], $this->primes[2]));
     $h = $m_i[1]->subtract($m_i[2]);
     $h = $h->multiply($this->coefficients[2]);
     list(, $h) = $h->divide($this->primes[1]);
     $m = $m_i[2]->add($h->multiply($this->primes[2]));
     $r = $this->primes[1];
     for ($i = 3; $i <= $num_primes; $i++) {
         $m_i = $x->modPow($this->exponents[$i], $this->primes[$i]);
         $r = $r->multiply($this->primes[$i - 1]);
         $h = $m_i->subtract($m);
         $h = $h->multiply($this->coefficients[$i]);
         list(, $h) = $h->divide($this->primes[$i]);
         $m = $m->add($r->multiply($h));
     }
     return $m;
 }