Merge branch 'rsa-pss'

This commit is contained in:
terrafrost 2019-06-01 16:07:48 -05:00
commit 5b89ff4177
31 changed files with 390 additions and 89 deletions

View File

@ -40,17 +40,14 @@ trait Fingerprint
*/ */
public function getFingerprint($algorithm = 'md5') public function getFingerprint($algorithm = 'md5')
{ {
$type = self::validatePlugin('Keys', 'OpenSSH', 'getBinaryOutput'); $type = self::validatePlugin('Keys', 'OpenSSH', 'savePublicKey');
if ($type === false) { if ($type === false) {
return false; return false;
} }
$status = $type::getBinaryOutput(); $key = $this->toString('OpenSSH', ['binary' => true]);
$type::setBinaryOutput(true);
$key = $this->toString('OpenSSH');
if ($key === false) { if ($key === false) {
return false; return false;
} }
$type::setBinaryOutput($status);
switch ($algorithm) { switch ($algorithm) {
case 'sha256': case 'sha256':
$hash = new Hash('sha256'); $hash = new Hash('sha256');

View File

@ -125,15 +125,4 @@ abstract class OpenSSH
{ {
self::$binary = $enabled; self::$binary = $enabled;
} }
/**
* Returns the current binary output value
*
* @access public
* @return bool
*/
public static function getBinaryOutput()
{
return (bool) self::$binary;
}
} }

View File

@ -179,9 +179,10 @@ abstract class PKCS1 extends PKCS
* @param string $key * @param string $key
* @param string $type * @param string $type
* @param string $password * @param string $password
* @param array $options optional
* @return string * @return string
*/ */
protected static function wrapPrivateKey($key, $type, $password) protected static function wrapPrivateKey($key, $type, $password, $options = [])
{ {
if (empty($password) || !is_string($password)) { if (empty($password) || !is_string($password)) {
return "-----BEGIN $type PRIVATE KEY-----\r\n" . return "-----BEGIN $type PRIVATE KEY-----\r\n" .
@ -189,14 +190,16 @@ abstract class PKCS1 extends PKCS
"-----END $type PRIVATE KEY-----"; "-----END $type PRIVATE KEY-----";
} }
$cipher = self::getEncryptionObject(self::$defaultEncryptionAlgorithm); $encryptionAlgorithm = isset($options['encryptionAlgorithm']) ? $options['encryptionAlgorithm'] : self::$defaultEncryptionAlgorithm;
$cipher = self::getEncryptionObject($encryptionAlgorithm);
$iv = Random::string($cipher->getBlockLength() >> 3); $iv = Random::string($cipher->getBlockLength() >> 3);
$cipher->setKey(self::generateSymmetricKey($password, $iv, $cipher->getKeyLength() >> 3)); $cipher->setKey(self::generateSymmetricKey($password, $iv, $cipher->getKeyLength() >> 3));
$cipher->setIV($iv); $cipher->setIV($iv);
$iv = strtoupper(Hex::encode($iv)); $iv = strtoupper(Hex::encode($iv));
return "-----BEGIN $type PRIVATE KEY-----\r\n" . return "-----BEGIN $type PRIVATE KEY-----\r\n" .
"Proc-Type: 4,ENCRYPTED\r\n" . "Proc-Type: 4,ENCRYPTED\r\n" .
"DEK-Info: " . self::$defaultEncryptionAlgorithm . ",$iv\r\n" . "DEK-Info: " . $encryptionAlgorithm. ",$iv\r\n" .
"\r\n" . "\r\n" .
chunk_split(Base64::encode($cipher->encrypt($key)), 64) . chunk_split(Base64::encode($cipher->encrypt($key)), 64) .
"-----END $type PRIVATE KEY-----"; "-----END $type PRIVATE KEY-----";

View File

@ -526,9 +526,10 @@ abstract class PKCS8 extends PKCS
* @param string $password * @param string $password
* @param string $oid optional * @param string $oid optional
* @param string $publicKey optional * @param string $publicKey optional
* @param array $options optional
* @return string * @return string
*/ */
protected static function wrapPrivateKey($key, $attr, $params, $password, $oid = null, $publicKey = '') protected static function wrapPrivateKey($key, $attr, $params, $password, $oid = null, $publicKey = '', $options = [])
{ {
self::initialize_static_variables(); self::initialize_static_variables();
@ -550,18 +551,22 @@ abstract class PKCS8 extends PKCS
$key = ASN1::encodeDER($key, Maps\OneAsymmetricKey::MAP); $key = ASN1::encodeDER($key, Maps\OneAsymmetricKey::MAP);
if (!empty($password) && is_string($password)) { if (!empty($password) && is_string($password)) {
$salt = Random::string(8); $salt = Random::string(8);
$iterationCount = self::$defaultIterationCount;
if (self::$defaultEncryptionAlgorithm == 'id-PBES2') { $iterationCount = isset($options['iterationCount']) ? $options['iterationCount'] : self::$defaultIterationCount;
$crypto = self::getPBES2EncryptionObject(self::$defaultEncryptionScheme); $encryptionAlgorithm = isset($options['encryptionAlgorithm']) ? $options['encryptionAlgorithm'] : self::$defaultEncryptionAlgorithm;
$hash = str_replace('-', '/', substr(self::$defaultPRF, 11)); $encryptionScheme = isset($options['encryptionScheme']) ? $options['encryptionScheme'] : self::$defaultEncryptionScheme;
$prf = isset($options['PRF']) ? $options['PRF'] : self::$defaultPRF;
if ($encryptionAlgorithm == 'id-PBES2') {
$crypto = self::getPBES2EncryptionObject($encryptionScheme);
$hash = str_replace('-', '/', substr($prf, 11));
$kdf = 'pbkdf2'; $kdf = 'pbkdf2';
$iv = Random::string($crypto->getBlockLength() >> 3); $iv = Random::string($crypto->getBlockLength() >> 3);
$PBKDF2params = [ $PBKDF2params = [
'salt' => $salt, 'salt' => $salt,
'iterationCount' => $iterationCount, 'iterationCount' => $iterationCount,
'prf' => ['algorithm' => self::$defaultPRF, 'parameters' => null] 'prf' => ['algorithm' => $prf, 'parameters' => null]
]; ];
$PBKDF2params = ASN1::encodeDER($PBKDF2params, Maps\PBKDF2params::MAP); $PBKDF2params = ASN1::encodeDER($PBKDF2params, Maps\PBKDF2params::MAP);
@ -582,7 +587,7 @@ abstract class PKCS8 extends PKCS
'parameters' => new ASN1\Element($PBKDF2params) 'parameters' => new ASN1\Element($PBKDF2params)
], ],
'encryptionScheme' => [ 'encryptionScheme' => [
'algorithm' => self::$defaultEncryptionScheme, 'algorithm' => $encryptionScheme,
'parameters' => $params 'parameters' => $params
] ]
]; ];
@ -590,9 +595,9 @@ abstract class PKCS8 extends PKCS
$crypto->setIV($iv); $crypto->setIV($iv);
} else { } else {
$crypto = self::getPBES1EncryptionObject(self::$defaultEncryptionAlgorithm); $crypto = self::getPBES1EncryptionObject($encryptionAlgorithm);
$hash = self::getPBES1Hash(self::$defaultEncryptionAlgorithm); $hash = self::getPBES1Hash($encryptionAlgorithm);
$kdf = self::getPBES1KDF(self::$defaultEncryptionAlgorithm); $kdf = self::getPBES1KDF($encryptionAlgorithm);
$params = [ $params = [
'salt' => $salt, 'salt' => $salt,
@ -605,7 +610,7 @@ abstract class PKCS8 extends PKCS
$key = [ $key = [
'encryptionAlgorithm' => [ 'encryptionAlgorithm' => [
'algorithm' => self::$defaultEncryptionAlgorithm, 'algorithm' => $encryptionAlgorithm,
'parameters' => new ASN1\Element($params) 'parameters' => new ASN1\Element($params)
], ],
'encryptedData' => $key 'encryptedData' => $key

View File

@ -172,9 +172,10 @@ abstract class PuTTY
* @param string $private * @param string $private
* @param string $type * @param string $type
* @param string $password * @param string $password
* @param array $options optional
* @return string * @return string
*/ */
protected static function wrapPrivateKey($public, $private, $type, $password) protected static function wrapPrivateKey($public, $private, $type, $password, $options = [])
{ {
$key = "PuTTY-User-Key-File-2: " . $type . "\r\nEncryption: "; $key = "PuTTY-User-Key-File-2: " . $type . "\r\nEncryption: ";
$encryption = (!empty($password) || is_string($password)) ? 'aes256-cbc' : 'none'; $encryption = (!empty($password) || is_string($password)) ? 'aes256-cbc' : 'none';
@ -183,7 +184,8 @@ abstract class PuTTY
$public = Strings::packSSH2('s', $type) . $public; $public = Strings::packSSH2('s', $type) . $public;
$source = Strings::packSSH2('ssss', $type, $encryption, self::$comment, $public); $comment = isset($options['comment']) ? $options['comment'] : self::$comment;
$source = Strings::packSSH2('ssss', $type, $encryption, $comment, $public);
$public = Base64::encode($public); $public = Base64::encode($public);
$key.= "Public-Lines: " . ((strlen($public) + 63) >> 6) . "\r\n"; $key.= "Public-Lines: " . ((strlen($public) + 63) >> 6) . "\r\n";

View File

@ -62,9 +62,10 @@ abstract class OpenSSH extends Progenitor
* @param \phpseclib\Math\BigInteger $q * @param \phpseclib\Math\BigInteger $q
* @param \phpseclib\Math\BigInteger $g * @param \phpseclib\Math\BigInteger $g
* @param \phpseclib\Math\BigInteger $y * @param \phpseclib\Math\BigInteger $y
* @param array $options optional
* @return string * @return string
*/ */
public static function savePublicKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y) public static function savePublicKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, $options = [])
{ {
if ($q->getLength() != 160) { if ($q->getLength() != 160) {
throw new \InvalidArgumentException('SSH only supports keys with an N (length of Group Order q) of 160'); throw new \InvalidArgumentException('SSH only supports keys with an N (length of Group Order q) of 160');
@ -78,11 +79,12 @@ abstract class OpenSSH extends Progenitor
// mpint y // mpint y
$DSAPublicKey = Strings::packSSH2('siiii', 'ssh-dss', $p, $q, $g, $y); $DSAPublicKey = Strings::packSSH2('siiii', 'ssh-dss', $p, $q, $g, $y);
if (self::$binary) { if (isset($options['binary']) ? $options['binary'] : self::$binary) {
return $DSAPublicKey; return $DSAPublicKey;
} }
$DSAPublicKey = 'ssh-dss ' . Base64::encode($DSAPublicKey) . ' ' . self::$comment; $comment = isset($options['comment']) ? $options['comment'] : self::$comment;
$DSAPublicKey = 'ssh-dss ' . Base64::encode($DSAPublicKey) . ' ' . $comment;
return $DSAPublicKey; return $DSAPublicKey;
} }

View File

@ -113,9 +113,10 @@ abstract class PKCS1 extends Progenitor
* @param \phpseclib\Math\BigInteger $x * @param \phpseclib\Math\BigInteger $x
* @param \phpseclib\Math\BigInteger $y * @param \phpseclib\Math\BigInteger $y
* @param string $password optional * @param string $password optional
* @param array $options optional
* @return string * @return string
*/ */
public static function savePrivateKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, BigInteger $x, $password = '') public static function savePrivateKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, BigInteger $x, $password = '', $options = [])
{ {
$key = [ $key = [
'version' => 0, 'version' => 0,
@ -128,7 +129,7 @@ abstract class PKCS1 extends Progenitor
$key = ASN1::encodeDER($key, Maps\DSAPrivateKey::MAP); $key = ASN1::encodeDER($key, Maps\DSAPrivateKey::MAP);
return self::wrapPrivateKey($key, 'DSA', $password); return self::wrapPrivateKey($key, 'DSA', $password, $options);
} }
/** /**

View File

@ -127,9 +127,10 @@ abstract class PKCS8 extends Progenitor
* @param \phpseclib\Math\BigInteger $x * @param \phpseclib\Math\BigInteger $x
* @param \phpseclib\Math\BigInteger $y * @param \phpseclib\Math\BigInteger $y
* @param string $password optional * @param string $password optional
* @param array $options optional
* @return string * @return string
*/ */
public static function savePrivateKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, BigInteger $x, $password = '') public static function savePrivateKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, BigInteger $x, $password = '', $options = [])
{ {
$params = [ $params = [
'p' => $p, 'p' => $p,
@ -139,7 +140,7 @@ abstract class PKCS8 extends Progenitor
$params = ASN1::encodeDER($params, Maps\DSAParams::MAP); $params = ASN1::encodeDER($params, Maps\DSAParams::MAP);
$params = new ASN1\Element($params); $params = new ASN1\Element($params);
$key = ASN1::encodeDER($x, Maps\DSAPublicKey::MAP); $key = ASN1::encodeDER($x, Maps\DSAPublicKey::MAP);
return self::wrapPrivateKey($key, [], $params, $password); return self::wrapPrivateKey($key, [], $params, $password, $options);
} }
/** /**
@ -150,9 +151,10 @@ abstract class PKCS8 extends Progenitor
* @param \phpseclib\Math\BigInteger $q * @param \phpseclib\Math\BigInteger $q
* @param \phpseclib\Math\BigInteger $g * @param \phpseclib\Math\BigInteger $g
* @param \phpseclib\Math\BigInteger $y * @param \phpseclib\Math\BigInteger $y
* @param array $options optional
* @return string * @return string
*/ */
public static function savePublicKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y) public static function savePublicKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, $options = [])
{ {
$params = [ $params = [
'p' => $p, 'p' => $p,

View File

@ -91,9 +91,10 @@ abstract class PuTTY extends Progenitor
* @param \phpseclib\Math\BigInteger $y * @param \phpseclib\Math\BigInteger $y
* @param \phpseclib\Math\BigInteger $x * @param \phpseclib\Math\BigInteger $x
* @param string $password optional * @param string $password optional
* @param array $options optional
* @return string * @return string
*/ */
public static function savePrivateKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, BigInteger $x, $password = false) public static function savePrivateKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, BigInteger $x, $password = false, $options = [])
{ {
if ($q->getLength() != 160) { if ($q->getLength() != 160) {
throw new \InvalidArgumentException('SSH only supports keys with an N (length of Group Order q) of 160'); throw new \InvalidArgumentException('SSH only supports keys with an N (length of Group Order q) of 160');
@ -102,7 +103,7 @@ abstract class PuTTY extends Progenitor
$public = Strings::packSSH2('iiii', $p, $q, $g, $y); $public = Strings::packSSH2('iiii', $p, $q, $g, $y);
$private = Strings::packSSH2('i', $x); $private = Strings::packSSH2('i', $x);
return self::wrapPrivateKey($public, $private, 'ssh-dsa', $password); return self::wrapPrivateKey($public, $private, 'ssh-dsa', $password, $options);
} }
/** /**

View File

@ -25,15 +25,16 @@ use phpseclib\Crypt\DSA;
class Parameters extends DSA class Parameters extends DSA
{ {
/** /**
* Returns the public key * Returns the parameters
* *
* @param string $type * @param string $type
* @param array $options optional
* @return string * @return string
*/ */
public function toString($type = 'PKCS1') public function toString($type = 'PKCS1', $options = [])
{ {
$type = self::validatePlugin('Keys', 'PKCS1', 'saveParameters'); $type = self::validatePlugin('Keys', 'PKCS1', 'saveParameters');
return $type::saveParameters($this->p, $this->q, $this->g); return $type::saveParameters($this->p, $this->q, $this->g, $options);
} }
} }

View File

@ -144,9 +144,10 @@ class PrivateKey extends DSA implements Common\PrivateKey
* Returns the private key * Returns the private key
* *
* @param string $type * @param string $type
* @param array $options optional
* @return string * @return string
*/ */
public function toString($type) public function toString($type, $options = [])
{ {
$type = self::validatePlugin('Keys', $type, 'savePrivateKey'); $type = self::validatePlugin('Keys', $type, 'savePrivateKey');
@ -154,6 +155,6 @@ class PrivateKey extends DSA implements Common\PrivateKey
$this->y = $this->g->powMod($this->x, $this->p); $this->y = $this->g->powMod($this->x, $this->p);
} }
return $type::savePrivateKey($this->p, $this->q, $this->g, $this->y, $this->x, $this->password); return $type::savePrivateKey($this->p, $this->q, $this->g, $this->y, $this->x, $this->password, $options);
} }
} }

View File

@ -80,12 +80,13 @@ class PublicKey extends DSA implements Common\PublicKey
* Returns the public key * Returns the public key
* *
* @param string $type * @param string $type
* @param array $options optional
* @return string * @return string
*/ */
public function toString($type) public function toString($type, $options = [])
{ {
$type = self::validatePlugin('Keys', $type, 'savePublicKey'); $type = self::validatePlugin('Keys', $type, 'savePublicKey');
return $type::savePublicKey($this->p, $this->q, $this->g, $this->y); return $type::savePublicKey($this->p, $this->q, $this->g, $this->y, $options);
} }
} }

View File

@ -186,10 +186,13 @@ abstract class OpenSSH extends Progenitor
* @access public * @access public
* @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve * @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve
* @param \phpseclib\Math\Common\FiniteField\Integer[] $publicKey * @param \phpseclib\Math\Common\FiniteField\Integer[] $publicKey
* @param array $options optional
* @return string * @return string
*/ */
public static function savePublicKey(BaseCurve $curve, array $publicKey) public static function savePublicKey(BaseCurve $curve, array $publicKey, $options = [])
{ {
$comment = isset($options['comment']) ? $options['comment'] : self::$comment;
if ($curve instanceof Ed25519) { if ($curve instanceof Ed25519) {
$key = Strings::packSSH2('ss', 'ssh-ed25519', $curve->encodePoint($publicKey)); $key = Strings::packSSH2('ss', 'ssh-ed25519', $curve->encodePoint($publicKey));
@ -197,7 +200,7 @@ abstract class OpenSSH extends Progenitor
return $key; return $key;
} }
$key = 'ssh-ed25519 ' . Base64::encode($key) . ' ' . self::$comment; $key = 'ssh-ed25519 ' . Base64::encode($key) . ' ' . $comment;
return $key; return $key;
} }
@ -226,11 +229,11 @@ abstract class OpenSSH extends Progenitor
$points = "\4" . $publicKey[0]->toBytes() . $publicKey[1]->toBytes(); $points = "\4" . $publicKey[0]->toBytes() . $publicKey[1]->toBytes();
$key = Strings::packSSH2('sss', 'ecdsa-sha2-' . $alias, $alias, $points); $key = Strings::packSSH2('sss', 'ecdsa-sha2-' . $alias, $alias, $points);
if (self::$binary) { if (isset($options['binary']) ? $options['binary'] : self::$binary) {
return $key; return $key;
} }
$key = 'ecdsa-sha2-' . $alias . ' ' . Base64::encode($key) . ' ' . self::$comment; $key = 'ecdsa-sha2-' . $alias . ' ' . Base64::encode($key) . ' ' . $comment;
return $key; return $key;
} }

View File

@ -115,9 +115,10 @@ abstract class PKCS1 extends Progenitor
* @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve * @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve
* @param \phpseclib\Math\Common\FiniteField\Integer[] $publicKey * @param \phpseclib\Math\Common\FiniteField\Integer[] $publicKey
* @param string $password optional * @param string $password optional
* @param array $options optional
* @return string * @return string
*/ */
public static function savePrivateKey(Integer $privateKey, BaseCurve $curve, array $publicKey, $password = '') public static function savePrivateKey(Integer $privateKey, BaseCurve $curve, array $publicKey, $password = '', $options = [])
{ {
self::initialize_static_variables(); self::initialize_static_variables();
@ -136,6 +137,6 @@ abstract class PKCS1 extends Progenitor
$key = ASN1::encodeDER($key, Maps\ECPrivateKey::MAP); $key = ASN1::encodeDER($key, Maps\ECPrivateKey::MAP);
return self::wrapPrivateKey($key, 'EC', $password); return self::wrapPrivateKey($key, 'EC', $password, $options);
} }
} }

View File

@ -198,9 +198,10 @@ abstract class PKCS8 extends Progenitor
* @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve * @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve
* @param \phpseclib\Math\Common\FiniteField\Integer[] $publicKey * @param \phpseclib\Math\Common\FiniteField\Integer[] $publicKey
* @param string $password optional * @param string $password optional
* @param array $options optional
* @return string * @return string
*/ */
public static function savePrivateKey(Integer $privateKey, BaseCurve $curve, array $publicKey, $password = '') public static function savePrivateKey(Integer $privateKey, BaseCurve $curve, array $publicKey, $password = '', $options = [])
{ {
self::initialize_static_variables(); self::initialize_static_variables();
@ -228,6 +229,6 @@ abstract class PKCS8 extends Progenitor
$key = ASN1::encodeDER($key, Maps\ECPrivateKey::MAP); $key = ASN1::encodeDER($key, Maps\ECPrivateKey::MAP);
return self::wrapPrivateKey($key, [], $params, $password, 'id-ecPublicKey'); return self::wrapPrivateKey($key, [], $params, $password, 'id-ecPublicKey', $options);
} }
} }

