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

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;
} }
} }