mirror of
https://github.com/phpseclib/phpseclib.git
synced 2025-02-03 20:38:29 +00:00
RSA: changes to OpenSSH and PuTTY plugins
This commit is contained in:
parent
7b1b7c22e2
commit
43165d976c
@ -62,46 +62,40 @@ class OpenSSH
|
||||
|
||||
$parts = explode(' ', $key, 3);
|
||||
|
||||
$key = isset($parts[1]) ? base64_decode($parts[1]) : false;
|
||||
$key = isset($parts[1]) ? base64_decode($parts[1]) : base64_decode($parts[0]);
|
||||
if ($key === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$comment = isset($parts[2]) ? $parts[2] : false;
|
||||
|
||||
$cleanup = substr($key, 0, 11) == "\0\0\0\7ssh-rsa";
|
||||
|
||||
if (substr($key, 0, 11) != "\0\0\0\7ssh-rsa") {
|
||||
return false;
|
||||
}
|
||||
self::_string_shift($key, 11);
|
||||
if (strlen($key) <= 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nlength', self::_string_shift($key, 4)));
|
||||
if (strlen($key) <= $length) {
|
||||
return false;
|
||||
}
|
||||
$publicExponent = new BigInteger(self::_string_shift($key, $length), -256);
|
||||
if (strlen($key) <= 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nlength', self::_string_shift($key, 4)));
|
||||
if (strlen($key) != $length) {
|
||||
return false;
|
||||
}
|
||||
$modulus = new BigInteger(self::_string_shift($key, $length), -256);
|
||||
|
||||
if ($cleanup && strlen($key)) {
|
||||
if (strlen($key) <= 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nlength', self::_string_shift($key, 4)));
|
||||
$realModulus = new BigInteger(self::_string_shift($key, $length), -256);
|
||||
return strlen($key) ? false : array(
|
||||
'isPublicKey' => true,
|
||||
'modulus' => $realModulus,
|
||||
'publicExponent' => $modulus,
|
||||
'comment' => $comment
|
||||
);
|
||||
} else {
|
||||
return strlen($key) ? false : array(
|
||||
'isPublicKey' => true,
|
||||
'modulus' => $modulus,
|
||||
'publicExponent' => $publicExponent,
|
||||
'comment' => $comment
|
||||
);
|
||||
}
|
||||
return array(
|
||||
'isPublicKey' => true,
|
||||
'modulus' => $modulus,
|
||||
'publicExponent' => $publicExponent,
|
||||
'comment' => $comment
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -32,29 +32,54 @@ abstract class PKCS
|
||||
/**#@+
|
||||
* @access private
|
||||
* @see \phpseclib\Crypt\RSA::createKey()
|
||||
*/
|
||||
*/
|
||||
/**
|
||||
* ASN1 Integer
|
||||
*/
|
||||
*/
|
||||
const ASN1_INTEGER = 2;
|
||||
/**
|
||||
* ASN1 Bit String
|
||||
*/
|
||||
*/
|
||||
const ASN1_BITSTRING = 3;
|
||||
/**
|
||||
* ASN1 Octet String
|
||||
*/
|
||||
*/
|
||||
const ASN1_OCTETSTRING = 4;
|
||||
/**
|
||||
* ASN1 Object Identifier
|
||||
*/
|
||||
*/
|
||||
const ASN1_OBJECT = 6;
|
||||
/**
|
||||
* ASN1 Sequence (with the constucted bit set)
|
||||
*/
|
||||
*/
|
||||
const ASN1_SEQUENCE = 48;
|
||||
/**#@-*/
|
||||
|
||||
/**#@+
|
||||
* @access private
|
||||
*/
|
||||
/**
|
||||
* Auto-detect the format
|
||||
*/
|
||||
const MODE_ANY = 0;
|
||||
/**
|
||||
* Require base64-encoded PEM's be supplied
|
||||
*/
|
||||
const MODE_PEM = 1;
|
||||
/**
|
||||
* Require raw DER's be supplied
|
||||
*/
|
||||
const MODE_DER = 2;
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
* Is the key a base-64 encoded PEM, DER or should it be auto-detected?
|
||||
*
|
||||
* @access private
|
||||
* @param int
|
||||
*/
|
||||
static $format = self::MODE_ANY;
|
||||
|
||||
/**
|
||||
* Returns the mode constant corresponding to the mode string
|
||||
*
|
||||
@ -166,13 +191,19 @@ abstract class PKCS
|
||||
$crypto = self::getEncryptionObject($matches[1]);
|
||||
$crypto->setKey(self::generateSymmetricKey($password, $iv, $crypto->getKeyLength() >> 3));
|
||||
$crypto->setIV($iv);
|
||||
$decoded = $crypto->decrypt($ciphertext);
|
||||
$key = $crypto->decrypt($ciphertext);
|
||||
if ($key === false) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
$decoded = self::_extractBER($key);
|
||||
}
|
||||
|
||||
if ($decoded !== false) {
|
||||
$key = $decoded;
|
||||
if (self::$format != self::MODE_DER) {
|
||||
$decoded = self::_extractBER($key);
|
||||
if ($decoded !== false) {
|
||||
$key = $decoded;
|
||||
} elseif (self::$format == self::MODE_PEM) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ord(self::_string_shift($key)) != self::ASN1_SEQUENCE) {
|
||||
@ -332,6 +363,41 @@ abstract class PKCS
|
||||
return $components;
|
||||
}
|
||||
|
||||
/**
|
||||
* Require base64-encoded PEM's be supplied
|
||||
*
|
||||
* @see self::load()
|
||||
* @access public
|
||||
*/
|
||||
static function requirePEM()
|
||||
{
|
||||
self::$format = self::MODE_PEM;
|
||||
}
|
||||
|
||||
/**
|
||||
* Require raw DER's be supplied
|
||||
*
|
||||
* @see self::load()
|
||||
* @access public
|
||||
*/
|
||||
static function requireDER()
|
||||
{
|
||||
self::$format = self::MODE_DER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept any format and auto detect the format
|
||||
*
|
||||
* This is the default setting
|
||||
*
|
||||
* @see self::load()
|
||||
* @access public
|
||||
*/
|
||||
static function requireAny()
|
||||
{
|
||||
self::$format = self::MODE_ANY;
|
||||
}
|
||||
|
||||
/**
|
||||
* DER-decode the length
|
||||
*
|
||||
|
@ -17,6 +17,7 @@ namespace phpseclib\Crypt\RSA;
|
||||
use phpseclib\Math\BigInteger;
|
||||
use phpseclib\Crypt\AES;
|
||||
use phpseclib\Crypt\Hash;
|
||||
use phpseclib\Crypt\RSA\OpenSSH;
|
||||
|
||||
/**
|
||||
* PuTTY Formatted RSA Key Handler
|
||||
@ -85,6 +86,24 @@ class PuTTY
|
||||
$one = new BigInteger(1);
|
||||
}
|
||||
|
||||
if (strpos($key, 'BEGIN SSH2 PUBLIC KEY')) {
|
||||
$data = preg_split('#[\r\n]+#', $key);
|
||||
$data = array_splice($data, 2, -1);
|
||||
$data = implode('', $data);
|
||||
|
||||
$components = OpenSSH::load($data);
|
||||
if ($components === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!preg_match('#Comment: "(.+)"#', $key, $matches)) {
|
||||
return false;
|
||||
}
|
||||
$components['comment'] = str_replace(array('\\\\', '\"'), array('\\', '"'), $matches[1]);
|
||||
|
||||
return $components;
|
||||
}
|
||||
|
||||
$components = array('isPublicKey' => false);
|
||||
$key = preg_split('#\r\n|\r|\n#', $key);
|
||||
$type = trim(preg_replace('#PuTTY-User-Key-File-2: (.+)#', '$1', $key[0]));
|
||||
@ -258,4 +277,34 @@ class PuTTY
|
||||
|
||||
return $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
$n = $n->toBytes(true);
|
||||
$e = $e->toBytes(true);
|
||||
|
||||
$key = pack(
|
||||
'Na*Na*Na*',
|
||||
strlen('ssh-rsa'),
|
||||
'ssh-rsa',
|
||||
strlen($e),
|
||||
$e,
|
||||
strlen($n),
|
||||
$n
|
||||
);
|
||||
$key = "---- BEGIN SSH2 PUBLIC KEY ----\r\n" .
|
||||
'Comment: "' . str_replace(array('\\', '"'), array('\\\\', '\"'), self::$comment) . "\"\r\n";
|
||||
chunk_split(base64_encode($key), 64) .
|
||||
'---- END SSH2 PUBLIC KEY ----';
|
||||
|
||||
return $key;
|
||||
}
|
||||
}
|
||||
|
@ -1301,7 +1301,7 @@ class SSH1
|
||||
{
|
||||
/*
|
||||
$rsa = new RSA();
|
||||
$rsa->load($key, RSA::PUBLIC_FORMAT_RAW);
|
||||
$rsa->load($key, 'raw');
|
||||
$rsa->setEncryptionMode(RSA::ENCRYPTION_PKCS1);
|
||||
return $rsa->encrypt($m);
|
||||
*/
|
||||
|
@ -4040,7 +4040,7 @@ class SSH2
|
||||
|
||||
$rsa = new RSA();
|
||||
$rsa->setSignatureMode(RSA::SIGNATURE_PKCS1);
|
||||
$rsa->load(array('e' => $e, 'n' => $n), 'Raw');
|
||||
$rsa->load(array('e' => $e, 'n' => $n), 'raw');
|
||||
if (!$rsa->verify($this->exchange_hash, $signature)) {
|
||||
//user_error('Bad server signature');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
|
||||
|
@ -441,4 +441,34 @@ Private-MAC: 35134b7434bf828b21404099861d455e660e8740';
|
||||
|
||||
$this->assertSame($privKey->decrypt($ciphertext), $plaintext);
|
||||
}
|
||||
|
||||
public function testNakedOpenSSHKey()
|
||||
{
|
||||
$key = 'AAAAB3NzaC1yc2EAAAABIwAAAIEA/NcGSQFZ0ZgN1EbDusV6LLwLnQjs05ljKcVVP7Z6aKIJUyhUDHE30uJa5XfwPPBsZ3L3Q7S0yycVcuuHjdauugmpn9xx+gyoYs7UiV5G5rvxNcA/Tc+MofGhAMiTmNicorNAs5mv6fRoVbkpIONRXPz6WK0kjx/X04EV42Vm9Qk=';
|
||||
|
||||
$rsa = new RSA();
|
||||
$rsa->load($key);
|
||||
|
||||
$this->assertSame($rsa->getLoadedFormat(), 'OpenSSH');
|
||||
|
||||
$this->assertGreaterThanOrEqual(1, strlen("$rsa"));
|
||||
}
|
||||
|
||||
public function testPuttyPublicKey()
|
||||
{
|
||||
$key = '---- BEGIN SSH2 PUBLIC KEY ----
|
||||
Comment: "rsa-key-20151023"
|
||||
AAAAB3NzaC1yc2EAAAABJQAAAIEAhC/CSqJ+8vgeQ4H7fJru29h/McqAC9zdGzw0
|
||||
9QsifLQ7s5MvXCavhjUPYIfV0KsdLQydNPLJcbKpXmpVD9azo61zLXwsYr8d1eHr
|
||||
C/EwUYl8b0fAwEsEF3myb+ryzgA9ihY08Zs9NZdmt1Maa+I7lQcLX9F/65YdcAch
|
||||
ILaEujU=
|
||||
---- END SSH2 PUBLIC KEY ----';
|
||||
|
||||
$rsa = new RSA();
|
||||
$rsa->load($key);
|
||||
|
||||
$this->assertSame($rsa->getLoadedFormat(), 'PuTTY');
|
||||
|
||||
$this->assertGreaterThanOrEqual(1, strlen("$rsa"));
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user