View File

@ -96,9 +96,10 @@ abstract class PuTTY extends Progenitor
* @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve * @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve
* @param \phpseclib\Math\Common\FiniteField\Integer[] $publicKey * @param \phpseclib\Math\Common\FiniteField\Integer[] $publicKey
* @param string $password optional * @param string $password optional
* @param array $options optional
* @return string * @return string
*/ */
public static function savePrivateKey(Integer $privateKey, BaseCurve $curve, array $publicKey, $password = false) public static function savePrivateKey(Integer $privateKey, BaseCurve $curve, array $publicKey, $password = false, $options = [])
{ {
self::initialize_static_variables(); self::initialize_static_variables();
@ -121,7 +122,7 @@ abstract class PuTTY extends Progenitor
Strings::packSSH2('s', $privateKey->secret) : Strings::packSSH2('s', $privateKey->secret) :
Strings::packSSH2('s', $private); Strings::packSSH2('s', $private);
return self::wrapPrivateKey($public, $private, $name, $password); return self::wrapPrivateKey($public, $private, $name, $password, $options);
} }
/** /**

View File

@ -25,15 +25,16 @@ use phpseclib\Crypt\ECDSA;
class Parameters extends ECDSA class Parameters extends ECDSA
{ {
/** /**
* Returns the public key * Returns the parameters
* *
* @param string $type * @param string $type
* @param array $options optional
* @return string * @return string
*/ */
public function toString($type = 'PKCS1') public function toString($type = 'PKCS1', $options = [])
{ {
$type = self::validatePlugin('Keys', 'PKCS1', 'saveParameters'); $type = self::validatePlugin('Keys', 'PKCS1', 'saveParameters');
return $type::saveParameters($this->curve); return $type::saveParameters($this->curve, $options);
} }
} }

