Update the phpseclib via composer.

This commit is contained in:
Llewellyn van der Merwe 2019-07-17 01:53:34 +02:00
parent 8d2af8365b
commit fcd5846c5a
No known key found for this signature in database
GPG Key ID: CAD7B16D27AF28C5
23 changed files with 1174 additions and 274 deletions

View File

@ -146,7 +146,7 @@ TODO
+ *Author*: [Llewellyn van der Merwe](mailto:llewellyn@joomlacomponentbuilder.com) + *Author*: [Llewellyn van der Merwe](mailto:llewellyn@joomlacomponentbuilder.com)
+ *Name*: [Component Builder](https://github.com/vdm-io/Joomla-Component-Builder) + *Name*: [Component Builder](https://github.com/vdm-io/Joomla-Component-Builder)
+ *First Build*: 30th April, 2015 + *First Build*: 30th April, 2015
+ *Last Build*: 16th July, 2019 + *Last Build*: 17th July, 2019
+ *Version*: 2.9.32 + *Version*: 2.9.32
+ *Copyright*: Copyright (C) 2015 - 2019 Vast Development Method. All rights reserved. + *Copyright*: Copyright (C) 2015 - 2019 Vast Development Method. All rights reserved.
+ *License*: GNU General Public License version 2 or later; see LICENSE.txt + *License*: GNU General Public License version 2 or later; see LICENSE.txt

View File

@ -146,7 +146,7 @@ TODO
+ *Author*: [Llewellyn van der Merwe](mailto:llewellyn@joomlacomponentbuilder.com) + *Author*: [Llewellyn van der Merwe](mailto:llewellyn@joomlacomponentbuilder.com)
+ *Name*: [Component Builder](https://github.com/vdm-io/Joomla-Component-Builder) + *Name*: [Component Builder](https://github.com/vdm-io/Joomla-Component-Builder)
+ *First Build*: 30th April, 2015 + *First Build*: 30th April, 2015
+ *Last Build*: 16th July, 2019 + *Last Build*: 17th July, 2019
+ *Version*: 2.9.32 + *Version*: 2.9.32
+ *Copyright*: Copyright (C) 2015 - 2019 Vast Development Method. All rights reserved. + *Copyright*: Copyright (C) 2015 - 2019 Vast Development Method. All rights reserved.
+ *License*: GNU General Public License version 2 or later; see LICENSE.txt + *License*: GNU General Public License version 2 or later; see LICENSE.txt

View File

@ -1094,7 +1094,7 @@
readonly="false" readonly="false"
disabled="false" disabled="false"
required="true" required="true"
filter="WORD" filter="STRING"
message="COM_COMPONENTBUILDER_ADMIN_VIEW_KEY_MESSAGE" message="COM_COMPONENTBUILDER_ADMIN_VIEW_KEY_MESSAGE"
hint="COM_COMPONENTBUILDER_ADMIN_VIEW_KEY_HINT" hint="COM_COMPONENTBUILDER_ADMIN_VIEW_KEY_HINT"
/> />

View File

@ -179,7 +179,7 @@ class ComponentbuilderModelServer extends JModelAdmin
$item->tags->getTagIds($item->id, 'com_componentbuilder.server'); $item->tags->getTagIds($item->id, 'com_componentbuilder.server');
} }
} }
$this->sales_serverorupdate_servervvvw = $item->id; $this->sales_serverupdate_servervvvw = $item->id;
return $item; return $item;
} }
@ -203,19 +203,19 @@ class ComponentbuilderModelServer extends JModelAdmin
// From the componentbuilder_joomla_component table // From the componentbuilder_joomla_component table
$query->from($db->quoteName('#__componentbuilder_joomla_component', 'a')); $query->from($db->quoteName('#__componentbuilder_joomla_component', 'a'));
// Filter by sales_serverorupdate_servervvvw global. // Filter by sales_serverupdate_servervvvw global.
$sales_serverorupdate_servervvvw = $this->sales_serverorupdate_servervvvw; $sales_serverupdate_servervvvw = $this->sales_serverupdate_servervvvw;
if (is_numeric($sales_serverorupdate_servervvvw )) if (is_numeric($sales_serverupdate_servervvvw ))
{ {
$query->where('a.sales_serverORupdate_server = ' . (int) $sales_serverorupdate_servervvvw ); $query->where('a.sales_server = ' . (int) $sales_serverupdate_servervvvw . ' OR a.update_server = ' . (int) $sales_serverupdate_servervvvw, ' OR');
} }
elseif (is_string($sales_serverorupdate_servervvvw)) elseif (is_string($sales_serverupdate_servervvvw))
{ {
$query->where('a.sales_serverORupdate_server = ' . $db->quote($sales_serverorupdate_servervvvw)); $query->where('a.sales_server = ' . $db->quote($sales_serverupdate_servervvvw) . ' OR a.update_server = ' . $db->quote($sales_serverupdate_servervvvw), ' OR');
} }
else else
{ {
$query->where('a.sales_serverORupdate_server = -5'); $query->where('a.update_server = -5');
} }
// Join over the asset groups. // Join over the asset groups.

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<extension type="component" version="3.2" method="upgrade"> <extension type="component" version="3.2" method="upgrade">
<name>COM_COMPONENTBUILDER</name> <name>COM_COMPONENTBUILDER</name>
<creationDate>16th July, 2019</creationDate> <creationDate>17th July, 2019</creationDate>
<author>Llewellyn van der Merwe</author> <author>Llewellyn van der Merwe</author>
<authorEmail>llewellyn@joomlacomponentbuilder.com</authorEmail> <authorEmail>llewellyn@joomlacomponentbuilder.com</authorEmail>
<authorUrl>http://www.joomlacomponentbuilder.com</authorUrl> <authorUrl>http://www.joomlacomponentbuilder.com</authorUrl>

View File

