From d999aad1afc29079ad2c689dc5f01dca91384e32 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Oct 2026 07:11:06 +0000 Subject: [PATCH 1/2] build(deps): bump phpseclib/phpseclib from 3.0.55 to 3.0.57 Bumps [phpseclib/phpseclib](https://github.com/phpseclib/phpseclib) from 3.0.55 to 3.0.57. - [Release notes](https://github.com/phpseclib/phpseclib/releases) - [Changelog](https://github.com/phpseclib/phpseclib/blob/master/CHANGELOG.md) - [Commits](https://github.com/phpseclib/phpseclib/compare/3.0.55...3.0.57) --- updated-dependencies: - dependency-name: phpseclib/phpseclib dependency-version: 3.0.57 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- composer.json | 2 +- composer.lock | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index ecad6a790..600270bb9 100644 --- a/composer.json +++ b/composer.json @@ -46,7 +46,7 @@ "pear/pear-core-minimal": "^1.10", "php-http/guzzle7-adapter": "^1.1.0", "php-opencloud/openstack": "^3.17", - "phpseclib/phpseclib": "^3.0.55", + "phpseclib/phpseclib": "^3.0.57", "pimple/pimple": "^3.6.2", "predis/predis": "^3.4.2", "psr/clock": "^1.0", diff --git a/composer.lock b/composer.lock index 66a30c161..ab67adffa 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "b76b0147561138211083a0568e0378e4", + "content-hash": "f9f63025eac895e9a2a90f0af9fcb84b", "packages": [ { "name": "aws/aws-crt-php", @@ -3010,16 +3010,16 @@ }, { "name": "phpseclib/phpseclib", - "version": "3.0.55", + "version": "3.0.57", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "db9744e6d47e742b1f974e965ad49bdd041105af" + "reference": "d17e0ddaeaf6f22f7e007cbb437d78792fe2a0e4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/db9744e6d47e742b1f974e965ad49bdd041105af", - "reference": "db9744e6d47e742b1f974e965ad49bdd041105af", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/d17e0ddaeaf6f22f7e007cbb437d78792fe2a0e4", + "reference": "d17e0ddaeaf6f22f7e007cbb437d78792fe2a0e4", "shasum": "" }, "require": { @@ -3100,7 +3100,7 @@ ], "support": { "issues": "https://github.com/phpseclib/phpseclib/issues", - "source": "https://github.com/phpseclib/phpseclib/tree/3.0.55" + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.57" }, "funding": [ { @@ -3116,7 +3116,7 @@ "type": "tidelift" } ], - "time": "2026-06-14T23:24:10+00:00" + "time": "2026-08-26T12:13:21+00:00" }, { "name": "pimple/pimple", From 9de9b59467b080b4cb973c1326df06a5dd65bceb Mon Sep 17 00:00:00 2001 From: nextcloud-command Date: Mon, 5 Oct 2026 07:32:50 +0000 Subject: [PATCH 2/2] chore(autoloader): Dump autoloader Signed-off-by: nextcloud-command --- composer/installed.json | 14 +-- composer/installed.php | 6 +- phpseclib/phpseclib/phpseclib/Crypt/AES.php | 2 +- .../phpseclib/phpseclib/Crypt/ChaCha20.php | 6 +- .../phpseclib/Crypt/Common/StreamCipher.php | 2 +- .../phpseclib/Crypt/Common/SymmetricKey.php | 54 +++++----- phpseclib/phpseclib/phpseclib/Crypt/DES.php | 10 +- phpseclib/phpseclib/phpseclib/Crypt/DH.php | 20 ++-- .../phpseclib/Crypt/DSA/PrivateKey.php | 2 +- phpseclib/phpseclib/phpseclib/Crypt/EC.php | 2 +- .../Crypt/EC/BaseCurves/Montgomery.php | 6 ++ .../Crypt/EC/Formats/Keys/Common.php | 51 +++++++++ .../EC/Formats/Keys/MontgomeryPrivate.php | 12 ++- .../phpseclib/Crypt/EC/Formats/Keys/PKCS1.php | 4 +- .../phpseclib/Crypt/EC/Formats/Keys/PKCS8.php | 14 +-- .../phpseclib/Crypt/EC/PrivateKey.php | 8 +- phpseclib/phpseclib/phpseclib/Crypt/RC2.php | 2 +- phpseclib/phpseclib/phpseclib/Crypt/RC4.php | 6 +- phpseclib/phpseclib/phpseclib/Crypt/RSA.php | 50 +++++++-- .../phpseclib/Crypt/RSA/PublicKey.php | 19 +++- .../phpseclib/phpseclib/Crypt/Rijndael.php | 6 +- .../phpseclib/phpseclib/Crypt/Salsa20.php | 8 +- .../phpseclib/phpseclib/Crypt/TripleDES.php | 2 +- phpseclib/phpseclib/phpseclib/File/ASN1.php | 14 ++- phpseclib/phpseclib/phpseclib/File/X509.php | 36 +++---- .../phpseclib/Math/BigInteger/Engines/PHP.php | 13 ++- .../phpseclib/Math/PrimeField/Integer.php | 52 ++++++--- phpseclib/phpseclib/phpseclib/Net/SCP.php | 5 +- phpseclib/phpseclib/phpseclib/Net/SFTP.php | 101 ++++++++++++++++-- .../phpseclib/phpseclib/Net/SFTP/Stream.php | 6 +- phpseclib/phpseclib/phpseclib/Net/SSH2.php | 18 ++-- .../phpseclib/phpseclib/System/SSH/Agent.php | 1 - 32 files changed, 391 insertions(+), 161 deletions(-) diff --git a/composer/installed.json b/composer/installed.json index 2148a31ef..711dab9ce 100644 --- a/composer/installed.json +++ b/composer/installed.json @@ -3139,17 +3139,17 @@ }, { "name": "phpseclib/phpseclib", - "version": "3.0.55", - "version_normalized": "3.0.55.0", + "version": "3.0.57", + "version_normalized": "3.0.57.0", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "db9744e6d47e742b1f974e965ad49bdd041105af" + "reference": "d17e0ddaeaf6f22f7e007cbb437d78792fe2a0e4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/db9744e6d47e742b1f974e965ad49bdd041105af", - "reference": "db9744e6d47e742b1f974e965ad49bdd041105af", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/d17e0ddaeaf6f22f7e007cbb437d78792fe2a0e4", + "reference": "d17e0ddaeaf6f22f7e007cbb437d78792fe2a0e4", "shasum": "" }, "require": { @@ -3167,7 +3167,7 @@ "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations." }, - "time": "2026-06-14T23:24:10+00:00", + "time": "2026-08-26T12:13:21+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -3232,7 +3232,7 @@ ], "support": { "issues": "https://github.com/phpseclib/phpseclib/issues", - "source": "https://github.com/phpseclib/phpseclib/tree/3.0.55" + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.57" }, "funding": [ { diff --git a/composer/installed.php b/composer/installed.php index 7ceb49253..26ae272bd 100644 --- a/composer/installed.php +++ b/composer/installed.php @@ -443,9 +443,9 @@ 'dev_requirement' => false, ), 'phpseclib/phpseclib' => array( - 'pretty_version' => '3.0.55', - 'version' => '3.0.55.0', - 'reference' => 'db9744e6d47e742b1f974e965ad49bdd041105af', + 'pretty_version' => '3.0.57', + 'version' => '3.0.57.0', + 'reference' => 'd17e0ddaeaf6f22f7e007cbb437d78792fe2a0e4', 'type' => 'library', 'install_path' => __DIR__ . '/../phpseclib/phpseclib', 'aliases' => array(), diff --git a/phpseclib/phpseclib/phpseclib/Crypt/AES.php b/phpseclib/phpseclib/phpseclib/Crypt/AES.php index 403871627..270986dac 100644 --- a/phpseclib/phpseclib/phpseclib/Crypt/AES.php +++ b/phpseclib/phpseclib/phpseclib/Crypt/AES.php @@ -59,7 +59,7 @@ class AES extends Rijndael * * Since \phpseclib3\Crypt\AES extends \phpseclib3\Crypt\Rijndael, this function is, technically, available, but it doesn't do anything. * - * @see \phpseclib3\Crypt\Rijndael::setBlockLength() + * @see Rijndael::setBlockLength() * @param int $length * @throws \BadMethodCallException anytime it's called */ diff --git a/phpseclib/phpseclib/phpseclib/Crypt/ChaCha20.php b/phpseclib/phpseclib/phpseclib/Crypt/ChaCha20.php index dc365aa7a..88c4b5d94 100644 --- a/phpseclib/phpseclib/phpseclib/Crypt/ChaCha20.php +++ b/phpseclib/phpseclib/phpseclib/Crypt/ChaCha20.php @@ -35,7 +35,7 @@ class ChaCha20 extends Salsa20 * * This is mainly just a wrapper to set things up for \phpseclib3\Crypt\Common\SymmetricKey::isValidEngine() * - * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct() + * @see SymmetricKey::__construct() * @param int $engine * @return bool */ @@ -73,7 +73,7 @@ protected function isValidEngineHelper($engine) /** * Encrypts a message. * - * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt() + * @see SymmetricKey::decrypt() * @see self::crypt() * @param string $plaintext * @return string $ciphertext @@ -95,7 +95,7 @@ public function encrypt($plaintext) * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)). * At least if the continuous buffer is disabled. * - * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt() + * @see SymmetricKey::encrypt() * @see self::crypt() * @param string $ciphertext * @return string $plaintext diff --git a/phpseclib/phpseclib/phpseclib/Crypt/Common/StreamCipher.php b/phpseclib/phpseclib/phpseclib/Crypt/Common/StreamCipher.php index c7c080f4e..e44f5c87f 100644 --- a/phpseclib/phpseclib/phpseclib/Crypt/Common/StreamCipher.php +++ b/phpseclib/phpseclib/phpseclib/Crypt/Common/StreamCipher.php @@ -34,7 +34,7 @@ abstract class StreamCipher extends SymmetricKey /** * Default Constructor. * - * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct() + * @see SymmetricKey::__construct() * @return StreamCipher */ public function __construct() diff --git a/phpseclib/phpseclib/phpseclib/Crypt/Common/SymmetricKey.php b/phpseclib/phpseclib/phpseclib/Crypt/Common/SymmetricKey.php index 6e70be416..b24a1943f 100644 --- a/phpseclib/phpseclib/phpseclib/Crypt/Common/SymmetricKey.php +++ b/phpseclib/phpseclib/phpseclib/Crypt/Common/SymmetricKey.php @@ -60,76 +60,76 @@ abstract class SymmetricKey * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode. * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 - * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt() - * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt() + * SymmetricKey::encrypt() + * SymmetricKey::decrypt() */ const MODE_CTR = -1; /** * Encrypt / decrypt using the Electronic Code Book mode. * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29 - * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt() - * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt() + * SymmetricKey::encrypt() + * SymmetricKey::decrypt() */ const MODE_ECB = 1; /** * Encrypt / decrypt using the Code Book Chaining mode. * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 - * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt() - * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt() + * SymmetricKey::encrypt() + * SymmetricKey::decrypt() */ const MODE_CBC = 2; /** * Encrypt / decrypt using the Cipher Feedback mode. * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 - * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt() - * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt() + * SymmetricKey::encrypt() + * SymmetricKey::decrypt() */ const MODE_CFB = 3; /** * Encrypt / decrypt using the Cipher Feedback mode (8bit) * - * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt() - * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt() + * SymmetricKey::encrypt() + * SymmetricKey::decrypt() */ const MODE_CFB8 = 7; /** * Encrypt / decrypt using the Output Feedback mode (8bit) * - * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt() - * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt() + * SymmetricKey::encrypt() + * SymmetricKey::decrypt() */ const MODE_OFB8 = 8; /** * Encrypt / decrypt using the Output Feedback mode. * * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 - * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt() - * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt() + * SymmetricKey::encrypt() + * SymmetricKey::decrypt() */ const MODE_OFB = 4; /** * Encrypt / decrypt using Galois/Counter mode. * * @link https://en.wikipedia.org/wiki/Galois/Counter_Mode - * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt() - * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt() + * SymmetricKey::encrypt() + * SymmetricKey::decrypt() */ const MODE_GCM = 5; /** * Encrypt / decrypt using streaming mode. * - * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt() - * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt() + * SymmetricKey::encrypt() + * SymmetricKey::decrypt() */ const MODE_STREAM = 6; /** * Mode Map * - * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct() + * SymmetricKey::__construct() */ const MODE_MAP = [ 'ctr' => self::MODE_CTR, @@ -146,44 +146,44 @@ abstract class SymmetricKey /** * Base value for the internal implementation $engine switch * - * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct() + * SymmetricKey::__construct() */ const ENGINE_INTERNAL = 1; /** * Base value for the eval() implementation $engine switch * - * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct() + * SymmetricKey::__construct() */ const ENGINE_EVAL = 2; /** * Base value for the mcrypt implementation $engine switch * - * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct() + * SymmetricKey::__construct() */ const ENGINE_MCRYPT = 3; /** * Base value for the openssl implementation $engine switch * - * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct() + * SymmetricKey::__construct() */ const ENGINE_OPENSSL = 4; /** * Base value for the libsodium implementation $engine switch * - * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct() + * SymmetricKey::__construct() */ const ENGINE_LIBSODIUM = 5; /** * Base value for the openssl / gcm implementation $engine switch * - * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct() + * SymmetricKey::__construct() */ const ENGINE_OPENSSL_GCM = 6; /** * Engine Reverse Map * - * @see \phpseclib3\Crypt\Common\SymmetricKey::getEngine() + * SymmetricKey::getEngine() */ const ENGINE_MAP = [ self::ENGINE_INTERNAL => 'PHP', @@ -1270,7 +1270,7 @@ public function encrypt($plaintext) if ($this->continuousBuffer) { $this->encryptIV = $iv; } - break; + return $ciphertext; case self::MODE_OFB: return $this->openssl_ofb_process($plaintext, $this->encryptIV, $this->enbuffer); } diff --git a/phpseclib/phpseclib/phpseclib/Crypt/DES.php b/phpseclib/phpseclib/phpseclib/Crypt/DES.php index d02d29e95..6123f18f2 100644 --- a/phpseclib/phpseclib/phpseclib/Crypt/DES.php +++ b/phpseclib/phpseclib/phpseclib/Crypt/DES.php @@ -53,15 +53,15 @@ class DES extends BlockCipher /** * Contains $keys[self::ENCRYPT] * - * @see \phpseclib3\Crypt\DES::setupKey() - * @see \phpseclib3\Crypt\DES::processBlock() + * @see DES::setupKey() + * @see DES::processBlock() */ const ENCRYPT = 0; /** * Contains $keys[self::DECRYPT] * - * @see \phpseclib3\Crypt\DES::setupKey() - * @see \phpseclib3\Crypt\DES::processBlock() + * @see DES::setupKey() + * @see DES::processBlock() */ const DECRYPT = 1; @@ -1295,7 +1295,7 @@ protected function setupInlineCrypt() $sbox1 = array_map(["' . self::class . '", "safe_intval"], self::$sbox1); $sbox2 = array_map(["' . self::class . '", "safe_intval"], self::$sbox2); $sbox3 = array_map(["' . self::class . '", "safe_intval"], self::$sbox3); - $sbox4 = array_map(["' . self::class .'", "safe_intval"], self::$sbox4); + $sbox4 = array_map(["' . self::class . '", "safe_intval"], self::$sbox4); $sbox5 = array_map(["' . self::class . '", "safe_intval"], self::$sbox5); $sbox6 = array_map(["' . self::class . '", "safe_intval"], self::$sbox6); $sbox7 = array_map(["' . self::class . '", "safe_intval"], self::$sbox7); diff --git a/phpseclib/phpseclib/phpseclib/Crypt/DH.php b/phpseclib/phpseclib/phpseclib/Crypt/DH.php index bab2e9a41..6e95381b9 100644 --- a/phpseclib/phpseclib/phpseclib/Crypt/DH.php +++ b/phpseclib/phpseclib/phpseclib/Crypt/DH.php @@ -28,14 +28,9 @@ use phpseclib3\Crypt\DH\Parameters; use phpseclib3\Crypt\DH\PrivateKey; use phpseclib3\Crypt\DH\PublicKey; -use phpseclib3\Crypt\EC\Curves\Curve25519; -use phpseclib3\Crypt\EC\Curves\Curve448; -use phpseclib3\Crypt\EC\Formats\Keys\PKCS1; use phpseclib3\Exception\BadConfigurationException; use phpseclib3\Exception\NoKeyLoadedException; use phpseclib3\Exception\UnsupportedOperationException; -use phpseclib3\File\ASN1; -use phpseclib3\File\ASN1\Maps; use phpseclib3\Math\BigInteger; /** @@ -344,8 +339,21 @@ public static function computeSecret($private, $public) $public = EC::convertPointToPublicKey($curveName, $public, false); } $point = $private->multiply($public); + if ($isMontgomeryCurve) { + /* + "Both MAY check, without leaking extra information about the value of K, + whether K is the all-zero value and abort if so" + -- https://datatracker.ietf.org/doc/html/rfc7748#section-6.1 (and #section-6.2) + */ + $size = $curveName == 'Curve25519' ? 32 : 56; + // throw exception if hash_equals is false, otherwise, return $point + if (hash_equals(str_repeat("\0", $size), $point)) { + throw new \UnexpectedValueException('All-zero shared secret detected (points order is too small)'); + } + return $point; + } // according to https://www.secg.org/sec1-v2.pdf#page=33 only X is returned - $secret = $isMontgomeryCurve ? $point : substr($point, 1, (strlen($point) - 1) >> 1); + $secret = substr($point, 1, (strlen($point) - 1) >> 1); /* if (($secret[0] & "\x80") === "\x80") { $secret = "\0$secret"; diff --git a/phpseclib/phpseclib/phpseclib/Crypt/DSA/PrivateKey.php b/phpseclib/phpseclib/phpseclib/Crypt/DSA/PrivateKey.php index b30d913c6..0b1a24c95 100644 --- a/phpseclib/phpseclib/phpseclib/Crypt/DSA/PrivateKey.php +++ b/phpseclib/phpseclib/phpseclib/Crypt/DSA/PrivateKey.php @@ -14,8 +14,8 @@ use phpseclib3\Crypt\Common; use phpseclib3\Crypt\DSA; use phpseclib3\Crypt\DSA\Formats\Signature\ASN1 as ASN1Signature; -use phpseclib3\Math\BigInteger; use phpseclib3\Exception\BadConfigurationException; +use phpseclib3\Math\BigInteger; /** * DSA Private Key diff --git a/phpseclib/phpseclib/phpseclib/Crypt/EC.php b/phpseclib/phpseclib/phpseclib/Crypt/EC.php index fa4d91a03..5393085b6 100644 --- a/phpseclib/phpseclib/phpseclib/Crypt/EC.php +++ b/phpseclib/phpseclib/phpseclib/Crypt/EC.php @@ -542,7 +542,7 @@ public function getParameters($type = 'PKCS1') /** * Determines the signature padding mode * - * Valid values are: ASN1, SSH2, Raw + * Valid values are: ASN1, IEEE, SSH2, Raw * * @param string $format */ diff --git a/phpseclib/phpseclib/phpseclib/Crypt/EC/BaseCurves/Montgomery.php b/phpseclib/phpseclib/phpseclib/Crypt/EC/BaseCurves/Montgomery.php index 431f9575c..30ca623e0 100644 --- a/phpseclib/phpseclib/phpseclib/Crypt/EC/BaseCurves/Montgomery.php +++ b/phpseclib/phpseclib/phpseclib/Crypt/EC/BaseCurves/Montgomery.php @@ -223,6 +223,9 @@ public function multiplyPoint(array $p, BigInteger $d) $p2 = $this->convertToInternal($p); $x = $p[0]; + $r = $this->randomInteger(); + $p2 = [$p2[0]->multiply($r), $p2[1]->multiply($r)]; + $b = $d->toBits(); $b = str_pad($b, 256, '0', STR_PAD_LEFT); for ($i = 0; $i < strlen($b); $i++) { @@ -274,6 +277,9 @@ public function convertToAffine(array $p) return $p; } list($x, $z) = $p; + if ($z->equals($this->zero)) { + return [clone $this->zero]; + } return [$x->divide($z)]; } } diff --git a/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/Common.php b/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/Common.php index bf62d6388..df6ac124e 100644 --- a/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/Common.php +++ b/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/Common.php @@ -14,11 +14,14 @@ namespace phpseclib3\Crypt\EC\Formats\Keys; use phpseclib3\Common\Functions\Strings; +use phpseclib3\Crypt\EC; use phpseclib3\Crypt\EC\BaseCurves\Base as BaseCurve; use phpseclib3\Crypt\EC\BaseCurves\Binary as BinaryCurve; use phpseclib3\Crypt\EC\BaseCurves\Montgomery; use phpseclib3\Crypt\EC\BaseCurves\Prime as PrimeCurve; use phpseclib3\Crypt\EC\BaseCurves\TwistedEdwards as TwistedEdwardsCurve; +use phpseclib3\Crypt\EC\Curves\Curve25519; +use phpseclib3\Exception\BadConfigurationException; use phpseclib3\Exception\UnsupportedCurveException; use phpseclib3\File\ASN1; use phpseclib3\File\ASN1\Maps; @@ -528,6 +531,54 @@ private static function encodeParameters(BaseCurve $curve, $returnArray = false, throw new UnsupportedCurveException('Curve cannot be serialized'); } + private static function deriveMontgomeryPublicKey(array $components) + { + $curve = $components['curve']; + $dA = $components['dA']; + $forcedEngine = EC::getForcedEngine(); + + $useLibsodium = !isset($forcedEngine) && $curve instanceof Curve25519 && function_exists('sodium_crypto_box_publickey_from_secretkey'); + if ($forcedEngine === 'libsodium') { + $useLibsodium = true; + if (!$curve instanceof Curve25519) { + throw new \RuntimeException('Engine libsodium is forced but is not supported for Curve448'); + } + if (!function_exists('sodium_crypto_box_publickey_from_secretkey')) { + throw new BadConfigurationException('Engine libsodium is forced but not available'); + } + } + + if ($useLibsodium) { + //$r = pack('H*', '0900000000000000000000000000000000000000000000000000000000000000'); + //$QA = sodium_crypto_scalarmult($dA->toBytes(), $r); + $QA = sodium_crypto_box_publickey_from_secretkey(str_pad($dA->toBytes(), 32, chr(0), STR_PAD_LEFT)); + return [$components['curve']->convertInteger(new BigInteger(strrev($QA), 256))]; + } + + $useOpenSSL = !isset($forcedEngine) && function_exists('openssl_pkey_get_private'); + if ($forcedEngine == 'OpenSSL') { + $useOpenSSL = true; + if (!function_exists('openssl_pkey_get_private')) { + throw new BadConfigurationException('Engine OpenSSL is forced but is not available'); + } + } + + if ($useOpenSSL) { + $pem = PKCS8::savePrivateKey($dA, $curve, []); + $res = openssl_pkey_get_private($pem); + if ($res !== false && ($details = openssl_pkey_get_details($res)) !== false) { + $index = $curve instanceof Curve25519 ? 'x25519' : 'x448'; + return isset($details[$index]['pub_key']) ? + [$curve->convertInteger(new BigInteger(strrev($details[$index]['pub_key']), 256))] : + PKCS8::load($details['key'])['QA']; + } elseif ($forcedEngine == 'OpenSSL') { + throw new BadConfigurationException('Engine OpenSSL is forced but was unable to derive the public key because of ' . openssl_error_string()); + } + } + + return [$components['curve']->multiplyPoint($components['curve']->getBasePoint(), $components['dA'])[0]]; + } + /** * Use Specified Curve * diff --git a/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/MontgomeryPrivate.php b/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/MontgomeryPrivate.php index 533259d1c..0277c8678 100644 --- a/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/MontgomeryPrivate.php +++ b/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/MontgomeryPrivate.php @@ -33,6 +33,8 @@ */ abstract class MontgomeryPrivate { + use Common; + /** * Is invisible flag * @@ -59,11 +61,11 @@ public static function load($key, $password = '') throw new \LengthException('The only supported lengths are 32 and 56'); } - $components = ['curve' => $curve]; - $components['dA'] = new BigInteger($key, 256); - $curve->rangeCheck($components['dA']); - // note that EC::getEncodedCoordinates does some additional "magic" (it does strrev on the result) - $components['QA'] = $components['curve']->multiplyPoint($components['curve']->getBasePoint(), $components['dA']); + $components = [ + 'curve' => $curve, + 'dA' => new BigInteger($key, 256) + ]; + $components['QA'] = self::deriveMontgomeryPublicKey($components); return $components; } diff --git a/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/PKCS1.php b/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/PKCS1.php index 756ffb957..e67e68b21 100644 --- a/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/PKCS1.php +++ b/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/PKCS1.php @@ -132,8 +132,8 @@ public static function load($key, $password = '') $components = []; $components['curve'] = self::loadCurveByParam($key['parameters']); $components['dA'] = new BigInteger($key['privateKey'], 256); - $components['QA'] = isset($ecPrivate['publicKey']) ? - self::extractPoint($ecPrivate['publicKey'], $components['curve']) : + $components['QA'] = isset($key['publicKey']) ? + self::extractPoint($key['publicKey'], $components['curve']) : $components['curve']->multiplyPoint($components['curve']->getBasePoint(), $components['dA']); return $components; diff --git a/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/PKCS8.php b/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/PKCS8.php index c25d5a611..6df0c9174 100644 --- a/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/PKCS8.php +++ b/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/PKCS8.php @@ -23,7 +23,6 @@ namespace phpseclib3\Crypt\EC\Formats\Keys; -use phpseclib3\Math\Common\FiniteField\Integer; use phpseclib3\Crypt\Common\Formats\Keys\PKCS8 as Progenitor; use phpseclib3\Crypt\EC\BaseCurves\Base as BaseCurve; use phpseclib3\Crypt\EC\BaseCurves\Montgomery as MontgomeryCurve; @@ -32,10 +31,10 @@ use phpseclib3\Crypt\EC\Curves\Curve448; use phpseclib3\Crypt\EC\Curves\Ed25519; use phpseclib3\Crypt\EC\Curves\Ed448; -use phpseclib3\Exception\UnsupportedCurveException; use phpseclib3\File\ASN1; use phpseclib3\File\ASN1\Maps; use phpseclib3\Math\BigInteger; +use phpseclib3\Math\Common\FiniteField\Integer; /** * PKCS#8 Formatted EC Key Handler @@ -191,14 +190,7 @@ private static function loadECDH(array $key) } if (isset($key['privateKey']) && !isset($components['QA'])) { - if ($components['curve'] instanceof Curve25519 && function_exists('sodium_crypto_box_publickey_from_secretkey')) { - //$r = pack('H*', '0900000000000000000000000000000000000000000000000000000000000000'); - //$QA = sodium_crypto_scalarmult($components['dA']->toBytes(), $r); - $QA = sodium_crypto_box_publickey_from_secretkey(str_pad($components['dA']->toBytes(), 32, chr(0), STR_PAD_LEFT)); - $components['QA'] = [$components['curve']->convertInteger(new BigInteger(strrev($QA), 256))]; - } else { - $components['QA'] = [$components['curve']->multiplyPoint($components['curve']->getBasePoint(), $components['dA'])[0]]; - } + $components['QA'] = self::deriveMontgomeryPublicKey($components); } return $components; @@ -245,7 +237,7 @@ public static function savePublicKey(BaseCurve $curve, array $publicKey, array $ * * @param BigInteger $privateKey * @param BaseCurve $curve - * @param \phpseclib3\Math\Common\FiniteField\Integer[] $publicKey + * @param Integer[] $publicKey * @param string $secret optional * @param string $password optional * @param array $options optional diff --git a/phpseclib/phpseclib/phpseclib/Crypt/EC/PrivateKey.php b/phpseclib/phpseclib/phpseclib/Crypt/EC/PrivateKey.php index 383e8e084..b786222c2 100644 --- a/phpseclib/phpseclib/phpseclib/Crypt/EC/PrivateKey.php +++ b/phpseclib/phpseclib/phpseclib/Crypt/EC/PrivateKey.php @@ -74,7 +74,13 @@ public function multiply($coordinates) } if (function_exists('sodium_crypto_scalarmult')) { $dA = str_pad($this->dA->toBytes(), 32, "\0", STR_PAD_LEFT); - return sodium_crypto_scalarmult($dA, $coordinates); + try { + return sodium_crypto_scalarmult($dA, $coordinates); + } catch (\SodiumException $e) { + if (self::$forcedEngine == 'libsodium') { + throw new BadConfigurationException('Engine libsodium is forced but was unable to perform multiplication because of ' . $e->getMessage()); + } + } } } diff --git a/phpseclib/phpseclib/phpseclib/Crypt/RC2.php b/phpseclib/phpseclib/phpseclib/Crypt/RC2.php index 175c52e7b..f6b16761f 100644 --- a/phpseclib/phpseclib/phpseclib/Crypt/RC2.php +++ b/phpseclib/phpseclib/phpseclib/Crypt/RC2.php @@ -73,7 +73,7 @@ class RC2 extends BlockCipher /** * Key Length (in bytes) * - * @see \phpseclib3\Crypt\RC2::setKeyLength() + * @see RC2::setKeyLength() * @var int */ protected $key_length = 16; // = 128 bits diff --git a/phpseclib/phpseclib/phpseclib/Crypt/RC4.php b/phpseclib/phpseclib/phpseclib/Crypt/RC4.php index 98cf01165..c31efc116 100644 --- a/phpseclib/phpseclib/phpseclib/Crypt/RC4.php +++ b/phpseclib/phpseclib/phpseclib/Crypt/RC4.php @@ -52,19 +52,19 @@ class RC4 extends StreamCipher { /** - * @see \phpseclib3\Crypt\RC4::_crypt() + * @see RC4::_crypt() */ const ENCRYPT = 0; /** - * @see \phpseclib3\Crypt\RC4::_crypt() + * @see RC4::_crypt() */ const DECRYPT = 1; /** * Key Length (in bytes) * - * @see \phpseclib3\Crypt\RC4::setKeyLength() + * @see RC4::setKeyLength() * @var int */ protected $key_length = 128; // = 1024 bits diff --git a/phpseclib/phpseclib/phpseclib/Crypt/RSA.php b/phpseclib/phpseclib/phpseclib/Crypt/RSA.php index 892775d8b..30ad1536f 100644 --- a/phpseclib/phpseclib/phpseclib/Crypt/RSA.php +++ b/phpseclib/phpseclib/phpseclib/Crypt/RSA.php @@ -228,6 +228,13 @@ abstract class RSA extends AsymmetricKey */ protected static $enableBlinding = true; + /** + * Enable automatic salt length determination + * + * @var bool + */ + protected static $autoSaltLength = true; + /** * Smallest Prime * @@ -340,14 +347,14 @@ public static function createKey($bits = 2048) $e = new BigInteger(self::$defaultExponent); } - $n = clone self::$one; - $exponents = $coefficients = $primes = []; - $lcm = [ - 'top' => clone self::$one, - 'bottom' => false - ]; - do { + $n = clone self::$one; + $exponents = $coefficients = $primes = []; + $lcm = [ + 'top' => clone self::$one, + 'bottom' => false + ]; + for ($i = 1; $i <= $num_primes; $i++) { if ($i != $num_primes) { $primes[$i] = BigInteger::randomPrime($regSize); @@ -785,7 +792,6 @@ public function withMGFHash($hash) /** * Returns the MGF hash algorithm currently being used - * */ public function getMGFHash() { @@ -932,6 +938,16 @@ public static function disableBlinding() static::$enableBlinding = false; } + public static function enableSaltLengthDiscovery() + { + static::$autoSaltLength = true; + } + + public static function disableSaltLengthDiscovery() + { + static::$autoSaltLength = false; + } + /** * Handles OpenSSL encryption / decryption / signature creation / verification * @@ -965,6 +981,7 @@ protected function handleOpenSSL($func, $message, $signature = null) throw new BadConfigurationException('Engine OpenSSL is forced but unavailable for RSA'); } if ($this->$paddingType === self::SIGNATURE_PSS) { + $create = $func === 'openssl_sign'; switch (true) { case !defined('OPENSSL_PKCS1_PSS_PADDING'): $error = 'Engine OpenSSL is forced but PSS encryption requires PHP >= 8.5.0'; @@ -972,8 +989,18 @@ protected function handleOpenSSL($func, $message, $signature = null) case $this->hash->getHash() !== $this->mgfHash->getHash(): $error = 'Engine OpenSSL is forced but can\'t be used because the Hash and MGF Hash do not match'; break; - case $this->getSaltLength() !== $this->hLen: + case !$create && !static::$autoSaltLength: + $error = 'Engine OpenSSL is forced but auto calculation of the salt length is disabled'; + break; + case $create && $this->getSaltLength() !== $this->hLen: $error = 'Engine OpenSSL is forced but can\'t be used because the salt length doesn\'t match the hash length'; + break; + case $create && $this->getLength() < 8 * (2 * $this->getSaltLength() + 2): + $error = 'Engine OpenSSL is forced but can\'t be used for PSS signing because the key is too small for OpenSSL to use the configured salt length'; + break; + case $create && OPENSSL_VERSION_NUMBER < 0x30100000: + $error = 'Engine OpenSSL is forced but can\'t be used for PSS signing because OpenSSL < 3.1.0 defaults to the maximum salt length instead of the hash length'; + break; } } /* @@ -1062,7 +1089,10 @@ protected function handleOpenSSL($func, $message, $signature = null) restore_error_handler(); } - if ($func === 'openssl_verify' && $result !== -1 && $result !== false) { + if ($func === 'openssl_verify') { + if ($result === -1 || $result === false) { + throw new BadConfigurationException('Engine OpenSSL is forced but was unable to verify signature because of ' . openssl_error_string()); + } return (bool) $result; } if ($result) { diff --git a/phpseclib/phpseclib/phpseclib/Crypt/RSA/PublicKey.php b/phpseclib/phpseclib/phpseclib/Crypt/RSA/PublicKey.php index 6a80bf533..63563d79d 100644 --- a/phpseclib/phpseclib/phpseclib/Crypt/RSA/PublicKey.php +++ b/phpseclib/phpseclib/phpseclib/Crypt/RSA/PublicKey.php @@ -17,7 +17,6 @@ use phpseclib3\Crypt\Random; use phpseclib3\Crypt\RSA; use phpseclib3\Crypt\RSA\Formats\Keys\PSS; -use phpseclib3\Exception\BadConfigurationException; use phpseclib3\Exception\UnsupportedAlgorithmException; use phpseclib3\Exception\UnsupportedFormatException; use phpseclib3\File\ASN1; @@ -229,7 +228,11 @@ private function emsa_pss_verify($m, $em, $emBits) // be output. $emLen = ($emBits + 7) >> 3; // ie. ceil($emBits / 8); - $sLen = $this->sLen !== null ? $this->sLen : $this->hLen; + if (static::$autoSaltLength) { + $sLen = 0; + } else { + $sLen = $this->sLen !== null ? $this->sLen : $this->hLen; + } $mHash = $this->hash->hash($m); if ($emLen < $this->hLen + $sLen + 2) { @@ -249,11 +252,17 @@ private function emsa_pss_verify($m, $em, $emBits) $dbMask = $this->mgf1($h, $emLen - $this->hLen - 1); $db = $maskedDB ^ $dbMask; $db[0] = ~chr(256 - (1 << ($emBits & 7))) & $db[0]; - $temp = $emLen - $this->hLen - $sLen - 2; - if (substr($db, 0, $temp) != str_repeat(chr(0), $temp) || ord($db[$temp]) != 1) { + + // PS is a run of zero bytes terminated by a single 0x01 + $psLen = strspn($db, "\0"); + if ($psLen == strlen($db) || $db[$psLen] != chr(0x01)) { return false; } - $salt = substr($db, $temp + 1); // should be $sLen long + if (!static::$autoSaltLength && $psLen != $emLen - $this->hLen - $sLen - 2) { + return false; + } + + $salt = substr($db, $psLen + 1); // should be $sLen long $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt; $h2 = $this->hash->hash($m2); return hash_equals($h, $h2); diff --git a/phpseclib/phpseclib/phpseclib/Crypt/Rijndael.php b/phpseclib/phpseclib/phpseclib/Crypt/Rijndael.php index 07b196d18..3638adb48 100644 --- a/phpseclib/phpseclib/phpseclib/Crypt/Rijndael.php +++ b/phpseclib/phpseclib/phpseclib/Crypt/Rijndael.php @@ -262,7 +262,7 @@ public function setBlockLength($length) * * This is mainly just a wrapper to set things up for \phpseclib3\Crypt\Common\SymmetricKey::isValidEngine() * - * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct() + * Common\SymmetricKey::__construct() * @param int $engine * @return bool */ @@ -511,7 +511,7 @@ protected function setup() /** * Setup the key (expansion) * - * @see \phpseclib3\Crypt\Common\SymmetricKey::setupKey() + * Common\SymmetricKey::setupKey() */ protected function setupKey() { @@ -828,7 +828,7 @@ protected function &getInvTables() /** * Setup the performance-optimized function for de/encrypt() * - * @see \phpseclib3\Crypt\Common\SymmetricKey::setupInlineCrypt() + * Common\SymmetricKey::setupInlineCrypt() */ protected function setupInlineCrypt() { diff --git a/phpseclib/phpseclib/phpseclib/Crypt/Salsa20.php b/phpseclib/phpseclib/phpseclib/Crypt/Salsa20.php index 78c300059..6a79436f3 100644 --- a/phpseclib/phpseclib/phpseclib/Crypt/Salsa20.php +++ b/phpseclib/phpseclib/phpseclib/Crypt/Salsa20.php @@ -47,12 +47,12 @@ class Salsa20 extends StreamCipher protected $key_length = 32; // = 256 bits /** - * @see \phpseclib3\Crypt\Salsa20::crypt() + * @see Salsa20::crypt() */ const ENCRYPT = 0; /** - * @see \phpseclib3\Crypt\Salsa20::crypt() + * @see Salsa20::crypt() */ const DECRYPT = 1; @@ -236,7 +236,7 @@ protected function setupKey() /** * Encrypts a message. * - * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt() + * @see SymmetricKey::decrypt() * @see self::crypt() * @param string $plaintext * @return string $ciphertext @@ -256,7 +256,7 @@ public function encrypt($plaintext) * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)). * At least if the continuous buffer is disabled. * - * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt() + * @see SymmetricKey::encrypt() * @see self::crypt() * @param string $ciphertext * @return string $plaintext diff --git a/phpseclib/phpseclib/phpseclib/Crypt/TripleDES.php b/phpseclib/phpseclib/phpseclib/Crypt/TripleDES.php index 932b7c611..bbe3139a9 100644 --- a/phpseclib/phpseclib/phpseclib/Crypt/TripleDES.php +++ b/phpseclib/phpseclib/phpseclib/Crypt/TripleDES.php @@ -58,7 +58,7 @@ class TripleDES extends DES /** * Key Length (in bytes) * - * @see \phpseclib3\Crypt\TripleDES::setKeyLength() + * @see TripleDES::setKeyLength() * @var int */ protected $key_length = 24; diff --git a/phpseclib/phpseclib/phpseclib/File/ASN1.php b/phpseclib/phpseclib/phpseclib/File/ASN1.php index b2a7c1250..aea426ebd 100644 --- a/phpseclib/phpseclib/phpseclib/File/ASN1.php +++ b/phpseclib/phpseclib/phpseclib/File/ASN1.php @@ -540,7 +540,7 @@ public static function asn1map(array $decoded, $mapping, $special = []) case $mapping['type'] == self::TYPE_CHOICE: foreach ($mapping['children'] as $key => $option) { switch (true) { - case isset($option['constant']) && $option['constant'] == $decoded['constant']: + case isset($option['constant']) && isset($decoded['constant']) && $option['constant'] == $decoded['constant']: case !isset($option['constant']) && $option['type'] == $decoded['type']: $value = self::asn1map($decoded, $option, $special); break; @@ -624,6 +624,13 @@ public static function asn1map(array $decoded, $mapping, $special = []) // Can only match if no constant expected and type matches or is generic. $maymatch = !isset($child['constant']) && array_search($child['type'], [$temp['type'], self::TYPE_ANY, self::TYPE_CHOICE]) !== false; } + } elseif (isset($child['constant'])) { + // a CHOICE that is itself tagged is identified by that tag. its alternatives + // can't be used to tell it apart from a sibling with the same CHOICE definition + // (eg. issuerLogo [1] / subjectLogo [2] in RFC 9399's LogotypeExtn). + $maymatch = isset($temp['constant']) && + $child['constant'] == $temp['constant'] && + $temp['type'] == self::CLASS_CONTEXT_SPECIFIC; } } @@ -696,6 +703,11 @@ public static function asn1map(array $decoded, $mapping, $special = []) // Can only match if no constant expected and type matches or is generic. $maymatch = !isset($child['constant']) && array_search($child['type'], [$temp['type'], self::TYPE_ANY, self::TYPE_CHOICE]) !== false; } + } elseif (isset($child['constant'])) { + // see the comment in the TYPE_SEQUENCE case + $maymatch = isset($temp['constant']) && + $child['constant'] == $temp['constant'] && + $tempClass == self::CLASS_CONTEXT_SPECIFIC; } if ($maymatch) { diff --git a/phpseclib/phpseclib/phpseclib/File/X509.php b/phpseclib/phpseclib/phpseclib/File/X509.php index 70895ab30..70f6fa365 100644 --- a/phpseclib/phpseclib/phpseclib/File/X509.php +++ b/phpseclib/phpseclib/phpseclib/File/X509.php @@ -57,37 +57,37 @@ class X509 /** * Return internal array representation * - * @see \phpseclib3\File\X509::getDN() + * @see X509::getDN() */ const DN_ARRAY = 0; /** * Return string * - * @see \phpseclib3\File\X509::getDN() + * @see X509::getDN() */ const DN_STRING = 1; /** * Return ASN.1 name string * - * @see \phpseclib3\File\X509::getDN() + * @see X509::getDN() */ const DN_ASN1 = 2; /** * Return OpenSSL compatible array * - * @see \phpseclib3\File\X509::getDN() + * @see X509::getDN() */ const DN_OPENSSL = 3; /** * Return canonical ASN.1 RDNs string * - * @see \phpseclib3\File\X509::getDN() + * @see X509::getDN() */ const DN_CANON = 4; /** * Return name hash for file indexing * - * @see \phpseclib3\File\X509::getDN() + * @see X509::getDN() */ const DN_HASH = 5; @@ -96,25 +96,25 @@ class X509 * * ie. a base64-encoded PEM with a header and a footer * - * @see \phpseclib3\File\X509::saveX509() - * @see \phpseclib3\File\X509::saveCSR() - * @see \phpseclib3\File\X509::saveCRL() + * @see X509::saveX509() + * @see X509::saveCSR() + * @see X509::saveCRL() */ const FORMAT_PEM = 0; /** * Save as DER * - * @see \phpseclib3\File\X509::saveX509() - * @see \phpseclib3\File\X509::saveCSR() - * @see \phpseclib3\File\X509::saveCRL() + * @see X509::saveX509() + * @see X509::saveCSR() + * @see X509::saveCRL() */ const FORMAT_DER = 1; /** * Save as a SPKAC * - * @see \phpseclib3\File\X509::saveX509() - * @see \phpseclib3\File\X509::saveCSR() - * @see \phpseclib3\File\X509::saveCRL() + * @see X509::saveX509() + * @see X509::saveCSR() + * @see X509::saveCRL() * * Only works on CSRs. Not currently supported. */ @@ -124,9 +124,9 @@ class X509 * * Used only by the load*() functions * - * @see \phpseclib3\File\X509::saveX509() - * @see \phpseclib3\File\X509::saveCSR() - * @see \phpseclib3\File\X509::saveCRL() + * @see X509::saveX509() + * @see X509::saveCSR() + * @see X509::saveCRL() */ const FORMAT_AUTO_DETECT = 3; diff --git a/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP.php b/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP.php index de556a3b2..9f2ba94c1 100644 --- a/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP.php +++ b/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP.php @@ -304,7 +304,7 @@ protected static function addHelper(array $x_value, $x_negative, array $y_value, * @param bool $y_negative * @return array */ - public static function subtractHelper(array $x_value, $x_negative, array $y_value, $y_negative) + protected static function subtractHelper(array $x_value, $x_negative, array $y_value, $y_negative) { $x_size = count($x_value); $y_size = count($y_value); @@ -533,7 +533,11 @@ protected function divideHelper(PHP $y) $quotient = new static(); $remainder = new static(); $quotient->value = $q; - if ($this->is_negative) { + // The common residue is the first positive modulo, so it is only the + // negative remainders that need the divisor added. A remainder of 0 is + // already the residue; adding the divisor would return the modulus + // itself, which is never a valid residue. + if ($this->is_negative && $r) { $r = $y->value[0] - $r; } $remainder->value = [$r]; @@ -667,8 +671,9 @@ protected function divideHelper(PHP $y) $quotient->is_negative = $x_sign != $y_sign; - // calculate the "common residue", if appropriate - if ($x_sign) { + // calculate the "common residue", if appropriate. A remainder of 0 is + // already the residue -- see divideHelper's single-digit branch. + if ($x_sign && count($x->value)) { $y->rshift($shift); $x = $y->subtract($x); } diff --git a/phpseclib/phpseclib/phpseclib/Math/PrimeField/Integer.php b/phpseclib/phpseclib/phpseclib/Math/PrimeField/Integer.php index 1ebb2f5d7..e2aa3e7a0 100644 --- a/phpseclib/phpseclib/phpseclib/Math/PrimeField/Integer.php +++ b/phpseclib/phpseclib/phpseclib/Math/PrimeField/Integer.php @@ -72,6 +72,13 @@ class Integer extends Base */ protected static $two; + /** + * Constant Time Mask + * + * @var BigInteger[] + */ + protected static $mask; + /** * Default constructor * @@ -98,6 +105,11 @@ public function __construct($instanceID, $num = null) public static function setModulo($instanceID, BigInteger $modulo) { static::$modulo[$instanceID] = $modulo; + $one = new BigInteger(1); + static::$mask[$instanceID] = [ + new BigInteger(0), + $one->bitwise_leftShift($modulo->getLength())->subtract($one) + ]; } /** @@ -124,6 +136,7 @@ public static function cleanupCache($instanceID) unset(static::$zero[$instanceID]); unset(static::$one[$instanceID]); unset(static::$two[$instanceID]); + unset(static::$mask[$instanceID]); } /** @@ -175,6 +188,25 @@ public function compare(self $x) return $this->value->compare($x->value); } + /** + * Conditionally add the modulus, without branching on the value. + * + * $diff must be in (-modulo, modulo). Returns $diff + modulo when $diff is + * negative, $diff otherwise. + * + * @return static + */ + private function conditionalAddModulo(BigInteger $diff) + { + $mask = static::$mask[$this->instanceID][(int) $diff->isNegative()]; + + $temp = new static($this->instanceID); + $temp->value = $diff->add( + static::$modulo[$this->instanceID]->bitwise_and($mask) + ); + return $temp; + } + /** * Adds two PrimeFieldIntegers. * @@ -184,13 +216,10 @@ public function add(self $x) { static::checkInstance($this, $x); - $temp = new static($this->instanceID); - $temp->value = $this->value->add($x->value); - if ($temp->value->compare(static::$modulo[$this->instanceID]) >= 0) { - $temp->value = $temp->value->subtract(static::$modulo[$this->instanceID]); - } - - return $temp; + // $this->value + $x->value is in [0, 2m), so subtracting once lands in [-m, m) + return $this->conditionalAddModulo( + $this->value->add($x->value)->subtract(static::$modulo[$this->instanceID]) + ); } /** @@ -202,13 +231,8 @@ public function subtract(self $x) { static::checkInstance($this, $x); - $temp = new static($this->instanceID); - $temp->value = $this->value->subtract($x->value); - if ($temp->value->isNegative()) { - $temp->value = $temp->value->add(static::$modulo[$this->instanceID]); - } - - return $temp; + // already in (-m, m) + return $this->conditionalAddModulo($this->value->subtract($x->value)); } /** diff --git a/phpseclib/phpseclib/phpseclib/Net/SCP.php b/phpseclib/phpseclib/phpseclib/Net/SCP.php index ae5c8ec08..6d603deab 100644 --- a/phpseclib/phpseclib/phpseclib/Net/SCP.php +++ b/phpseclib/phpseclib/phpseclib/Net/SCP.php @@ -31,7 +31,6 @@ namespace phpseclib3\Net; -use phpseclib3\Common\Functions\Strings; use phpseclib3\Exception\FileNotFoundException; /** @@ -44,13 +43,13 @@ class SCP extends SSH2 /** * Reads data from a local file. * - * @see \phpseclib3\Net\SCP::put() + * @see SCP::put() */ const SOURCE_LOCAL_FILE = 1; /** * Reads data from a string. * - * @see \phpseclib3\Net\SCP::put() + * @see SCP::put() */ // this value isn't really used anymore but i'm keeping it reserved for historical reasons const SOURCE_STRING = 2; diff --git a/phpseclib/phpseclib/phpseclib/Net/SFTP.php b/phpseclib/phpseclib/phpseclib/Net/SFTP.php index ddc6715bf..038b19154 100644 --- a/phpseclib/phpseclib/phpseclib/Net/SFTP.php +++ b/phpseclib/phpseclib/phpseclib/Net/SFTP.php @@ -35,6 +35,7 @@ use phpseclib3\Common\Functions\Strings; use phpseclib3\Exception\FileNotFoundException; +use phpseclib3\Exception\TimeoutException; /** * Pure-PHP implementations of SFTP. @@ -48,21 +49,21 @@ class SFTP extends SSH2 * * \phpseclib3\Net\SSH2::exec() uses 0 and \phpseclib3\Net\SSH2::read() / \phpseclib3\Net\SSH2::write() use 1. * - * @see \phpseclib3\Net\SSH2::send_channel_packet() - * @see \phpseclib3\Net\SSH2::get_channel_packet() + * @see SSH2::send_channel_packet() + * @see SSH2::get_channel_packet() */ const CHANNEL = 0x100; /** * Reads data from a local file. * - * @see \phpseclib3\Net\SFTP::put() + * @see SFTP::put() */ const SOURCE_LOCAL_FILE = 1; /** * Reads data from a string. * - * @see \phpseclib3\Net\SFTP::put() + * @see SFTP::put() */ // this value isn't really used anymore but i'm keeping it reserved for historical reasons const SOURCE_STRING = 2; @@ -70,19 +71,19 @@ class SFTP extends SSH2 * Reads data from callback: * function callback($length) returns string to proceed, null for EOF * - * @see \phpseclib3\Net\SFTP::put() + * @see SFTP::put() */ const SOURCE_CALLBACK = 16; /** * Resumes an upload * - * @see \phpseclib3\Net\SFTP::put() + * @see SFTP::put() */ const RESUME = 4; /** * Append a local file to an already existing remote file * - * @see \phpseclib3\Net\SFTP::put() + * @see SFTP::put() */ const RESUME_START = 8; @@ -598,6 +599,9 @@ private function partial_init_sftp_connection() $response = $this->get_sftp_packet(); if ($this->packet_type != NET_SFTP_VERSION) { + if ($this->is_timeout) { + throw new TimeoutException('Timed out waiting for SFTP packet response'); + } throw new \UnexpectedValueException('Expected NET_SFTP_VERSION. ' . 'Got packet type: ' . $this->packet_type); } @@ -667,6 +671,9 @@ private function init_sftp_connection() $this->send_sftp_packet(NET_SFTP_EXTENDED, $packet); $response = $this->get_sftp_packet(); if ($this->packet_type != NET_SFTP_STATUS) { + if ($this->is_timeout) { + throw new TimeoutException('Timed out waiting for SFTP packet response'); + } throw new \UnexpectedValueException('Expected NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } @@ -883,6 +890,9 @@ public function realpath($path) $this->logError($response); return false; default: + if ($this->is_timeout) { + throw new TimeoutException('Timed out waiting for SFTP packet response'); + } throw new \UnexpectedValueException('Expected NET_SFTP_NAME or NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } @@ -963,6 +973,9 @@ public function chdir($dir) $this->logError($response); return false; default: + if ($this->is_timeout) { + throw new TimeoutException('Timed out waiting for SFTP packet response'); + } throw new \UnexpectedValueException('Expected NET_SFTP_HANDLE or NET_SFTP_STATUS' . 'Got packet type: ' . $this->packet_type); } @@ -1115,6 +1128,9 @@ private function readlist($dir, $raw = true) $this->logError($response, $status); return $status; default: + if ($this->is_timeout) { + throw new TimeoutException('Timed out waiting for SFTP packet response'); + } throw new \UnexpectedValueException('Expected NET_SFTP_HANDLE or NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } @@ -1525,6 +1541,9 @@ private function stat_helper($filename, $type) return false; } + if ($this->is_timeout) { + throw new TimeoutException('Timed out waiting for SFTP packet response'); + } throw new \UnexpectedValueException('Expected NET_SFTP_ATTRS or NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } @@ -1592,6 +1611,9 @@ public function touch($filename, $time = null, $atime = null) $this->logError($response); break; default: + if ($this->is_timeout) { + throw new TimeoutException('Timed out waiting for SFTP packet response'); + } throw new \UnexpectedValueException('Expected NET_SFTP_HANDLE or NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } @@ -1716,6 +1738,9 @@ public function chmod($mode, $filename, $recursive = false) return false; } + if ($this->is_timeout) { + throw new TimeoutException('Timed out waiting for SFTP packet response'); + } throw new \UnexpectedValueException('Expected NET_SFTP_ATTRS or NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } @@ -1764,6 +1789,9 @@ private function setstat($filename, $attr, $recursive) */ $response = $this->get_sftp_packet(); if ($this->packet_type != NET_SFTP_STATUS) { + if ($this->is_timeout) { + throw new TimeoutException('Timed out waiting for SFTP packet response'); + } throw new \UnexpectedValueException('Expected NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } @@ -1877,6 +1905,9 @@ public function readlink($link) $this->logError($response); return false; default: + if ($this->is_timeout) { + throw new TimeoutException('Timed out waiting for SFTP packet response'); + } throw new \UnexpectedValueException('Expected NET_SFTP_NAME or NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } @@ -1945,6 +1976,9 @@ public function symlink($target, $link) $response = $this->get_sftp_packet(); if ($this->packet_type != NET_SFTP_STATUS) { + if ($this->is_timeout) { + throw new TimeoutException('Timed out waiting for SFTP packet response'); + } throw new \UnexpectedValueException('Expected NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } @@ -2005,6 +2039,9 @@ private function mkdir_helper($dir, $mode) $response = $this->get_sftp_packet(); if ($this->packet_type != NET_SFTP_STATUS) { + if ($this->is_timeout) { + throw new TimeoutException('Timed out waiting for SFTP packet response'); + } throw new \UnexpectedValueException('Expected NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } @@ -2044,6 +2081,9 @@ public function rmdir($dir) $response = $this->get_sftp_packet(); if ($this->packet_type != NET_SFTP_STATUS) { + if ($this->is_timeout) { + throw new TimeoutException('Timed out waiting for SFTP packet response'); + } throw new \UnexpectedValueException('Expected NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } @@ -2167,6 +2207,9 @@ public function put($remote_file, $data, $mode = self::SOURCE_STRING, $start = - $this->logError($response); return false; default: + if ($this->is_timeout) { + throw new TimeoutException('Timed out waiting for SFTP packet response'); + } throw new \UnexpectedValueException('Expected NET_SFTP_HANDLE or NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } @@ -2309,6 +2352,9 @@ private function read_put_responses($i) while ($i--) { $response = $this->get_sftp_packet(); if ($this->packet_type != NET_SFTP_STATUS) { + if ($this->is_timeout) { + throw new TimeoutException('Timed out waiting for SFTP packet response'); + } throw new \UnexpectedValueException('Expected NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } @@ -2338,6 +2384,9 @@ private function close_handle($handle) // -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.3 $response = $this->get_sftp_packet(); if ($this->packet_type != NET_SFTP_STATUS) { + if ($this->is_timeout) { + throw new TimeoutException('Timed out waiting for SFTP packet response'); + } throw new \UnexpectedValueException('Expected NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } @@ -2394,6 +2443,9 @@ public function get($remote_file, $local_file = false, $offset = 0, $length = -1 $this->logError($response); return false; default: + if ($this->is_timeout) { + throw new TimeoutException('Timed out waiting for SFTP packet response'); + } throw new \UnexpectedValueException('Expected NET_SFTP_HANDLE or NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } @@ -2486,6 +2538,8 @@ public function get($remote_file, $local_file = false, $offset = 0, $length = -1 $this->partial_init = false; $this->init_sftp_connection(); return false; + } elseif ($this->is_timeout) { + throw new TimeoutException('Timed out waiting for SFTP packet response'); } else { throw new \UnexpectedValueException('Expected NET_SFTP_DATA or NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); @@ -2549,6 +2603,9 @@ public function delete($path, $recursive = true) $response = $this->get_sftp_packet(); if ($this->packet_type != NET_SFTP_STATUS) { + if ($this->is_timeout) { + throw new TimeoutException('Timed out waiting for SFTP packet response'); + } throw new \UnexpectedValueException('Expected NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } @@ -2734,6 +2791,9 @@ public function is_readable($path) case NET_SFTP_STATUS: // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED return false; default: + if ($this->is_timeout) { + throw new TimeoutException('Timed out waiting for SFTP packet response'); + } throw new \UnexpectedValueException('Expected NET_SFTP_HANDLE or NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } @@ -2761,6 +2821,9 @@ public function is_writable($path) case NET_SFTP_STATUS: // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED return false; default: + if ($this->is_timeout) { + throw new TimeoutException('Timed out waiting for SFTP packet response'); + } throw new \UnexpectedValueException('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } @@ -3001,6 +3064,9 @@ public function rename($oldname, $newname) $response = $this->get_sftp_packet(); if ($this->packet_type != NET_SFTP_STATUS) { + if ($this->is_timeout) { + throw new TimeoutException('Timed out waiting for SFTP packet response'); + } throw new \UnexpectedValueException('Expected NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } @@ -3626,6 +3692,9 @@ public function copy($oldname, $newname) $this->logError($response); return false; default: + if ($this->is_timeout) { + throw new TimeoutException('Timed out waiting for SFTP packet response'); + } throw new \UnexpectedValueException('Expected NET_SFTP_HANDLE or NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } @@ -3651,6 +3720,9 @@ public function copy($oldname, $newname) $this->logError($response); return false; default: + if ($this->is_timeout) { + throw new TimeoutException('Timed out waiting for SFTP packet response'); + } throw new \UnexpectedValueException('Expected NET_SFTP_HANDLE or NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } @@ -3660,6 +3732,9 @@ public function copy($oldname, $newname) $response = $this->get_sftp_packet(); if ($this->packet_type != NET_SFTP_STATUS) { + if ($this->is_timeout) { + throw new TimeoutException('Timed out waiting for SFTP packet response'); + } throw new \UnexpectedValueException('Expected NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } @@ -3701,6 +3776,9 @@ public function posix_rename($oldname, $newname) $packet = Strings::packSSH2('sss', 'posix-rename@openssh.com', $oldname, $newname); $this->send_sftp_packet(NET_SFTP_EXTENDED, $packet); } else { + if ($this->is_timeout) { + throw new TimeoutException('Timed out waiting for SFTP packet response'); + } throw new \RuntimeException( "Extension 'posix-rename@openssh.com' is not supported by the server. " . "Call getSupportedVersions() to see a list of supported extension" @@ -3709,6 +3787,9 @@ public function posix_rename($oldname, $newname) $response = $this->get_sftp_packet(); if ($this->packet_type != NET_SFTP_STATUS) { + if ($this->is_timeout) { + throw new TimeoutException('Timed out waiting for SFTP packet response'); + } throw new \UnexpectedValueException('Expected NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } @@ -3761,6 +3842,9 @@ public function statvfs($path) $response = $this->get_sftp_packet(); if ($this->packet_type !== NET_SFTP_EXTENDED_REPLY) { + if ($this->is_timeout) { + throw new TimeoutException('Timed out waiting for SFTP packet response'); + } throw new \UnexpectedValueException( 'Expected SSH_FXP_EXTENDED_REPLY. ' . 'Got packet type: ' . $this->packet_type @@ -3814,6 +3898,9 @@ public function hardlink($oldpath, $newpath) $response = $this->get_sftp_packet(); if ($this->packet_type !== NET_SFTP_STATUS) { + if ($this->is_timeout) { + throw new TimeoutException('Timed out waiting for SFTP packet response'); + } throw new \UnexpectedValueException('Expected NET_SFTP_STATUS. ' . 'Got packet type: ' . $this->packet_type); } diff --git a/phpseclib/phpseclib/phpseclib/Net/SFTP/Stream.php b/phpseclib/phpseclib/phpseclib/Net/SFTP/Stream.php index a1f2fa245..eedd1a0e3 100644 --- a/phpseclib/phpseclib/phpseclib/Net/SFTP/Stream.php +++ b/phpseclib/phpseclib/phpseclib/Net/SFTP/Stream.php @@ -177,9 +177,9 @@ protected function parse_path($path) } $this->sftp = $host; } else { - if (isset($this->context)) { - $context = stream_context_get_options($this->context); - } + $context = isset($this->context) ? + stream_context_get_options($this->context) : + stream_context_get_options(stream_context_get_default()); if (isset($context[$scheme]['session'])) { $sftp = $context[$scheme]['session']; } diff --git a/phpseclib/phpseclib/phpseclib/Net/SSH2.php b/phpseclib/phpseclib/phpseclib/Net/SSH2.php index 6f844e115..e8e48947a 100644 --- a/phpseclib/phpseclib/phpseclib/Net/SSH2.php +++ b/phpseclib/phpseclib/phpseclib/Net/SSH2.php @@ -118,10 +118,10 @@ class SSH2 * open request, and 'sender channel' is the channel number allocated by * the other side. * - * @see \phpseclib3\Net\SSH2::send_channel_packet() - * @see \phpseclib3\Net\SSH2::get_channel_packet() + * @see SSH2::send_channel_packet() + * @see SSH2::get_channel_packet() */ - const CHANNEL_EXEC = 1; // PuTTy uses 0x100 + const CHANNEL_EXEC = 1; // PuTTY uses 0x100 const CHANNEL_SHELL = 2; const CHANNEL_SUBSYSTEM = 3; const CHANNEL_AGENT_FORWARD = 4; @@ -130,13 +130,13 @@ class SSH2 /** * Returns the message numbers * - * @see \phpseclib3\Net\SSH2::getLog() + * @see SSH2::getLog() */ const LOG_SIMPLE = 1; /** * Returns the message content * - * @see \phpseclib3\Net\SSH2::getLog() + * @see SSH2::getLog() */ const LOG_COMPLEX = 2; /** @@ -158,20 +158,20 @@ class SSH2 /** * Make sure that the log never gets larger than this * - * @see \phpseclib3\Net\SSH2::getLog() + * @see SSH2::getLog() */ const LOG_MAX_SIZE = 1048576; // 1024 * 1024 /** * Returns when a string matching $expect exactly is found * - * @see \phpseclib3\Net\SSH2::read() + * @see SSH2::read() */ const READ_SIMPLE = 1; /** * Returns when a string matching the regular expression $expect is found * - * @see \phpseclib3\Net\SSH2::read() + * @see SSH2::read() */ const READ_REGEX = 2; /** @@ -180,7 +180,7 @@ class SSH2 * Some data packets may only contain a single character so it may be necessary * to call read() multiple times when using this option * - * @see \phpseclib3\Net\SSH2::read() + * @see SSH2::read() */ const READ_NEXT = 3; diff --git a/phpseclib/phpseclib/phpseclib/System/SSH/Agent.php b/phpseclib/phpseclib/phpseclib/System/SSH/Agent.php index 376d77bfe..7defe8e5d 100644 --- a/phpseclib/phpseclib/phpseclib/System/SSH/Agent.php +++ b/phpseclib/phpseclib/phpseclib/System/SSH/Agent.php @@ -35,7 +35,6 @@ use phpseclib3\Common\Functions\Strings; use phpseclib3\Crypt\Common\PublicKey; use phpseclib3\Crypt\PublicKeyLoader; -use phpseclib3\Crypt\RSA; use phpseclib3\Exception\BadConfigurationException; use phpseclib3\Net\SSH2; use phpseclib3\System\SSH\Agent\Identity;