View File

@ -182,13 +182,14 @@ class PrivateKey extends ECDSA implements Common\PrivateKey
* Returns the private key * Returns the private key
* *
* @param string $type * @param string $type
* @param array $options optional
* @return string * @return string
*/ */
public function toString($type) public function toString($type, $options = [])
{ {
$type = self::validatePlugin('Keys', $type, 'savePrivateKey'); $type = self::validatePlugin('Keys', $type, 'savePrivateKey');
return $type::savePrivateKey($this->dA, $this->curve, $this->QA, $this->password); return $type::savePrivateKey($this->dA, $this->curve, $this->QA, $this->password, $options);
} }
/** /**

View File

@ -159,12 +159,13 @@ class PublicKey extends ECDSA implements Common\PublicKey
* Returns the public key * Returns the public key
* *
* @param string $type * @param string $type
* @param array $options optional
* @return string * @return string
*/ */
public function toString($type) public function toString($type, $options = [])
{ {
$type = self::validatePlugin('Keys', $type, 'savePublicKey'); $type = self::validatePlugin('Keys', $type, 'savePublicKey');
return $type::savePublicKey($this->curve, $this->QA); return $type::savePublicKey($this->curve, $this->QA, $options);
} }
} }

View File

@ -63,17 +63,19 @@ abstract class OpenSSH extends Progenitor
* @access public * @access public
* @param \phpseclib\Math\BigInteger $n * @param \phpseclib\Math\BigInteger $n
* @param \phpseclib\Math\BigInteger $e * @param \phpseclib\Math\BigInteger $e
* @param array $options optional
* @return string * @return string
*/ */
public static function savePublicKey(BigInteger $n, BigInteger $e) public static function savePublicKey(BigInteger $n, BigInteger $e, $options = [])
{ {
$RSAPublicKey = Strings::packSSH2('sii', 'ssh-rsa', $e, $n); $RSAPublicKey = Strings::packSSH2('sii', 'ssh-rsa', $e, $n);
if (self::$binary) { if (isset($options['binary']) ? $options['binary'] : self::$binary) {
return $RSAPublicKey; return $RSAPublicKey;
} }
$RSAPublicKey = 'ssh-rsa ' . Base64::encode($RSAPublicKey) . ' ' . self::$comment; $comment = isset($options['comment']) ? $options['comment'] : self::$comment;
$RSAPublicKey = 'ssh-rsa ' . Base64::encode($RSAPublicKey) . ' ' . $comment;
return $RSAPublicKey; return $RSAPublicKey;
} }