@ -279,7 +279,7 @@ class ClassLoader
*/ */
public function setApcuPrefix($apcuPrefix) public function setApcuPrefix($apcuPrefix)
{ {
$this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null; $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
} }
/** /**
@ -377,7 +377,7 @@ class ClassLoader
$subPath = $class; $subPath = $class;
while (false !== $lastPos = strrpos($subPath, '\\')) { while (false !== $lastPos = strrpos($subPath, '\\')) {
$subPath = substr($subPath, 0, $lastPos); $subPath = substr($subPath, 0, $lastPos);
$search = $subPath.'\\'; $search = $subPath . '\\';
if (isset($this->prefixDirsPsr4[$search])) { if (isset($this->prefixDirsPsr4[$search])) {
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
foreach ($this->prefixDirsPsr4[$search] as $dir) { foreach ($this->prefixDirsPsr4[$search] as $dir) {

View File

@ -6,28 +6,4 @@ $vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir); $baseDir = dirname($vendorDir);
return array( return array(
'phpseclib\\Crypt\\AES' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/AES.php',
'phpseclib\\Crypt\\Base' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/Base.php',
'phpseclib\\Crypt\\Blowfish' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/Blowfish.php',
'phpseclib\\Crypt\\DES' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/DES.php',
'phpseclib\\Crypt\\Hash' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/Hash.php',
'phpseclib\\Crypt\\RC2' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/RC2.php',
'phpseclib\\Crypt\\RC4' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/RC4.php',
'phpseclib\\Crypt\\RSA' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/RSA.php',
'phpseclib\\Crypt\\Random' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/Random.php',
'phpseclib\\Crypt\\Rijndael' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/Rijndael.php',
'phpseclib\\Crypt\\TripleDES' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/TripleDES.php',
'phpseclib\\Crypt\\Twofish' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/Twofish.php',
'phpseclib\\File\\ANSI' => $vendorDir . '/phpseclib/phpseclib/phpseclib/File/ANSI.php',
'phpseclib\\File\\ASN1' => $vendorDir . '/phpseclib/phpseclib/phpseclib/File/ASN1.php',
'phpseclib\\File\\ASN1\\Element' => $vendorDir . '/phpseclib/phpseclib/phpseclib/File/ASN1/Element.php',
'phpseclib\\File\\X509' => $vendorDir . '/phpseclib/phpseclib/phpseclib/File/X509.php',
'phpseclib\\Math\\BigInteger' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Math/BigInteger.php',
'phpseclib\\Net\\SCP' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Net/SCP.php',
'phpseclib\\Net\\SFTP' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Net/SFTP.php',
'phpseclib\\Net\\SFTP\\Stream' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Net/SFTP/Stream.php',
'phpseclib\\Net\\SSH1' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Net/SSH1.php',
'phpseclib\\Net\\SSH2' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Net/SSH2.php',
'phpseclib\\System\\SSH\\Agent' => $vendorDir . '/phpseclib/phpseclib/phpseclib/System/SSH/Agent.php',
'phpseclib\\System\\SSH\\Agent\\Identity' => $vendorDir . '/phpseclib/phpseclib/phpseclib/System/SSH/Agent/Identity.php',
); );

View File

@ -24,39 +24,11 @@ class ComposerStaticInit10d22a526bd476954b93748a871e7ad4
), ),
); );
public static $classMap = array (
'phpseclib\\Crypt\\AES' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/AES.php',
'phpseclib\\Crypt\\Base' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/Base.php',
'phpseclib\\Crypt\\Blowfish' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/Blowfish.php',
'phpseclib\\Crypt\\DES' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/DES.php',
'phpseclib\\Crypt\\Hash' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/Hash.php',
'phpseclib\\Crypt\\RC2' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/RC2.php',
'phpseclib\\Crypt\\RC4' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/RC4.php',
'phpseclib\\Crypt\\RSA' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/RSA.php',
'phpseclib\\Crypt\\Random' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/Random.php',
'phpseclib\\Crypt\\Rijndael' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/Rijndael.php',
'phpseclib\\Crypt\\TripleDES' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/TripleDES.php',
'phpseclib\\Crypt\\Twofish' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Crypt/Twofish.php',
'phpseclib\\File\\ANSI' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/File/ANSI.php',
'phpseclib\\File\\ASN1' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/File/ASN1.php',
'phpseclib\\File\\ASN1\\Element' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/File/ASN1/Element.php',
'phpseclib\\File\\X509' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/File/X509.php',
'phpseclib\\Math\\BigInteger' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Math/BigInteger.php',
'phpseclib\\Net\\SCP' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Net/SCP.php',
'phpseclib\\Net\\SFTP' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Net/SFTP.php',
'phpseclib\\Net\\SFTP\\Stream' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Net/SFTP/Stream.php',
'phpseclib\\Net\\SSH1' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Net/SSH1.php',
'phpseclib\\Net\\SSH2' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Net/SSH2.php',
'phpseclib\\System\\SSH\\Agent' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/System/SSH/Agent.php',
'phpseclib\\System\\SSH\\Agent\\Identity' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/System/SSH/Agent/Identity.php',
);
public static function getInitializer(ClassLoader $loader) public static function getInitializer(ClassLoader $loader)
{ {
return \Closure::bind(function () use ($loader) { return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInit10d22a526bd476954b93748a871e7ad4::$prefixLengthsPsr4; $loader->prefixLengthsPsr4 = ComposerStaticInit10d22a526bd476954b93748a871e7ad4::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit10d22a526bd476954b93748a871e7ad4::$prefixDirsPsr4; $loader->prefixDirsPsr4 = ComposerStaticInit10d22a526bd476954b93748a871e7ad4::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInit10d22a526bd476954b93748a871e7ad4::$classMap;
}, null, ClassLoader::class); }, null, ClassLoader::class);
} }

View File

@ -1,17 +1,17 @@
[ [
{ {
"name": "phpseclib/phpseclib", "name": "phpseclib/phpseclib",
"version": "2.0.10", "version": "2.0.21",
"version_normalized": "2.0.10.0", "version_normalized": "2.0.21.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpseclib/phpseclib.git", "url": "https://github.com/phpseclib/phpseclib.git",
"reference": "d305b780829ea4252ed9400b3f5937c2c99b51d4" "reference": "9f1287e68b3f283339a9f98f67515dd619e5bf9d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/d305b780829ea4252ed9400b3f5937c2c99b51d4", "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/9f1287e68b3f283339a9f98f67515dd619e5bf9d",
"reference": "d305b780829ea4252ed9400b3f5937c2c99b51d4", "reference": "9f1287e68b3f283339a9f98f67515dd619e5bf9d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -29,7 +29,7 @@
"ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", "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." "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations."
}, },
"time": "2018-02-19T04:29:13+00:00", "time": "2019-07-12T12:53:49+00:00",
"type": "library", "type": "library",
"installation-source": "dist", "installation-source": "dist",
"autoload": { "autoload": {

View File

@ -1,5 +1,4 @@
Copyright 2007-2016 TerraFrost and other contributors Copyright (c) 2011-2019 TerraFrost and other contributors
http://phpseclib.sourceforge.net/
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the a copy of this software and associated documentation files (the
@ -18,4 +17,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -2,6 +2,14 @@
[![Build Status](https://travis-ci.org/phpseclib/phpseclib.svg?branch=2.0)](https://travis-ci.org/phpseclib/phpseclib) [![Build Status](https://travis-ci.org/phpseclib/phpseclib.svg?branch=2.0)](https://travis-ci.org/phpseclib/phpseclib)
## Supporting phpseclib
- [Become a backer or sponsor on Patreon](https://www.patreon.com/phpseclib)
- [One-time donation via PayPal or crypto-currencies](http://sourceforge.net/donate/index.php?group_id=198487)
- [Subscribe to Tidelift](https://tidelift.com/subscription/pkg/packagist-phpseclib-phpseclib?utm_source=packagist-phpseclib-phpseclib&utm_medium=referral&utm_campaign=readme)
## Introduction
MIT-licensed pure-PHP implementations of an arbitrary-precision integer MIT-licensed pure-PHP implementations of an arbitrary-precision integer
arithmetic library, fully PKCS#1 (v2.1) compliant RSA, DES, 3DES, RC4, Rijndael, arithmetic library, fully PKCS#1 (v2.1) compliant RSA, DES, 3DES, RC4, Rijndael,
AES, Blowfish, Twofish, SSH-1, SSH-2, SFTP, and X.509 AES, Blowfish, Twofish, SSH-1, SSH-2, SFTP, and X.509
@ -24,19 +32,24 @@ AES, Blowfish, Twofish, SSH-1, SSH-2, SFTP, and X.509
### 2.0 ### 2.0
* Long term support (LTS) release
* Modernized version of 1.0 * Modernized version of 1.0
* Minimum PHP version: 5.3.3 * Minimum PHP version: 5.3.3
* PSR-4 autoloading with namespace rooted at `\phpseclib` * PSR-4 autoloading with namespace rooted at `\phpseclib`
* Install via Composer: `composer require phpseclib/phpseclib ~2.0` * Install via Composer: `composer require phpseclib/phpseclib:~2.0`
### 1.0 ### 1.0
* Long term support (LTS) release * Long term support (LTS) release
* PHP4 compatible * PHP4 compatible
* Composer compatible (PSR-0 autoloading) * Composer compatible (PSR-0 autoloading)
* Install using Composer: `composer require phpseclib/phpseclib ~1.0` * Install using Composer: `composer require phpseclib/phpseclib:~1.0`
* Install using PEAR: See [phpseclib PEAR Channel Documentation](http://phpseclib.sourceforge.net/pear.htm) * Install using PEAR: See [phpseclib PEAR Channel Documentation](http://phpseclib.sourceforge.net/pear.htm)
* [Download 1.0.10 as ZIP](http://sourceforge.net/projects/phpseclib/files/phpseclib1.0.10.zip/download) * [Download 1.0.16 as ZIP](http://sourceforge.net/projects/phpseclib/files/phpseclib1.0.16.zip/download)
## Security contact information
To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure.
## Support ## Support

View File

@ -0,0 +1,27 @@
build: false
shallow_clone: false
platform:
- x86
- x64
clone_folder: C:\projects\phpseclib
install:
- cinst -y OpenSSL.Light
- SET PATH=C:\Program Files\OpenSSL;%PATH%
- sc config wuauserv start= auto
- net start wuauserv
- cinst -y php --version 5.6.30
- cd c:\tools\php56
- copy php.ini-production php.ini
- echo date.timezone="UTC" >> php.ini
- echo extension_dir=ext >> php.ini
- echo extension=php_openssl.dll >> php.ini
- echo extension=php_gmp.dll >> php.ini
- cd C:\projects\phpseclib
- SET PATH=C:\tools\php56;%PATH%
- php.exe -r "readfile('http://getcomposer.org/installer');" | php.exe
- php.exe composer.phar install --prefer-source --no-interaction
test_script:
- cd C:\projects\phpseclib
- vendor\bin\phpunit.bat tests/Windows32Test.php

View File

@ -76,6 +76,10 @@ abstract class Base
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
*/ */
const MODE_CFB = 3; const MODE_CFB = 3;
/**
* Encrypt / decrypt using the Cipher Feedback mode (8bit)
*/
const MODE_CFB8 = 38;
/** /**
* Encrypt / decrypt using the Output Feedback mode. * Encrypt / decrypt using the Output Feedback mode.
* *
@ -479,6 +483,7 @@ abstract class Base
break; break;
case self::MODE_CTR: case self::MODE_CTR:
case self::MODE_CFB: case self::MODE_CFB:
case self::MODE_CFB8:
case self::MODE_OFB: case self::MODE_OFB:
case self::MODE_STREAM: case self::MODE_STREAM:
$this->mode = $mode; $this->mode = $mode;
@ -644,10 +649,10 @@ abstract class Base
case !function_exists('hash_algos'): case !function_exists('hash_algos'):
case !in_array($hash, hash_algos()): case !in_array($hash, hash_algos()):
$i = 1; $i = 1;
$hmac = new Hash();
$hmac->setHash($hash);
$hmac->setKey($password);
while (strlen($key) < $dkLen) { while (strlen($key) < $dkLen) {
$hmac = new Hash();
$hmac->setHash($hash);
$hmac->setKey($password);
$f = $u = $hmac->hash($salt . pack('N', $i++)); $f = $u = $hmac->hash($salt . pack('N', $i++));
for ($j = 2; $j <= $count; ++$j) { for ($j = 2; $j <= $count; ++$j) {
$u = $hmac->hash($u); $u = $hmac->hash($u);
@ -702,7 +707,7 @@ abstract class Base
case self::MODE_STREAM: case self::MODE_STREAM:
return openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options); return openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
case self::MODE_ECB: case self::MODE_ECB:
$result = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options); $result = @openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
return !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result; return !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result;
case self::MODE_CBC: case self::MODE_CBC:
$result = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->encryptIV); $result = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->encryptIV);
@ -762,6 +767,16 @@ abstract class Base
$iv = substr($ciphertext, -$this->block_size); $iv = substr($ciphertext, -$this->block_size);
} }
return $ciphertext;
case self::MODE_CFB8:
$ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->encryptIV);
if ($this->continuousBuffer) {
if (($len = strlen($ciphertext)) >= $this->block_size) {
$this->encryptIV = substr($ciphertext, -$this->block_size);
} else {
$this->encryptIV = substr($this->encryptIV, $len - $this->block_size) . substr($ciphertext, -$len);
}
}
return $ciphertext; return $ciphertext;
case self::MODE_OFB: case self::MODE_OFB:
return $this->_openssl_ofb_process($plaintext, $this->encryptIV, $this->enbuffer); return $this->_openssl_ofb_process($plaintext, $this->encryptIV, $this->enbuffer);
@ -942,6 +957,24 @@ abstract class Base
$pos = $len; $pos = $len;
} }
break; break;
case self::MODE_CFB8:
$ciphertext = '';
$len = strlen($plaintext);
$iv = $this->encryptIV;
for ($i = 0; $i < $len; ++$i) {
$ciphertext .= ($c = $plaintext[$i] ^ $this->_encryptBlock($iv));
$iv = substr($iv, 1) . $c;
}
if ($this->continuousBuffer) {
if ($len >= $block_size) {
$this->encryptIV = substr($ciphertext, -$block_size);
} else {
$this->encryptIV = substr($this->encryptIV, $len - $block_size) . substr($ciphertext, -$len);
}
}
break;
case self::MODE_OFB: case self::MODE_OFB:
$xor = $this->encryptIV; $xor = $this->encryptIV;
if (strlen($buffer['xor'])) { if (strlen($buffer['xor'])) {
@ -1007,14 +1040,14 @@ abstract class Base
break; break;
case self::MODE_ECB: case self::MODE_ECB:
if (!defined('OPENSSL_RAW_DATA')) { if (!defined('OPENSSL_RAW_DATA')) {
$ciphertext.= openssl_encrypt('', $this->cipher_name_openssl_ecb, $this->key, true); $ciphertext.= @openssl_encrypt('', $this->cipher_name_openssl_ecb, $this->key, true);
} }
$plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options); $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
break; break;
case self::MODE_CBC: case self::MODE_CBC:
if (!defined('OPENSSL_RAW_DATA')) { if (!defined('OPENSSL_RAW_DATA')) {
$padding = str_repeat(chr($this->block_size), $this->block_size) ^ substr($ciphertext, -$this->block_size); $padding = str_repeat(chr($this->block_size), $this->block_size) ^ substr($ciphertext, -$this->block_size);
$ciphertext.= substr(openssl_encrypt($padding, $this->cipher_name_openssl_ecb, $this->key, true), 0, $this->block_size); $ciphertext.= substr(@openssl_encrypt($padding, $this->cipher_name_openssl_ecb, $this->key, true), 0, $this->block_size);
$offset = 2 * $this->block_size; $offset = 2 * $this->block_size;
} else { } else {
$offset = $this->block_size; $offset = $this->block_size;
@ -1072,6 +1105,16 @@ abstract class Base
$iv = substr($ciphertext, -$this->block_size); $iv = substr($ciphertext, -$this->block_size);
} }
break; break;
case self::MODE_CFB8:
$plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->decryptIV);
if ($this->continuousBuffer) {
if (($len = strlen($ciphertext)) >= $this->block_size) {
$this->decryptIV = substr($ciphertext, -$this->block_size);
} else {
$this->decryptIV = substr($this->decryptIV, $len - $this->block_size) . substr($ciphertext, -$len);
}
}
break;
case self::MODE_OFB: case self::MODE_OFB:
$plaintext = $this->_openssl_ofb_process($ciphertext, $this->decryptIV, $this->debuffer); $plaintext = $this->_openssl_ofb_process($ciphertext, $this->decryptIV, $this->debuffer);
} }
@ -1235,6 +1278,24 @@ abstract class Base
$pos = $len; $pos = $len;
} }
break; break;
case self::MODE_CFB8:
$plaintext = '';
$len = strlen($ciphertext);
$iv = $this->decryptIV;
for ($i = 0; $i < $len; ++$i) {
$plaintext .= $ciphertext[$i] ^ $this->_encryptBlock($iv);
$iv = substr($iv, 1) . $ciphertext[$i];
}
if ($this->continuousBuffer) {
if ($len >= $block_size) {
$this->decryptIV = substr($ciphertext, -$block_size);
} else {
$this->decryptIV = substr($this->decryptIV, $len - $block_size) . substr($ciphertext, -$len);
}
}
break;
case self::MODE_OFB: case self::MODE_OFB:
$xor = $this->decryptIV; $xor = $this->decryptIV;
if (strlen($buffer['xor'])) { if (strlen($buffer['xor'])) {
@ -1297,7 +1358,7 @@ abstract class Base
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
$block = substr($plaintext, $i, $block_size); $block = substr($plaintext, $i, $block_size);
if (strlen($block) > strlen($buffer['ciphertext'])) { if (strlen($block) > strlen($buffer['ciphertext'])) {
$result = openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, $this->openssl_options); $result = @openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
$result = !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result; $result = !defined('OPENSSL_RAW_DATA') ? substr($result, 0, -$this->block_size) : $result;
$buffer['ciphertext'].= $result; $buffer['ciphertext'].= $result;
} }
@ -1308,7 +1369,7 @@ abstract class Base
} else { } else {
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
$block = substr($plaintext, $i, $block_size); $block = substr($plaintext, $i, $block_size);
$otp = openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, $this->openssl_options); $otp = @openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
$otp = !defined('OPENSSL_RAW_DATA') ? substr($otp, 0, -$this->block_size) : $otp; $otp = !defined('OPENSSL_RAW_DATA') ? substr($otp, 0, -$this->block_size) : $otp;
$this->_increment_str($xor); $this->_increment_str($xor);
$ciphertext.= $block ^ $otp; $ciphertext.= $block ^ $otp;
@ -1352,7 +1413,7 @@ abstract class Base
} }
if ($this->continuousBuffer) { if ($this->continuousBuffer) {
if (!defined('OPENSSL_RAW_DATA')) { if (!defined('OPENSSL_RAW_DATA')) {
$encryptIV.= openssl_encrypt('', $this->cipher_name_openssl_ecb, $key, $this->openssl_options); $encryptIV.= @openssl_encrypt('', $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
} }
$encryptIV = openssl_decrypt($encryptIV, $this->cipher_name_openssl_ecb, $key, $this->openssl_options); $encryptIV = openssl_decrypt($encryptIV, $this->cipher_name_openssl_ecb, $key, $this->openssl_options);
if ($overflow) { if ($overflow) {
@ -1435,6 +1496,8 @@ abstract class Base
return 'ctr'; return 'ctr';
case self::MODE_CFB: case self::MODE_CFB:
return 'cfb'; return 'cfb';
case self::MODE_CFB8:
return 'cfb8';
case self::MODE_OFB: case self::MODE_OFB:
return 'ofb'; return 'ofb';
} }
@ -1788,6 +1851,7 @@ abstract class Base
self::MODE_ECB => MCRYPT_MODE_ECB, self::MODE_ECB => MCRYPT_MODE_ECB,
self::MODE_CBC => MCRYPT_MODE_CBC, self::MODE_CBC => MCRYPT_MODE_CBC,
self::MODE_CFB => 'ncfb', self::MODE_CFB => 'ncfb',
self::MODE_CFB8 => MCRYPT_MODE_CFB,
self::MODE_OFB => MCRYPT_MODE_NOFB, self::MODE_OFB => MCRYPT_MODE_NOFB,
self::MODE_STREAM => MCRYPT_MODE_STREAM, self::MODE_STREAM => MCRYPT_MODE_STREAM,
); );
@ -2359,6 +2423,52 @@ abstract class Base
$_pos = $_len; $_pos = $_len;
} }
return $_plaintext;
';
break;
case self::MODE_CFB8:
$encrypt = $init_encrypt . '
$_ciphertext = "";
$_len = strlen($_text);
$_iv = $self->encryptIV;
for ($_i = 0; $_i < $_len; ++$_i) {
$in = $_iv;
'.$encrypt_block.'
$_ciphertext .= ($_c = $_text[$_i] ^ $in);
$_iv = substr($_iv, 1) . $_c;
}
if ($self->continuousBuffer) {
if ($_len >= '.$block_size.') {
$self->encryptIV = substr($_ciphertext, -'.$block_size.');
} else {
$self->encryptIV = substr($self->encryptIV, $_len - '.$block_size.') . substr($_ciphertext, -$_len);
}
}
return $_ciphertext;
';
$decrypt = $init_encrypt . '
$_plaintext = "";
$_len = strlen($_text);
$_iv = $self->decryptIV;
for ($_i = 0; $_i < $_len; ++$_i) {
$in = $_iv;
'.$encrypt_block.'
$_plaintext .= $_text[$_i] ^ $in;
$_iv = substr($_iv, 1) . $_text[$_i];
}
if ($self->continuousBuffer) {
if ($_len >= '.$block_size.') {
$self->decryptIV = substr($_text, -'.$block_size.');
} else {
$self->decryptIV = substr($self->decryptIV, $_len - '.$block_size.') . substr($_text, -$_len);
}
}
return $_plaintext; return $_plaintext;
'; ';
break; break;

View File

@ -112,6 +112,15 @@ class Hash
*/ */
var $key = false; var $key = false;
/**
* Computed Key
*
* @see self::_computeKey()
* @var string
* @access private
*/
var $computedKey = false;
/** /**
* Outer XOR (Internal HMAC) * Outer XOR (Internal HMAC)
* *
@ -130,6 +139,15 @@ class Hash
*/ */
var $ipad; var $ipad;
/**
* Engine
*
* @see self::setHash()
* @var string
* @access private
*/
var $engine;
/** /**
* Default Constructor. * Default Constructor.
* *
@ -166,6 +184,43 @@ class Hash
function setKey($key = false) function setKey($key = false)
{ {
$this->key = $key; $this->key = $key;
$this->_computeKey();
}
/**
* Pre-compute the key used by the HMAC
*
* Quoting http://tools.ietf.org/html/rfc2104#section-2, "Applications that use keys longer than B bytes
* will first hash the key using H and then use the resultant L byte string as the actual key to HMAC."
*
* As documented in https://www.reddit.com/r/PHP/comments/9nct2l/symfonypolyfill_hash_pbkdf2_correct_fix_for/
* when doing an HMAC multiple times it's faster to compute the hash once instead of computing it during
* every call
*
* @access private
*/
function _computeKey()
{
if ($this->key === false) {
$this->computedKey = false;
return;
}
if (strlen($this->key) <= $this->b) {
$this->computedKey = $this->key;
return;
}
switch ($this->engine) {
case self::MODE_MHASH:
$this->computedKey = mhash($this->hash, $this->key);
break;
case self::MODE_HASH:
$this->computedKey = hash($this->hash, $this->key, true);
break;
case self::MODE_INTERNAL:
$this->computedKey = call_user_func($this->hash, $this->key);
}
} }
/** /**
@ -216,19 +271,38 @@ class Hash
} }
switch ($hash) { switch ($hash) {
case 'md2-96':
case 'md2': case 'md2':
$mode = CRYPT_HASH_MODE == self::MODE_HASH && in_array('md2', hash_algos()) ? $this->b = 16;
case 'md5-96':
case 'sha1-96':
case 'sha224-96':
case 'sha256-96':
case 'md2':
case 'md5':
case 'sha1':
case 'sha224':
case 'sha256':
$this->b = 64;
break;
default:
$this->b = 128;
}
switch ($hash) {
case 'md2':
$this->engine = CRYPT_HASH_MODE == self::MODE_HASH && in_array('md2', hash_algos()) ?
self::MODE_HASH : self::MODE_INTERNAL; self::MODE_HASH : self::MODE_INTERNAL;
break; break;
case 'sha384': case 'sha384':
case 'sha512': case 'sha512':
$mode = CRYPT_HASH_MODE == self::MODE_MHASH ? self::MODE_INTERNAL : CRYPT_HASH_MODE; $this->engine = CRYPT_HASH_MODE == self::MODE_MHASH ? self::MODE_INTERNAL : CRYPT_HASH_MODE;
break; break;
default: default:
$mode = CRYPT_HASH_MODE; $this->engine = CRYPT_HASH_MODE;
} }
switch ($mode) { switch ($this->engine) {
case self::MODE_MHASH: case self::MODE_MHASH:
switch ($hash) { switch ($hash) {
case 'md5': case 'md5':
@ -241,6 +315,7 @@ class Hash
default: default:
$this->hash = MHASH_SHA1; $this->hash = MHASH_SHA1;
} }
$this->_computeKey(self::MODE_MHASH);
return; return;
case self::MODE_HASH: case self::MODE_HASH:
switch ($hash) { switch ($hash) {
@ -257,35 +332,33 @@ class Hash
default: default:
$this->hash = 'sha1'; $this->hash = 'sha1';
} }
$this->_computeKey(self::MODE_HASH);
return; return;
} }
switch ($hash) { switch ($hash) {
case 'md2': case 'md2':
$this->b = 16;
$this->hash = array($this, '_md2'); $this->hash = array($this, '_md2');
break; break;
case 'md5': case 'md5':
$this->b = 64;
$this->hash = array($this, '_md5'); $this->hash = array($this, '_md5');
break; break;
case 'sha256': case 'sha256':
$this->b = 64;
$this->hash = array($this, '_sha256'); $this->hash = array($this, '_sha256');
break; break;
case 'sha384': case 'sha384':
case 'sha512': case 'sha512':
$this->b = 128;
$this->hash = array($this, '_sha512'); $this->hash = array($this, '_sha512');
break; break;
case 'sha1': case 'sha1':
default: default:
$this->b = 64;
$this->hash = array($this, '_sha1'); $this->hash = array($this, '_sha1');
} }
$this->ipad = str_repeat(chr(0x36), $this->b); $this->ipad = str_repeat(chr(0x36), $this->b);
$this->opad = str_repeat(chr(0x5C), $this->b); $this->opad = str_repeat(chr(0x5C), $this->b);
$this->_computeKey(self::MODE_INTERNAL);
} }
/** /**
@ -297,33 +370,25 @@ class Hash
*/ */
function hash($text) function hash($text)
{ {
$mode = is_array($this->hash) ? self::MODE_INTERNAL : CRYPT_HASH_MODE;
if (!empty($this->key) || is_string($this->key)) { if (!empty($this->key) || is_string($this->key)) {
switch ($mode) { switch ($this->engine) {
case self::MODE_MHASH: case self::MODE_MHASH:
$output = mhash($this->hash, $text, $this->key); $output = mhash($this->hash, $text, $this->computedKey);
break; break;
case self::MODE_HASH: case self::MODE_HASH:
$output = hash_hmac($this->hash, $text, $this->key, true); $output = hash_hmac($this->hash, $text, $this->computedKey, true);
break; break;
case self::MODE_INTERNAL: case self::MODE_INTERNAL:
/* "Applications that use keys longer than B bytes will first hash the key using H and then use the $key = str_pad($this->computedKey, $this->b, chr(0)); // step 1
resultant L byte string as the actual key to HMAC." $temp = $this->ipad ^ $key; // step 2
$temp .= $text; // step 3
-- http://tools.ietf.org/html/rfc2104#section-2 */ $temp = call_user_func($this->hash, $temp); // step 4
$key = strlen($this->key) > $this->b ? call_user_func($this->hash, $this->key) : $this->key; $output = $this->opad ^ $key; // step 5
$output.= $temp; // step 6
$key = str_pad($key, $this->b, chr(0)); // step 1 $output = call_user_func($this->hash, $output); // step 7
$temp = $this->ipad ^ $key; // step 2
$temp .= $text; // step 3
$temp = call_user_func($this->hash, $temp); // step 4
$output = $this->opad ^ $key; // step 5
$output.= $temp; // step 6
$output = call_user_func($this->hash, $output); // step 7
} }
} else { } else {
switch ($mode) { switch ($this->engine) {
case self::MODE_MHASH: case self::MODE_MHASH:
$output = mhash($this->hash, $text); $output = mhash($this->hash, $text);
break; break;

View File

@ -182,6 +182,10 @@ class RSA
* PKCS#8 formatted private key * PKCS#8 formatted private key
*/ */
const PRIVATE_FORMAT_PKCS8 = 8; const PRIVATE_FORMAT_PKCS8 = 8;
/**
* OpenSSH formatted private key
*/
const PRIVATE_FORMAT_OPENSSH = 9;
/**#@-*/ /**#@-*/
/**#@+ /**#@+
@ -468,23 +472,27 @@ class RSA
break; break;
case extension_loaded('openssl') && file_exists($this->configFile): case extension_loaded('openssl') && file_exists($this->configFile):
// some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work // some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work
ob_start();
@phpinfo();
$content = ob_get_contents();
ob_end_clean();
preg_match_all('#OpenSSL (Header|Library) Version(.*)#im', $content, $matches);
$versions = array(); $versions = array();
if (!empty($matches[1])) {
for ($i = 0; $i < count($matches[1]); $i++) {
$fullVersion = trim(str_replace('=>', '', strip_tags($matches[2][$i])));
// Remove letter part in OpenSSL version // avoid generating errors (even with suppression) when phpinfo() is disabled (common in production systems)
if (!preg_match('/(\d+\.\d+\.\d+)/i', $fullVersion, $m)) { if (strpos(ini_get('disable_functions'), 'phpinfo') === false) {
$versions[$matches[1][$i]] = $fullVersion; ob_start();
} else { @phpinfo();
$versions[$matches[1][$i]] = $m[0]; $content = ob_get_contents();
ob_end_clean();
preg_match_all('#OpenSSL (Header|Library) Version(.*)#im', $content, $matches);
if (!empty($matches[1])) {
for ($i = 0; $i < count($matches[1]); $i++) {
$fullVersion = trim(str_replace('=>', '', strip_tags($matches[2][$i])));
// Remove letter part in OpenSSL version
if (!preg_match('/(\d+\.\d+\.\d+)/i', $fullVersion, $m)) {
$versions[$matches[1][$i]] = $fullVersion;
} else {
$versions[$matches[1][$i]] = $m[0];
}
} }
} }
} }
@ -816,6 +824,58 @@ class RSA
$key.= 'Private-MAC: ' . bin2hex($hash->hash($source)) . "\r\n"; $key.= 'Private-MAC: ' . bin2hex($hash->hash($source)) . "\r\n";
return $key; return $key;
case self::PRIVATE_FORMAT_OPENSSH:
if ($num_primes != 2) {
return false;
}
$publicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($raw['publicExponent']), $raw['publicExponent'], strlen($raw['modulus']), $raw['modulus']);
$privateKey = pack(
'Na*Na*Na*Na*Na*Na*Na*',
strlen('ssh-rsa'),
'ssh-rsa',
strlen($raw['modulus']),
$raw['modulus'],
strlen($raw['publicExponent']),
$raw['publicExponent'],
strlen($raw['privateExponent']),
$raw['privateExponent'],
strlen($raw['coefficient']),
$raw['coefficient'],
strlen($raw['prime1']),
$raw['prime1'],
strlen($raw['prime2']),
$raw['prime2']
);
$checkint = Random::string(4);
$paddedKey = pack(
'a*Na*',
$checkint . $checkint . $privateKey,
strlen($this->comment),
$this->comment
);
$paddingLength = (7 * strlen($paddedKey)) % 8;
for ($i = 1; $i <= $paddingLength; $i++) {
$paddedKey.= chr($i);
}
$key = pack(
'Na*Na*Na*NNa*Na*',
strlen('none'),
'none',
strlen('none'),
'none',
0,
'',
1,
strlen($publicKey),
$publicKey,
strlen($paddedKey),
$paddedKey
);
$key = "openssh-key-v1\0$key";
return "-----BEGIN OPENSSH PRIVATE KEY-----\r\n" .
chunk_split(base64_encode($key), 70) .
"-----END OPENSSH PRIVATE KEY-----";
default: // eg. self::PRIVATE_FORMAT_PKCS1 default: // eg. self::PRIVATE_FORMAT_PKCS1
$components = array(); $components = array();
foreach ($raw as $name => $value) { foreach ($raw as $name => $value) {
@ -1016,9 +1076,9 @@ class RSA
* @access private * @access private
* @see self::_convertPublicKey() * @see self::_convertPublicKey()
* @see self::_convertPrivateKey() * @see self::_convertPrivateKey()
* @param string $key * @param string|array $key
* @param int $type * @param int $type
* @return array * @return array|bool
*/ */
function _parseKey($key, $type) function _parseKey($key, $type)
{ {
@ -1329,9 +1389,14 @@ class RSA
xml_set_character_data_handler($xml, '_data_handler'); xml_set_character_data_handler($xml, '_data_handler');
// add <xml></xml> to account for "dangling" tags like <BitStrength>...</BitStrength> that are sometimes added // add <xml></xml> to account for "dangling" tags like <BitStrength>...</BitStrength> that are sometimes added
if (!xml_parse($xml, '<xml>' . $key . '</xml>')) { if (!xml_parse($xml, '<xml>' . $key . '</xml>')) {
xml_parser_free($xml);
unset($xml);
return false; return false;
} }
xml_parser_free($xml);
unset($xml);
return isset($this->components['modulus']) && isset($this->components['publicExponent']) ? $this->components : false; return isset($this->components['modulus']) && isset($this->components['publicExponent']) ? $this->components : false;
// from PuTTY's SSHPUBK.C // from PuTTY's SSHPUBK.C
case self::PRIVATE_FORMAT_PUTTY: case self::PRIVATE_FORMAT_PUTTY:
@ -1403,6 +1468,75 @@ class RSA
} }
$components['coefficients'] = array(2 => new BigInteger($this->_string_shift($private, $length), -256)); $components['coefficients'] = array(2 => new BigInteger($this->_string_shift($private, $length), -256));
return $components;
case self::PRIVATE_FORMAT_OPENSSH:
$components = array();
$decoded = $this->_extractBER($key);
$magic = $this->_string_shift($decoded, 15);
if ($magic !== "openssh-key-v1\0") {
return false;
}
$options = $this->_string_shift($decoded, 24);
// \0\0\0\4none = ciphername
// \0\0\0\4none = kdfname
// \0\0\0\0 = kdfoptions
// \0\0\0\1 = numkeys
if ($options != "\0\0\0\4none\0\0\0\4none\0\0\0\0\0\0\0\1") {
return false;
}
extract(unpack('Nlength', $this->_string_shift($decoded, 4)));
if (strlen($decoded) < $length) {
return false;
}
$publicKey = $this->_string_shift($decoded, $length);
extract(unpack('Nlength', $this->_string_shift($decoded, 4)));
if (strlen($decoded) < $length) {
return false;
}
$paddedKey = $this->_string_shift($decoded, $length);
if ($this->_string_shift($publicKey, 11) !== "\0\0\0\7ssh-rsa") {
return false;
}
$checkint1 = $this->_string_shift($paddedKey, 4);
$checkint2 = $this->_string_shift($paddedKey, 4);
if (strlen($checkint1) != 4 || $checkint1 !== $checkint2) {
return false;
}
if ($this->_string_shift($paddedKey, 11) !== "\0\0\0\7ssh-rsa") {
return false;
}
$values = array(
&$components['modulus'],
&$components['publicExponent'],
&$components['privateExponent'],
&$components['coefficients'][2],
&$components['primes'][1],
&$components['primes'][2]
);
foreach ($values as &$value) {
extract(unpack('Nlength', $this->_string_shift($paddedKey, 4)));
if (strlen($paddedKey) < $length) {
return false;
}
$value = new BigInteger($this->_string_shift($paddedKey, $length), -256);
}
extract(unpack('Nlength', $this->_string_shift($paddedKey, 4)));
if (strlen($paddedKey) < $length) {
return false;
}
$components['comment'] = $this->_string_shift($decoded, $length);
$temp = $components['primes'][1]->subtract($this->one);
$components['exponents'] = array(1 => $components['publicExponent']->modInverse($temp));
$temp = $components['primes'][2]->subtract($this->one);
$components['exponents'][] = $components['publicExponent']->modInverse($temp);
return $components; return $components;
} }
} }
@ -1501,8 +1635,9 @@ class RSA
* Returns true on success and false on failure (ie. an incorrect password was provided or the key was malformed) * Returns true on success and false on failure (ie. an incorrect password was provided or the key was malformed)
* *
* @access public * @access public
* @param string $key * @param string|RSA|array $key
* @param int $type optional * @param bool|int $type optional
* @return bool
*/ */
function loadKey($key, $type = false) function loadKey($key, $type = false)
{ {
@ -1559,7 +1694,8 @@ class RSA
self::PRIVATE_FORMAT_PKCS1, self::PRIVATE_FORMAT_PKCS1,
self::PRIVATE_FORMAT_XML, self::PRIVATE_FORMAT_XML,
self::PRIVATE_FORMAT_PUTTY, self::PRIVATE_FORMAT_PUTTY,
self::PUBLIC_FORMAT_OPENSSH self::PUBLIC_FORMAT_OPENSSH,
self::PRIVATE_FORMAT_OPENSSH
); );
foreach ($types as $type) { foreach ($types as $type) {
$components = $this->_parseKey($key, $type); $components = $this->_parseKey($key, $type);
@ -2207,16 +2343,21 @@ class RSA
*/ */
function _equals($x, $y) function _equals($x, $y)
{ {
if (function_exists('hash_equals')) {
return hash_equals($x, $y);
}
if (strlen($x) != strlen($y)) { if (strlen($x) != strlen($y)) {
return false; return false;
} }
$result = 0; $result = "\0";
$x^= $y;
for ($i = 0; $i < strlen($x); $i++) { for ($i = 0; $i < strlen($x); $i++) {
$result |= ord($x[$i]) ^ ord($y[$i]); $result|= $x[$i];
} }
return $result == 0; return $result === "\0";
} }
/** /**
@ -2423,19 +2564,26 @@ class RSA
$db = $maskedDB ^ $dbMask; $db = $maskedDB ^ $dbMask;
$lHash2 = substr($db, 0, $this->hLen); $lHash2 = substr($db, 0, $this->hLen);
$m = substr($db, $this->hLen); $m = substr($db, $this->hLen);
if (!$this->_equals($lHash, $lHash2)) { $hashesMatch = $this->_equals($lHash, $lHash2);
user_error('Decryption error'); $leadingZeros = 1;
return false; $patternMatch = 0;
$offset = 0;
for ($i = 0; $i < strlen($m); $i++) {
$patternMatch|= $leadingZeros & ($m[$i] === "\1");
$leadingZeros&= $m[$i] === "\0";
$offset+= $patternMatch ? 0 : 1;
} }
$m = ltrim($m, chr(0));
if (ord($m[0]) != 1) { // we do & instead of && to avoid https://en.wikipedia.org/wiki/Short-circuit_evaluation
// to protect against timing attacks
if (!$hashesMatch & !$patternMatch) {
user_error('Decryption error'); user_error('Decryption error');
return false; return false;
} }
// Output the message M // Output the message M
return substr($m, 1); return substr($m, $offset + 1);
} }
/** /**

View File

@ -244,9 +244,10 @@ class ASN1
$tag = 0; $tag = 0;
// process septets (since the eighth bit is ignored, it's not an octet) // process septets (since the eighth bit is ignored, it's not an octet)
do { do {
$loop = ord($encoded[0]) >> 7; $temp = ord($encoded[$encoded_pos++]);
$loop = $temp >> 7;
$tag <<= 7; $tag <<= 7;
$tag |= ord($encoded[$encoded_pos++]) & 0x7F; $tag |= $temp & 0x7F;
$start++; $start++;
} while ($loop); } while ($loop);
} }
@ -308,6 +309,9 @@ class ASN1
$remainingLength = $length; $remainingLength = $length;
while ($remainingLength > 0) { while ($remainingLength > 0) {
$temp = $this->_decode_ber($content, $start, $content_pos); $temp = $this->_decode_ber($content, $start, $content_pos);
if ($temp === false) {
break;
}
$length = $temp['length']; $length = $temp['length'];
// end-of-content octets - see paragraph 8.1.5 // end-of-content octets - see paragraph 8.1.5
if (substr($content, $content_pos + $length, 2) == "\0\0") { if (substr($content, $content_pos + $length, 2) == "\0\0") {
@ -359,6 +363,9 @@ class ASN1
$current['content'] = substr($content, $content_pos); $current['content'] = substr($content, $content_pos);
} else { } else {
$temp = $this->_decode_ber($content, $start, $content_pos); $temp = $this->_decode_ber($content, $start, $content_pos);
if ($temp === false) {
return false;
}
$length-= (strlen($content) - $content_pos); $length-= (strlen($content) - $content_pos);
$last = count($temp) - 1; $last = count($temp) - 1;
for ($i = 0; $i < $last; $i++) { for ($i = 0; $i < $last; $i++) {
@ -383,6 +390,9 @@ class ASN1
$length = 0; $length = 0;
while (substr($content, $content_pos, 2) != "\0\0") { while (substr($content, $content_pos, 2) != "\0\0") {
$temp = $this->_decode_ber($content, $length + $start, $content_pos); $temp = $this->_decode_ber($content, $length + $start, $content_pos);
if ($temp === false) {
return false;
}
$content_pos += $temp['length']; $content_pos += $temp['length'];
// all subtags should be octet strings // all subtags should be octet strings
//if ($temp['type'] != self::TYPE_OCTET_STRING) { //if ($temp['type'] != self::TYPE_OCTET_STRING) {
@ -415,30 +425,16 @@ class ASN1
break 2; break 2;
} }
$temp = $this->_decode_ber($content, $start + $offset, $content_pos); $temp = $this->_decode_ber($content, $start + $offset, $content_pos);
if ($temp === false) {
return false;
}
$content_pos += $temp['length']; $content_pos += $temp['length'];
$current['content'][] = $temp; $current['content'][] = $temp;
$offset+= $temp['length']; $offset+= $temp['length'];
} }
break; break;
case self::TYPE_OBJECT_IDENTIFIER: case self::TYPE_OBJECT_IDENTIFIER:
$temp = ord($content[$content_pos++]); $current['content'] = $this->_decodeOID(substr($content, $content_pos));
$current['content'] = sprintf('%d.%d', floor($temp / 40), $temp % 40);
$valuen = 0;
// process septets
$content_len = strlen($content);
while ($content_pos < $content_len) {
$temp = ord($content[$content_pos++]);
$valuen <<= 7;
$valuen |= $temp & 0x7F;
if (~$temp & 0x80) {
$current['content'].= ".$valuen";
$valuen = 0;
}
}
// the eighth bit of the last byte should not be 1
//if ($temp >> 7) {
// return false;
//}
break; break;
/* Each character string type shall be encoded as if it had been declared: /* Each character string type shall be encoded as if it had been declared:
[UNIVERSAL x] IMPLICIT OCTET STRING [UNIVERSAL x] IMPLICIT OCTET STRING
@ -582,7 +578,7 @@ class ASN1
$childClass = $tempClass = self::CLASS_UNIVERSAL; $childClass = $tempClass = self::CLASS_UNIVERSAL;
$constant = null; $constant = null;
if (isset($temp['constant'])) { if (isset($temp['constant'])) {
$tempClass = isset($temp['class']) ? $temp['class'] : self::CLASS_CONTEXT_SPECIFIC; $tempClass = $temp['type'];
} }
if (isset($child['class'])) { if (isset($child['class'])) {
$childClass = $child['class']; $childClass = $child['class'];
@ -645,7 +641,7 @@ class ASN1
$temp = $decoded['content'][$i]; $temp = $decoded['content'][$i];
$tempClass = self::CLASS_UNIVERSAL; $tempClass = self::CLASS_UNIVERSAL;
if (isset($temp['constant'])) { if (isset($temp['constant'])) {
$tempClass = isset($temp['class']) ? $temp['class'] : self::CLASS_CONTEXT_SPECIFIC; $tempClass = $temp['type'];
} }
foreach ($mapping['children'] as $key => $child) { foreach ($mapping['children'] as $key => $child) {
@ -1001,27 +997,7 @@ class ASN1
$value = base64_decode($source); $value = base64_decode($source);
break; break;
case self::TYPE_OBJECT_IDENTIFIER: case self::TYPE_OBJECT_IDENTIFIER:
$oid = preg_match('#(?:\d+\.)+#', $source) ? $source : array_search($source, $this->oids); $value = $this->_encodeOID($source);
if ($oid === false) {
user_error('Invalid OID');
return false;
}
$value = '';
$parts = explode('.', $oid);
$value = chr(40 * $parts[0] + $parts[1]);
for ($i = 2; $i < count($parts); $i++) {
$temp = '';
if (!$parts[$i]) {
$temp = "\0";
} else {
while ($parts[$i]) {
$temp = chr(0x80 | ($parts[$i] & 0x7F)) . $temp;
$parts[$i] >>= 7;
}
$temp[strlen($temp) - 1] = $temp[strlen($temp) - 1] & chr(0x7F);
}
$value.= $temp;
}
break; break;
case self::TYPE_ANY: case self::TYPE_ANY:
$loc = $this->location; $loc = $this->location;
@ -1120,6 +1096,108 @@ class ASN1
return pack('Ca*', 0x80 | strlen($temp), $temp); return pack('Ca*', 0x80 | strlen($temp), $temp);
} }
/**
* BER-decode the OID
*
* Called by _decode_ber()
*
* @access private
* @param string $content
* @return string
*/
function _decodeOID($content)
{
static $eighty;
if (!$eighty) {
$eighty = new BigInteger(80);
}
$oid = array();
$pos = 0;
$len = strlen($content);
$n = new BigInteger();
while ($pos < $len) {
$temp = ord($content[$pos++]);
$n = $n->bitwise_leftShift(7);
$n = $n->bitwise_or(new BigInteger($temp & 0x7F));
if (~$temp & 0x80) {
$oid[] = $n;
$n = new BigInteger();
}
}
$part1 = array_shift($oid);
$first = floor(ord($content[0]) / 40);
/*
"This packing of the first two object identifier components recognizes that only three values are allocated from the root
node, and at most 39 subsequent values from nodes reached by X = 0 and X = 1."
-- https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=22
*/
if ($first <= 2) { // ie. 0 <= ord($content[0]) < 120 (0x78)
array_unshift($oid, ord($content[0]) % 40);
array_unshift($oid, $first);
} else {
array_unshift($oid, $part1->subtract($eighty));
array_unshift($oid, 2);
}
return implode('.', $oid);
}
/**
* DER-encode the OID
*
* Called by _encode_der()
*
* @access private
* @param string $content
* @return string
*/
function _encodeOID($source)
{
static $mask, $zero, $forty;
if (!$mask) {
$mask = new BigInteger(0x7F);
$zero = new BigInteger();
$forty = new BigInteger(40);
}
$oid = preg_match('#(?:\d+\.)+#', $source) ? $source : array_search($source, $this->oids);
if ($oid === false) {
user_error('Invalid OID');
return false;
}
$parts = explode('.', $oid);
$part1 = array_shift($parts);
$part2 = array_shift($parts);
$first = new BigInteger($part1);
$first = $first->multiply($forty);
$first = $first->add(new BigInteger($part2));
array_unshift($parts, $first->toString());
$value = '';
foreach ($parts as $part) {
if (!$part) {
$temp = "\0";
} else {
$temp = '';
$part = new BigInteger($part);
while (!$part->equals($zero)) {
$submask = $part->bitwise_and($mask);
$submask->setPrecision(8);
$temp = (chr(0x80) | $submask->toBytes()) . $temp;
$part = $part->bitwise_rightShift(7);
}
$temp[strlen($temp) - 1] = $temp[strlen($temp) - 1] & chr(0x7F);
}
$value.= $temp;
}
return $value;
}
/** /**
* BER-decode the time * BER-decode the time
* *

View File

@ -305,6 +305,22 @@ class X509
*/ */
var $challenge; var $challenge;
/**
* Recursion Limit
*
* @var int
* @access private
*/
static $recur_limit = 5;
/**
* URL fetch flag
*
* @var bool
* @access private
*/
static $disable_url_fetch = false;
/** /**
* Default Constructor. * Default Constructor.
* *
@ -1912,6 +1928,9 @@ class X509
// "Certificate Transparency" // "Certificate Transparency"
// https://tools.ietf.org/html/rfc6962 // https://tools.ietf.org/html/rfc6962
case '1.3.6.1.4.1.11129.2.4.2': case '1.3.6.1.4.1.11129.2.4.2':
// "Qualified Certificate statements"
// https://tools.ietf.org/html/rfc3739#section-3.2.6
case '1.3.6.1.5.5.7.1.3':
return true; return true;
// CSR attributes // CSR attributes
@ -2076,7 +2095,7 @@ class X509
* *
* If $date isn't defined it is assumed to be the current date. * If $date isn't defined it is assumed to be the current date.
* *
* @param int $date optional * @param \DateTime|string $date optional
* @access public * @access public
*/ */
function validateDate($date = null) function validateDate($date = null)
@ -2086,7 +2105,7 @@ class X509
} }
if (!isset($date)) { if (!isset($date)) {
$date = new DateTime($date, new DateTimeZone(@date_default_timezone_get())); $date = new DateTime(null, new DateTimeZone(@date_default_timezone_get()));
} }
$notBefore = $this->currentCert['tbsCertificate']['validity']['notBefore']; $notBefore = $this->currentCert['tbsCertificate']['validity']['notBefore'];
@ -2095,15 +2114,133 @@ class X509
$notAfter = $this->currentCert['tbsCertificate']['validity']['notAfter']; $notAfter = $this->currentCert['tbsCertificate']['validity']['notAfter'];
$notAfter = isset($notAfter['generalTime']) ? $notAfter['generalTime'] : $notAfter['utcTime']; $notAfter = isset($notAfter['generalTime']) ? $notAfter['generalTime'] : $notAfter['utcTime'];
if (is_string($date)) {
$date = new DateTime($date, new DateTimeZone(@date_default_timezone_get()));
}
$notBefore = new DateTime($notBefore, new DateTimeZone(@date_default_timezone_get()));
$notAfter = new DateTime($notAfter, new DateTimeZone(@date_default_timezone_get()));
switch (true) { switch (true) {
case $date < new DateTime($notBefore, new DateTimeZone(@date_default_timezone_get())): case $date < $notBefore:
case $date > new DateTime($notAfter, new DateTimeZone(@date_default_timezone_get())): case $date > $notAfter:
return false; return false;
} }
return true; return true;
} }
/**
* Fetches a URL
*
* @param string $url
* @access private
* @return bool|string
*/
static function _fetchURL($url)
{
if (self::$disable_url_fetch) {
return false;
}
$parts = parse_url($url);
$data = '';
switch ($parts['scheme']) {
case 'http':
$fsock = @fsockopen($parts['host'], isset($parts['port']) ? $parts['port'] : 80);
if (!$fsock) {
return false;
}
fputs($fsock, "GET $parts[path] HTTP/1.0\r\n");
fputs($fsock, "Host: $parts[host]\r\n\r\n");
$line = fgets($fsock, 1024);
if (strlen($line) < 3) {
return false;
}
preg_match('#HTTP/1.\d (\d{3})#', $line, $temp);
if ($temp[1] != '200') {
return false;
}
// skip the rest of the headers in the http response
while (!feof($fsock) && fgets($fsock, 1024) != "\r\n") {
}
while (!feof($fsock)) {
$data.= fread($fsock, 1024);
}
break;
//case 'ftp':
//case 'ldap':
//default:
}
return $data;
}
/**
* Validates an intermediate cert as identified via authority info access extension
*
* See https://tools.ietf.org/html/rfc4325 for more info
*
* @param bool $caonly
* @param int $count
* @access private
* @return bool
*/
function _testForIntermediate($caonly, $count)
{
$opts = $this->getExtension('id-pe-authorityInfoAccess');
if (!is_array($opts)) {
return false;
}
foreach ($opts as $opt) {
if ($opt['accessMethod'] == 'id-ad-caIssuers') {
// accessLocation is a GeneralName. GeneralName fields support stuff like email addresses, IP addresses, LDAP,
// etc, but we're only supporting URI's. URI's and LDAP are the only thing https://tools.ietf.org/html/rfc4325
// discusses
if (isset($opt['accessLocation']['uniformResourceIdentifier'])) {
$url = $opt['accessLocation']['uniformResourceIdentifier'];
break;
}
}
}
if (!isset($url)) {
return false;
}
$cert = static::_fetchURL($url);
if (!is_string($cert)) {
return false;
}
$parent = new static();
$parent->CAs = $this->CAs;
/*
"Conforming applications that support HTTP or FTP for accessing
certificates MUST be able to accept .cer files and SHOULD be able
to accept .p7c files." -- https://tools.ietf.org/html/rfc4325
A .p7c file is 'a "certs-only" CMS message as specified in RFC 2797"
These are currently unsupported
*/
if (!is_array($parent->loadX509($cert))) {
return false;
}
if (!$parent->_validateSignatureCountable($caonly, ++$count)) {
return false;
}
$this->CAs[] = $parent->currentCert;
//$this->loadCA($cert);
return true;
}
/** /**
* Validate a signature * Validate a signature
* *
@ -2120,11 +2257,30 @@ class X509
* @return mixed * @return mixed
*/ */
function validateSignature($caonly = true) function validateSignature($caonly = true)
{
return $this->_validateSignatureCountable($caonly, 0);
}
/**
* Validate a signature
*
* Performs said validation whilst keeping track of how many times validation method is called
*
* @param bool $caonly
* @param int $count
* @access private
* @return mixed
*/
function _validateSignatureCountable($caonly, $count)
{ {
if (!is_array($this->currentCert) || !isset($this->signatureSubject)) { if (!is_array($this->currentCert) || !isset($this->signatureSubject)) {
return null; return null;
} }
if ($count == self::$recur_limit) {
return false;
}
/* TODO: /* TODO:
"emailAddress attribute values are not case-sensitive (e.g., "subscriber@example.com" is the same as "SUBSCRIBER@EXAMPLE.COM")." "emailAddress attribute values are not case-sensitive (e.g., "subscriber@example.com" is the same as "SUBSCRIBER@EXAMPLE.COM")."
-- http://tools.ietf.org/html/rfc5280#section-4.1.2.6 -- http://tools.ietf.org/html/rfc5280#section-4.1.2.6
@ -2170,10 +2326,10 @@ class X509
} }
} }
if (count($this->CAs) == $i && $caonly) { if (count($this->CAs) == $i && $caonly) {
return false; return $this->_testForIntermediate($caonly, $count) && $this->validateSignature($caonly);
} }
} elseif (!isset($signingCert) || $caonly) { } elseif (!isset($signingCert) || $caonly) {
return false; return $this->_testForIntermediate($caonly, $count) && $this->validateSignature($caonly);
} }
return $this->_validateSignature( return $this->_validateSignature(
$signingCert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'], $signingCert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'],
@ -2280,6 +2436,41 @@ class X509
return true; return true;
} }
/**
* Sets the recursion limit
*
* When validating a signature it may be necessary to download intermediate certs from URI's.
* An intermediate cert that linked to itself would result in an infinite loop so to prevent
* that we set a recursion limit. A negative number means that there is no recursion limit.
*
* @param int $count
* @access public
*/
static function setRecurLimit($count)
{
self::$recur_limit = $count;
}
/**
* Prevents URIs from being automatically retrieved
*
* @access public
*/
static function disableURLFetch()
{
self::$disable_url_fetch = true;
}
/**
* Allows URIs to be automatically retrieved
*
* @access public
*/
static function enableURLFetch()
{
self::$disable_url_fetch = false;
}
/** /**
* Reformat public keys * Reformat public keys
* *
@ -2739,7 +2930,7 @@ class X509
} }
$output.= $desc . '=' . $value; $output.= $desc . '=' . $value;
$result[$desc] = isset($result[$desc]) ? $result[$desc] = isset($result[$desc]) ?
array_merge((array) $dn[$prop], array($value)) : array_merge((array) $result[$desc], array($value)) :
$value; $value;
$start = false; $start = false;
} }
@ -3447,7 +3638,7 @@ class X509
'tbsCertificate' => 'tbsCertificate' =>
array( array(
'version' => 'v3', 'version' => 'v3',
'serialNumber' => $serialNumber, // $this->setserialNumber() 'serialNumber' => $serialNumber, // $this->setSerialNumber()
'signature' => array('algorithm' => $signatureAlgorithm), 'signature' => array('algorithm' => $signatureAlgorithm),
'issuer' => false, // this is going to be overwritten later 'issuer' => false, // this is going to be overwritten later
'validity' => array( 'validity' => array(

View File

@ -45,7 +45,6 @@
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright 2006 Jim Wigginton * @copyright 2006 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/ */
namespace phpseclib\Math; namespace phpseclib\Math;
@ -266,23 +265,27 @@ class BigInteger
if (extension_loaded('openssl') && !defined('MATH_BIGINTEGER_OPENSSL_DISABLE') && !defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) { if (extension_loaded('openssl') && !defined('MATH_BIGINTEGER_OPENSSL_DISABLE') && !defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
// some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work // some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work
ob_start();
@phpinfo();
$content = ob_get_contents();
ob_end_clean();
preg_match_all('#OpenSSL (Header|Library) Version(.*)#im', $content, $matches);
$versions = array(); $versions = array();
if (!empty($matches[1])) {
for ($i = 0; $i < count($matches[1]); $i++) {
$fullVersion = trim(str_replace('=>', '', strip_tags($matches[2][$i])));
// Remove letter part in OpenSSL version // avoid generating errors (even with suppression) when phpinfo() is disabled (common in production systems)
if (!preg_match('/(\d+\.\d+\.\d+)/i', $fullVersion, $m)) { if (strpos(ini_get('disable_functions'), 'phpinfo') === false) {
$versions[$matches[1][$i]] = $fullVersion; ob_start();
} else { @phpinfo();
$versions[$matches[1][$i]] = $m[0]; $content = ob_get_contents();
ob_end_clean();
preg_match_all('#OpenSSL (Header|Library) Version(.*)#im', $content, $matches);
if (!empty($matches[1])) {
for ($i = 0; $i < count($matches[1]); $i++) {
$fullVersion = trim(str_replace('=>', '', strip_tags($matches[2][$i])));
// Remove letter part in OpenSSL version
if (!preg_match('/(\d+\.\d+\.\d+)/i', $fullVersion, $m)) {
$versions[$matches[1][$i]] = $fullVersion;
} else {
$versions[$matches[1][$i]] = $m[0];
}
} }
} }
} }
@ -442,6 +445,9 @@ class BigInteger
// (?<=^|-)0*: find any 0's that are preceded by the start of the string or by a - (ie. octals) // (?<=^|-)0*: find any 0's that are preceded by the start of the string or by a - (ie. octals)
// [^-0-9].*: find any non-numeric characters and then any characters that follow that // [^-0-9].*: find any non-numeric characters and then any characters that follow that
$x = preg_replace('#(?<!^)(?:-).*|(?<=^|-)0*|[^-0-9].*#', '', $x); $x = preg_replace('#(?<!^)(?:-).*|(?<=^|-)0*|[^-0-9].*#', '', $x);
if (!strlen($x) || $x == '-') {
$x = '0';
}
switch (MATH_BIGINTEGER_MODE) { switch (MATH_BIGINTEGER_MODE) {
case self::MODE_GMP: case self::MODE_GMP:
@ -535,7 +541,7 @@ class BigInteger
$temp = $comparison < 0 ? $this->add(new static(1)) : $this->copy(); $temp = $comparison < 0 ? $this->add(new static(1)) : $this->copy();
$bytes = $temp->toBytes(); $bytes = $temp->toBytes();
if (empty($bytes)) { // eg. if the number we're trying to convert is -1 if (!strlen($bytes)) { // eg. if the number we're trying to convert is -1
$bytes = chr(0); $bytes = chr(0);
} }
@ -1555,7 +1561,9 @@ class BigInteger
$temp_value = array($quotient_value[$q_index]); $temp_value = array($quotient_value[$q_index]);
$temp = $temp->multiply($y); $temp = $temp->multiply($y);
$temp_value = &$temp->value; $temp_value = &$temp->value;
$temp_value = array_merge($adjust, $temp_value); if (count($temp_value)) {
$temp_value = array_merge($adjust, $temp_value);
}
$x = $x->subtract($temp); $x = $x->subtract($temp);
@ -2688,7 +2696,14 @@ class BigInteger
{ {
switch (MATH_BIGINTEGER_MODE) { switch (MATH_BIGINTEGER_MODE) {
case self::MODE_GMP: case self::MODE_GMP:
return gmp_cmp($this->value, $y->value); $r = gmp_cmp($this->value, $y->value);
if ($r < -1) {
$r = -1;
}
if ($r > 1) {
$r = 1;
}
return $r;
case self::MODE_BCMATH: case self::MODE_BCMATH:
return bccomp($this->value, $y->value, 0); return bccomp($this->value, $y->value, 0);
} }
@ -3569,6 +3584,7 @@ class BigInteger
$value = &$result->value; $value = &$result->value;
if (!count($value)) { if (!count($value)) {
$result->is_negative = false;
return $result; return $result;
} }

View File

@ -144,6 +144,11 @@ class SCP
return false; return false;
} }
if (empty($remote_file)) {
user_error('remote_file cannot be blank', E_USER_NOTICE);
return false;
}
if (!$this->ssh->exec('scp -t ' . escapeshellarg($remote_file), false)) { // -t = to if (!$this->ssh->exec('scp -t ' . escapeshellarg($remote_file), false)) { // -t = to
return false; return false;
} }

View File

@ -109,11 +109,11 @@ class SFTP extends SSH2
* The request ID exists in the off chance that a packet is sent out-of-order. Of course, this library doesn't support * The request ID exists in the off chance that a packet is sent out-of-order. Of course, this library doesn't support
* concurrent actions, so it's somewhat academic, here. * concurrent actions, so it's somewhat academic, here.
* *
* @var int * @var boolean
* @see self::_send_sftp_packet() * @see self::_send_sftp_packet()
* @access private * @access private
*/ */
var $request_id = false; var $use_request_id = false;
/** /**
* The Packet Type * The Packet Type
@ -250,6 +250,15 @@ class SFTP extends SSH2
*/ */
var $canonicalize_paths = true; var $canonicalize_paths = true;
/**
* Request Buffers
*
* @see self::_get_sftp_packet()
* @var array
* @access private
*/
var $requestBuffer = array();
/** /**
* Default Constructor. * Default Constructor.
* *
@ -519,7 +528,7 @@ class SFTP extends SSH2
} }
*/ */
$this->request_id = 1; $this->use_request_id = true;
/* /*
A Note on SFTPv4/5/6 support: A Note on SFTPv4/5/6 support:
@ -833,6 +842,7 @@ class SFTP extends SSH2
} }
if (is_array($this->_query_stat_cache($this->_realpath($dir . '/' . $value)))) { if (is_array($this->_query_stat_cache($this->_realpath($dir . '/' . $value)))) {
$temp = $this->_nlist_helper($dir . '/' . $value, true, $relativeDir . $value . '/'); $temp = $this->_nlist_helper($dir . '/' . $value, true, $relativeDir . $value . '/');
$temp = is_array($temp) ? $temp : array();
$result = array_merge($result, $temp); $result = array_merge($result, $temp);
} else { } else {
$result[] = $relativeDir . $value; $result[] = $relativeDir . $value;
@ -864,7 +874,17 @@ class SFTP extends SSH2
unset($files[$key]); unset($files[$key]);
continue; continue;
} }
if ($key != '.' && $key != '..' && is_array($this->_query_stat_cache($this->_realpath($dir . '/' . $key)))) { $is_directory = false;
if ($key != '.' && $key != '..') {
if ($this->use_stat_cache) {
$is_directory = is_array($this->_query_stat_cache($this->_realpath($dir . '/' . $key)));
} else {
$stat = $this->lstat($dir . '/' . $key);
$is_directory = $stat && $stat['type'] === NET_SFTP_TYPE_DIRECTORY;
}
}
if ($is_directory) {
$depth++; $depth++;
$files[$key] = $this->rawlist($dir . '/' . $key, true); $files[$key] = $this->rawlist($dir . '/' . $key, true);
$depth--; $depth--;
@ -2128,10 +2148,11 @@ class SFTP extends SSH2
* @param string $local_file * @param string $local_file
* @param int $offset * @param int $offset
* @param int $length * @param int $length
* @param callable|null $progressCallback
* @return mixed * @return mixed
* @access public * @access public
*/ */
function get($remote_file, $local_file = false, $offset = 0, $length = -1) function get($remote_file, $local_file = false, $offset = 0, $length = -1, $progressCallback = null)
{ {
if (!($this->bitmap & SSH2::MASK_LOGIN)) { if (!($this->bitmap & SSH2::MASK_LOGIN)) {
return false; return false;
@ -2189,7 +2210,7 @@ class SFTP extends SSH2
$packet_size = $length > 0 ? min($this->max_sftp_packet, $length - $read) : $this->max_sftp_packet; $packet_size = $length > 0 ? min($this->max_sftp_packet, $length - $read) : $this->max_sftp_packet;
$packet = pack('Na*N3', strlen($handle), $handle, $tempoffset / 4294967296, $tempoffset, $packet_size); $packet = pack('Na*N3', strlen($handle), $handle, $tempoffset / 4294967296, $tempoffset, $packet_size);
if (!$this->_send_sftp_packet(NET_SFTP_READ, $packet)) { if (!$this->_send_sftp_packet(NET_SFTP_READ, $packet, $i)) {
if ($fclose_check) { if ($fclose_check) {
fclose($fp); fclose($fp);
} }
@ -2197,6 +2218,9 @@ class SFTP extends SSH2
} }
$packet = null; $packet = null;
$read+= $packet_size; $read+= $packet_size;
if (is_callable($progressCallback)) {
call_user_func($progressCallback, $read);
}
$i++; $i++;
} }
@ -2204,15 +2228,17 @@ class SFTP extends SSH2
break; break;
} }
$packets_sent = $i - 1;
$clear_responses = false; $clear_responses = false;
while ($i > 0) { while ($i > 0) {
$i--; $i--;
if ($clear_responses) { if ($clear_responses) {
$this->_get_sftp_packet(); $this->_get_sftp_packet($packets_sent - $i);
continue; continue;
} else { } else {
$response = $this->_get_sftp_packet(); $response = $this->_get_sftp_packet($packets_sent - $i);
} }
switch ($this->packet_type) { switch ($this->packet_type) {
@ -2921,10 +2947,10 @@ class SFTP extends SSH2
* @return bool * @return bool
* @access private * @access private
*/ */
function _send_sftp_packet($type, $data) function _send_sftp_packet($type, $data, $request_id = 1)
{ {
$packet = $this->request_id !== false ? $packet = $this->use_request_id ?
pack('NCNa*', strlen($data) + 5, $type, $this->request_id, $data) : pack('NCNa*', strlen($data) + 5, $type, $request_id, $data) :
pack('NCa*', strlen($data) + 1, $type, $data); pack('NCa*', strlen($data) + 1, $type, $data);
$start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838 $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
@ -2962,9 +2988,18 @@ class SFTP extends SSH2
* @return string * @return string
* @access private * @access private
*/ */
function _get_sftp_packet() function _get_sftp_packet($request_id = null)
{ {
$this->curTimeout = false; if (isset($request_id) && isset($this->requestBuffer[$request_id])) {
$this->packet_type = $this->requestBuffer[$request_id]['packet_type'];
$temp = $this->requestBuffer[$request_id]['packet'];
unset($this->requestBuffer[$request_id]);
return $temp;
}
// in SSH2.php the timeout is cumulative per function call. eg. exec() will
// timeout after 10s. but for SFTP.php it's cumulative per packet
$this->curTimeout = $this->timeout;
$start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838 $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
@ -2985,6 +3020,13 @@ class SFTP extends SSH2
$tempLength = $length; $tempLength = $length;
$tempLength-= strlen($this->packet_buffer); $tempLength-= strlen($this->packet_buffer);
// 256 * 1024 is what SFTP_MAX_MSG_LENGTH is set to in OpenSSH's sftp-common.h
if ($tempLength > 256 * 1024) {
user_error('Invalid SFTP packet size');
return false;
}
// SFTP packet type and data payload // SFTP packet type and data payload
while ($tempLength > 0) { while ($tempLength > 0) {
$temp = $this->_get_channel_packet(self::CHANNEL, true); $temp = $this->_get_channel_packet(self::CHANNEL, true);
@ -3001,8 +3043,8 @@ class SFTP extends SSH2
$this->packet_type = ord($this->_string_shift($this->packet_buffer)); $this->packet_type = ord($this->_string_shift($this->packet_buffer));
if ($this->request_id !== false) { if ($this->use_request_id) {
$this->_string_shift($this->packet_buffer, 4); // remove the request id extract(unpack('Npacket_id', $this->_string_shift($this->packet_buffer, 4))); // remove the request id
$length-= 5; // account for the request id and the packet type $length-= 5; // account for the request id and the packet type
} else { } else {
$length-= 1; // account for the packet type $length-= 1; // account for the packet type
@ -3025,6 +3067,14 @@ class SFTP extends SSH2
} }
} }
if (isset($request_id) && $this->use_request_id && $packet_id != $request_id) {
$this->requestBuffer[$packet_id] = array(
'packet_type' => $this->packet_type,
'packet' => $packet
);
return $this->_get_sftp_packet($request_id);
}
return $packet; return $packet;
} }

View File

@ -104,6 +104,7 @@ class SSH2
const CHANNEL_SHELL = 2; const CHANNEL_SHELL = 2;
const CHANNEL_SUBSYSTEM = 3; const CHANNEL_SUBSYSTEM = 3;
const CHANNEL_AGENT_FORWARD = 4; const CHANNEL_AGENT_FORWARD = 4;
const CHANNEL_KEEP_ALIVE = 5;
/**#@-*/ /**#@-*/
/**#@+ /**#@+
@ -145,7 +146,10 @@ class SSH2
*/ */
const READ_REGEX = 2; const READ_REGEX = 2;
/** /**
* Returns when a string matching the regular expression $expect is found * Returns whenever a data packet is received.
*
* Some data packets may only contain a single character so it may be necessary
* to call read() multiple times when using this option
*/ */
const READ_NEXT = 3; const READ_NEXT = 3;
/**#@-*/ /**#@-*/
@ -918,6 +922,22 @@ class SSH2
*/ */
var $binary_packet_buffer = false; var $binary_packet_buffer = false;
/**
* Preferred Signature Format
*
* @var string|false
* @access private
*/
var $preferred_signature_format = false;
/**
* Authentication Credentials
*
* @var array
* @access private
*/
var $auth = array();
/** /**
* Default Constructor. * Default Constructor.
* *
@ -1124,11 +1144,12 @@ class SSH2
} }
$elapsed = microtime(true) - $start; $elapsed = microtime(true) - $start;
$this->curTimeout-= $elapsed; if ($this->curTimeout) {
$this->curTimeout-= $elapsed;
if ($this->curTimeout <= 0) { if ($this->curTimeout < 0) {
$this->is_timeout = true; $this->is_timeout = true;
return false; return false;
}
} }
} }
@ -1193,6 +1214,7 @@ class SSH2
} }
if (feof($this->fsock)) { if (feof($this->fsock)) {
$this->bitmap = 0;
user_error('Connection closed by server'); user_error('Connection closed by server');
return false; return false;
} }
@ -1206,7 +1228,7 @@ class SSH2
$this->server_identifier = trim($temp, "\r\n"); $this->server_identifier = trim($temp, "\r\n");
if (strlen($extra)) { if (strlen($extra)) {
$this->errors[] = utf8_decode($data); $this->errors[] = $data;
} }
if (version_compare($matches[3], '1.99', '<')) { if (version_compare($matches[3], '1.99', '<')) {
@ -1221,6 +1243,7 @@ class SSH2
if (!$this->send_kex_first) { if (!$this->send_kex_first) {
$response = $this->_get_binary_packet(); $response = $this->_get_binary_packet();
if ($response === false) { if ($response === false) {
$this->bitmap = 0;
user_error('Connection closed by server'); user_error('Connection closed by server');
return false; return false;
} }
@ -1309,6 +1332,8 @@ class SSH2
} }
$server_host_key_algorithms = array( $server_host_key_algorithms = array(
'rsa-sha2-256', // RFC 8332
'rsa-sha2-512', // RFC 8332
'ssh-rsa', // RECOMMENDED sign Raw RSA Key 'ssh-rsa', // RECOMMENDED sign Raw RSA Key
'ssh-dss' // REQUIRED sign Raw DSS Key 'ssh-dss' // REQUIRED sign Raw DSS Key
); );
@ -1459,6 +1484,7 @@ class SSH2
$kexinit_payload_server = $this->_get_binary_packet(); $kexinit_payload_server = $this->_get_binary_packet();
if ($kexinit_payload_server === false) { if ($kexinit_payload_server === false) {
$this->bitmap = 0;
user_error('Connection closed by server'); user_error('Connection closed by server');
return false; return false;
} }
@ -1595,6 +1621,7 @@ class SSH2
$response = $this->_get_binary_packet(); $response = $this->_get_binary_packet();
if ($response === false) { if ($response === false) {
$this->bitmap = 0;
user_error('Connection closed by server'); user_error('Connection closed by server');
return false; return false;
} }
@ -1687,12 +1714,14 @@ class SSH2
$data = pack('CNa*', $clientKexInitMessage, strlen($eBytes), $eBytes); $data = pack('CNa*', $clientKexInitMessage, strlen($eBytes), $eBytes);
if (!$this->_send_binary_packet($data)) { if (!$this->_send_binary_packet($data)) {
$this->bitmap = 0;
user_error('Connection closed by server'); user_error('Connection closed by server');
return false; return false;
} }
$response = $this->_get_binary_packet(); $response = $this->_get_binary_packet();
if ($response === false) { if ($response === false) {
$this->bitmap = 0;
user_error('Connection closed by server'); user_error('Connection closed by server');
return false; return false;
} }
@ -1782,9 +1811,25 @@ class SSH2
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
} }
if ($public_key_format != $server_host_key_algorithm || $this->signature_format != $server_host_key_algorithm) { switch ($server_host_key_algorithm) {
user_error('Server Host Key Algorithm Mismatch'); case 'ssh-dss':
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); $expected_key_format = 'ssh-dss';
break;
//case 'rsa-sha2-256':
//case 'rsa-sha2-512':
//case 'ssh-rsa':
default:
$expected_key_format = 'ssh-rsa';
}
if ($public_key_format != $expected_key_format || $this->signature_format != $server_host_key_algorithm) {
switch (true) {
case $this->signature_format == $server_host_key_algorithm:
case $server_host_key_algorithm != 'rsa-sha2-256' && $server_host_key_algorithm != 'rsa-sha2-512':
case $this->signature_format != 'ssh-rsa':
user_error('Server Host Key Algorithm Mismatch');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
}
} }
$packet = pack( $packet = pack(
@ -1799,6 +1844,7 @@ class SSH2
$response = $this->_get_binary_packet(); $response = $this->_get_binary_packet();
if ($response === false) { if ($response === false) {
$this->bitmap = 0;
user_error('Connection closed by server'); user_error('Connection closed by server');
return false; return false;
} }
@ -1820,7 +1866,7 @@ class SSH2
$this->encrypt = $this->_encryption_algorithm_to_crypt_instance($encrypt); $this->encrypt = $this->_encryption_algorithm_to_crypt_instance($encrypt);
if ($this->encrypt) { if ($this->encrypt) {
if ($this->crypto_engine) { if ($this->crypto_engine) {
$this->encrypt->setEngine($this->crypto_engine); $this->encrypt->setPreferredEngine($this->crypto_engine);
} }
if ($this->encrypt->block_size) { if ($this->encrypt->block_size) {
$this->encrypt_block_size = $this->encrypt->block_size; $this->encrypt_block_size = $this->encrypt->block_size;
@ -1844,7 +1890,7 @@ class SSH2
$this->decrypt = $this->_encryption_algorithm_to_crypt_instance($decrypt); $this->decrypt = $this->_encryption_algorithm_to_crypt_instance($decrypt);
if ($this->decrypt) { if ($this->decrypt) {
if ($this->crypto_engine) { if ($this->crypto_engine) {
$this->decrypt->setEngine($this->crypto_engine); $this->decrypt->setPreferredEngine($this->crypto_engine);
} }
if ($this->decrypt->block_size) { if ($this->decrypt->block_size) {
$this->decrypt_block_size = $this->decrypt->block_size; $this->decrypt_block_size = $this->decrypt->block_size;
@ -2095,6 +2141,7 @@ class SSH2
function login($username) function login($username)
{ {
$args = func_get_args(); $args = func_get_args();
$this->auth[] = $args;
return call_user_func_array(array(&$this, '_login'), $args); return call_user_func_array(array(&$this, '_login'), $args);
} }
@ -2166,6 +2213,7 @@ class SSH2
} }
return $this->_login_helper($username, $password); return $this->_login_helper($username, $password);
} }
$this->bitmap = 0;
user_error('Connection closed by server'); user_error('Connection closed by server');
return false; return false;
} }
@ -2218,6 +2266,7 @@ class SSH2
$response = $this->_get_binary_packet(); $response = $this->_get_binary_packet();
if ($response === false) { if ($response === false) {
$this->bitmap = 0;
user_error('Connection closed by server'); user_error('Connection closed by server');
return false; return false;
} }
@ -2276,6 +2325,7 @@ class SSH2
$response = $this->_get_binary_packet(); $response = $this->_get_binary_packet();
if ($response === false) { if ($response === false) {
$this->bitmap = 0;
user_error('Connection closed by server'); user_error('Connection closed by server');
return false; return false;
} }
@ -2294,7 +2344,7 @@ class SSH2
return false; return false;
} }
extract(unpack('Nlength', $this->_string_shift($response, 4))); extract(unpack('Nlength', $this->_string_shift($response, 4)));
$this->errors[] = 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ: ' . utf8_decode($this->_string_shift($response, $length)); $this->errors[] = 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ: ' . $this->_string_shift($response, $length);
return $this->_disconnect(NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER); return $this->_disconnect(NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER);
case NET_SSH2_MSG_USERAUTH_FAILURE: case NET_SSH2_MSG_USERAUTH_FAILURE:
// can we use keyboard-interactive authentication? if not then either the login is bad or the server employees // can we use keyboard-interactive authentication? if not then either the login is bad or the server employees
@ -2376,6 +2426,7 @@ class SSH2
} else { } else {
$orig = $response = $this->_get_binary_packet(); $orig = $response = $this->_get_binary_packet();
if ($response === false) { if ($response === false) {
$this->bitmap = 0;
user_error('Connection closed by server'); user_error('Connection closed by server');
return false; return false;
} }
@ -2545,6 +2596,21 @@ class SSH2
$publickey['n'] $publickey['n']
); );
switch ($this->signature_format) {
case 'rsa-sha2-512':
$hash = 'sha512';
$signatureType = 'rsa-sha2-512';
break;
case 'rsa-sha2-256':
$hash = 'sha256';
$signatureType = 'rsa-sha2-256';
break;
//case 'ssh-rsa':
default:
$hash = 'sha1';
$signatureType = 'ssh-rsa';
}
$part1 = pack( $part1 = pack(
'CNa*Na*Na*', 'CNa*Na*Na*',
NET_SSH2_MSG_USERAUTH_REQUEST, NET_SSH2_MSG_USERAUTH_REQUEST,
@ -2555,7 +2621,7 @@ class SSH2
strlen('publickey'), strlen('publickey'),
'publickey' 'publickey'
); );
$part2 = pack('Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publickey), $publickey); $part2 = pack('Na*Na*', strlen($signatureType), $signatureType, strlen($publickey), $publickey);
$packet = $part1 . chr(0) . $part2; $packet = $part1 . chr(0) . $part2;
if (!$this->_send_binary_packet($packet)) { if (!$this->_send_binary_packet($packet)) {
@ -2564,6 +2630,7 @@ class SSH2
$response = $this->_get_binary_packet(); $response = $this->_get_binary_packet();
if ($response === false) { if ($response === false) {
$this->bitmap = 0;
user_error('Connection closed by server'); user_error('Connection closed by server');
return false; return false;
} }
@ -2595,8 +2662,9 @@ class SSH2
$packet = $part1 . chr(1) . $part2; $packet = $part1 . chr(1) . $part2;
$privatekey->setSignatureMode(RSA::SIGNATURE_PKCS1); $privatekey->setSignatureMode(RSA::SIGNATURE_PKCS1);
$privatekey->setHash($hash);
$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));
$signature = pack('Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($signature), $signature); $signature = pack('Na*Na*', strlen($signatureType), $signatureType, strlen($signature), $signature);
$packet.= pack('Na*', strlen($signature), $signature); $packet.= pack('Na*', strlen($signature), $signature);
if (!$this->_send_binary_packet($packet)) { if (!$this->_send_binary_packet($packet)) {
@ -2605,6 +2673,7 @@ class SSH2
$response = $this->_get_binary_packet(); $response = $this->_get_binary_packet();
if ($response === false) { if ($response === false) {
$this->bitmap = 0;
user_error('Connection closed by server'); user_error('Connection closed by server');
return false; return false;
} }
@ -2731,6 +2800,7 @@ class SSH2
$response = $this->_get_binary_packet(); $response = $this->_get_binary_packet();
if ($response === false) { if ($response === false) {
$this->bitmap = 0;
user_error('Connection closed by server'); user_error('Connection closed by server');
return false; return false;
} }
@ -2870,6 +2940,7 @@ class SSH2
$response = $this->_get_binary_packet(); $response = $this->_get_binary_packet();
if ($response === false) { if ($response === false) {
$this->bitmap = 0;
user_error('Connection closed by server'); user_error('Connection closed by server');
return false; return false;
} }
@ -3184,6 +3255,66 @@ class SSH2
return (bool) ($this->bitmap & self::MASK_LOGIN); return (bool) ($this->bitmap & self::MASK_LOGIN);
} }
/**
* Pings a server connection, or tries to reconnect if the connection has gone down
*
* Inspired by http://php.net/manual/en/mysqli.ping.php
*
* @return bool
* @access public
*/
function ping()
{
if (!$this->isAuthenticated()) {
return false;
}
$this->window_size_server_to_client[self::CHANNEL_KEEP_ALIVE] = $this->window_size;
$packet_size = 0x4000;
$packet = pack(
'CNa*N3',
NET_SSH2_MSG_CHANNEL_OPEN,
strlen('session'),
'session',
self::CHANNEL_KEEP_ALIVE,
$this->window_size_server_to_client[self::CHANNEL_KEEP_ALIVE],
$packet_size
);
if (!@$this->_send_binary_packet($packet)) {
return $this->_reconnect();
}
$this->channel_status[self::CHANNEL_KEEP_ALIVE] = NET_SSH2_MSG_CHANNEL_OPEN;
$response = @$this->_get_channel_packet(self::CHANNEL_KEEP_ALIVE);
if ($response !== false) {
$this->_close_channel(self::CHANNEL_KEEP_ALIVE);
return true;
}
return $this->_reconnect();
}
/**
* In situ reconnect method
*
* @return boolean
* @access private
*/
function _reconnect()
{
$this->_reset_connection(NET_SSH2_DISCONNECT_CONNECTION_LOST);
$this->retry_connect = true;
if (!$this->_connect()) {
return false;
}
foreach ($this->auth as $auth) {
$result = call_user_func_array(array(&$this, 'login'), $auth);
}
return $result;
}
/** /**
* Resets a connection for re-use * Resets a connection for re-use
* *
@ -3214,8 +3345,8 @@ class SSH2
function _get_binary_packet($skip_channel_filter = false) function _get_binary_packet($skip_channel_filter = false)
{ {
if (!is_resource($this->fsock) || feof($this->fsock)) { if (!is_resource($this->fsock) || feof($this->fsock)) {
user_error('Connection closed prematurely');
$this->bitmap = 0; $this->bitmap = 0;
user_error('Connection closed prematurely');
return false; return false;
} }
@ -3258,8 +3389,8 @@ class SSH2
while ($remaining_length > 0) { while ($remaining_length > 0) {
$temp = stream_get_contents($this->fsock, $remaining_length); $temp = stream_get_contents($this->fsock, $remaining_length);
if ($temp === false || feof($this->fsock)) { if ($temp === false || feof($this->fsock)) {
user_error('Error reading from socket');
$this->bitmap = 0; $this->bitmap = 0;
user_error('Error reading from socket');
return false; return false;
} }
$buffer.= $temp; $buffer.= $temp;
@ -3277,8 +3408,8 @@ class SSH2
if ($this->hmac_check !== false) { if ($this->hmac_check !== false) {
$hmac = stream_get_contents($this->fsock, $this->hmac_size); $hmac = stream_get_contents($this->fsock, $this->hmac_size);
if ($hmac === false || strlen($hmac) != $this->hmac_size) { if ($hmac === false || strlen($hmac) != $this->hmac_size) {
user_error('Error reading socket');
$this->bitmap = 0; $this->bitmap = 0;
user_error('Error reading socket');
return false; return false;
} elseif ($hmac != $this->hmac_check->hash(pack('NNCa*', $this->get_seq_no, $packet_length, $padding_length, $payload . $padding))) { } elseif ($hmac != $this->hmac_check->hash(pack('NNCa*', $this->get_seq_no, $packet_length, $padding_length, $payload . $padding))) {
user_error('Invalid HMAC'); user_error('Invalid HMAC');
@ -3322,7 +3453,7 @@ class SSH2
return false; return false;
} }
extract(unpack('Nreason_code/Nlength', $this->_string_shift($payload, 8))); extract(unpack('Nreason_code/Nlength', $this->_string_shift($payload, 8)));
$this->errors[] = 'SSH_MSG_DISCONNECT: ' . $this->disconnect_reasons[$reason_code] . "\r\n" . utf8_decode($this->_string_shift($payload, $length)); $this->errors[] = 'SSH_MSG_DISCONNECT: ' . $this->disconnect_reasons[$reason_code] . "\r\n" . $this->_string_shift($payload, $length);
$this->bitmap = 0; $this->bitmap = 0;
return false; return false;
case NET_SSH2_MSG_IGNORE: case NET_SSH2_MSG_IGNORE:
@ -3334,7 +3465,7 @@ class SSH2
return false; return false;
} }
extract(unpack('Nlength', $this->_string_shift($payload, 4))); extract(unpack('Nlength', $this->_string_shift($payload, 4)));
$this->errors[] = 'SSH_MSG_DEBUG: ' . utf8_decode($this->_string_shift($payload, $length)); $this->errors[] = 'SSH_MSG_DEBUG: ' . $this->_string_shift($payload, $length);
$payload = $this->_get_binary_packet($skip_channel_filter); $payload = $this->_get_binary_packet($skip_channel_filter);
break; break;
case NET_SSH2_MSG_UNIMPLEMENTED: case NET_SSH2_MSG_UNIMPLEMENTED:
@ -3357,7 +3488,7 @@ class SSH2
return false; return false;
} }
extract(unpack('Nlength', $this->_string_shift($payload, 4))); extract(unpack('Nlength', $this->_string_shift($payload, 4)));
$this->banner_message = utf8_decode($this->_string_shift($payload, $length)); $this->banner_message = $this->_string_shift($payload, $length);
$payload = $this->_get_binary_packet(); $payload = $this->_get_binary_packet();
} }
@ -3561,7 +3692,12 @@ class SSH2
$response = $this->binary_packet_buffer; $response = $this->binary_packet_buffer;
$this->binary_packet_buffer = false; $this->binary_packet_buffer = false;
} else { } else {
if ($this->curTimeout) { $read = array($this->fsock);
$write = $except = null;
if (!$this->curTimeout) {
@stream_select($read, $write, $except, null);
} else {
if ($this->curTimeout < 0) { if ($this->curTimeout < 0) {
$this->is_timeout = true; $this->is_timeout = true;
return true; return true;
@ -3576,6 +3712,9 @@ class SSH2
// on windows this returns a "Warning: Invalid CRT parameters detected" error // on windows this returns a "Warning: Invalid CRT parameters detected" error
if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) { if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {
$this->is_timeout = true; $this->is_timeout = true;
if ($client_channel == self::CHANNEL_EXEC && !$this->request_pty) {
$this->_close_channel($client_channel);
}
return true; return true;
} }
$elapsed = microtime(true) - $start; $elapsed = microtime(true) - $start;
@ -3584,6 +3723,7 @@ class SSH2
$response = $this->_get_binary_packet(true); $response = $this->_get_binary_packet(true);
if ($response === false) { if ($response === false) {
$this->bitmap = 0;
user_error('Connection closed by server'); user_error('Connection closed by server');
return false; return false;
} }
@ -3592,10 +3732,6 @@ class SSH2
if ($client_channel == -1 && $response === true) { if ($client_channel == -1 && $response === true) {
return true; return true;
} }
if (!strlen($response)) {
return '';
}
if (!strlen($response)) { if (!strlen($response)) {
return false; return false;
} }
@ -3626,7 +3762,7 @@ class SSH2
switch ($type) { switch ($type) {
case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA: case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA:
/* /*
if ($client_channel == NET_SSH2_CHANNEL_EXEC) { if ($client_channel == self::CHANNEL_EXEC) {
$this->_send_channel_packet($client_channel, chr(0)); $this->_send_channel_packet($client_channel, chr(0));
} }
*/ */
@ -3818,8 +3954,8 @@ class SSH2
function _send_binary_packet($data, $logged = null) function _send_binary_packet($data, $logged = null)
{ {
if (!is_resource($this->fsock) || feof($this->fsock)) { if (!is_resource($this->fsock) || feof($this->fsock)) {
user_error('Connection closed prematurely');
$this->bitmap = 0; $this->bitmap = 0;
user_error('Connection closed prematurely');
return false; return false;
} }
@ -4480,6 +4616,8 @@ class SSH2
break; break;
case 'ssh-rsa': case 'ssh-rsa':
case 'rsa-sha2-256':
case 'rsa-sha2-512':
if (strlen($server_public_host_key) < 4) { if (strlen($server_public_host_key) < 4) {
return false; return false;
} }
@ -4502,8 +4640,21 @@ class SSH2
$signature = $this->_string_shift($signature, $temp['length']); $signature = $this->_string_shift($signature, $temp['length']);
$rsa = new RSA(); $rsa = new RSA();
switch ($this->signature_format) {
case 'rsa-sha2-512':
$hash = 'sha512';
break;
case 'rsa-sha2-256':
$hash = 'sha256';
break;
//case 'ssh-rsa':
default:
$hash = 'sha1';
}
$rsa->setHash($hash);
$rsa->setSignatureMode(RSA::SIGNATURE_PKCS1); $rsa->setSignatureMode(RSA::SIGNATURE_PKCS1);
$rsa->loadKey(array('e' => $e, 'n' => $n), RSA::PUBLIC_FORMAT_RAW); $rsa->loadKey(array('e' => $e, 'n' => $n), RSA::PUBLIC_FORMAT_RAW);
if (!$rsa->verify($this->exchange_hash, $signature)) { if (!$rsa->verify($this->exchange_hash, $signature)) {
user_error('Bad server signature'); user_error('Bad server signature');
return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE); return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
@ -4530,7 +4681,30 @@ class SSH2
$s = $s->modPow($e, $n); $s = $s->modPow($e, $n);
$s = $s->toBytes(); $s = $s->toBytes();
$h = pack('N4H*', 0x00302130, 0x0906052B, 0x0E03021A, 0x05000414, sha1($this->exchange_hash)); switch ($this->signature_format) {
case 'rsa-sha2-512':
$hash = 'sha512';
break;
case 'rsa-sha2-256':
$hash = 'sha256';
break;
//case 'ssh-rsa':
default:
$hash = 'sha1';
}
$hashObj = new Hash($hash);
switch ($this->signature_format) {
case 'rsa-sha2-512':
$h = pack('N5a*', 0x00305130, 0x0D060960, 0x86480165, 0x03040203, 0x05000440, $hashObj->hash($this->exchange_hash));
break;
case 'rsa-sha2-256':
$h = pack('N5a*', 0x00303130, 0x0D060960, 0x86480165, 0x03040201, 0x05000420, $hashObj->hash($this->exchange_hash));
break;
//case 'ssh-rsa':
default:
$hash = 'sha1';
$h = pack('N4a*', 0x00302130, 0x0906052B, 0x0E03021A, 0x05000414, $hashObj->hash($this->exchange_hash));
}
$h = chr(0x01) . str_repeat(chr(0xFF), $nLength - 2 - strlen($h)) . $h; $h = chr(0x01) . str_repeat(chr(0xFF), $nLength - 2 - strlen($h)) . $h;
if ($s != $h) { if ($s != $h) {

View File

@ -43,7 +43,7 @@ use phpseclib\System\SSH\Agent\Identity;
* *
* @package SSH\Agent * @package SSH\Agent
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @access internal * @access public
*/ */
class Agent class Agent
{ {
@ -117,18 +117,20 @@ class Agent
* @return \phpseclib\System\SSH\Agent * @return \phpseclib\System\SSH\Agent
* @access public * @access public
*/ */
function __construct() function __construct($address = null)
{ {
switch (true) { if (!$address) {
case isset($_SERVER['SSH_AUTH_SOCK']): switch (true) {
$address = $_SERVER['SSH_AUTH_SOCK']; case isset($_SERVER['SSH_AUTH_SOCK']):
break; $address = $_SERVER['SSH_AUTH_SOCK'];
case isset($_ENV['SSH_AUTH_SOCK']): break;
$address = $_ENV['SSH_AUTH_SOCK']; case isset($_ENV['SSH_AUTH_SOCK']):
break; $address = $_ENV['SSH_AUTH_SOCK'];
default: break;
user_error('SSH_AUTH_SOCK not found'); default:
return false; user_error('SSH_AUTH_SOCK not found');
return false;
}
} }
$this->fsock = fsockopen('unix://' . $address, 0, $errno, $errstr); $this->fsock = fsockopen('unix://' . $address, 0, $errno, $errstr);
@ -155,12 +157,14 @@ class Agent
$packet = pack('NC', 1, self::SSH_AGENTC_REQUEST_IDENTITIES); $packet = pack('NC', 1, self::SSH_AGENTC_REQUEST_IDENTITIES);
if (strlen($packet) != fputs($this->fsock, $packet)) { if (strlen($packet) != fputs($this->fsock, $packet)) {
user_error('Connection closed while requesting identities'); user_error('Connection closed while requesting identities');
return array();
} }
$length = current(unpack('N', fread($this->fsock, 4))); $length = current(unpack('N', fread($this->fsock, 4)));
$type = ord(fread($this->fsock, 1)); $type = ord(fread($this->fsock, 1));
if ($type != self::SSH_AGENT_IDENTITIES_ANSWER) { if ($type != self::SSH_AGENT_IDENTITIES_ANSWER) {
user_error('Unable to request identities'); user_error('Unable to request identities');
return array();
} }
$identities = array(); $identities = array();

View File

@ -32,6 +32,17 @@ use phpseclib\System\SSH\Agent;
*/ */
class Identity class Identity
{ {
/**@+
* Signature Flags
*
* See https://tools.ietf.org/html/draft-miller-ssh-agent-00#section-5.3
*
* @access private
*/
const SSH_AGENT_RSA2_256 = 2;
const SSH_AGENT_RSA2_512 = 4;
/**#@-*/
/** /**
* Key Object * Key Object
* *
@ -59,6 +70,16 @@ class Identity
*/ */
var $fsock; var $fsock;
/**
* Signature flags
*
* @var int
* @access private
* @see self::sign()
* @see self::setHash()
*/
var $flags = 0;
/** /**
* Default Constructor. * Default Constructor.
* *
@ -126,6 +147,31 @@ class Identity
{ {
} }
/**
* Set Hash
*
* ssh-agent doesn't support using hashes for RSA other than SHA1
*
* @param string $hash
* @access public
*/
function setHash($hash)
{
$this->flags = 0;
switch ($hash) {
case 'sha1':
break;
case 'sha256':
$this->flags = self::SSH_AGENT_RSA2_256;
break;
case 'sha512':
$this->flags = self::SSH_AGENT_RSA2_512;
break;
default:
user_error('The only supported hashes for RSA are sha1, sha256 and sha512');
}
}
/** /**
* Create a signature * Create a signature
* *
@ -138,7 +184,7 @@ class Identity
function sign($message) function sign($message)
{ {
// the last parameter (currently 0) is for flags and ssh-agent only defines one flag (for ssh-dss): SSH_AGENT_OLD_SIGNATURE // 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); $packet = pack('CNa*Na*N', Agent::SSH_AGENTC_SIGN_REQUEST, strlen($this->key_blob), $this->key_blob, strlen($message), $message, $this->flags);
$packet = pack('Na*', strlen($packet), $packet); $packet = pack('Na*', strlen($packet), $packet);
if (strlen($packet) != fputs($this->fsock, $packet)) { if (strlen($packet) != fputs($this->fsock, $packet)) {
user_error('Connection closed during signing'); user_error('Connection closed during signing');
@ -151,8 +197,34 @@ class Identity
} }
$signature_blob = fread($this->fsock, $length - 1); $signature_blob = fread($this->fsock, $length - 1);
// the only other signature format defined - ssh-dss - is the same length as ssh-rsa $length = current(unpack('N', $this->_string_shift($signature_blob, 4)));
// the + 12 is for the other various SSH added length fields if ($length != strlen($signature_blob)) {
return substr($signature_blob, strlen('ssh-rsa') + 12); user_error('Malformed signature blob');
}
$length = current(unpack('N', $this->_string_shift($signature_blob, 4)));
if ($length > strlen($signature_blob) + 4) {
user_error('Malformed signature blob');
}
$type = $this->_string_shift($signature_blob, $length);
$this->_string_shift($signature_blob, 4);
return $signature_blob;
}
/**
* String Shift
*
* Inspired by array_shift
*
* @param string $string
* @param int $index
* @return string
* @access private
*/
function _string_shift(&$string, $index = 1)
{
$substr = substr($string, 0, $index);
$string = substr($string, $index);
return $substr;
} }
} }