public function setPublicKey($key = false, $type = false) { if ($key === false && !empty($this->modulus)) { $this->publicExponent = $this->exponent; return true; } if ($type === false) { $types = array(CRYPT_RSA_PUBLIC_FORMAT_RAW, CRYPT_RSA_PUBLIC_FORMAT_PKCS1, CRYPT_RSA_PUBLIC_FORMAT_XML, CRYPT_RSA_PUBLIC_FORMAT_OPENSSH); foreach ($types as $type) { $components = $this->_parseKey($key, $type); if ($components !== false) { break; } } } else { $components = $this->_parseKey($key, $type); } if ($components === false) { return false; } if (empty($this->modulus) || !$this->modulus->equals($components['modulus'])) { $this->modulus = $components['modulus']; $this->exponent = $this->publicExponent = $components['publicExponent']; return true; } $this->publicExponent = $components['publicExponent']; return true; }
/** * Returns the server public host key. * * Caching this the first time you connect to a server and checking the result on subsequent connections * is recommended. Returns false if the server signature is not signed correctly with the public host key. * * @return Mixed * @access public */ function getServerPublicHostKey() { if (!($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR)) { $this->bitmap |= NET_SSH2_MASK_CONSTRUCTOR; if (!$this->_connect()) { return false; } } $signature = $this->signature; $server_public_host_key = $this->server_public_host_key; extract(unpack('Nlength', $this->_string_shift($server_public_host_key, 4))); $this->_string_shift($server_public_host_key, $length); if ($this->signature_validated) { return $this->bitmap ? $this->signature_format . ' ' . base64_encode($this->server_public_host_key) : false; } $this->signature_validated = true; switch ($this->signature_format) { case 'ssh-dss': $zero = new Math_BigInteger(); $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'); 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); switch (true) { case $r->equals($zero): case $r->compare($q) >= 0: case $s->equals($zero): case $s->compare($q) >= 0: user_error('Invalid signature'); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } $w = $s->modInverse($q); $u1 = $w->multiply(new Math_BigInteger(sha1($this->exchange_hash), 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('Bad server signature'); 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')) { include_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($this->exchange_hash, $signature)) { user_error('Bad server signature'); 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'); 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($this->exchange_hash)); $h = chr(0x1) . str_repeat(chr(0xff), $nLength - 3 - strlen($h)) . $h; if ($s != $h) { user_error('Bad server signature'); return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE); } break; default: user_error('Unsupported signature format'); return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE); } return $this->signature_format . ' ' . base64_encode($this->server_public_host_key); }
/** * Defines the public key * * Some private key formats define the public exponent and some don't. Those that don't define it are problematic when * used in certain contexts. For example, in SSH-2, RSA authentication works by sending the public key along with a * message signed by the private key to the server. The SSH-2 server looks the public key up in an index of public keys * and if it's present then proceeds to verify the signature. Problem is, if your private key doesn't include the public * exponent this won't work unless you manually add the public exponent. * * Do note that when a new key is loaded the index will be cleared. * * Returns true on success, false on failure * * @see getPublicKey() * @access public * @param String $key * @param Integer $type optional * @return Boolean */ function setPublicKey($key, $type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1) { $components = $this->_parseKey($key, $type); if (empty($this->modulus) || !$this->modulus->equals($components['modulus'])) { return false; } $this->publicExponent = $components['publicExponent']; }
/** * Defines the public key * * Some private key formats define the public exponent and some don't. Those that don't define it are problematic when * used in certain contexts. For example, in SSH-2, RSA authentication works by sending the public key along with a * message signed by the private key to the server. The SSH-2 server looks the public key up in an index of public keys * and if it's present then proceeds to verify the signature. Problem is, if your private key doesn't include the public * exponent this won't work unless you manually add the public exponent. * * Do note that when a new key is loaded the index will be cleared. * * Returns true on success, false on failure * * @see getPublicKey() * @access public * @param String $key * @param Integer $type optional * @return Boolean */ function setPublicKey($key, $type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1) { $components = $this->_parseKey($key, $type); if (empty($this->modulus) || !$this->modulus->equals($components['modulus'])) { user_error('Trying to load a public key? Use loadKey() instead. It\'s called loadKey() and not loadPrivateKey() for a reason.', E_USER_NOTICE); return false; } $this->publicExponent = $components['publicExponent']; return true; }
/** * Defines the public key * * Some private key formats define the public exponent and some don't. Those that don't define it are problematic when * used in certain contexts. For example, in SSH-2, RSA authentication works by sending the public key along with a * message signed by the private key to the server. The SSH-2 server looks the public key up in an index of public keys * and if it's present then proceeds to verify the signature. Problem is, if your private key doesn't include the public * exponent this won't work unless you manually add the public exponent. * * Do note that when a new key is loaded the index will be cleared. * * Returns true on success, false on failure * * @see getPublicKey() * @access public * @param String $key optional * @param Integer $type optional * @return Boolean */ function setPublicKey($key = false, $type = false) { if ($key === false && !empty($this->modulus)) { $this->publicExponent = $this->exponent; return true; } if ($type === false) { $types = array(CRYPT_RSA_PUBLIC_FORMAT_RAW, CRYPT_RSA_PUBLIC_FORMAT_PKCS1, CRYPT_RSA_PUBLIC_FORMAT_XML, CRYPT_RSA_PUBLIC_FORMAT_OPENSSH); foreach ($types as $type) { try { $components = $this->_parseKey($key, $type); break; } catch (FormatNotSupportedException $e) { } } if (!isset($components)) { throw new FormatNotSupportedException('Unable to find matching format'); } } else { $components = $this->_parseKey($key, $type); } if (empty($this->modulus) || !$this->modulus->equals($components['modulus'])) { $this->modulus = $components['modulus']; $this->exponent = $this->publicExponent = $components['publicExponent']; return true; } $this->publicExponent = $components['publicExponent']; return true; }
/** * * @param unknown $text string * @param unknown $unblindf string: hex encoded bigInt * @param unknown $blindedHash string: hex encoded bigInt */ function verifyBlindedHash($text, $unblindf, $blindedHash) { $hashByMe = hash('sha256', $text); $hashByMeBigInt = new Math_BigInteger($hashByMe, 16); $blindedHashBigInt = new Math_BigInteger($blindedHash, 16); $signedblindedHash = $this->myPrivateKey['privRsa']->_rsasp1($blindedHashBigInt); $unblindf = new Math_BigInteger($unblindf, 16); $unblindedSignedHash = $this->myPrivateKey['privRsa']->rsaUnblind($signedblindedHash, $unblindf); $verifyHash = $this->myPrivateKey['pubRsa']->_rsasp1($unblindedSignedHash); $hashOk = $hashByMeBigInt->equals($verifyHash); if ($hashOk !== true) { WrongRequestException::throwException(1002, "Error: blinded hash verification failed", "expected hash: {$hashByMe}, got unblinded hash: {$verifyHash}, blinded Hash {$blindedHash}, unblinding factor {$unblindf}"); } return $hashOk; }