View File

@ -101,9 +101,10 @@ abstract class PKCS1 extends Progenitor
* @param array $exponents * @param array $exponents
* @param array $coefficients * @param array $coefficients
* @param string $password optional * @param string $password optional
* @param array $options optional
* @return string * @return string
*/ */
public static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, $primes, $exponents, $coefficients, $password = '') public static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, $primes, $exponents, $coefficients, $password = '', $options = [])
{ {
$num_primes = count($primes); $num_primes = count($primes);
$key = [ $key = [
@ -127,7 +128,7 @@ abstract class PKCS1 extends Progenitor
$key = ASN1::encodeDER($key, Maps\RSAPrivateKey::MAP); $key = ASN1::encodeDER($key, Maps\RSAPrivateKey::MAP);
return self::wrapPrivateKey($key, 'RSA', $password); return self::wrapPrivateKey($key, 'RSA', $password, $options);
} }
/** /**

View File

@ -32,7 +32,7 @@ use phpseclib\Crypt\Common\Keys\PKCS8 as Progenitor;
use phpseclib\File\ASN1; use phpseclib\File\ASN1;
/** /**
* PKCS#1 Formatted RSA Key Handler * PKCS#8 Formatted RSA Key Handler
* *
* @package RSA * @package RSA
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
@ -104,13 +104,14 @@ abstract class PKCS8 extends Progenitor
* @param array $exponents * @param array $exponents
* @param array $coefficients * @param array $coefficients
* @param string $password optional * @param string $password optional
* @param array $options optional
* @return string * @return string
*/ */
public static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, $primes, $exponents, $coefficients, $password = '') public static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, $primes, $exponents, $coefficients, $password = '', $options = [])
{ {
$key = PKCS1::savePrivateKey($n, $e, $d, $primes, $exponents, $coefficients); $key = PKCS1::savePrivateKey($n, $e, $d, $primes, $exponents, $coefficients);
$key = ASN1::extractBER($key); $key = ASN1::extractBER($key);
return self::wrapPrivateKey($key, [], null, $password); return self::wrapPrivateKey($key, [], null, $password, $options);
} }
/** /**
@ -119,9 +120,10 @@ abstract class PKCS8 extends Progenitor
* @access public * @access public
* @param \phpseclib\Math\BigInteger $n * @param \phpseclib\Math\BigInteger $n
* @param \phpseclib\Math\BigInteger $e * @param \phpseclib\Math\BigInteger $e
* @param array $options optional
* @return string * @return string
*/ */
public static function savePublicKey(BigInteger $n, BigInteger $e) public static function savePublicKey(BigInteger $n, BigInteger $e, $options = [])
{ {
$key = PKCS1::savePublicKey($n, $e); $key = PKCS1::savePublicKey($n, $e);
$key = ASN1::extractBER($key); $key = ASN1::extractBER($key);

View File

@ -0,0 +1,149 @@
<?php
/**
* PKCS#8 Formatted RSA-PSS Key Handler
*
* PHP version 5
*
* Used by PHP's openssl_public_encrypt() and openssl's rsautl (when -pubin is set)
*
* Processes keys with the following headers:
*
* -----BEGIN PUBLIC KEY-----
*
* Analogous to ssh-keygen's pkcs8 format (as specified by -m). Although PKCS8
* is specific to private keys it's basically creating a DER-encoded wrapper
* for keys. This just extends that same concept to public keys (much like ssh-keygen)
*
* @category Crypt
* @package RSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace phpseclib\Crypt\RSA\Keys;
use phpseclib\Math\BigInteger;
use phpseclib\Crypt\Common\Keys\PKCS8 as Progenitor;
use phpseclib\File\ASN1;
/**
* PKCS#8 Formatted RSA-PSS Key Handler
*
* @package RSA
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
abstract class PSS extends Progenitor
{
/**
* OID Name
*
* @var string
* @access private
*/
const OID_NAME = 'id-RSASSA-PSS';
/**
* OID Value
*
* @var string
* @access private
*/
const OID_VALUE = '1.2.840.113549.1.1.10';
/**
* OIDs loaded
*
* @var bool
* @access private
*/
private static $oidsLoaded = false;
/**
* Child OIDs loaded
*
* @var bool
* @access private
*/
protected static $childOIDsLoaded = false;
/**
* Initialize static variables
*/
private static function initialize_static_variables()
{
if (!self::$oidsLoaded) {
ASN1::loadOIDs([
'md2' => '1.2.840.113549.2.2',
'md4' => '1.2.840.113549.2.4',
'md5' => '1.2.840.113549.2.5',
'id-sha1' => '1.3.14.3.2.26',
'id-sha256' => '2.16.840.1.101.3.4.2.1',
'id-sha384' => '2.16.840.1.101.3.4.2.2',
'id-sha512' => '2.16.840.1.101.3.4.2.3',
'id-sha224' => '2.16.840.1.101.3.4.2.4',
'id-sha512/224' => '2.16.840.1.101.3.4.2.5',
'id-sha512/256' => '2.16.840.1.101.3.4.2.6',
'id-mgf1' => '1.2.840.113549.1.1.8'
]);
self::$oidsLoaded = true;
}
}
/**
* Break a public or private key down into its constituent components
*
* @access public
* @param string $key
* @param string $password optional
* @return array
*/
public static function load($key, $password = '')
{
self::initialize_static_variables();
if (!is_string($key)) {
throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key));
}
$components = ['isPublicKey' => strpos($key, 'PUBLIC') !== false];
$key = parent::load($key, $password);
$type = isset($key['privateKey']) ? 'private' : 'public';
$result = $components + PKCS1::load($key[$type . 'Key']);
$decoded = ASN1::decodeBER($key[$type . 'KeyAlgorithm']['parameters']);
if ($decoded === false) {
throw new \UnexpectedValueException('Unable to decode parameters');
}
$params = ASN1::asn1map($decoded[0], ASN1\Maps\RSASSA_PSS_params::MAP);
if (isset($params['maskGenAlgorithm']['parameters'])) {
$decoded = ASN1::decodeBER($params['maskGenAlgorithm']['parameters']);
if ($decoded === false) {
throw new \UnexpectedValueException('Unable to decode parameters');
}
$params['maskGenAlgorithm']['parameters'] = ASN1::asn1map($decoded[0], ASN1\Maps\HashAlgorithm::MAP);
} else {
$params['maskGenAlgorithm'] = [
'algorithm' => 'id-mgf1',
'parameters' => ['algorithm' => 'id-sha1']
];
}
$result['hash'] = str_replace('id-', '', $params['hashAlgorithm']['algorithm']);
$result['MGFHash'] = str_replace('id-', '', $params['maskGenAlgorithm']['parameters']['algorithm']);
$result['saltLength'] = (int) $params['saltLength']->toString();
if (isset($key['meta'])) {
$result['meta'] = $key['meta'];
}
return $result;
}
}

