/** * Convert a public key to the appropriate format * * @access public * @param \phpseclib\Math\BigInteger $n * @param \phpseclib\Math\BigInteger $e * @return string */ static function savePublicKey(BigInteger $n, BigInteger $e) { $modulus = $n->toBytes(true); $publicExponent = $e->toBytes(true); // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.1>: // RSAPublicKey ::= SEQUENCE { // modulus INTEGER, -- n // publicExponent INTEGER -- e // } $components = array('modulus' => pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($modulus)), $modulus), 'publicExponent' => pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($publicExponent)), $publicExponent)); $RSAPublicKey = pack('Ca*a*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])), $components['modulus'], $components['publicExponent']); $RSAPublicKey = "-----BEGIN RSA PUBLIC KEY-----\r\n" . chunk_split(base64_encode($RSAPublicKey), 64) . '-----END RSA PUBLIC KEY-----'; return $RSAPublicKey; }
/** * Convert a private key to the appropriate format. * * @access public * @param \phpseclib\Math\BigInteger $n * @param \phpseclib\Math\BigInteger $e * @param \phpseclib\Math\BigInteger $d * @param array $primes * @param array $exponents * @param array $coefficients * @param string $password optional * @return string */ static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, $primes, $exponents, $coefficients, $password = '') { if (count($primes) != 2) { return false; } $raw = array('modulus' => $n->toBytes(true), 'publicExponent' => $e->toBytes(true), 'privateExponent' => $d->toBytes(true), 'prime1' => $primes[1]->toBytes(true), 'prime2' => $primes[2]->toBytes(true), 'exponent1' => $exponents[1]->toBytes(true), 'exponent2' => $exponents[2]->toBytes(true), 'coefficient' => $coefficients[2]->toBytes(true)); $key = "PuTTY-User-Key-File-2: ssh-rsa\r\nEncryption: "; $encryption = !empty($password) || is_string($password) ? 'aes256-cbc' : 'none'; $key .= $encryption; $key .= "\r\nComment: " . self::$comment . "\r\n"; $public = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($raw['publicExponent']), $raw['publicExponent'], strlen($raw['modulus']), $raw['modulus']); $source = pack('Na*Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($encryption), $encryption, strlen(self::$comment), self::$comment, strlen($public), $public); $public = base64_encode($public); $key .= "Public-Lines: " . (strlen($public) + 63 >> 6) . "\r\n"; $key .= chunk_split($public, 64); $private = pack('Na*Na*Na*Na*', strlen($raw['privateExponent']), $raw['privateExponent'], strlen($raw['prime1']), $raw['prime1'], strlen($raw['prime2']), $raw['prime2'], strlen($raw['coefficient']), $raw['coefficient']); if (empty($password) && !is_string($password)) { $source .= pack('Na*', strlen($private), $private); $hashkey = 'putty-private-key-file-mac-key'; } else { $private .= Random::string(16 - (strlen($private) & 15)); $source .= pack('Na*', strlen($private), $private); $crypto = new AES(); $crypto->setKey(static::generateSymmetricKey($password, 32)); $crypto->disablePadding(); $private = $crypto->encrypt($private); $hashkey = 'putty-private-key-file-mac-key' . $password; } $private = base64_encode($private); $key .= 'Private-Lines: ' . (strlen($private) + 63 >> 6) . "\r\n"; $key .= chunk_split($private, 64); $hash = new Hash('sha1'); $hash->setKey(pack('H*', sha1($hashkey))); $key .= 'Private-MAC: ' . bin2hex($hash->hash($source)) . "\r\n"; return $key; }
/** * Convert a public key to the appropriate format * * @access public * @param \phpseclib\Math\BigInteger $n * @param \phpseclib\Math\BigInteger $e * @return string */ function savePublicKey(BigInteger $n, BigInteger $e) { $publicExponent = $e->toBytes(true); $modulus = $n->toBytes(true); // from <http://tools.ietf.org/html/rfc4253#page-15>: // string "ssh-rsa" // mpint e // mpint n $RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus); $RSAPublicKey = 'ssh-rsa ' . base64_encode($RSAPublicKey) . ' ' . self::$comment; return $RSAPublicKey; }
/** * Convert a private key to the appropriate format. * * @access public * @param \phpseclib\Math\BigInteger $n * @param \phpseclib\Math\BigInteger $e * @param \phpseclib\Math\BigInteger $d * @param array $primes * @param array $exponents * @param array $coefficients * @param string $password optional * @return string */ static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, $primes, $exponents, $coefficients, $password = '') { $n = strrev($n->toBytes()); $e = str_pad(strrev($e->toBytes()), 4, ""); $key = pack('aavV', chr(self::PRIVATEKEYBLOB), chr(2), 0, self::CALG_RSA_KEYX); $key .= pack('VVa*', self::RSA2, 8 * strlen($n), $e); $key .= $n; $key .= strrev($primes[1]->toBytes()); $key .= strrev($primes[2]->toBytes()); $key .= strrev($exponents[1]->toBytes()); $key .= strrev($exponents[2]->toBytes()); $key .= strrev($coefficients[1]->toBytes()); $key .= strrev($d->toBytes()); return base64_encode($key); }
/** * Connect to an SSHv1 server * * @return bool * @throws \UnexpectedValueException on receipt of unexpected packets * @throws \RuntimeException on other errors * @access private */ function _connect() { $this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $this->connectionTimeout); if (!$this->fsock) { throw new \RuntimeException(rtrim("Cannot connect to {$host}. Error {$errno}. {$errstr}")); } $this->server_identification = $init_line = fgets($this->fsock, 255); if (defined('NET_SSH1_LOGGING')) { $this->_append_log('<-', $this->server_identification); $this->_append_log('->', $this->identifier . "\r\n"); } if (!preg_match('#SSH-([0-9\\.]+)-(.+)#', $init_line, $parts)) { throw new \RuntimeException('Can only connect to SSH servers'); } if ($parts[1][0] != 1) { throw new \RuntimeException("Cannot connect to {$parts['1']} servers"); } fputs($this->fsock, $this->identifier . "\r\n"); $response = $this->_get_binary_packet(); if ($response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_PUBLIC_KEY) { throw new \UnexpectedValueException('Expected SSH_SMSG_PUBLIC_KEY'); } $anti_spoofing_cookie = $this->_string_shift($response[self::RESPONSE_DATA], 8); $this->_string_shift($response[self::RESPONSE_DATA], 4); $temp = unpack('nlen', $this->_string_shift($response[self::RESPONSE_DATA], 2)); $server_key_public_exponent = new BigInteger($this->_string_shift($response[self::RESPONSE_DATA], ceil($temp['len'] / 8)), 256); $this->server_key_public_exponent = $server_key_public_exponent; $temp = unpack('nlen', $this->_string_shift($response[self::RESPONSE_DATA], 2)); $server_key_public_modulus = new BigInteger($this->_string_shift($response[self::RESPONSE_DATA], ceil($temp['len'] / 8)), 256); $this->server_key_public_modulus = $server_key_public_modulus; $this->_string_shift($response[self::RESPONSE_DATA], 4); $temp = unpack('nlen', $this->_string_shift($response[self::RESPONSE_DATA], 2)); $host_key_public_exponent = new BigInteger($this->_string_shift($response[self::RESPONSE_DATA], ceil($temp['len'] / 8)), 256); $this->host_key_public_exponent = $host_key_public_exponent; $temp = unpack('nlen', $this->_string_shift($response[self::RESPONSE_DATA], 2)); $host_key_public_modulus = new BigInteger($this->_string_shift($response[self::RESPONSE_DATA], ceil($temp['len'] / 8)), 256); $this->host_key_public_modulus = $host_key_public_modulus; $this->_string_shift($response[self::RESPONSE_DATA], 4); // get a list of the supported ciphers extract(unpack('Nsupported_ciphers_mask', $this->_string_shift($response[self::RESPONSE_DATA], 4))); foreach ($this->supported_ciphers as $mask => $name) { if (($supported_ciphers_mask & 1 << $mask) == 0) { unset($this->supported_ciphers[$mask]); } } // get a list of the supported authentications extract(unpack('Nsupported_authentications_mask', $this->_string_shift($response[self::RESPONSE_DATA], 4))); foreach ($this->supported_authentications as $mask => $name) { if (($supported_authentications_mask & 1 << $mask) == 0) { unset($this->supported_authentications[$mask]); } } $session_id = pack('H*', md5($host_key_public_modulus->toBytes() . $server_key_public_modulus->toBytes() . $anti_spoofing_cookie)); $session_key = Random::string(32); $double_encrypted_session_key = $session_key ^ str_pad($session_id, 32, chr(0)); if ($server_key_public_modulus->compare($host_key_public_modulus) < 0) { $double_encrypted_session_key = $this->_rsa_crypt($double_encrypted_session_key, array($server_key_public_exponent, $server_key_public_modulus)); $double_encrypted_session_key = $this->_rsa_crypt($double_encrypted_session_key, array($host_key_public_exponent, $host_key_public_modulus)); } else { $double_encrypted_session_key = $this->_rsa_crypt($double_encrypted_session_key, array($host_key_public_exponent, $host_key_public_modulus)); $double_encrypted_session_key = $this->_rsa_crypt($double_encrypted_session_key, array($server_key_public_exponent, $server_key_public_modulus)); } $cipher = isset($this->supported_ciphers[$this->cipher]) ? $this->cipher : self::CIPHER_3DES; $data = pack('C2a*na*N', NET_SSH1_CMSG_SESSION_KEY, $cipher, $anti_spoofing_cookie, 8 * strlen($double_encrypted_session_key), $double_encrypted_session_key, 0); if (!$this->_send_binary_packet($data)) { throw new \RuntimeException('Error sending SSH_CMSG_SESSION_KEY'); } switch ($cipher) { //case self::CIPHER_NONE: // $this->crypto = new \phpseclib\Crypt\Null(); // break; case self::CIPHER_DES: $this->crypto = new DES(); $this->crypto->disablePadding(); $this->crypto->enableContinuousBuffer(); $this->crypto->setKey(substr($session_key, 0, 8)); break; case self::CIPHER_3DES: $this->crypto = new TripleDES(TripleDES::MODE_3CBC); $this->crypto->disablePadding(); $this->crypto->enableContinuousBuffer(); $this->crypto->setKey(substr($session_key, 0, 24)); break; //case self::CIPHER_RC4: // $this->crypto = new RC4(); // $this->crypto->enableContinuousBuffer(); // $this->crypto->setKey(substr($session_key, 0, 16)); // break; } $response = $this->_get_binary_packet(); if ($response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) { throw new \UnexpectedValueException('Expected SSH_SMSG_SUCCESS'); } $this->bitmap = self::MASK_CONNECTED; return true; }
/** * Convert a public key to the appropriate format * * @access public * @param \phpseclib\Math\BigInteger $n * @param \phpseclib\Math\BigInteger $e * @return string */ static function savePublicKey(BigInteger $n, BigInteger $e) { return "<RSAKeyValue>\r\n" . ' <Modulus>' . base64_encode($n->toBytes()) . "</Modulus>\r\n" . ' <Exponent>' . base64_encode($e->toBytes()) . "</Exponent>\r\n" . '</RSAKeyValue>'; }