diff --git a/phpseclib/Crypt/RSA.php b/phpseclib/Crypt/RSA.php index c05da504..8c4de35c 100644 --- a/phpseclib/Crypt/RSA.php +++ b/phpseclib/Crypt/RSA.php @@ -48,6 +48,7 @@ namespace phpseclib\Crypt; use phpseclib\Crypt\Hash; use phpseclib\Crypt\Random; use phpseclib\Math\BigInteger; +use phpseclib\File\ASN1; /** * Pure-PHP PKCS#1 compliant implementation of RSA. @@ -67,26 +68,32 @@ class RSA * Use {@link http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding Optimal Asymmetric Encryption Padding} * (OAEP) for encryption / decryption. * - * Uses sha1 by default. + * Uses sha256 by default * * @see self::setHash() * @see self::setMGFHash() */ - const ENCRYPTION_OAEP = 1; + const PADDING_OAEP = 1; /** * Use PKCS#1 padding. * - * Although self::ENCRYPTION_OAEP offers more security, including PKCS#1 padding is necessary for purposes of backwards + * Although self::PADDING_OAEP / self::PADDING_PSS offers more security, including PKCS#1 padding is necessary for purposes of backwards * compatibility with protocols (like SSH-1) written before OAEP's introduction. */ - const ENCRYPTION_PKCS1 = 2; + const PADDING_PKCS1 = 2; /** * Do not use any padding * * Although this method is not recommended it can none-the-less sometimes be useful if you're trying to decrypt some legacy * stuff, if you're trying to diagnose why an encrypted message isn't decrypting, etc. */ - const ENCRYPTION_NONE = 3; + const PADDING_NONE = 3; + /** + * Use PKCS#1 padding with PKCS1 v1.5 compatability + * + * A PKCS1 v2.1 encrypted message may not successfully decrypt with a PKCS1 v1.5 implementation (such as OpenSSL). + */ + const PADDING_PKCS15_COMPAT = 6; /**#@-*/ /**#@+ @@ -98,19 +105,17 @@ class RSA /** * Use the Probabilistic Signature Scheme for signing * - * Uses sha1 by default. + * Uses sha256 and 0 as the salt length * * @see self::setSaltLength() * @see self::setMGFHash() + * @see self::setHash() */ - const SIGNATURE_PSS = 1; + const PADDING_PSS = 4; /** - * Use the PKCS#1 scheme by default. - * - * Although self::SIGNATURE_PSS offers more security, including PKCS#1 signing is necessary for purposes of backwards - * compatibility with protocols (like SSH-2) written before PSS's introduction. + * Use a relaxed version of PKCS#1 padding for signature verification */ - const SIGNATURE_PKCS1 = 2; + const PADDING_RELAXED_PKCS1 = 5; /**#@-*/ /**#@+ @@ -283,22 +288,6 @@ class RSA */ var $mgfHLen; - /** - * Encryption mode - * - * @var int - * @access private - */ - var $encryptionMode = self::ENCRYPTION_OAEP; - - /** - * Signature mode - * - * @var int - * @access private - */ - var $signatureMode = self::SIGNATURE_PSS; - /** * Public Exponent * @@ -394,10 +383,10 @@ class RSA { self::_initialize_static_variables(); - $this->hash = new Hash('sha1'); + $this->hash = new Hash('sha256'); $this->hLen = $this->hash->getLength(); - $this->hashName = 'sha1'; - $this->mgfHash = new Hash('sha1'); + $this->hashName = 'sha256'; + $this->mgfHash = new Hash('sha256'); $this->mgfHLen = $this->mgfHash->getLength(); } @@ -706,8 +695,6 @@ class RSA $this->hLen = $key->hLen; $this->sLen = $key->sLen; $this->mgfHLen = $key->mgfHLen; - $this->encryptionMode = $key->encryptionMode; - $this->signatureMode = $key->signatureMode; $this->password = $key->password; if (is_object($key->hash)) { @@ -1233,7 +1220,7 @@ class RSA /** * Determines which hashing function should be used * - * Used with signature production / verification and (if the encryption mode is self::ENCRYPTION_OAEP) encryption and + * Used with signature production / verification and (if the encryption mode is self::PADDING_OAEP) encryption and * decryption. If $hash isn't supported, sha1 is used. * * @access public @@ -1253,8 +1240,8 @@ class RSA $this->hashName = $hash; break; default: - $this->hash = new Hash('sha1'); - $this->hashName = 'sha1'; + $this->hash = new Hash('sha256'); + $this->hashName = 'sha256'; } $this->hLen = $this->hash->getLength(); } @@ -1262,7 +1249,7 @@ class RSA /** * Determines which hashing function should be used for the mask generation function * - * The mask generation function is used by self::ENCRYPTION_OAEP and self::SIGNATURE_PSS and although it's + * The mask generation function is used by self::PADDING_OAEP and self::PADDING_PSS and although it's * best if Hash and MGFHash are set to the same thing this is not a requirement. * * @access public @@ -1310,14 +1297,13 @@ class RSA * @access private * @param \phpseclib\Math\BigInteger $x * @param int $xLen - * @throws \OutOfBoundsException if strlen($x) > $xLen - * @return string + * @return bool|string */ function _i2osp($x, $xLen) { $x = $x->toBytes(); if (strlen($x) > $xLen) { - throw new \OutOfBoundsException('Integer too large'); + return false; } return str_pad($x, $xLen, chr(0), STR_PAD_LEFT); } @@ -1470,13 +1456,12 @@ class RSA * * @access private * @param \phpseclib\Math\BigInteger $m - * @throws \OutOfRangeException if $m < 0 or $m > $this->modulus - * @return \phpseclib\Math\BigInteger + * @return bool|\phpseclib\Math\BigInteger */ function _rsaep($m) { if ($m->compare(self::$zero) < 0 || $m->compare($this->modulus) > 0) { - throw new \OutOfRangeException('Message representative out of range'); + return false; } return $this->_exponentiate($m); } @@ -1488,13 +1473,12 @@ class RSA * * @access private * @param \phpseclib\Math\BigInteger $c - * @throws \OutOfRangeException if $c < 0 or $c > $this->modulus - * @return \phpseclib\Math\BigInteger + * @return bool|\phpseclib\Math\BigInteger */ function _rsadp($c) { if ($c->compare(self::$zero) < 0 || $c->compare($this->modulus) > 0) { - throw new \OutOfRangeException('Ciphertext representative out of range'); + return false; } return $this->_exponentiate($c); } @@ -1506,13 +1490,12 @@ class RSA * * @access private * @param \phpseclib\Math\BigInteger $m - * @throws \OutOfRangeException if $m < 0 or $m > $this->modulus - * @return \phpseclib\Math\BigInteger + * @return bool|\phpseclib\Math\BigInteger */ function _rsasp1($m) { if ($m->compare(self::$zero) < 0 || $m->compare($this->modulus) > 0) { - throw new \OutOfRangeException('Message representative out of range'); + return false; } return $this->_exponentiate($m); } @@ -1524,13 +1507,12 @@ class RSA * * @access private * @param \phpseclib\Math\BigInteger $s - * @throws \OutOfRangeException if $s < 0 or $s > $this->modulus - * @return \phpseclib\Math\BigInteger + * @return bool|\phpseclib\Math\BigInteger */ function _rsavp1($s) { if ($s->compare(self::$zero) < 0 || $s->compare($this->modulus) > 0) { - throw new \OutOfRangeException('Signature representative out of range'); + return false; } return $this->_exponentiate($s); } @@ -1631,8 +1613,7 @@ class RSA * @access private * @param string $c * @param string $l - * @throws \RuntimeException on decryption error - * @return string + * @return bool|string */ function _rsaes_oaep_decrypt($c, $l = '') { @@ -1642,7 +1623,7 @@ class RSA // be output. if (strlen($c) != $this->k || $this->k < 2 * $this->hLen + 2) { - throw new \RuntimeException('Decryption error'); + return false; } // RSA decryption @@ -1650,7 +1631,7 @@ class RSA $c = $this->_os2ip($c); $m = $this->_rsadp($c); if ($m === false) { - throw new \RuntimeException('Decryption error'); + return false; } $em = $this->_i2osp($m, $this->k); @@ -1667,11 +1648,11 @@ class RSA $lHash2 = substr($db, 0, $this->hLen); $m = substr($db, $this->hLen); if ($lHash != $lHash2) { - throw new \RuntimeException('Decryption error'); + return false; } $m = ltrim($m, chr(0)); if (ord($m[0]) != 1) { - throw new \RuntimeException('Decryption error'); + return false; } // Output the message M @@ -1705,7 +1686,7 @@ class RSA * @throws \OutOfBoundsException if strlen($m) > $this->k - 11 * @return string */ - function _rsaes_pkcs1_v1_5_encrypt($m) + function _rsaes_pkcs1_v1_5_encrypt($m, $pkcs15_compat = false) { $mLen = strlen($m); @@ -1726,7 +1707,7 @@ class RSA } $type = 2; // see the comments of _rsaes_pkcs1_v1_5_decrypt() to understand why this is being done - if (defined('CRYPT_RSA_PKCS15_COMPAT') && (!isset($this->publicExponent) || $this->exponent !== $this->publicExponent)) { + if ($pkcs15_compat && (!isset($this->publicExponent) || $this->exponent !== $this->publicExponent)) { $type = 1; // "The padding string PS shall consist of k-3-||D|| octets. ... for block type 01, they shall have value FF" $ps = str_repeat("\xFF", $psLen); @@ -1761,15 +1742,14 @@ class RSA * * @access private * @param string $c - * @throws \RuntimeException on decryption error - * @return string + * @return bool|string */ function _rsaes_pkcs1_v1_5_decrypt($c) { // Length checking if (strlen($c) != $this->k) { // or if k < 11 - throw new \RuntimeException('Decryption error'); + return false; } // RSA decryption @@ -1778,21 +1758,21 @@ class RSA $m = $this->_rsadp($c); if ($m === false) { - throw new \RuntimeException('Decryption error'); + return false; } $em = $this->_i2osp($m, $this->k); // EME-PKCS1-v1_5 decoding if (ord($em[0]) != 0 || ord($em[1]) > 2) { - throw new \RuntimeException('Decryption error'); + return false; } $ps = substr($em, 2, strpos($em, chr(0), 2) - 2); $m = substr($em, strlen($ps) + 3); if (strlen($ps) < 8) { - throw new \RuntimeException('Decryption error'); + return false; } // Output M @@ -1820,7 +1800,7 @@ class RSA $mHash = $this->hash->hash($m); if ($emLen < $this->hLen + $sLen + 2) { - throw new \RuntimeException('Encoding error'); + return false; } $salt = Random::string($sLen); @@ -1917,7 +1897,6 @@ class RSA * @access private * @param string $m * @param string $s - * @throws \RuntimeException on invalid signature * @return string */ function _rsassa_pss_verify($m, $s) @@ -1925,7 +1904,7 @@ class RSA // Length checking if (strlen($s) != $this->k) { - throw new \RuntimeException('Invalid signature'); + return false; } // RSA verification @@ -1935,11 +1914,11 @@ class RSA $s2 = $this->_os2ip($s); $m2 = $this->_rsavp1($s2); if ($m2 === false) { - throw new \RuntimeException('Invalid signature'); + return false; } $em = $this->_i2osp($m2, $modBits >> 3); if ($em === false) { - throw new \RuntimeException('Invalid signature'); + return false; } // EMSA-PSS verification @@ -2013,9 +1992,11 @@ class RSA { // EMSA-PKCS1-v1_5 encoding + // If the encoding operation outputs "intended encoded message length too short," output "RSA modulus + // too short" and stop. $em = $this->_emsa_pkcs1_v1_5_encode($m, $this->k); if ($em === false) { - throw new \LengthException('RSA modulus too short'); + return false; } // RSA signature @@ -2036,16 +2017,15 @@ class RSA * * @access private * @param string $m - * @throws \RuntimeException if the signature is invalid * @throws \LengthException if the RSA modulus is too short - * @return string + * @return bool|string */ function _rsassa_pkcs1_v1_5_verify($m, $s) { // Length checking if (strlen($s) != $this->k) { - throw new \RuntimeException('Invalid signature'); + return false; } // RSA verification @@ -2053,17 +2033,20 @@ class RSA $s = $this->_os2ip($s); $m2 = $this->_rsavp1($s); if ($m2 === false) { - throw new \RuntimeException('Invalid signature'); + return false; } $em = $this->_i2osp($m2, $this->k); if ($em === false) { - throw new \RuntimeException('Invalid signature'); + return false; } // EMSA-PKCS1-v1_5 encoding - $em2 = $this->_emsa_pkcs1_v1_5_encode($m, $this->k); - if ($em2 === false) { + // If the encoding operation outputs "intended encoded message length too short," output "RSA modulus + // too short" and stop. + try { + $em2 = $this->_emsa_pkcs1_v1_5_encode($m, $this->k); + } catch (\LengthException $e) { throw new \LengthException('RSA modulus too short'); } @@ -2072,55 +2055,133 @@ class RSA } /** - * Set Encryption Mode + * RSASSA-PKCS1-V1_5-VERIFY (relaxed matching) * - * Valid values include self::ENCRYPTION_OAEP and self::ENCRYPTION_PKCS1. + * Per {@link http://tools.ietf.org/html/rfc3447#page-43 RFC3447#page-43} PKCS1 v1.5 + * specified the use BER encoding rather than DER encoding that PKCS1 v2.0 specified. + * This means that under rare conditions you can have a perfectly valid v1.5 signature + * that fails to validate with _rsassa_pkcs1_v1_5_verify(). PKCS1 v2.1 also recommends + * that if you're going to validate these types of signatures you "should indicate + * whether the underlying BER encoding is a DER encoding and hence whether the signature + * is valid with respect to the specification given in [PKCS1 v2.0+]". so if you do + * $rsa->getLastPadding() and get RSA::PADDING_RELAXED_PKCS1 back instead of + * RSA::PADDING_PKCS1... that means BER encoding was used. * - * @access public - * @param int $mode + * @access private + * @param string $m + * @return bool|string */ - function setEncryptionMode($mode) + function _rsassa_pkcs1_v1_5_relaxed_verify($m, $s) { - $this->encryptionMode = $mode; - } + // Length checking - /** - * Set Signature Mode - * - * Valid values include self::SIGNATURE_PSS and self::SIGNATURE_PKCS1 - * - * @access public - * @param int $mode - */ - function setSignatureMode($mode) - { - $this->signatureMode = $mode; + if (strlen($s) != $this->k) { + return false; + } + + // RSA verification + + $s = $this->_os2ip($s); + $m2 = $this->_rsavp1($s); + if ($m2 === false) { + return false; + } + $em = $this->_i2osp($m2, $this->k); + if ($em === false) { + return false; + } + + if ($this->_string_shift($em, 2) != "\0\1") { + return false; + } + + $em = ltrim($em, "\xFF"); + if ($this->_string_shift($em) != "\0") { + return false; + } + + $asn1 = new ASN1(); + $decoded = $asn1->decodeBER($em); + if (!is_array($decoded) || empty($decoded[0]) || strlen($em) > $decoded[0]['length']) { + return false; + } + + $AlgorithmIdentifier = array( + 'type' => ASN1::TYPE_SEQUENCE, + 'children' => array( + 'algorithm' => array('type' => ASN1::TYPE_OBJECT_IDENTIFIER), + 'parameters' => array( + 'type' => ASN1::TYPE_ANY, + 'optional' => true + ) + ) + ); + + $DigestInfo = array( + 'type' => ASN1::TYPE_SEQUENCE, + 'children' => array( + 'digestAlgorithm' => $AlgorithmIdentifier, + 'digest' => array('type' => ASN1::TYPE_OCTET_STRING) + ) + ); + + $oids = array( + '1.2.840.113549.2.2' => 'md2', + '1.2.840.113549.2.4' => 'md4', // from PKCS1 v1.5 + '1.2.840.113549.2.5' => 'md5', + '1.3.14.3.2.26' => 'sha1', + '2.16.840.1.101.3.4.2.1' => 'sha256', + '2.16.840.1.101.3.4.2.2' => 'sha384', + '2.16.840.1.101.3.4.2.3' => 'sha512', + // from PKCS1 v2.2 + //'2.16.840.1.101.3.4.2.5' => 'sha512/224', + //'2.16.840.1.101.3.4.2.6' => 'sha512/256', + ); + + $asn1->loadOIDs($oids); + + $decoded = $asn1->asn1map($decoded[0], $DigestInfo); + if (!isset($decoded) || $decoded === false) { + return false; + } + + if (!in_array($decoded['digestAlgorithm']['algorithm'], $oids)) { + return false; + } + + $hash = new Hash($decoded['digestAlgorithm']['algorithm']); + $em = $hash->hash($m); + $em2 = base64_decode($decoded['digest']); + + return $this->_equals($em, $em2); } /** * Encryption * - * Both self::ENCRYPTION_OAEP and self::ENCRYPTION_PKCS1 both place limits on how long $plaintext can be. + * Both self::PADDING_OAEP and self::PADDING_PKCS1 both place limits on how long $plaintext can be. * If $plaintext exceeds those limits it will be broken up so that it does and the resultant ciphertext's will * be concatenated together. * * @see self::decrypt() * @access public * @param string $plaintext + * @param int $padding * @return string * @throws \LengthException if the RSA modulus is too short */ - function encrypt($plaintext) + function encrypt($plaintext, $padding = self::PADDING_OAEP) { - switch ($this->encryptionMode) { - case self::ENCRYPTION_NONE: + switch ($padding) { + case self::PADDING_NONE: $plaintext = str_split($plaintext, $this->k); $ciphertext = ''; foreach ($plaintext as $m) { $ciphertext.= $this->_raw_encrypt($m); } return $ciphertext; - case self::ENCRYPTION_PKCS1: + case self::PADDING_PKCS15_COMPAT: + case self::PADDING_PKCS1: $length = $this->k - 11; if ($length <= 0) { throw new \LengthException('RSA modulus too short (' . $this->k . ' bytes long; should be more than 11 bytes with PKCS1)'); @@ -2129,14 +2190,14 @@ class RSA $plaintext = str_split($plaintext, $length); $ciphertext = ''; foreach ($plaintext as $m) { - $ciphertext.= $this->_rsaes_pkcs1_v1_5_encrypt($m); + $ciphertext.= $this->_rsaes_pkcs1_v1_5_encrypt($m, $padding == self::PADDING_PKCS15_COMPAT); } return $ciphertext; - //case self::ENCRYPTION_OAEP: + //case self::PADDING_OAEP: default: $length = $this->k - 2 * $this->hLen - 2; if ($length <= 0) { - throw new \LengthException('RSA modulus too short (' . $this->k . ' bytes long; should be more than ' . (2 * $this->hLen - 2) . ' bytes with OAEP / ' . $this->hashName . ')'); + throw new \LengthException('RSA modulus too short (' . $this->k . ' bytes long; should be more than ' . (2 * $this->hLen + 2) . ' bytes with OAEP / ' . $this->hashName . ')'); } $plaintext = str_split($plaintext, $length); @@ -2154,9 +2215,10 @@ class RSA * @see self::encrypt() * @access public * @param string $plaintext + * @param int|bool $padding * @return string */ - function decrypt($ciphertext) + function decrypt($ciphertext, $padding = self::PADDING_OAEP) { if ($this->k <= 0) { return false; @@ -2167,14 +2229,14 @@ class RSA $plaintext = ''; - switch ($this->encryptionMode) { - case self::ENCRYPTION_NONE: + switch ($padding) { + case self::PADDING_NONE: $decrypt = '_raw_encrypt'; break; - case self::ENCRYPTION_PKCS1: + case self::PADDING_PKCS1: $decrypt = '_rsaes_pkcs1_v1_5_decrypt'; break; - //case self::ENCRYPTION_OAEP: + //case self::PADDING_OAEP: default: $decrypt = '_rsaes_oaep_decrypt'; } @@ -2196,18 +2258,20 @@ class RSA * @see self::verify() * @access public * @param string $message + * @param int $padding * @return string */ - function sign($message) + function sign($message, $padding = self::PADDING_PSS) { if (empty($this->modulus) || empty($this->exponent)) { return false; } - switch ($this->signatureMode) { - case self::SIGNATURE_PKCS1: + switch ($padding) { + case self::PADDING_PKCS1: + case self::PADDING_RELAXED_PKCS1: return $this->_rsassa_pkcs1_v1_5_sign($message); - //case self::SIGNATURE_PSS: + //case self::PADDING_PSS: default: return $this->_rsassa_pss_sign($message); } @@ -2220,18 +2284,21 @@ class RSA * @access public * @param string $message * @param string $signature + * @param int|bool $padding * @return bool */ - function verify($message, $signature) + function verify($message, $signature, $padding = self::PADDING_PSS) { if (empty($this->modulus) || empty($this->exponent)) { return false; } - switch ($this->signatureMode) { - case self::SIGNATURE_PKCS1: + switch ($padding) { + case self::PADDING_RELAXED_PKCS1: + return $this->_rsassa_pkcs1_v1_5_relaxed_verify($message, $signature); + case self::PADDING_PKCS1: return $this->_rsassa_pkcs1_v1_5_verify($message, $signature); - //case self::SIGNATURE_PSS: + //case self::PADDING_PSS: default: return $this->_rsassa_pss_verify($message, $signature); } diff --git a/phpseclib/File/X509.php b/phpseclib/File/X509.php index 47e723b2..6986b327 100644 --- a/phpseclib/File/X509.php +++ b/phpseclib/File/X509.php @@ -2149,8 +2149,7 @@ class X509 case 'sha384WithRSAEncryption': case 'sha512WithRSAEncryption': $rsa->setHash(preg_replace('#WithRSAEncryption$#', '', $signatureAlgorithm)); - $rsa->setSignatureMode(RSA::SIGNATURE_PKCS1); - if (!@$rsa->verify($signatureSubject, $signature)) { + if (!@$rsa->verify($signatureSubject, $signature, RSA::PADDING_PKCS1)) { return false; } break; @@ -3671,9 +3670,8 @@ class X509 case 'sha384WithRSAEncryption': case 'sha512WithRSAEncryption': $key->setHash(preg_replace('#WithRSAEncryption$#', '', $signatureAlgorithm)); - $key->setSignatureMode(RSA::SIGNATURE_PKCS1); - $this->currentCert['signature'] = base64_encode("\0" . $key->sign($this->signatureSubject)); + $this->currentCert['signature'] = base64_encode("\0" . $key->sign($this->signatureSubject, RSA::PADDING_PKCS1)); return $this->currentCert; default: throw new UnsupportedAlgorithmException('Signature algorithm unsupported'); diff --git a/phpseclib/Net/SSH1.php b/phpseclib/Net/SSH1.php index b0903386..f1c53492 100644 --- a/phpseclib/Net/SSH1.php +++ b/phpseclib/Net/SSH1.php @@ -1302,8 +1302,7 @@ class SSH1 /* $rsa = new RSA(); $rsa->load($key, 'raw'); - $rsa->setEncryptionMode(RSA::ENCRYPTION_PKCS1); - return $rsa->encrypt($m); + return $rsa->encrypt($m, RSA::PADDING_PKCS1); */ // To quote from protocol-1.5.txt: diff --git a/phpseclib/Net/SSH2.php b/phpseclib/Net/SSH2.php index 409d29c5..d5179e00 100644 --- a/phpseclib/Net/SSH2.php +++ b/phpseclib/Net/SSH2.php @@ -2306,8 +2306,7 @@ class SSH2 } $packet = $part1 . chr(1) . $part2; - $privatekey->setSignatureMode(RSA::SIGNATURE_PKCS1); - $signature = $privatekey->sign(pack('Na*a*', strlen($this->session_id), $this->session_id, $packet)); + $signature = $privatekey->sign(pack('Na*a*', strlen($this->session_id), $this->session_id, $packet), RSA::PADDING_PKCS1); $signature = pack('Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($signature), $signature); $packet.= pack('Na*', strlen($signature), $signature); @@ -4054,9 +4053,8 @@ class SSH2 $signature = $this->_string_shift($signature, $temp['length']); $rsa = new RSA(); - $rsa->setSignatureMode(RSA::SIGNATURE_PKCS1); $rsa->load(array('e' => $e, 'n' => $n), 'raw'); - if (!$rsa->verify($this->exchange_hash, $signature)) { + if (!$rsa->verify($this->exchange_hash, $signature, RSA::PADDING_PKCS1)) { //user_error('Bad server signature'); return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE); } diff --git a/phpseclib/System/SSH/Agent/Identity.php b/phpseclib/System/SSH/Agent/Identity.php index 09b2e4c4..fd28a638 100644 --- a/phpseclib/System/SSH/Agent/Identity.php +++ b/phpseclib/System/SSH/Agent/Identity.php @@ -23,9 +23,8 @@ use phpseclib\System\SSH\Agent; * Instantiation should only be performed by \phpseclib\System\SSH\Agent class. * This could be thought of as implementing an interface that phpseclib\Crypt\RSA * implements. ie. maybe a Net_SSH_Auth_PublicKey interface or something. - * The methods in this interface would be getPublicKey, setSignatureMode - * and sign since those are the methods phpseclib looks for to perform - * public key authentication. + * The methods in this interface would be getPublicKey and sign since those are the + * methods phpseclib looks for to perform public key authentication. * * @package SSH\Agent * @author Jim Wigginton @@ -114,30 +113,18 @@ class Identity return !isset($format) ? $this->key->getPublicKey() : $this->key->getPublicKey($format); } - /** - * Set Signature Mode - * - * Doesn't do anything as ssh-agent doesn't let you pick and choose the signature mode. ie. - * ssh-agent's only supported mode is \phpseclib\Crypt\RSA::SIGNATURE_PKCS1 - * - * @param int $mode - * @access public - */ - function setSignatureMode($mode) - { - } - /** * Create a signature * * See "2.6.2 Protocol 2 private key signature request" * * @param string $message + * @param int|bool $padding * @return string * @throws \RuntimeException on connection errors * @access public */ - function sign($message) + function sign($message, $padding = false) { // the last parameter (currently 0) is for flags and ssh-agent only defines one flag (for ssh-dss): SSH_AGENT_OLD_SIGNATURE $packet = pack('CNa*Na*N', Agent::SSH_AGENTC_SIGN_REQUEST, strlen($this->key_blob), $this->key_blob, strlen($message), $message, 0); diff --git a/tests/Unit/Crypt/RSA/CreateKeyTest.php b/tests/Unit/Crypt/RSA/CreateKeyTest.php index 4b9a89fd..e7478be3 100644 --- a/tests/Unit/Crypt/RSA/CreateKeyTest.php +++ b/tests/Unit/Crypt/RSA/CreateKeyTest.php @@ -11,7 +11,7 @@ class Unit_Crypt_RSA_CreateKeyTest extends PhpseclibTestCase { public function testCreateKey() { - extract(RSA::createKey(512)); + extract(RSA::createKey(768)); $this->assertInstanceOf('\phpseclib\Crypt\RSA', $privatekey); $this->assertInstanceOf('\phpseclib\Crypt\RSA', $publickey); $this->assertNotEmpty("$privatekey"); diff --git a/tests/Unit/Crypt/RSA/ModeTest.php b/tests/Unit/Crypt/RSA/ModeTest.php index 16a99b04..c335d78a 100644 --- a/tests/Unit/Crypt/RSA/ModeTest.php +++ b/tests/Unit/Crypt/RSA/ModeTest.php @@ -32,17 +32,16 @@ U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ $rsa->load($privatekey); $rsa->load($rsa->getPublicKey()); - $rsa->setEncryptionMode(RSA::ENCRYPTION_NONE); $expected = '105b92f59a87a8ad4da52c128b8c99491790ef5a54770119e0819060032fb9e772ed6772828329567f3d7e9472154c1530f8156ba7fd732f52ca1c06' . '5a3f5ed8a96c442e4662e0464c97f133aed31262170201993085a589565d67cc9e727e0d087e3b225c8965203b271e38a499c92fc0d6502297eca712' . '4d04bd467f6f1e7c'; $expected = pack('H*', $expected); - $result = $rsa->encrypt($plaintext); + $result = $rsa->encrypt($plaintext, RSA::PADDING_NONE); $this->assertEquals($result, $expected); $rsa->load($privatekey); - $this->assertEquals(trim($rsa->decrypt($result), "\0"), $plaintext); + $this->assertEquals(trim($rsa->decrypt($result, RSA::PADDING_NONE), "\0"), $plaintext); } /** @@ -51,6 +50,8 @@ U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ public function testPSSSigs() { $rsa = new RSA(); + $rsa->setHash('sha1'); + $rsa->setMGFHash('sha1'); $rsa->load('-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqGKukO1De7zhZj6+H0qtjTkVx wTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUpwmJG8wVQZKjeGcjDOL5UlsuusFnc @@ -78,4 +79,24 @@ p0GbMJDyR4e9T04ZZwIDAQAB $rsa->load(array('n' => $n, 'e' => $e)); $rsa->encrypt($plaintext); } + + public function testPKCS1LooseVerify() + { + $rsa = new RSA(); + $rsa->load('-----BEGIN RSA PUBLIC KEY----- +MIGJAoGBAMuqkz8ij+ESAaNvgocVGmapjlrIldmhRo4h2NX4e6IXiCLTSxASQtY4 +iqRnmyxqQSfaan2okTfQ6sP95bl8Qz8lgneW3ClC6RXG/wpJgsx7TXQ2kodlcKBF +m4k72G75QXhZ+I40ZG7cjBf1/9egakR0a0X0MpeOrKCzMBLv9+mpAgMBAAE= +-----END RSA PUBLIC KEY-----'); + + $message = base64_decode('MYIBLjAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0xNDA1MTUxNDM4MzRaMC8GCSqGSIb3DQEJBDEiBCBLzLIBGdOf0L2WRrIY' . + '9KTwiHnReBW48S9C7LNRaPp5mDCBwgYLKoZIhvcNAQkQAi8xgbIwga8wgawwgakEIJDB9ZGwihf+TaiwrHQNkNHkqbN8Nuws0e77QNObkvFZMIGEMHCkbjBs' . + 'MQswCQYDVQQGEwJJVDEYMBYGA1UECgwPQXJ1YmFQRUMgUy5wLkEuMSEwHwYDVQQLDBhDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eUMxIDAeBgNVBAMMF0FydWJh' . + 'UEVDIFMucC5BLiBORyBDQSAzAhAv4L3QcFssQNLDYN/Vu40R'); + + $sig = base64_decode('XDSZWw6IcUj8ICxRJf04HzF8stzoiFAZSR2a0Rw3ziZxTOT0/NVUYJO5+9TaaREXEgxuCLpgmA+6W2SWrrGoxbbNfaI90ZoKeOAws4IX+9RfiWuooibjKcvt' . + 'GJYVVOCcjvQYxUUNbQ4EjCUonk3h7ECXfCCmWqbeq2LsyXeeYGE='); + + $this->assertTrue($rsa->verify($message, $sig, RSA::PADDING_RELAXED_PKCS1)); + } }