View File

@ -100,9 +100,10 @@ abstract class PuTTY extends Progenitor
* @param array $exponents * @param array $exponents
* @param array $coefficients * @param array $coefficients
* @param string $password optional * @param string $password optional
* @param array $options optional
* @return string * @return string
*/ */
public static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, $primes, $exponents, $coefficients, $password = '') public static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, $primes, $exponents, $coefficients, $password = '', $options = [])
{ {
if (count($primes) != 2) { if (count($primes) != 2) {
throw new \InvalidArgumentException('PuTTY does not support multi-prime RSA keys'); throw new \InvalidArgumentException('PuTTY does not support multi-prime RSA keys');
@ -111,7 +112,7 @@ abstract class PuTTY extends Progenitor
$public = Strings::packSSH2('ii', $e, $n); $public = Strings::packSSH2('ii', $e, $n);
$private = Strings::packSSH2('iiii', $d, $primes[1], $primes[2], $coefficients[2]); $private = Strings::packSSH2('iiii', $d, $primes[1], $primes[2], $coefficients[2]);
return self::wrapPrivateKey($public, $private, 'ssh-rsa', $password); return self::wrapPrivateKey($public, $private, 'ssh-rsa', $password, $options);
} }
/** /**

View File

@ -514,9 +514,10 @@ class PrivateKey extends RSA implements Common\PrivateKey
* Returns the private key * Returns the private key
* *
* @param string $type * @param string $type
* @param array $options optional
* @return string * @return string
*/ */
public function toString($type) public function toString($type, $options = [])
{ {
$type = self::validatePlugin( $type = self::validatePlugin(
'Keys', 'Keys',
@ -528,10 +529,10 @@ class PrivateKey extends RSA implements Common\PrivateKey
return $type::savePublicKey($this->modulus, $this->exponent); return $type::savePublicKey($this->modulus, $this->exponent);
} }
return $type::savePrivateKey($this->modulus, $this->publicExponent, $this->exponent, $this->primes, $this->exponents, $this->coefficients, $this->password); return $type::savePrivateKey($this->modulus, $this->publicExponent, $this->exponent, $this->primes, $this->exponents, $this->coefficients, $this->password, $options);
/* /*
$key = $type::savePrivateKey($this->modulus, $this->publicExponent, $this->exponent, $this->primes, $this->exponents, $this->coefficients, $this->password); $key = $type::savePrivateKey($this->modulus, $this->publicExponent, $this->exponent, $this->primes, $this->exponents, $this->coefficients, $this->password, $options);
if ($key !== false || count($this->primes) == 2) { if ($key !== false || count($this->primes) == 2) {
return $key; return $key;
} }
@ -555,7 +556,7 @@ class PrivateKey extends RSA implements Common\PrivateKey
$exponents[$i] = $this->modulus->modInverse($temp); $exponents[$i] = $this->modulus->modInverse($temp);
} }
return $type::savePrivateKey($this->modulus, $this->publicExponent, $this->exponent, $primes, $exponents, $coefficients, $this->password); return $type::savePrivateKey($this->modulus, $this->publicExponent, $this->exponent, $primes, $exponents, $coefficients, $this->password, $options);
*/ */
} }
} }

View File

@ -465,13 +465,14 @@ class PublicKey extends RSA implements Common\PublicKey
* function won't return it since this library, for the most part, doesn't distinguish between public and private keys. * function won't return it since this library, for the most part, doesn't distinguish between public and private keys.
* *
* @param string $type * @param string $type
* @param array $options optional
* @return mixed * @return mixed
*/ */
public function toString($type) public function toString($type, $options = [])
{ {
$type = self::validatePlugin('Keys', $type, 'savePublicKey'); $type = self::validatePlugin('Keys', $type, 'savePublicKey');
return $type::savePublicKey($this->modulus, $this->publicExponent); return $type::savePublicKey($this->modulus, $this->publicExponent, $options);
} }
/** /**

View File

@ -642,9 +642,13 @@ abstract class ASN1
case ASN1::TYPE_INTEGER: case ASN1::TYPE_INTEGER:
$map[$key] = new BigInteger($child['default']); $map[$key] = new BigInteger($child['default']);
break; break;
//case self::TYPE_OBJECT_IDENTIFIER:
// if (!isset(self::$reverseOIDs[$name])) {
// return null;
// }
//case ASN1::TYPE_BOOLEAN: //case ASN1::TYPE_BOOLEAN:
default: default:
$map[$key] = $child['type']; $map[$key] = $child['default'];
} }
} elseif (!isset($child['optional'])) { } elseif (!isset($child['optional'])) {
return null; // Syntax error. return null; // Syntax error.
@ -1491,7 +1495,7 @@ abstract class ASN1
* @param string $name * @param string $name
* @return string * @return string
*/ */
static function getOID($name) public static function getOID($name)
{ {
return isset(self::$reverseOIDs[$name]) ? self::$reverseOIDs[$name] : $name; return isset(self::$reverseOIDs[$name]) ? self::$reverseOIDs[$name] : $name;
} }

View File

@ -0,0 +1,30 @@
<?php
/**
* MaskGenAglorithm
*
* PHP version 5
*
* @category File
* @package ASN1
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2016 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace phpseclib\File\ASN1\Maps;
use phpseclib\File\ASN1;
/**
* MaskGenAglorithm
*
* @package ASN1
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
abstract class MaskGenAlgorithm
{
const MAP = AlgorithmIdentifier::MAP;
}

View File

@ -0,0 +1,62 @@
<?php
/**
* RSASSA_PSS_params
*
* As defined in https://tools.ietf.org/html/rfc4055#section-3.1
*
* PHP version 5
*
* @category File
* @package ASN1
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2016 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace phpseclib\File\ASN1\Maps;
use phpseclib\File\ASN1;
/**
* RSASSA_PSS_params
*
* @package ASN1
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
abstract class RSASSA_PSS_params
{
const MAP = [
'type' => ASN1::TYPE_SEQUENCE,
'children' => [
'hashAlgorithm' => [
'constant' => 0,
'optional' => true,
'explicit' => true,
'default' => 'sha1Identifier'
] + HashAlgorithm::MAP,
'maskGenAlgorithm' => [
'constant' => 1,
'optional' => true,
'explicit' => true,
'default' => 'mgf1SHA1Identifier'
] + MaskGenAlgorithm::MAP,
'saltLength' => [
'type' => ASN1::TYPE_INTEGER,
'constant' => 2,
'optional' => true,
'explicit' => true,
'default' => 20
],
'trailerField' => [
'type' => ASN1::TYPE_INTEGER,
'constant' => 3,
'optional' => true,
'explicit' => true,
'default' => 1
]
]
];
}

View File

@ -2447,10 +2447,7 @@ class SSH2
throw new UnsupportedAlgorithmException('Please use either an RSA key, an ECDSA one or a DSA key'); throw new UnsupportedAlgorithmException('Please use either an RSA key, an ECDSA one or a DSA key');
} }
$status = OpenSSH::getBinaryOutput(); $publickeyStr = $publickey->toString('OpenSSH', ['binary' => true]);
OpenSSH::setBinaryOutput(true);
$publickeyStr = $publickey->toString('OpenSSH');
OpenSSH::setBinaryOutput($status);
$part1 = Strings::packSSH2( $part1 = Strings::packSSH2(
'Csss', 'Csss',

View File

@ -878,4 +878,41 @@ OFLPBrLe4Hw=
$this->assertInstanceOf(PrivateKey::class, $rsa); $this->assertInstanceOf(PrivateKey::class, $rsa);
$this->assertInstanceOf(PublicKey::class, $rsa->getPublicKey()); $this->assertInstanceOf(PublicKey::class, $rsa->getPublicKey());
} }
public function testPSS()
{
$key = '-----BEGIN PRIVATE KEY-----
MIIE7QIBADA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCAaEaMBgGCSqGSIb3
DQEBCDALBglghkgBZQMEAgOiAwIBBQSCBKcwggSjAgEAAoIBAQD6L3Z2XUPH7vRU
1Xl5aLpW2jH/uhqOitRV2/1QAEQk6VasI2TjJefP6SmL+te71gE4PVTMpm0LoluR
IzvQYgeLwDFUzLsn2r/H3lKlS/K0KL890aNPSNuHwKVYQsBd2OuSQQZ04xM1E0VN
xELcW4Vc63FTyGzR4okQ2MGHQfxP/FoNNfaIxjyb7ly9feGNR3pIRcL2CEMfyZkq
rEE3SxNoGTHMTbIhMGchWTrX1V+VykSgy9+KmD0AD8SwP3nFH3BNLeoLDhkU2L6L
p9XYijx3RAvPeYRlMAyOpylRxXM5Z1oBmzaClDVE8mtJkMPpZshGbVwxbzrph8VA
FBf3FzYFAgMBAAECggEAMu3Igq3Xp3KIQGC4erOMAzQlq3YaA9xU/ylqNofnV1A8
uYv29Jp5xwQi1gD5O56D3wv1IDfcyNqDI1d1zKS3/oXgRO/sRV+tXKVwU3/TZ0NI
MvBi+zfMoKThw8bK3A/VXI9qHg8/kLVcjUkfhzYGPvUau8B4Dn28AzbspnkTQMCq
FpuC41a8UzOX7rvEKPTLp87fwI1u48ycDKVK0ZKjJMQQl3SbYaVIKZa4ctav/9wC
e5LAnap55S0L13FdUHbGJKzUqIk61NgCr8Wo16AYCOULzTTNVE24jl2Dc1H+sk61
b1FC/TxW9iWZx9givR1VgjG5fULbxwA/Mve7SYtfIQKBgQD+a/y8pxIPgBXb90Z4
poCqRsgJVPmu6sQ8STb0WibtyD/IKECooGOpI16A/884kNyXkfcIwK6txnnPYbmv
KlNHgSUnhEeavrHfeUmyyrQaTAs3I0iuL4stOSRHHPDD72PRSkPky6NMErX4F4Vv
Y6jkFhwsNJetxf2qInJn5WZ6LQKBgQD7vL+KE0HHLZ3DVaP7pRMOx9FvkhrtmqLZ
fSuMUweKqnAFHnkEPZFuyFRMoPL3cHaVLPkGmX8vK/GL/QECKPeDyE/jEFzGQV+L
n4PeraS1jzu77uYzWcuKdabFQN939iZ2gV5MUB7Jt4zfURf26fH1UHku7rs/Mik3
jLfE9elKOQKBgDzhFi8GQ1oWKiTifKhuHyefnEovXTev0ZkjY9UApYQMgMaiayZu
iqp0Xi68B5ffggl60gP0J1hJv+gR2F7D3/2iN4PHMWMj8mgpG6t+ua35OE3PUZrs
oX8Gx1mE4U/hPp9cB/b9i2uupoBhEHrg/A7oA4HIa+sXD2XgrEOULvtZAoGBAJ73
RRkDKhGGG87jAMeDKXK2+elzoO+UK+wdX+ef8u48zLpe0Nq9ql4DwUAWjvd0HF39
ZVAmlCsMm97jqMRdbFfaoZ/okD1dwOEhnRt8GbvRNE5sARBCTwcjXmnHmpZdaVKC
RTL5kUeeUiYfRnvUpcdcxvm9JZ81pNOAV/fXtjb5AoGAUVm4enVSfvPupBsjydU4
EHvU0Y0I2IH1FrnVF8TI/9Kpdu2W5bJN5XShb7j2CICIKTr7wVwn/a7VXscQKIVb
XCy8+Rnt/jddXFeFEu9zHWyJX9W4fGIkyE4zfRPmTkVK4S599SUQkHdgClzAOMZU
IBgv3a3Lyb+IQtT75LE1yjE=
-----END PRIVATE KEY-----';
$rsa = PublicKeyLoader::load($key);
$this->assertInstanceOf(PrivateKey::class, $rsa);
$this->assertInstanceOf(PublicKey::class, $rsa->getPublicKey());
}
} }