forked from friendica/friendica-addons
[securemail] Upgrade Composer dependencies to fix PHP8 issue
- Upgrading phpseclib/phpseclib (2.0.4 => 2.0.34) - Upgrading singpolyma/openpgp-php (0.3.0 => 0.5.0)
This commit is contained in:
parent
fb77e3c5ea
commit
0c7fd9a34d
65 changed files with 5407 additions and 3230 deletions
|
|
@ -11,7 +11,7 @@
|
|||
],
|
||||
"require": {
|
||||
"phpseclib/phpseclib": "^2.0",
|
||||
"singpolyma/openpgp-php": "^0.3.0"
|
||||
"singpolyma/openpgp-php": "^0.5.0"
|
||||
},
|
||||
"license": "AGPL-3.0+",
|
||||
"minimum-stability": "stable",
|
||||
|
|
|
|||
72
securemail/composer.lock
generated
72
securemail/composer.lock
generated
|
|
@ -4,20 +4,20 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "b3a33a493eae34d9245ca7cc1b4572ea",
|
||||
"content-hash": "159d6e7134aeceeb05fdf60ef672f3a3",
|
||||
"packages": [
|
||||
{
|
||||
"name": "phpseclib/phpseclib",
|
||||
"version": "2.0.4",
|
||||
"version": "2.0.34",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpseclib/phpseclib.git",
|
||||
"reference": "ab8028c93c03cc8d9c824efa75dc94f1db2369bf"
|
||||
"reference": "98a6fe587f3481aea319eef7e656d02cfe1675ec"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/ab8028c93c03cc8d9c824efa75dc94f1db2369bf",
|
||||
"reference": "ab8028c93c03cc8d9c824efa75dc94f1db2369bf",
|
||||
"url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/98a6fe587f3481aea319eef7e656d02cfe1675ec",
|
||||
"reference": "98a6fe587f3481aea319eef7e656d02cfe1675ec",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -25,8 +25,7 @@
|
|||
},
|
||||
"require-dev": {
|
||||
"phing/phing": "~2.7",
|
||||
"phpunit/phpunit": "~4.0",
|
||||
"sami/sami": "~2.0",
|
||||
"phpunit/phpunit": "^4.8.35|^5.7|^6.0|^9.4",
|
||||
"squizlabs/php_codesniffer": "~2.0"
|
||||
},
|
||||
"suggest": {
|
||||
|
|
@ -96,27 +95,49 @@
|
|||
"x.509",
|
||||
"x509"
|
||||
],
|
||||
"time": "2016-10-04T00:57:04+00:00"
|
||||
"support": {
|
||||
"issues": "https://github.com/phpseclib/phpseclib/issues",
|
||||
"source": "https://github.com/phpseclib/phpseclib/tree/2.0.34"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/terrafrost",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://www.patreon.com/phpseclib",
|
||||
"type": "patreon"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/phpseclib/phpseclib",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2021-10-27T02:46:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "singpolyma/openpgp-php",
|
||||
"version": "0.3.0",
|
||||
"version": "0.5.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/singpolyma/openpgp-php.git",
|
||||
"reference": "6006111bbc4c3b6cb8f0acb7d6c4a7047df366e8"
|
||||
"reference": "69292f6a46ed7f687083bfb8974b161a41ab213c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/singpolyma/openpgp-php/zipball/6006111bbc4c3b6cb8f0acb7d6c4a7047df366e8",
|
||||
"reference": "6006111bbc4c3b6cb8f0acb7d6c4a7047df366e8",
|
||||
"url": "https://api.github.com/repos/singpolyma/openpgp-php/zipball/69292f6a46ed7f687083bfb8974b161a41ab213c",
|
||||
"reference": "69292f6a46ed7f687083bfb8974b161a41ab213c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"phpseclib/phpseclib": ">=2.0.0 <=2.0.4"
|
||||
"php": "^5.6 || ^7.0 || ^8.0",
|
||||
"phpseclib/phpseclib": "^2.0 !=2.0.8"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.0"
|
||||
"phpunit/phpunit": "^9.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-mcrypt": "required if you use encryption cast5"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
|
|
@ -139,7 +160,25 @@
|
|||
}
|
||||
],
|
||||
"description": "Pure-PHP implementation of the OpenPGP Message Format (RFC 4880)",
|
||||
"time": "2017-04-12T21:23:15+00:00"
|
||||
"support": {
|
||||
"issues": "https://github.com/singpolyma/openpgp-php/issues",
|
||||
"source": "https://github.com/singpolyma/openpgp-php/tree/0.5.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/singpolyma",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://liberapay.com/singpolyma",
|
||||
"type": "liberapay"
|
||||
},
|
||||
{
|
||||
"url": "https://www.patreon.com/singpolyma",
|
||||
"type": "patreon"
|
||||
}
|
||||
],
|
||||
"time": "2021-05-26T00:35:20+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
|
|
@ -149,5 +188,6 @@
|
|||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": []
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "2.0.0"
|
||||
}
|
||||
|
|
|
|||
8
securemail/vendor/composer/ClassLoader.php
vendored
8
securemail/vendor/composer/ClassLoader.php
vendored
|
|
@ -37,8 +37,8 @@ namespace Composer\Autoload;
|
|||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
* @see http://www.php-fig.org/psr/psr-0/
|
||||
* @see http://www.php-fig.org/psr/psr-4/
|
||||
* @see https://www.php-fig.org/psr/psr-0/
|
||||
* @see https://www.php-fig.org/psr/psr-4/
|
||||
*/
|
||||
class ClassLoader
|
||||
{
|
||||
|
|
@ -60,7 +60,7 @@ class ClassLoader
|
|||
public function getPrefixes()
|
||||
{
|
||||
if (!empty($this->prefixesPsr0)) {
|
||||
return call_user_func_array('array_merge', $this->prefixesPsr0);
|
||||
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
|
||||
}
|
||||
|
||||
return array();
|
||||
|
|
@ -279,7 +279,7 @@ class ClassLoader
|
|||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
227
securemail/vendor/composer/InstalledVersions.php
vendored
Normal file
227
securemail/vendor/composer/InstalledVersions.php
vendored
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
<?php
|
||||
|
||||
namespace Composer;
|
||||
|
||||
use Composer\Semver\VersionParser;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class InstalledVersions
|
||||
{
|
||||
private static $installed = array (
|
||||
'root' =>
|
||||
array (
|
||||
'pretty_version' => 'dev-develop',
|
||||
'version' => 'dev-develop',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'fb77e3c5ea0bcc6497dd6f24960b3d9ff1a159bd',
|
||||
'name' => 'friendica-addons/securemail',
|
||||
),
|
||||
'versions' =>
|
||||
array (
|
||||
'friendica-addons/securemail' =>
|
||||
array (
|
||||
'pretty_version' => 'dev-develop',
|
||||
'version' => 'dev-develop',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'fb77e3c5ea0bcc6497dd6f24960b3d9ff1a159bd',
|
||||
),
|
||||
'phpseclib/phpseclib' =>
|
||||
array (
|
||||
'pretty_version' => '2.0.34',
|
||||
'version' => '2.0.34.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '98a6fe587f3481aea319eef7e656d02cfe1675ec',
|
||||
),
|
||||
'singpolyma/openpgp-php' =>
|
||||
array (
|
||||
'pretty_version' => '0.5.0',
|
||||
'version' => '0.5.0.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '69292f6a46ed7f687083bfb8974b161a41ab213c',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static function getInstalledPackages()
|
||||
{
|
||||
return array_keys(self::$installed['versions']);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static function isInstalled($packageName)
|
||||
{
|
||||
return isset(self::$installed['versions'][$packageName]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static function satisfies(VersionParser $parser, $packageName, $constraint)
|
||||
{
|
||||
$constraint = $parser->parseConstraints($constraint);
|
||||
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
|
||||
|
||||
return $provided->matches($constraint);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static function getVersionRanges($packageName)
|
||||
{
|
||||
if (!isset(self::$installed['versions'][$packageName])) {
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
$ranges = array();
|
||||
if (isset(self::$installed['versions'][$packageName]['pretty_version'])) {
|
||||
$ranges[] = self::$installed['versions'][$packageName]['pretty_version'];
|
||||
}
|
||||
if (array_key_exists('aliases', self::$installed['versions'][$packageName])) {
|
||||
$ranges = array_merge($ranges, self::$installed['versions'][$packageName]['aliases']);
|
||||
}
|
||||
if (array_key_exists('replaced', self::$installed['versions'][$packageName])) {
|
||||
$ranges = array_merge($ranges, self::$installed['versions'][$packageName]['replaced']);
|
||||
}
|
||||
if (array_key_exists('provided', self::$installed['versions'][$packageName])) {
|
||||
$ranges = array_merge($ranges, self::$installed['versions'][$packageName]['provided']);
|
||||
}
|
||||
|
||||
return implode(' || ', $ranges);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static function getVersion($packageName)
|
||||
{
|
||||
if (!isset(self::$installed['versions'][$packageName])) {
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
if (!isset(self::$installed['versions'][$packageName]['version'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return self::$installed['versions'][$packageName]['version'];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static function getPrettyVersion($packageName)
|
||||
{
|
||||
if (!isset(self::$installed['versions'][$packageName])) {
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
if (!isset(self::$installed['versions'][$packageName]['pretty_version'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return self::$installed['versions'][$packageName]['pretty_version'];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static function getReference($packageName)
|
||||
{
|
||||
if (!isset(self::$installed['versions'][$packageName])) {
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
if (!isset(self::$installed['versions'][$packageName]['reference'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return self::$installed['versions'][$packageName]['reference'];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static function getRootPackage()
|
||||
{
|
||||
return self::$installed['root'];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static function getRawData()
|
||||
{
|
||||
return self::$installed;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static function reload($data)
|
||||
{
|
||||
self::$installed = $data;
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ $vendorDir = dirname(dirname(__FILE__));
|
|||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
|
||||
'MCryptWrapper' => $vendorDir . '/singpolyma/openpgp-php/lib/openpgp_mcrypt_wrapper.php',
|
||||
'OpenPGP' => $vendorDir . '/singpolyma/openpgp-php/lib/openpgp.php',
|
||||
'OpenPGP_AsymmetricSessionKeyPacket' => $vendorDir . '/singpolyma/openpgp-php/lib/openpgp.php',
|
||||
|
|
@ -55,4 +56,5 @@ return array(
|
|||
'OpenPGP_TrustPacket' => $vendorDir . '/singpolyma/openpgp-php/lib/openpgp.php',
|
||||
'OpenPGP_UserAttributePacket' => $vendorDir . '/singpolyma/openpgp-php/lib/openpgp.php',
|
||||
'OpenPGP_UserIDPacket' => $vendorDir . '/singpolyma/openpgp-php/lib/openpgp.php',
|
||||
'OpenSSLWrapper' => $vendorDir . '/singpolyma/openpgp-php/lib/openpgp_openssl_wrapper.php',
|
||||
);
|
||||
|
|
|
|||
7
securemail/vendor/composer/autoload_real.php
vendored
7
securemail/vendor/composer/autoload_real.php
vendored
|
|
@ -13,19 +13,24 @@ class ComposerAutoloaderInitSecuremailAddon
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Composer\Autoload\ClassLoader
|
||||
*/
|
||||
public static function getLoader()
|
||||
{
|
||||
if (null !== self::$loader) {
|
||||
return self::$loader;
|
||||
}
|
||||
|
||||
require __DIR__ . '/platform_check.php';
|
||||
|
||||
spl_autoload_register(array('ComposerAutoloaderInitSecuremailAddon', 'loadClassLoader'), true, true);
|
||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInitSecuremailAddon', 'loadClassLoader'));
|
||||
|
||||
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
||||
if ($useStaticLoader) {
|
||||
require_once __DIR__ . '/autoload_static.php';
|
||||
require __DIR__ . '/autoload_static.php';
|
||||
|
||||
call_user_func(\Composer\Autoload\ComposerStaticInitSecuremailAddon::getInitializer($loader));
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ class ComposerStaticInitSecuremailAddon
|
|||
);
|
||||
|
||||
public static $classMap = array (
|
||||
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
|
||||
'MCryptWrapper' => __DIR__ . '/..' . '/singpolyma/openpgp-php/lib/openpgp_mcrypt_wrapper.php',
|
||||
'OpenPGP' => __DIR__ . '/..' . '/singpolyma/openpgp-php/lib/openpgp.php',
|
||||
'OpenPGP_AsymmetricSessionKeyPacket' => __DIR__ . '/..' . '/singpolyma/openpgp-php/lib/openpgp.php',
|
||||
|
|
@ -74,6 +75,7 @@ class ComposerStaticInitSecuremailAddon
|
|||
'OpenPGP_TrustPacket' => __DIR__ . '/..' . '/singpolyma/openpgp-php/lib/openpgp.php',
|
||||
'OpenPGP_UserAttributePacket' => __DIR__ . '/..' . '/singpolyma/openpgp-php/lib/openpgp.php',
|
||||
'OpenPGP_UserIDPacket' => __DIR__ . '/..' . '/singpolyma/openpgp-php/lib/openpgp.php',
|
||||
'OpenSSLWrapper' => __DIR__ . '/..' . '/singpolyma/openpgp-php/lib/openpgp_openssl_wrapper.php',
|
||||
);
|
||||
|
||||
public static function getInitializer(ClassLoader $loader)
|
||||
|
|
|
|||
315
securemail/vendor/composer/installed.json
vendored
315
securemail/vendor/composer/installed.json
vendored
|
|
@ -1,141 +1,186 @@
|
|||
[
|
||||
{
|
||||
"name": "phpseclib/phpseclib",
|
||||
"version": "2.0.4",
|
||||
"version_normalized": "2.0.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpseclib/phpseclib.git",
|
||||
"reference": "ab8028c93c03cc8d9c824efa75dc94f1db2369bf"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/ab8028c93c03cc8d9c824efa75dc94f1db2369bf",
|
||||
"reference": "ab8028c93c03cc8d9c824efa75dc94f1db2369bf",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phing/phing": "~2.7",
|
||||
"phpunit/phpunit": "~4.0",
|
||||
"sami/sami": "~2.0",
|
||||
"squizlabs/php_codesniffer": "~2.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.",
|
||||
"ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.",
|
||||
"ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.",
|
||||
"ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations."
|
||||
},
|
||||
"time": "2016-10-04T00:57:04+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"phpseclib/bootstrap.php"
|
||||
{
|
||||
"packages": [
|
||||
{
|
||||
"name": "phpseclib/phpseclib",
|
||||
"version": "2.0.34",
|
||||
"version_normalized": "2.0.34.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpseclib/phpseclib.git",
|
||||
"reference": "98a6fe587f3481aea319eef7e656d02cfe1675ec"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/98a6fe587f3481aea319eef7e656d02cfe1675ec",
|
||||
"reference": "98a6fe587f3481aea319eef7e656d02cfe1675ec",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phing/phing": "~2.7",
|
||||
"phpunit/phpunit": "^4.8.35|^5.7|^6.0|^9.4",
|
||||
"squizlabs/php_codesniffer": "~2.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.",
|
||||
"ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.",
|
||||
"ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.",
|
||||
"ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations."
|
||||
},
|
||||
"time": "2021-10-27T02:46:30+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"phpseclib/bootstrap.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"phpseclib\\": "phpseclib/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"psr-4": {
|
||||
"phpseclib\\": "phpseclib/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jim Wigginton",
|
||||
"email": "terrafrost@php.net",
|
||||
"role": "Lead Developer"
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jim Wigginton",
|
||||
"email": "terrafrost@php.net",
|
||||
"role": "Lead Developer"
|
||||
},
|
||||
{
|
||||
"name": "Patrick Monnerat",
|
||||
"email": "pm@datasphere.ch",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Andreas Fischer",
|
||||
"email": "bantu@phpbb.com",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Hans-Jürgen Petrich",
|
||||
"email": "petrich@tronic-media.com",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Graham Campbell",
|
||||
"email": "graham@alt-three.com",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.",
|
||||
"homepage": "http://phpseclib.sourceforge.net",
|
||||
"keywords": [
|
||||
"BigInteger",
|
||||
"aes",
|
||||
"asn.1",
|
||||
"asn1",
|
||||
"blowfish",
|
||||
"crypto",
|
||||
"cryptography",
|
||||
"encryption",
|
||||
"rsa",
|
||||
"security",
|
||||
"sftp",
|
||||
"signature",
|
||||
"signing",
|
||||
"ssh",
|
||||
"twofish",
|
||||
"x.509",
|
||||
"x509"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/phpseclib/phpseclib/issues",
|
||||
"source": "https://github.com/phpseclib/phpseclib/tree/2.0.34"
|
||||
},
|
||||
{
|
||||
"name": "Patrick Monnerat",
|
||||
"email": "pm@datasphere.ch",
|
||||
"role": "Developer"
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/terrafrost",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://www.patreon.com/phpseclib",
|
||||
"type": "patreon"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/phpseclib/phpseclib",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"install-path": "../phpseclib/phpseclib"
|
||||
},
|
||||
{
|
||||
"name": "singpolyma/openpgp-php",
|
||||
"version": "0.5.0",
|
||||
"version_normalized": "0.5.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/singpolyma/openpgp-php.git",
|
||||
"reference": "69292f6a46ed7f687083bfb8974b161a41ab213c"
|
||||
},
|
||||
{
|
||||
"name": "Andreas Fischer",
|
||||
"email": "bantu@phpbb.com",
|
||||
"role": "Developer"
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/singpolyma/openpgp-php/zipball/69292f6a46ed7f687083bfb8974b161a41ab213c",
|
||||
"reference": "69292f6a46ed7f687083bfb8974b161a41ab213c",
|
||||
"shasum": ""
|
||||
},
|
||||
{
|
||||
"name": "Hans-Jürgen Petrich",
|
||||
"email": "petrich@tronic-media.com",
|
||||
"role": "Developer"
|
||||
"require": {
|
||||
"php": "^5.6 || ^7.0 || ^8.0",
|
||||
"phpseclib/phpseclib": "^2.0 !=2.0.8"
|
||||
},
|
||||
{
|
||||
"name": "Graham Campbell",
|
||||
"email": "graham@alt-three.com",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.",
|
||||
"homepage": "http://phpseclib.sourceforge.net",
|
||||
"keywords": [
|
||||
"BigInteger",
|
||||
"aes",
|
||||
"asn.1",
|
||||
"asn1",
|
||||
"blowfish",
|
||||
"crypto",
|
||||
"cryptography",
|
||||
"encryption",
|
||||
"rsa",
|
||||
"security",
|
||||
"sftp",
|
||||
"signature",
|
||||
"signing",
|
||||
"ssh",
|
||||
"twofish",
|
||||
"x.509",
|
||||
"x509"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "singpolyma/openpgp-php",
|
||||
"version": "0.3.0",
|
||||
"version_normalized": "0.3.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/singpolyma/openpgp-php.git",
|
||||
"reference": "6006111bbc4c3b6cb8f0acb7d6c4a7047df366e8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/singpolyma/openpgp-php/zipball/6006111bbc4c3b6cb8f0acb7d6c4a7047df366e8",
|
||||
"reference": "6006111bbc4c3b6cb8f0acb7d6c4a7047df366e8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"phpseclib/phpseclib": ">=2.0.0 <=2.0.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.0"
|
||||
},
|
||||
"time": "2017-04-12T21:23:15+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"lib/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"Unlicense"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Arto Bendiken",
|
||||
"email": "arto.bendiken@gmail.com"
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.0"
|
||||
},
|
||||
{
|
||||
"name": "Stephen Paul Weber",
|
||||
"email": "singpolyma@singpolyma.net"
|
||||
}
|
||||
],
|
||||
"description": "Pure-PHP implementation of the OpenPGP Message Format (RFC 4880)"
|
||||
}
|
||||
]
|
||||
"suggest": {
|
||||
"ext-mcrypt": "required if you use encryption cast5"
|
||||
},
|
||||
"time": "2021-05-26T00:35:20+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"lib/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"Unlicense"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Arto Bendiken",
|
||||
"email": "arto.bendiken@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Stephen Paul Weber",
|
||||
"email": "singpolyma@singpolyma.net"
|
||||
}
|
||||
],
|
||||
"description": "Pure-PHP implementation of the OpenPGP Message Format (RFC 4880)",
|
||||
"support": {
|
||||
"issues": "https://github.com/singpolyma/openpgp-php/issues",
|
||||
"source": "https://github.com/singpolyma/openpgp-php/tree/0.5.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/singpolyma",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://liberapay.com/singpolyma",
|
||||
"type": "liberapay"
|
||||
},
|
||||
{
|
||||
"url": "https://www.patreon.com/singpolyma",
|
||||
"type": "patreon"
|
||||
}
|
||||
],
|
||||
"install-path": "../singpolyma/openpgp-php"
|
||||
}
|
||||
],
|
||||
"dev": true,
|
||||
"dev-package-names": []
|
||||
}
|
||||
|
|
|
|||
42
securemail/vendor/composer/installed.php
vendored
Normal file
42
securemail/vendor/composer/installed.php
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
<?php return array (
|
||||
'root' =>
|
||||
array (
|
||||
'pretty_version' => 'dev-develop',
|
||||
'version' => 'dev-develop',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'fb77e3c5ea0bcc6497dd6f24960b3d9ff1a159bd',
|
||||
'name' => 'friendica-addons/securemail',
|
||||
),
|
||||
'versions' =>
|
||||
array (
|
||||
'friendica-addons/securemail' =>
|
||||
array (
|
||||
'pretty_version' => 'dev-develop',
|
||||
'version' => 'dev-develop',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => 'fb77e3c5ea0bcc6497dd6f24960b3d9ff1a159bd',
|
||||
),
|
||||
'phpseclib/phpseclib' =>
|
||||
array (
|
||||
'pretty_version' => '2.0.34',
|
||||
'version' => '2.0.34.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '98a6fe587f3481aea319eef7e656d02cfe1675ec',
|
||||
),
|
||||
'singpolyma/openpgp-php' =>
|
||||
array (
|
||||
'pretty_version' => '0.5.0',
|
||||
'version' => '0.5.0.0',
|
||||
'aliases' =>
|
||||
array (
|
||||
),
|
||||
'reference' => '69292f6a46ed7f687083bfb8974b161a41ab213c',
|
||||
),
|
||||
),
|
||||
);
|
||||
26
securemail/vendor/composer/platform_check.php
vendored
Normal file
26
securemail/vendor/composer/platform_check.php
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
// platform_check.php @generated by Composer
|
||||
|
||||
$issues = array();
|
||||
|
||||
if (!(PHP_VERSION_ID >= 50600)) {
|
||||
$issues[] = 'Your Composer dependencies require a PHP version ">= 5.6.0". You are running ' . PHP_VERSION . '.';
|
||||
}
|
||||
|
||||
if ($issues) {
|
||||
if (!headers_sent()) {
|
||||
header('HTTP/1.1 500 Internal Server Error');
|
||||
}
|
||||
if (!ini_get('display_errors')) {
|
||||
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||
fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
|
||||
} elseif (!headers_sent()) {
|
||||
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
|
||||
}
|
||||
}
|
||||
trigger_error(
|
||||
'Composer detected issues in your platform: ' . implode(' ', $issues),
|
||||
E_USER_ERROR
|
||||
);
|
||||
}
|
||||
8
securemail/vendor/phpseclib/phpseclib/BACKERS.md
vendored
Normal file
8
securemail/vendor/phpseclib/phpseclib/BACKERS.md
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
# Backers
|
||||
|
||||
phpseclib ongoing development is made possible by [Tidelift](https://tidelift.com/subscription/pkg/packagist-phpseclib-phpseclib?utm_source=packagist-phpseclib-phpseclib&utm_medium=referral&utm_campaign=readme) and by contributions by users like you. Thank you.
|
||||
|
||||
## Backers
|
||||
|
||||
- Zane Hooper
|
||||
- [Setasign](https://www.setasign.com/)
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
Copyright 2007-2016 TerraFrost and other contributors
|
||||
http://phpseclib.sourceforge.net/
|
||||
Copyright (c) 2011-2019 TerraFrost and other contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
|
@ -18,4 +17,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
95
securemail/vendor/phpseclib/phpseclib/README.md
vendored
95
securemail/vendor/phpseclib/phpseclib/README.md
vendored
|
|
@ -1,22 +1,62 @@
|
|||
# phpseclib - PHP Secure Communications Library
|
||||
|
||||
[](https://travis-ci.org/phpseclib/phpseclib)
|
||||
[](https://travis-ci.com/phpseclib/phpseclib)
|
||||
|
||||
MIT-licensed pure-PHP implementations of an arbitrary-precision integer
|
||||
arithmetic library, fully PKCS#1 (v2.1) compliant RSA, DES, 3DES, RC4, Rijndael,
|
||||
AES, Blowfish, Twofish, SSH-1, SSH-2, SFTP, and X.509
|
||||
## 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 the following:
|
||||
|
||||
SSH-2, SFTP, X.509, an arbitrary-precision integer arithmetic library, Ed25519 / Ed449 / Curve25519 / Curve449, ECDSA / ECDH (with support for 66 curves), RSA (PKCS#1 v2.2 compliant), DSA / DH, DES / 3DES / RC4 / Rijndael / AES / Blowfish / Twofish / Salsa20 / ChaCha20, GCM / Poly1305
|
||||
|
||||
* [Download (1.0.4)](http://sourceforge.net/projects/phpseclib/files/phpseclib1.0.4.zip/download)
|
||||
* [Browse Git](https://github.com/phpseclib/phpseclib)
|
||||
* [Code Coverage Report](http://phpseclib.bantux.org/code_coverage/2.0/latest/)
|
||||
|
||||
<img src="http://phpseclib.sourceforge.net/pear-icon.png" alt="PEAR Channel" width="16" height="16">
|
||||
PEAR Channel: [phpseclib.sourceforge.net](http://phpseclib.sourceforge.net/pear.htm)
|
||||
|
||||
## Documentation
|
||||
|
||||
* [Documentation / Manual](http://phpseclib.sourceforge.net/)
|
||||
* [API Documentation](http://phpseclib.bantux.org/api/2.0/) (generated by Sami)
|
||||
* [Documentation / Manual](https://phpseclib.com/)
|
||||
* [API Documentation](https://api.phpseclib.com/2.0/) (generated by Doctum)
|
||||
|
||||
## Branches
|
||||
|
||||
### master
|
||||
|
||||
* Development Branch
|
||||
* Unstable API
|
||||
* Do not use in production
|
||||
|
||||
### 3.0
|
||||
|
||||
* Long term support (LTS) release
|
||||
* Major expansion of cryptographic primitives
|
||||
* Minimum PHP version: 5.6.1
|
||||
* PSR-4 autoloading with namespace rooted at `\phpseclib3`
|
||||
* Install via Composer: `composer require phpseclib/phpseclib:~3.0`
|
||||
|
||||
### 2.0
|
||||
|
||||
* Long term support (LTS) release
|
||||
* Modernized version of 1.0
|
||||
* Minimum PHP version: 5.3.3
|
||||
* PSR-4 autoloading with namespace rooted at `\phpseclib`
|
||||
* Install via Composer: `composer require phpseclib/phpseclib:~2.0`
|
||||
|
||||
### 1.0
|
||||
|
||||
* Long term support (LTS) release
|
||||
* PHP4 compatible
|
||||
* Composer compatible (PSR-0 autoloading)
|
||||
* Install using Composer: `composer require phpseclib/phpseclib:~1.0`
|
||||
* Install using PEAR: See [phpseclib PEAR Channel Documentation](http://phpseclib.sourceforge.net/pear.htm)
|
||||
* [Download 1.0.19 as ZIP](http://sourceforge.net/projects/phpseclib/files/phpseclib1.0.19.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
|
||||
|
||||
|
|
@ -26,40 +66,29 @@ Need Support?
|
|||
* [Create a Support Ticket on GitHub](https://github.com/phpseclib/phpseclib/issues/new)
|
||||
* [Browse the Support Forum](http://www.frostjedi.com/phpbb/viewforum.php?f=46) (no longer in use)
|
||||
|
||||
## Installing Development Dependencies
|
||||
|
||||
Dependencies are managed via Composer.
|
||||
|
||||
1. Download the [`composer.phar`](https://getcomposer.org/composer.phar) executable as per the
|
||||
[Composer Download Instructions](https://getcomposer.org/download/), e.g. by running
|
||||
|
||||
``` sh
|
||||
curl -sS https://getcomposer.org/installer | php
|
||||
```
|
||||
|
||||
2. Install Dependencies
|
||||
|
||||
``` sh
|
||||
php composer.phar install
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
1. Fork the Project
|
||||
|
||||
2. Install Development Dependencies
|
||||
2. Ensure you have Composer installed (see [Composer Download Instructions](https://getcomposer.org/download/))
|
||||
|
||||
3. Create a Feature Branch
|
||||
3. Install Development Dependencies
|
||||
|
||||
4. (Recommended) Run the Test Suite
|
||||
``` sh
|
||||
composer install
|
||||
```
|
||||
|
||||
4. Create a Feature Branch
|
||||
|
||||
5. (Recommended) Run the Test Suite
|
||||
|
||||
``` sh
|
||||
vendor/bin/phpunit
|
||||
```
|
||||
5. (Recommended) Check whether your code conforms to our Coding Standards by running
|
||||
6. (Recommended) Check whether your code conforms to our Coding Standards by running
|
||||
|
||||
``` sh
|
||||
vendor/bin/phing -f build/build.xml sniff
|
||||
```
|
||||
|
||||
6. Send us a Pull Request
|
||||
7. Send us a Pull Request
|
||||
|
|
|
|||
27
securemail/vendor/phpseclib/phpseclib/appveyor.yml
vendored
Normal file
27
securemail/vendor/phpseclib/phpseclib/appveyor.yml
vendored
Normal 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
|
||||
|
|
@ -55,8 +55,7 @@
|
|||
},
|
||||
"require-dev": {
|
||||
"phing/phing": "~2.7",
|
||||
"phpunit/phpunit": "~4.0",
|
||||
"sami/sami": "~2.0",
|
||||
"phpunit/phpunit": "^4.8.35|^5.7|^6.0|^9.4",
|
||||
"squizlabs/php_codesniffer": "~2.0"
|
||||
},
|
||||
"suggest": {
|
||||
|
|
|
|||
1819
securemail/vendor/phpseclib/phpseclib/composer.lock
generated
vendored
1819
securemail/vendor/phpseclib/phpseclib/composer.lock
generated
vendored
|
|
@ -1,1819 +0,0 @@
|
|||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"hash": "8599992bf6058a9da82372eb8bcae2c2",
|
||||
"content-hash": "fde47c84178c55c06de858a2128e3d07",
|
||||
"packages": [],
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "doctrine/instantiator",
|
||||
"version": "1.0.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/instantiator.git",
|
||||
"reference": "8e884e78f9f0eb1329e445619e04456e64d8051d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d",
|
||||
"reference": "8e884e78f9f0eb1329e445619e04456e64d8051d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3,<8.0-DEV"
|
||||
},
|
||||
"require-dev": {
|
||||
"athletic/athletic": "~0.1.8",
|
||||
"ext-pdo": "*",
|
||||
"ext-phar": "*",
|
||||
"phpunit/phpunit": "~4.0",
|
||||
"squizlabs/php_codesniffer": "~2.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Marco Pivetta",
|
||||
"email": "ocramius@gmail.com",
|
||||
"homepage": "http://ocramius.github.com/"
|
||||
}
|
||||
],
|
||||
"description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
|
||||
"homepage": "https://github.com/doctrine/instantiator",
|
||||
"keywords": [
|
||||
"constructor",
|
||||
"instantiate"
|
||||
],
|
||||
"time": "2015-06-14 21:17:01"
|
||||
},
|
||||
{
|
||||
"name": "michelf/php-markdown",
|
||||
"version": "1.6.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/michelf/php-markdown.git",
|
||||
"reference": "156e56ee036505ec637d761ee62dc425d807183c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/michelf/php-markdown/zipball/156e56ee036505ec637d761ee62dc425d807183c",
|
||||
"reference": "156e56ee036505ec637d761ee62dc425d807183c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-lib": "1.4.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Michelf": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Michel Fortin",
|
||||
"email": "michel.fortin@michelf.ca",
|
||||
"homepage": "https://michelf.ca/",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "John Gruber",
|
||||
"homepage": "https://daringfireball.net/"
|
||||
}
|
||||
],
|
||||
"description": "PHP Markdown",
|
||||
"homepage": "https://michelf.ca/projects/php-markdown/",
|
||||
"keywords": [
|
||||
"markdown"
|
||||
],
|
||||
"time": "2015-12-24 01:37:31"
|
||||
},
|
||||
{
|
||||
"name": "nikic/php-parser",
|
||||
"version": "v0.9.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nikic/PHP-Parser.git",
|
||||
"reference": "ef70767475434bdb3615b43c327e2cae17ef12eb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ef70767475434bdb3615b43c327e2cae17ef12eb",
|
||||
"reference": "ef70767475434bdb3615b43c327e2cae17ef12eb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-tokenizer": "*",
|
||||
"php": ">=5.2"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "0.9-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"PHPParser": "lib/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nikita Popov"
|
||||
}
|
||||
],
|
||||
"description": "A PHP parser written in PHP",
|
||||
"keywords": [
|
||||
"parser",
|
||||
"php"
|
||||
],
|
||||
"time": "2014-07-23 18:24:17"
|
||||
},
|
||||
{
|
||||
"name": "phing/phing",
|
||||
"version": "2.14.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phingofficial/phing.git",
|
||||
"reference": "7dd73c83c377623def54b58121f46b4dcb35dd61"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phingofficial/phing/zipball/7dd73c83c377623def54b58121f46b4dcb35dd61",
|
||||
"reference": "7dd73c83c377623def54b58121f46b4dcb35dd61",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-pdo_sqlite": "*",
|
||||
"lastcraft/simpletest": "@dev",
|
||||
"mikey179/vfsstream": "^1.6",
|
||||
"pdepend/pdepend": "2.x",
|
||||
"pear/archive_tar": "1.4.x",
|
||||
"pear/http_request2": "dev-trunk",
|
||||
"pear/net_growl": "dev-trunk",
|
||||
"pear/pear-core-minimal": "1.10.1",
|
||||
"pear/versioncontrol_git": "@dev",
|
||||
"pear/versioncontrol_svn": "~0.5",
|
||||
"phpdocumentor/phpdocumentor": "2.x",
|
||||
"phploc/phploc": "~2.0.6",
|
||||
"phpmd/phpmd": "~2.2",
|
||||
"phpunit/phpunit": ">=3.7",
|
||||
"sebastian/git": "~1.0",
|
||||
"sebastian/phpcpd": "2.x",
|
||||
"squizlabs/php_codesniffer": "~2.2",
|
||||
"symfony/yaml": "~2.7"
|
||||
},
|
||||
"suggest": {
|
||||
"pdepend/pdepend": "PHP version of JDepend",
|
||||
"pear/archive_tar": "Tar file management class",
|
||||
"pear/versioncontrol_git": "A library that provides OO interface to handle Git repository",
|
||||
"pear/versioncontrol_svn": "A simple OO-style interface for Subversion, the free/open-source version control system",
|
||||
"phpdocumentor/phpdocumentor": "Documentation Generator for PHP",
|
||||
"phploc/phploc": "A tool for quickly measuring the size of a PHP project",
|
||||
"phpmd/phpmd": "PHP version of PMD tool",
|
||||
"phpunit/php-code-coverage": "Library that provides collection, processing, and rendering functionality for PHP code coverage information",
|
||||
"phpunit/phpunit": "The PHP Unit Testing Framework",
|
||||
"sebastian/phpcpd": "Copy/Paste Detector (CPD) for PHP code",
|
||||
"tedivm/jshrink": "Javascript Minifier built in PHP"
|
||||
},
|
||||
"bin": [
|
||||
"bin/phing"
|
||||
],
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.14.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"classes/phing/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"include-path": [
|
||||
"classes"
|
||||
],
|
||||
"license": [
|
||||
"LGPL-3.0"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Michiel Rook",
|
||||
"email": "mrook@php.net"
|
||||
},
|
||||
{
|
||||
"name": "Phing Community",
|
||||
"homepage": "https://www.phing.info/trac/wiki/Development/Contributors"
|
||||
}
|
||||
],
|
||||
"description": "PHing Is Not GNU make; it's a PHP project build system or build tool based on Apache Ant.",
|
||||
"homepage": "https://www.phing.info/",
|
||||
"keywords": [
|
||||
"build",
|
||||
"phing",
|
||||
"task",
|
||||
"tool"
|
||||
],
|
||||
"time": "2016-03-10 21:39:23"
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/reflection-common",
|
||||
"version": "1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpDocumentor/ReflectionCommon.git",
|
||||
"reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c",
|
||||
"reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.5"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.6"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"phpDocumentor\\Reflection\\": [
|
||||
"src"
|
||||
]
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jaap van Otterdijk",
|
||||
"email": "opensource@ijaap.nl"
|
||||
}
|
||||
],
|
||||
"description": "Common reflection classes used by phpdocumentor to reflect the code structure",
|
||||
"homepage": "http://www.phpdoc.org",
|
||||
"keywords": [
|
||||
"FQSEN",
|
||||
"phpDocumentor",
|
||||
"phpdoc",
|
||||
"reflection",
|
||||
"static analysis"
|
||||
],
|
||||
"time": "2015-12-27 11:43:31"
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/reflection-docblock",
|
||||
"version": "3.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
|
||||
"reference": "9270140b940ff02e58ec577c237274e92cd40cdd"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/9270140b940ff02e58ec577c237274e92cd40cdd",
|
||||
"reference": "9270140b940ff02e58ec577c237274e92cd40cdd",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.5",
|
||||
"phpdocumentor/reflection-common": "^1.0@dev",
|
||||
"phpdocumentor/type-resolver": "^0.2.0",
|
||||
"webmozart/assert": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "^0.9.4",
|
||||
"phpunit/phpunit": "^4.4"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"phpDocumentor\\Reflection\\": [
|
||||
"src/"
|
||||
]
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Mike van Riel",
|
||||
"email": "me@mikevanriel.com"
|
||||
}
|
||||
],
|
||||
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
|
||||
"time": "2016-06-10 09:48:41"
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/type-resolver",
|
||||
"version": "0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpDocumentor/TypeResolver.git",
|
||||
"reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b39c7a5b194f9ed7bd0dd345c751007a41862443",
|
||||
"reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.5",
|
||||
"phpdocumentor/reflection-common": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "^0.9.4",
|
||||
"phpunit/phpunit": "^5.2||^4.8.24"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"phpDocumentor\\Reflection\\": [
|
||||
"src/"
|
||||
]
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Mike van Riel",
|
||||
"email": "me@mikevanriel.com"
|
||||
}
|
||||
],
|
||||
"time": "2016-06-10 07:14:17"
|
||||
},
|
||||
{
|
||||
"name": "phpspec/prophecy",
|
||||
"version": "v1.6.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpspec/prophecy.git",
|
||||
"reference": "58a8137754bc24b25740d4281399a4a3596058e0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/58a8137754bc24b25740d4281399a4a3596058e0",
|
||||
"reference": "58a8137754bc24b25740d4281399a4a3596058e0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/instantiator": "^1.0.2",
|
||||
"php": "^5.3|^7.0",
|
||||
"phpdocumentor/reflection-docblock": "^2.0|^3.0.2",
|
||||
"sebastian/comparator": "^1.1",
|
||||
"sebastian/recursion-context": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpspec/phpspec": "^2.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.6.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Prophecy\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Konstantin Kudryashov",
|
||||
"email": "ever.zet@gmail.com",
|
||||
"homepage": "http://everzet.com"
|
||||
},
|
||||
{
|
||||
"name": "Marcello Duarte",
|
||||
"email": "marcello.duarte@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Highly opinionated mocking framework for PHP 5.3+",
|
||||
"homepage": "https://github.com/phpspec/prophecy",
|
||||
"keywords": [
|
||||
"Double",
|
||||
"Dummy",
|
||||
"fake",
|
||||
"mock",
|
||||
"spy",
|
||||
"stub"
|
||||
],
|
||||
"time": "2016-06-07 08:13:47"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
"version": "2.2.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||
"reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979",
|
||||
"reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3",
|
||||
"phpunit/php-file-iterator": "~1.3",
|
||||
"phpunit/php-text-template": "~1.2",
|
||||
"phpunit/php-token-stream": "~1.3",
|
||||
"sebastian/environment": "^1.3.2",
|
||||
"sebastian/version": "~1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-xdebug": ">=2.1.4",
|
||||
"phpunit/phpunit": "~4"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-dom": "*",
|
||||
"ext-xdebug": ">=2.2.1",
|
||||
"ext-xmlwriter": "*"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.2.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sb@sebastian-bergmann.de",
|
||||
"role": "lead"
|
||||
}
|
||||
],
|
||||
"description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
|
||||
"homepage": "https://github.com/sebastianbergmann/php-code-coverage",
|
||||
"keywords": [
|
||||
"coverage",
|
||||
"testing",
|
||||
"xunit"
|
||||
],
|
||||
"time": "2015-10-06 15:47:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-file-iterator",
|
||||
"version": "1.4.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
|
||||
"reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0",
|
||||
"reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.4.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sb@sebastian-bergmann.de",
|
||||
"role": "lead"
|
||||
}
|
||||
],
|
||||
"description": "FilterIterator implementation that filters files based on a list of suffixes.",
|
||||
"homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
|
||||
"keywords": [
|
||||
"filesystem",
|
||||
"iterator"
|
||||
],
|
||||
"time": "2015-06-21 13:08:43"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-text-template",
|
||||
"version": "1.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-text-template.git",
|
||||
"reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
|
||||
"reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sebastian@phpunit.de",
|
||||
"role": "lead"
|
||||
}
|
||||
],
|
||||
"description": "Simple template engine.",
|
||||
"homepage": "https://github.com/sebastianbergmann/php-text-template/",
|
||||
"keywords": [
|
||||
"template"
|
||||
],
|
||||
"time": "2015-06-21 13:50:34"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-timer",
|
||||
"version": "1.0.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-timer.git",
|
||||
"reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260",
|
||||
"reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4|~5"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sb@sebastian-bergmann.de",
|
||||
"role": "lead"
|
||||
}
|
||||
],
|
||||
"description": "Utility class for timing",
|
||||
"homepage": "https://github.com/sebastianbergmann/php-timer/",
|
||||
"keywords": [
|
||||
"timer"
|
||||
],
|
||||
"time": "2016-05-12 18:03:57"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-token-stream",
|
||||
"version": "1.4.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
|
||||
"reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da",
|
||||
"reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-tokenizer": "*",
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.2"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.4-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sebastian@phpunit.de"
|
||||
}
|
||||
],
|
||||
"description": "Wrapper around PHP's tokenizer extension.",
|
||||
"homepage": "https://github.com/sebastianbergmann/php-token-stream/",
|
||||
"keywords": [
|
||||
"tokenizer"
|
||||
],
|
||||
"time": "2015-09-15 10:49:45"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "4.8.26",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "fc1d8cd5b5de11625979125c5639347896ac2c74"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/fc1d8cd5b5de11625979125c5639347896ac2c74",
|
||||
"reference": "fc1d8cd5b5de11625979125c5639347896ac2c74",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-dom": "*",
|
||||
"ext-json": "*",
|
||||
"ext-pcre": "*",
|
||||
"ext-reflection": "*",
|
||||
"ext-spl": "*",
|
||||
"php": ">=5.3.3",
|
||||
"phpspec/prophecy": "^1.3.1",
|
||||
"phpunit/php-code-coverage": "~2.1",
|
||||
"phpunit/php-file-iterator": "~1.4",
|
||||
"phpunit/php-text-template": "~1.2",
|
||||
"phpunit/php-timer": "^1.0.6",
|
||||
"phpunit/phpunit-mock-objects": "~2.3",
|
||||
"sebastian/comparator": "~1.1",
|
||||
"sebastian/diff": "~1.2",
|
||||
"sebastian/environment": "~1.3",
|
||||
"sebastian/exporter": "~1.2",
|
||||
"sebastian/global-state": "~1.0",
|
||||
"sebastian/version": "~1.0",
|
||||
"symfony/yaml": "~2.1|~3.0"
|
||||
},
|
||||
"suggest": {
|
||||
"phpunit/php-invoker": "~1.1"
|
||||
},
|
||||
"bin": [
|
||||
"phpunit"
|
||||
],
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.8.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sebastian@phpunit.de",
|
||||
"role": "lead"
|
||||
}
|
||||
],
|
||||
"description": "The PHP Unit Testing framework.",
|
||||
"homepage": "https://phpunit.de/",
|
||||
"keywords": [
|
||||
"phpunit",
|
||||
"testing",
|
||||
"xunit"
|
||||
],
|
||||
"time": "2016-05-17 03:09:28"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit-mock-objects",
|
||||
"version": "2.3.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
|
||||
"reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983",
|
||||
"reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/instantiator": "^1.0.2",
|
||||
"php": ">=5.3.3",
|
||||
"phpunit/php-text-template": "~1.2",
|
||||
"sebastian/exporter": "~1.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.4"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-soap": "*"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.3.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sb@sebastian-bergmann.de",
|
||||
"role": "lead"
|
||||
}
|
||||
],
|
||||
"description": "Mock Object library for PHPUnit",
|
||||
"homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
|
||||
"keywords": [
|
||||
"mock",
|
||||
"xunit"
|
||||
],
|
||||
"time": "2015-10-02 06:51:40"
|
||||
},
|
||||
{
|
||||
"name": "pimple/pimple",
|
||||
"version": "v2.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/silexphp/Pimple.git",
|
||||
"reference": "ea22fb2880faf7b7b0e17c9809c6fe25b071fd76"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/silexphp/Pimple/zipball/ea22fb2880faf7b7b0e17c9809c6fe25b071fd76",
|
||||
"reference": "ea22fb2880faf7b7b0e17c9809c6fe25b071fd76",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.1.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Pimple": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
}
|
||||
],
|
||||
"description": "Pimple is a simple Dependency Injection Container for PHP 5.3",
|
||||
"homepage": "http://pimple.sensiolabs.org",
|
||||
"keywords": [
|
||||
"container",
|
||||
"dependency injection"
|
||||
],
|
||||
"time": "2014-07-24 07:10:08"
|
||||
},
|
||||
{
|
||||
"name": "sami/sami",
|
||||
"version": "v2.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/FriendsOfPHP/Sami.git",
|
||||
"reference": "fa58b324f41aa2aefe21dac4f22d8c98965fc012"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/FriendsOfPHP/Sami/zipball/fa58b324f41aa2aefe21dac4f22d8c98965fc012",
|
||||
"reference": "fa58b324f41aa2aefe21dac4f22d8c98965fc012",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"michelf/php-markdown": "~1.3",
|
||||
"nikic/php-parser": "0.9.*",
|
||||
"php": ">=5.3.0",
|
||||
"pimple/pimple": "2.*",
|
||||
"symfony/console": "~2.1",
|
||||
"symfony/filesystem": "~2.1",
|
||||
"symfony/finder": "~2.1",
|
||||
"symfony/process": "~2.1",
|
||||
"symfony/yaml": "~2.1",
|
||||
"twig/twig": "1.*"
|
||||
},
|
||||
"bin": [
|
||||
"sami.php"
|
||||
],
|
||||
"type": "application",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Sami": "."
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
}
|
||||
],
|
||||
"description": "Sami, an API documentation generator",
|
||||
"homepage": "http://sami.sensiolabs.org",
|
||||
"keywords": [
|
||||
"phpdoc"
|
||||
],
|
||||
"time": "2014-06-25 12:05:18"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/comparator",
|
||||
"version": "1.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/comparator.git",
|
||||
"reference": "937efb279bd37a375bcadf584dec0726f84dbf22"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/937efb279bd37a375bcadf584dec0726f84dbf22",
|
||||
"reference": "937efb279bd37a375bcadf584dec0726f84dbf22",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3",
|
||||
"sebastian/diff": "~1.2",
|
||||
"sebastian/exporter": "~1.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.4"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.2.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jeff Welch",
|
||||
"email": "whatthejeff@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Volker Dusch",
|
||||
"email": "github@wallbash.com"
|
||||
},
|
||||
{
|
||||
"name": "Bernhard Schussek",
|
||||
"email": "bschussek@2bepublished.at"
|
||||
},
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sebastian@phpunit.de"
|
||||
}
|
||||
],
|
||||
"description": "Provides the functionality to compare PHP values for equality",
|
||||
"homepage": "http://www.github.com/sebastianbergmann/comparator",
|
||||
"keywords": [
|
||||
"comparator",
|
||||
"compare",
|
||||
"equality"
|
||||
],
|
||||
"time": "2015-07-26 15:48:44"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/diff",
|
||||
"version": "1.4.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/diff.git",
|
||||
"reference": "13edfd8706462032c2f52b4b862974dd46b71c9e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e",
|
||||
"reference": "13edfd8706462032c2f52b4b862974dd46b71c9e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.8"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.4-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Kore Nordmann",
|
||||
"email": "mail@kore-nordmann.de"
|
||||
},
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sebastian@phpunit.de"
|
||||
}
|
||||
],
|
||||
"description": "Diff implementation",
|
||||
"homepage": "https://github.com/sebastianbergmann/diff",
|
||||
"keywords": [
|
||||
"diff"
|
||||
],
|
||||
"time": "2015-12-08 07:14:41"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/environment",
|
||||
"version": "1.3.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/environment.git",
|
||||
"reference": "4e8f0da10ac5802913afc151413bc8c53b6c2716"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/4e8f0da10ac5802913afc151413bc8c53b6c2716",
|
||||
"reference": "4e8f0da10ac5802913afc151413bc8c53b6c2716",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.4"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.3.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sebastian@phpunit.de"
|
||||
}
|
||||
],
|
||||
"description": "Provides functionality to handle HHVM/PHP environments",
|
||||
"homepage": "http://www.github.com/sebastianbergmann/environment",
|
||||
"keywords": [
|
||||
"Xdebug",
|
||||
"environment",
|
||||
"hhvm"
|
||||
],
|
||||
"time": "2016-05-17 03:18:57"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/exporter",
|
||||
"version": "1.2.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/exporter.git",
|
||||
"reference": "42c4c2eec485ee3e159ec9884f95b431287edde4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4",
|
||||
"reference": "42c4c2eec485ee3e159ec9884f95b431287edde4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3",
|
||||
"sebastian/recursion-context": "~1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-mbstring": "*",
|
||||
"phpunit/phpunit": "~4.4"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.3.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jeff Welch",
|
||||
"email": "whatthejeff@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Volker Dusch",
|
||||
"email": "github@wallbash.com"
|
||||
},
|
||||
{
|
||||
"name": "Bernhard Schussek",
|
||||
"email": "bschussek@2bepublished.at"
|
||||
},
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sebastian@phpunit.de"
|
||||
},
|
||||
{
|
||||
"name": "Adam Harvey",
|
||||
"email": "aharvey@php.net"
|
||||
}
|
||||
],
|
||||
"description": "Provides the functionality to export PHP variables for visualization",
|
||||
"homepage": "http://www.github.com/sebastianbergmann/exporter",
|
||||
"keywords": [
|
||||
"export",
|
||||
"exporter"
|
||||
],
|
||||
"time": "2016-06-17 09:04:28"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/global-state",
|
||||
"version": "1.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/global-state.git",
|
||||
"reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4",
|
||||
"reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.2"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-uopz": "*"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sebastian@phpunit.de"
|
||||
}
|
||||
],
|
||||
"description": "Snapshotting of global state",
|
||||
"homepage": "http://www.github.com/sebastianbergmann/global-state",
|
||||
"keywords": [
|
||||
"global state"
|
||||
],
|
||||
"time": "2015-10-12 03:26:01"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/recursion-context",
|
||||
"version": "1.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/recursion-context.git",
|
||||
"reference": "913401df809e99e4f47b27cdd781f4a258d58791"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/913401df809e99e4f47b27cdd781f4a258d58791",
|
||||
"reference": "913401df809e99e4f47b27cdd781f4a258d58791",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.4"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jeff Welch",
|
||||
"email": "whatthejeff@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sebastian@phpunit.de"
|
||||
},
|
||||
{
|
||||
"name": "Adam Harvey",
|
||||
"email": "aharvey@php.net"
|
||||
}
|
||||
],
|
||||
"description": "Provides functionality to recursively process PHP variables",
|
||||
"homepage": "http://www.github.com/sebastianbergmann/recursion-context",
|
||||
"time": "2015-11-11 19:50:13"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/version",
|
||||
"version": "1.0.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/version.git",
|
||||
"reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
|
||||
"reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sebastian@phpunit.de",
|
||||
"role": "lead"
|
||||
}
|
||||
],
|
||||
"description": "Library that helps with managing the version number of Git-hosted PHP projects",
|
||||
"homepage": "https://github.com/sebastianbergmann/version",
|
||||
"time": "2015-06-21 13:59:46"
|
||||
},
|
||||
{
|
||||
"name": "squizlabs/php_codesniffer",
|
||||
"version": "2.6.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
|
||||
"reference": "fb72ed32f8418db5e7770be1653e62e0d6f5dd3d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/fb72ed32f8418db5e7770be1653e62e0d6f5dd3d",
|
||||
"reference": "fb72ed32f8418db5e7770be1653e62e0d6f5dd3d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-simplexml": "*",
|
||||
"ext-tokenizer": "*",
|
||||
"ext-xmlwriter": "*",
|
||||
"php": ">=5.1.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.0"
|
||||
},
|
||||
"bin": [
|
||||
"scripts/phpcs",
|
||||
"scripts/phpcbf"
|
||||
],
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"CodeSniffer.php",
|
||||
"CodeSniffer/CLI.php",
|
||||
"CodeSniffer/Exception.php",
|
||||
"CodeSniffer/File.php",
|
||||
"CodeSniffer/Fixer.php",
|
||||
"CodeSniffer/Report.php",
|
||||
"CodeSniffer/Reporting.php",
|
||||
"CodeSniffer/Sniff.php",
|
||||
"CodeSniffer/Tokens.php",
|
||||
"CodeSniffer/Reports/",
|
||||
"CodeSniffer/Tokenizers/",
|
||||
"CodeSniffer/DocGenerators/",
|
||||
"CodeSniffer/Standards/AbstractPatternSniff.php",
|
||||
"CodeSniffer/Standards/AbstractScopeSniff.php",
|
||||
"CodeSniffer/Standards/AbstractVariableSniff.php",
|
||||
"CodeSniffer/Standards/IncorrectPatternException.php",
|
||||
"CodeSniffer/Standards/Generic/Sniffs/",
|
||||
"CodeSniffer/Standards/MySource/Sniffs/",
|
||||
"CodeSniffer/Standards/PEAR/Sniffs/",
|
||||
"CodeSniffer/Standards/PSR1/Sniffs/",
|
||||
"CodeSniffer/Standards/PSR2/Sniffs/",
|
||||
"CodeSniffer/Standards/Squiz/Sniffs/",
|
||||
"CodeSniffer/Standards/Zend/Sniffs/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Greg Sherwood",
|
||||
"role": "lead"
|
||||
}
|
||||
],
|
||||
"description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
|
||||
"homepage": "http://www.squizlabs.com/php-codesniffer",
|
||||
"keywords": [
|
||||
"phpcs",
|
||||
"standards"
|
||||
],
|
||||
"time": "2016-05-30 22:24:32"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v2.8.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "5ac8bc9aa77bb2edf06af3a1bb6bc1020d23acd3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/5ac8bc9aa77bb2edf06af3a1bb6bc1020d23acd3",
|
||||
"reference": "5ac8bc9aa77bb2edf06af3a1bb6bc1020d23acd3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.9",
|
||||
"symfony/polyfill-mbstring": "~1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"psr/log": "~1.0",
|
||||
"symfony/event-dispatcher": "~2.1|~3.0.0",
|
||||
"symfony/process": "~2.1|~3.0.0"
|
||||
},
|
||||
"suggest": {
|
||||
"psr/log": "For using the console logger",
|
||||
"symfony/event-dispatcher": "",
|
||||
"symfony/process": ""
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.8-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Console\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Console Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2016-06-06 15:06:25"
|
||||
},
|
||||
{
|
||||
"name": "symfony/filesystem",
|
||||
"version": "v2.8.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/filesystem.git",
|
||||
"reference": "dee379131dceed90a429e951546b33edfe7dccbb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/dee379131dceed90a429e951546b33edfe7dccbb",
|
||||
"reference": "dee379131dceed90a429e951546b33edfe7dccbb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.9"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.8-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Filesystem\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Filesystem Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2016-04-12 18:01:21"
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v2.8.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/finder.git",
|
||||
"reference": "3ec095fab1800222732ca522a95dce8fa124007b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/3ec095fab1800222732ca522a95dce8fa124007b",
|
||||
"reference": "3ec095fab1800222732ca522a95dce8fa124007b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.9"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.8-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Finder\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Finder Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2016-06-06 11:11:27"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "dff51f72b0706335131b00a7f49606168c582594"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/dff51f72b0706335131b00a7f49606168c582594",
|
||||
"reference": "dff51f72b0706335131b00a7f49606168c582594",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-mbstring": "For best performance"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.2-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Mbstring\\": ""
|
||||
},
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill for the Mbstring extension",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"mbstring",
|
||||
"polyfill",
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"time": "2016-05-18 14:26:46"
|
||||
},
|
||||
{
|
||||
"name": "symfony/process",
|
||||
"version": "v2.8.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/process.git",
|
||||
"reference": "115347d00c342198cdc52a7bd8bc15b5ab43500c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/115347d00c342198cdc52a7bd8bc15b5ab43500c",
|
||||
"reference": "115347d00c342198cdc52a7bd8bc15b5ab43500c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.9"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.8-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Process\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Process Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2016-06-06 11:11:27"
|
||||
},
|
||||
{
|
||||
"name": "symfony/yaml",
|
||||
"version": "v2.8.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/yaml.git",
|
||||
"reference": "815fabf3f48c7d1df345a69d1ad1a88f59757b34"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/815fabf3f48c7d1df345a69d1ad1a88f59757b34",
|
||||
"reference": "815fabf3f48c7d1df345a69d1ad1a88f59757b34",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.9"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.8-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Yaml\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Yaml Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2016-06-06 11:11:27"
|
||||
},
|
||||
{
|
||||
"name": "twig/twig",
|
||||
"version": "v1.24.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/twigphp/Twig.git",
|
||||
"reference": "3566d311a92aae4deec6e48682dc5a4528c4a512"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/3566d311a92aae4deec6e48682dc5a4528c4a512",
|
||||
"reference": "3566d311a92aae4deec6e48682dc5a4528c4a512",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.2.7"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/debug": "~2.7",
|
||||
"symfony/phpunit-bridge": "~2.7"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.24-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Twig_": "lib/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com",
|
||||
"homepage": "http://fabien.potencier.org",
|
||||
"role": "Lead Developer"
|
||||
},
|
||||
{
|
||||
"name": "Armin Ronacher",
|
||||
"email": "armin.ronacher@active-4.com",
|
||||
"role": "Project Founder"
|
||||
},
|
||||
{
|
||||
"name": "Twig Team",
|
||||
"homepage": "http://twig.sensiolabs.org/contributors",
|
||||
"role": "Contributors"
|
||||
}
|
||||
],
|
||||
"description": "Twig, the flexible, fast, and secure template language for PHP",
|
||||
"homepage": "http://twig.sensiolabs.org",
|
||||
"keywords": [
|
||||
"templating"
|
||||
],
|
||||
"time": "2016-05-30 09:11:59"
|
||||
},
|
||||
{
|
||||
"name": "webmozart/assert",
|
||||
"version": "1.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/webmozart/assert.git",
|
||||
"reference": "30eed06dd6bc88410a4ff7f77b6d22f3ce13dbde"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/webmozart/assert/zipball/30eed06dd6bc88410a4ff7f77b6d22f3ce13dbde",
|
||||
"reference": "30eed06dd6bc88410a4ff7f77b6d22f3ce13dbde",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.6"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Webmozart\\Assert\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Bernhard Schussek",
|
||||
"email": "bschussek@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Assertions to validate method input/output with nice error messages.",
|
||||
"keywords": [
|
||||
"assert",
|
||||
"check",
|
||||
"validate"
|
||||
],
|
||||
"time": "2015-08-24 13:29:44"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"platform-dev": []
|
||||
}
|
||||
|
|
@ -76,6 +76,10 @@ abstract class Base
|
|||
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
|
||||
*/
|
||||
const MODE_CFB = 3;
|
||||
/**
|
||||
* Encrypt / decrypt using the Cipher Feedback mode (8bit)
|
||||
*/
|
||||
const MODE_CFB8 = 38;
|
||||
/**
|
||||
* Encrypt / decrypt using the Output Feedback mode.
|
||||
*
|
||||
|
|
@ -409,7 +413,7 @@ abstract class Base
|
|||
* @var mixed
|
||||
* @access private
|
||||
*/
|
||||
var $use_inline_crypt;
|
||||
var $use_inline_crypt = true;
|
||||
|
||||
/**
|
||||
* If OpenSSL can be used in ECB but not in CTR we can emulate CTR
|
||||
|
|
@ -479,6 +483,7 @@ abstract class Base
|
|||
break;
|
||||
case self::MODE_CTR:
|
||||
case self::MODE_CFB:
|
||||
case self::MODE_CFB8:
|
||||
case self::MODE_OFB:
|
||||
case self::MODE_STREAM:
|
||||
$this->mode = $mode;
|
||||
|
|
@ -490,11 +495,6 @@ abstract class Base
|
|||
}
|
||||
|
||||
$this->_setEngine();
|
||||
|
||||
// Determining whether inline crypting can be used by the cipher
|
||||
if ($this->use_inline_crypt !== false && function_exists('create_function')) {
|
||||
$this->use_inline_crypt = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -644,10 +644,10 @@ abstract class Base
|
|||
case !function_exists('hash_algos'):
|
||||
case !in_array($hash, hash_algos()):
|
||||
$i = 1;
|
||||
$hmac = new Hash();
|
||||
$hmac->setHash($hash);
|
||||
$hmac->setKey($password);
|
||||
while (strlen($key) < $dkLen) {
|
||||
$hmac = new Hash();
|
||||
$hmac->setHash($hash);
|
||||
$hmac->setKey($password);
|
||||
$f = $u = $hmac->hash($salt . pack('N', $i++));
|
||||
for ($j = 2; $j <= $count; ++$j) {
|
||||
$u = $hmac->hash($u);
|
||||
|
|
@ -702,7 +702,7 @@ abstract class Base
|
|||
case self::MODE_STREAM:
|
||||
return openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options);
|
||||
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;
|
||||
case self::MODE_CBC:
|
||||
$result = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, $this->openssl_options, $this->encryptIV);
|
||||
|
|
@ -762,6 +762,16 @@ abstract class Base
|
|||
$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;
|
||||
case self::MODE_OFB:
|
||||
return $this->_openssl_ofb_process($plaintext, $this->encryptIV, $this->enbuffer);
|
||||
|
|
@ -769,12 +779,14 @@ abstract class Base
|
|||
}
|
||||
|
||||
if ($this->engine === self::ENGINE_MCRYPT) {
|
||||
set_error_handler(array($this, 'do_nothing'));
|
||||
|
||||
if ($this->changed) {
|
||||
$this->_setupMcrypt();
|
||||
$this->changed = false;
|
||||
}
|
||||
if ($this->enchanged) {
|
||||
@mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
|
||||
mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
|
||||
$this->enchanged = false;
|
||||
}
|
||||
|
||||
|
|
@ -807,15 +819,15 @@ abstract class Base
|
|||
if ($len >= $block_size) {
|
||||
if ($this->enbuffer['enmcrypt_init'] === false || $len > $this->cfb_init_len) {
|
||||
if ($this->enbuffer['enmcrypt_init'] === true) {
|
||||
@mcrypt_generic_init($this->enmcrypt, $this->key, $iv);
|
||||
mcrypt_generic_init($this->enmcrypt, $this->key, $iv);
|
||||
$this->enbuffer['enmcrypt_init'] = false;
|
||||
}
|
||||
$ciphertext.= @mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % $block_size));
|
||||
$ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % $block_size));
|
||||
$iv = substr($ciphertext, -$block_size);
|
||||
$len%= $block_size;
|
||||
} else {
|
||||
while ($len >= $block_size) {
|
||||
$iv = @mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, $block_size);
|
||||
$iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, $block_size);
|
||||
$ciphertext.= $iv;
|
||||
$len-= $block_size;
|
||||
$i+= $block_size;
|
||||
|
|
@ -824,22 +836,26 @@ abstract class Base
|
|||
}
|
||||
|
||||
if ($len) {
|
||||
$iv = @mcrypt_generic($this->ecb, $iv);
|
||||
$iv = mcrypt_generic($this->ecb, $iv);
|
||||
$block = $iv ^ substr($plaintext, -$len);
|
||||
$iv = substr_replace($iv, $block, 0, $len);
|
||||
$ciphertext.= $block;
|
||||
$pos = $len;
|
||||
}
|
||||
|
||||
restore_error_handler();
|
||||
|
||||
return $ciphertext;
|
||||
}
|
||||
|
||||
$ciphertext = @mcrypt_generic($this->enmcrypt, $plaintext);
|
||||
$ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
|
||||
|
||||
if (!$this->continuousBuffer) {
|
||||
@mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
|
||||
mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
|
||||
}
|
||||
|
||||
restore_error_handler();
|
||||
|
||||
return $ciphertext;
|
||||
}
|
||||
|
||||
|
|
@ -942,6 +958,24 @@ abstract class Base
|
|||
$pos = $len;
|
||||
}
|
||||
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:
|
||||
$xor = $this->encryptIV;
|
||||
if (strlen($buffer['xor'])) {
|
||||
|
|
@ -1007,14 +1041,14 @@ abstract class Base
|
|||
break;
|
||||
case self::MODE_ECB:
|
||||
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);
|
||||
break;
|
||||
case self::MODE_CBC:
|
||||
if (!defined('OPENSSL_RAW_DATA')) {
|
||||
$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;
|
||||
} else {
|
||||
$offset = $this->block_size;
|
||||
|
|
@ -1072,6 +1106,16 @@ abstract class Base
|
|||
$iv = substr($ciphertext, -$this->block_size);
|
||||
}
|
||||
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:
|
||||
$plaintext = $this->_openssl_ofb_process($ciphertext, $this->decryptIV, $this->debuffer);
|
||||
}
|
||||
|
|
@ -1080,13 +1124,14 @@ abstract class Base
|
|||
}
|
||||
|
||||
if ($this->engine === self::ENGINE_MCRYPT) {
|
||||
set_error_handler(array($this, 'do_nothing'));
|
||||
$block_size = $this->block_size;
|
||||
if ($this->changed) {
|
||||
$this->_setupMcrypt();
|
||||
$this->changed = false;
|
||||
}
|
||||
if ($this->dechanged) {
|
||||
@mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
|
||||
mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
|
||||
$this->dechanged = false;
|
||||
}
|
||||
|
||||
|
|
@ -1114,26 +1159,30 @@ abstract class Base
|
|||
}
|
||||
if ($len >= $block_size) {
|
||||
$cb = substr($ciphertext, $i, $len - $len % $block_size);
|
||||
$plaintext.= @mcrypt_generic($this->ecb, $iv . $cb) ^ $cb;
|
||||
$plaintext.= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb;
|
||||
$iv = substr($cb, -$block_size);
|
||||
$len%= $block_size;
|
||||
}
|
||||
if ($len) {
|
||||
$iv = @mcrypt_generic($this->ecb, $iv);
|
||||
$iv = mcrypt_generic($this->ecb, $iv);
|
||||
$plaintext.= $iv ^ substr($ciphertext, -$len);
|
||||
$iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len);
|
||||
$pos = $len;
|
||||
}
|
||||
|
||||
restore_error_handler();
|
||||
|
||||
return $plaintext;
|
||||
}
|
||||
|
||||
$plaintext = @mdecrypt_generic($this->demcrypt, $ciphertext);
|
||||
$plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
|
||||
|
||||
if (!$this->continuousBuffer) {
|
||||
@mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
|
||||
mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
|
||||
}
|
||||
|
||||
restore_error_handler();
|
||||
|
||||
return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
|
||||
}
|
||||
|
||||
|
|
@ -1235,6 +1284,24 @@ abstract class Base
|
|||
$pos = $len;
|
||||
}
|
||||
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:
|
||||
$xor = $this->decryptIV;
|
||||
if (strlen($buffer['xor'])) {
|
||||
|
|
@ -1297,7 +1364,7 @@ abstract class Base
|
|||
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
|
||||
$block = substr($plaintext, $i, $block_size);
|
||||
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;
|
||||
$buffer['ciphertext'].= $result;
|
||||
}
|
||||
|
|
@ -1308,7 +1375,7 @@ abstract class Base
|
|||
} else {
|
||||
for ($i = 0; $i < strlen($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;
|
||||
$this->_increment_str($xor);
|
||||
$ciphertext.= $block ^ $otp;
|
||||
|
|
@ -1352,7 +1419,7 @@ abstract class Base
|
|||
}
|
||||
if ($this->continuousBuffer) {
|
||||
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);
|
||||
if ($overflow) {
|
||||
|
|
@ -1435,6 +1502,8 @@ abstract class Base
|
|||
return 'ctr';
|
||||
case self::MODE_CFB:
|
||||
return 'cfb';
|
||||
case self::MODE_CFB8:
|
||||
return 'cfb8';
|
||||
case self::MODE_OFB:
|
||||
return 'ofb';
|
||||
}
|
||||
|
|
@ -1591,9 +1660,12 @@ abstract class Base
|
|||
}
|
||||
return false;
|
||||
case self::ENGINE_MCRYPT:
|
||||
return $this->cipher_name_mcrypt &&
|
||||
set_error_handler(array($this, 'do_nothing'));
|
||||
$result = $this->cipher_name_mcrypt &&
|
||||
extension_loaded('mcrypt') &&
|
||||
in_array($this->cipher_name_mcrypt, @mcrypt_list_algorithms());
|
||||
in_array($this->cipher_name_mcrypt, mcrypt_list_algorithms());
|
||||
restore_error_handler();
|
||||
return $result;
|
||||
case self::ENGINE_INTERNAL:
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1670,17 +1742,19 @@ abstract class Base
|
|||
}
|
||||
|
||||
if ($this->engine != self::ENGINE_MCRYPT && $this->enmcrypt) {
|
||||
set_error_handler(array($this, 'do_nothing'));
|
||||
// Closing the current mcrypt resource(s). _mcryptSetup() will, if needed,
|
||||
// (re)open them with the module named in $this->cipher_name_mcrypt
|
||||
@mcrypt_module_close($this->enmcrypt);
|
||||
@mcrypt_module_close($this->demcrypt);
|
||||
mcrypt_module_close($this->enmcrypt);
|
||||
mcrypt_module_close($this->demcrypt);
|
||||
$this->enmcrypt = null;
|
||||
$this->demcrypt = null;
|
||||
|
||||
if ($this->ecb) {
|
||||
@mcrypt_module_close($this->ecb);
|
||||
mcrypt_module_close($this->ecb);
|
||||
$this->ecb = null;
|
||||
}
|
||||
restore_error_handler();
|
||||
}
|
||||
|
||||
$this->changed = true;
|
||||
|
|
@ -1788,23 +1862,24 @@ abstract class Base
|
|||
self::MODE_ECB => MCRYPT_MODE_ECB,
|
||||
self::MODE_CBC => MCRYPT_MODE_CBC,
|
||||
self::MODE_CFB => 'ncfb',
|
||||
self::MODE_CFB8 => MCRYPT_MODE_CFB,
|
||||
self::MODE_OFB => MCRYPT_MODE_NOFB,
|
||||
self::MODE_STREAM => MCRYPT_MODE_STREAM,
|
||||
);
|
||||
|
||||
$this->demcrypt = @mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');
|
||||
$this->enmcrypt = @mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');
|
||||
$this->demcrypt = mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');
|
||||
$this->enmcrypt = mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');
|
||||
|
||||
// we need the $ecb mcrypt resource (only) in MODE_CFB with enableContinuousBuffer()
|
||||
// to workaround mcrypt's broken ncfb implementation in buffered mode
|
||||
// see: {@link http://phpseclib.sourceforge.net/cfb-demo.phps}
|
||||
if ($this->mode == self::MODE_CFB) {
|
||||
$this->ecb = @mcrypt_module_open($this->cipher_name_mcrypt, '', MCRYPT_MODE_ECB, '');
|
||||
$this->ecb = mcrypt_module_open($this->cipher_name_mcrypt, '', MCRYPT_MODE_ECB, '');
|
||||
}
|
||||
} // else should mcrypt_generic_deinit be called?
|
||||
|
||||
if ($this->mode == self::MODE_CFB) {
|
||||
@mcrypt_generic_init($this->ecb, $this->key, str_repeat("\0", $this->block_size));
|
||||
mcrypt_generic_init($this->ecb, $this->key, str_repeat("\0", $this->block_size));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2359,6 +2434,52 @@ abstract class Base
|
|||
$_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;
|
||||
';
|
||||
break;
|
||||
|
|
@ -2492,7 +2613,8 @@ abstract class Base
|
|||
}
|
||||
|
||||
// Create the $inline function and return its name as string. Ready to run!
|
||||
return create_function('$_action, &$self, $_text', $init_crypt . 'if ($_action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' }');
|
||||
eval('$func = function ($_action, &$self, $_text) { ' . $init_crypt . 'if ($_action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' } };');
|
||||
return $func;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2521,7 +2643,7 @@ abstract class Base
|
|||
*
|
||||
* @see self::_setupInlineCrypt()
|
||||
* @access private
|
||||
* @param $bytes
|
||||
* @param string $bytes
|
||||
* @return string
|
||||
*/
|
||||
function _hashInlineCryptFunction($bytes)
|
||||
|
|
@ -2550,4 +2672,53 @@ abstract class Base
|
|||
return $result . pack('H*', sha1($hash));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert float to int
|
||||
*
|
||||
* On ARM CPUs converting floats to ints doesn't always work
|
||||
*
|
||||
* @access private
|
||||
* @param string $x
|
||||
* @return int
|
||||
*/
|
||||
function safe_intval($x)
|
||||
{
|
||||
switch (true) {
|
||||
case is_int($x):
|
||||
// PHP 5.3, per http://php.net/releases/5_3_0.php, introduced "more consistent float rounding"
|
||||
case (php_uname('m') & "\xDF\xDF\xDF") != 'ARM':
|
||||
return $x;
|
||||
}
|
||||
return (fmod($x, 0x80000000) & 0x7FFFFFFF) |
|
||||
((fmod(floor($x / 0x80000000), 2) & 1) << 31);
|
||||
}
|
||||
|
||||
/**
|
||||
* eval()'able string for in-line float to int
|
||||
*
|
||||
* @access private
|
||||
* @return string
|
||||
*/
|
||||
function safe_intval_inline()
|
||||
{
|
||||
switch (true) {
|
||||
case defined('PHP_INT_SIZE') && PHP_INT_SIZE == 8:
|
||||
case (php_uname('m') & "\xDF\xDF\xDF") != 'ARM':
|
||||
return '%s';
|
||||
break;
|
||||
default:
|
||||
$safeint = '(is_int($temp = %s) ? $temp : (fmod($temp, 0x80000000) & 0x7FFFFFFF) | ';
|
||||
return $safeint . '((fmod(floor($temp / 0x80000000), 2) & 1) << 31))';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dummy error handler to suppress mcrypt errors
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
function do_nothing()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -294,7 +294,7 @@ class Blowfish extends Base
|
|||
function setKeyLength($length)
|
||||
{
|
||||
if ($length < 32) {
|
||||
$this->key_length = 7;
|
||||
$this->key_length = 4;
|
||||
} elseif ($length > 448) {
|
||||
$this->key_length = 56;
|
||||
} else {
|
||||
|
|
@ -317,7 +317,10 @@ class Blowfish extends Base
|
|||
function isValidEngine($engine)
|
||||
{
|
||||
if ($engine == self::ENGINE_OPENSSL) {
|
||||
if ($this->key_length != 16) {
|
||||
if (version_compare(PHP_VERSION, '5.3.7') < 0 && $this->key_length != 16) {
|
||||
return false;
|
||||
}
|
||||
if ($this->key_length < 16) {
|
||||
return false;
|
||||
}
|
||||
$this->cipher_name_openssl_ecb = 'bf-ecb';
|
||||
|
|
@ -405,16 +408,14 @@ class Blowfish extends Base
|
|||
|
||||
for ($i = 0; $i < 16; $i+= 2) {
|
||||
$l^= $p[$i];
|
||||
$r^= ($sb_0[$l >> 24 & 0xff] +
|
||||
$sb_1[$l >> 16 & 0xff] ^
|
||||
$r^= $this->safe_intval(($this->safe_intval($sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]) ^
|
||||
$sb_2[$l >> 8 & 0xff]) +
|
||||
$sb_3[$l & 0xff];
|
||||
$sb_3[$l & 0xff]);
|
||||
|
||||
$r^= $p[$i + 1];
|
||||
$l^= ($sb_0[$r >> 24 & 0xff] +
|
||||
$sb_1[$r >> 16 & 0xff] ^
|
||||
$l^= $this->safe_intval(($this->safe_intval($sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]) ^
|
||||
$sb_2[$r >> 8 & 0xff]) +
|
||||
$sb_3[$r & 0xff];
|
||||
$sb_3[$r & 0xff]);
|
||||
}
|
||||
return pack("N*", $r ^ $p[17], $l ^ $p[16]);
|
||||
}
|
||||
|
|
@ -440,16 +441,14 @@ class Blowfish extends Base
|
|||
|
||||
for ($i = 17; $i > 2; $i-= 2) {
|
||||
$l^= $p[$i];
|
||||
$r^= ($sb_0[$l >> 24 & 0xff] +
|
||||
$sb_1[$l >> 16 & 0xff] ^
|
||||
$r^= $this->safe_intval(($this->safe_intval($sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]) ^
|
||||
$sb_2[$l >> 8 & 0xff]) +
|
||||
$sb_3[$l & 0xff];
|
||||
$sb_3[$l & 0xff]);
|
||||
|
||||
$r^= $p[$i - 1];
|
||||
$l^= ($sb_0[$r >> 24 & 0xff] +
|
||||
$sb_1[$r >> 16 & 0xff] ^
|
||||
$l^= $this->safe_intval(($this->safe_intval($sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]) ^
|
||||
$sb_2[$r >> 8 & 0xff]) +
|
||||
$sb_3[$r & 0xff];
|
||||
$sb_3[$r & 0xff]);
|
||||
}
|
||||
return pack("N*", $r ^ $p[0], $l ^ $p[1]);
|
||||
}
|
||||
|
|
@ -475,6 +474,8 @@ class Blowfish extends Base
|
|||
$code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
|
||||
}
|
||||
|
||||
$safeint = $this->safe_intval_inline();
|
||||
|
||||
if (!isset($lambda_functions[$code_hash])) {
|
||||
switch (true) {
|
||||
case $gen_hi_opt_code:
|
||||
|
|
@ -510,16 +511,14 @@ class Blowfish extends Base
|
|||
for ($i = 0; $i < 16; $i+= 2) {
|
||||
$encrypt_block.= '
|
||||
$l^= ' . $p[$i] . ';
|
||||
$r^= ($sb_0[$l >> 24 & 0xff] +
|
||||
$sb_1[$l >> 16 & 0xff] ^
|
||||
$r^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]') . ' ^
|
||||
$sb_2[$l >> 8 & 0xff]) +
|
||||
$sb_3[$l & 0xff];
|
||||
$sb_3[$l & 0xff]') . ';
|
||||
|
||||
$r^= ' . $p[$i + 1] . ';
|
||||
$l^= ($sb_0[$r >> 24 & 0xff] +
|
||||
$sb_1[$r >> 16 & 0xff] ^
|
||||
$l^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]') . ' ^
|
||||
$sb_2[$r >> 8 & 0xff]) +
|
||||
$sb_3[$r & 0xff];
|
||||
$sb_3[$r & 0xff]') . ';
|
||||
';
|
||||
}
|
||||
$encrypt_block.= '
|
||||
|
|
@ -539,16 +538,14 @@ class Blowfish extends Base
|
|||
for ($i = 17; $i > 2; $i-= 2) {
|
||||
$decrypt_block.= '
|
||||
$l^= ' . $p[$i] . ';
|
||||
$r^= ($sb_0[$l >> 24 & 0xff] +
|
||||
$sb_1[$l >> 16 & 0xff] ^
|
||||
$r^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$l >> 24 & 0xff] + $sb_1[$l >> 16 & 0xff]') . ' ^
|
||||
$sb_2[$l >> 8 & 0xff]) +
|
||||
$sb_3[$l & 0xff];
|
||||
$sb_3[$l & 0xff]') . ';
|
||||
|
||||
$r^= ' . $p[$i - 1] . ';
|
||||
$l^= ($sb_0[$r >> 24 & 0xff] +
|
||||
$sb_1[$r >> 16 & 0xff] ^
|
||||
$l^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb_0[$r >> 24 & 0xff] + $sb_1[$r >> 16 & 0xff]') . ' ^
|
||||
$sb_2[$r >> 8 & 0xff]) +
|
||||
$sb_3[$r & 0xff];
|
||||
$sb_3[$r & 0xff]') . ';
|
||||
';
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1357,8 +1357,8 @@ class DES extends Base
|
|||
$k[self::ENCRYPT][$i] = '$ke[' . $i . ']';
|
||||
$k[self::DECRYPT][$i] = '$kd[' . $i . ']';
|
||||
}
|
||||
$init_encrypt = '$ke = $self->keys[self::ENCRYPT];';
|
||||
$init_decrypt = '$kd = $self->keys[self::DECRYPT];';
|
||||
$init_encrypt = '$ke = $self->keys[$self::ENCRYPT];';
|
||||
$init_decrypt = '$kd = $self->keys[$self::DECRYPT];';
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -112,6 +112,15 @@ class Hash
|
|||
*/
|
||||
var $key = false;
|
||||
|
||||
/**
|
||||
* Computed Key
|
||||
*
|
||||
* @see self::_computeKey()
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
var $computedKey = false;
|
||||
|
||||
/**
|
||||
* Outer XOR (Internal HMAC)
|
||||
*
|
||||
|
|
@ -130,6 +139,15 @@ class Hash
|
|||
*/
|
||||
var $ipad;
|
||||
|
||||
/**
|
||||
* Engine
|
||||
*
|
||||
* @see self::setHash()
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
var $engine;
|
||||
|
||||
/**
|
||||
* Default Constructor.
|
||||
*
|
||||
|
|
@ -166,6 +184,43 @@ class Hash
|
|||
function setKey($key = false)
|
||||
{
|
||||
$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) {
|
||||
case 'md2-96':
|
||||
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;
|
||||
break;
|
||||
case 'sha384':
|
||||
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;
|
||||
default:
|
||||
$mode = CRYPT_HASH_MODE;
|
||||
$this->engine = CRYPT_HASH_MODE;
|
||||
}
|
||||
|
||||
switch ($mode) {
|
||||
switch ($this->engine) {
|
||||
case self::MODE_MHASH:
|
||||
switch ($hash) {
|
||||
case 'md5':
|
||||
|
|
@ -241,6 +315,7 @@ class Hash
|
|||
default:
|
||||
$this->hash = MHASH_SHA1;
|
||||
}
|
||||
$this->_computeKey(self::MODE_MHASH);
|
||||
return;
|
||||
case self::MODE_HASH:
|
||||
switch ($hash) {
|
||||
|
|
@ -257,35 +332,33 @@ class Hash
|
|||
default:
|
||||
$this->hash = 'sha1';
|
||||
}
|
||||
$this->_computeKey(self::MODE_HASH);
|
||||
return;
|
||||
}
|
||||
|
||||
switch ($hash) {
|
||||
case 'md2':
|
||||
$this->b = 16;
|
||||
$this->hash = array($this, '_md2');
|
||||
break;
|
||||
case 'md5':
|
||||
$this->b = 64;
|
||||
$this->hash = array($this, '_md5');
|
||||
break;
|
||||
case 'sha256':
|
||||
$this->b = 64;
|
||||
$this->hash = array($this, '_sha256');
|
||||
break;
|
||||
case 'sha384':
|
||||
case 'sha512':
|
||||
$this->b = 128;
|
||||
$this->hash = array($this, '_sha512');
|
||||
break;
|
||||
case 'sha1':
|
||||
default:
|
||||
$this->b = 64;
|
||||
$this->hash = array($this, '_sha1');
|
||||
}
|
||||
|
||||
$this->ipad = str_repeat(chr(0x36), $this->b);
|
||||
$this->opad = str_repeat(chr(0x5C), $this->b);
|
||||
|
||||
$this->_computeKey(self::MODE_INTERNAL);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -297,33 +370,25 @@ class Hash
|
|||
*/
|
||||
function hash($text)
|
||||
{
|
||||
$mode = is_array($this->hash) ? self::MODE_INTERNAL : CRYPT_HASH_MODE;
|
||||
|
||||
if (!empty($this->key) || is_string($this->key)) {
|
||||
switch ($mode) {
|
||||
switch ($this->engine) {
|
||||
case self::MODE_MHASH:
|
||||
$output = mhash($this->hash, $text, $this->key);
|
||||
$output = mhash($this->hash, $text, $this->computedKey);
|
||||
break;
|
||||
case self::MODE_HASH:
|
||||
$output = hash_hmac($this->hash, $text, $this->key, true);
|
||||
$output = hash_hmac($this->hash, $text, $this->computedKey, true);
|
||||
break;
|
||||
case self::MODE_INTERNAL:
|
||||
/* "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."
|
||||
|
||||
-- http://tools.ietf.org/html/rfc2104#section-2 */
|
||||
$key = strlen($this->key) > $this->b ? call_user_func($this->hash, $this->key) : $this->key;
|
||||
|
||||
$key = str_pad($key, $this->b, chr(0)); // step 1
|
||||
$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
|
||||
$key = str_pad($this->computedKey, $this->b, chr(0)); // step 1
|
||||
$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 {
|
||||
switch ($mode) {
|
||||
switch ($this->engine) {
|
||||
case self::MODE_MHASH:
|
||||
$output = mhash($this->hash, $text);
|
||||
break;
|
||||
|
|
@ -784,7 +849,6 @@ class Hash
|
|||
* _sha256() adds multiple unsigned 32-bit integers. Since PHP doesn't support unsigned integers and since the
|
||||
* possibility of overflow exists, care has to be taken. BigInteger could be used but this should be faster.
|
||||
*
|
||||
* @param int $...
|
||||
* @return int
|
||||
* @see self::_sha256()
|
||||
* @access private
|
||||
|
|
@ -802,7 +866,12 @@ class Hash
|
|||
$result+= $argument < 0 ? ($argument & 0x7FFFFFFF) + 0x80000000 : $argument;
|
||||
}
|
||||
|
||||
return fmod($result, $mod);
|
||||
if ((php_uname('m') & "\xDF\xDF\xDF") != 'ARM') {
|
||||
return fmod($result, $mod);
|
||||
}
|
||||
|
||||
return (fmod($result, 0x80000000) & 0x7FFFFFFF) |
|
||||
((fmod(floor($result / 0x80000000), 2) & 1) << 31);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -296,7 +296,7 @@ class RC2 extends Base
|
|||
function setKeyLength($length)
|
||||
{
|
||||
if ($length < 8) {
|
||||
$this->default_key_length = 8;
|
||||
$this->default_key_length = 1;
|
||||
} elseif ($length > 1024) {
|
||||
$this->default_key_length = 128;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ class RC4 extends Base
|
|||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
var $key = "\0";
|
||||
var $key;
|
||||
|
||||
/**
|
||||
* The Key Stream for decryption and encryption
|
||||
|
|
@ -144,8 +144,10 @@ class RC4 extends Base
|
|||
*/
|
||||
function isValidEngine($engine)
|
||||
{
|
||||
switch ($engine) {
|
||||
case Base::ENGINE_OPENSSL:
|
||||
if ($engine == Base::ENGINE_OPENSSL) {
|
||||
if (version_compare(PHP_VERSION, '5.3.7') >= 0) {
|
||||
$this->cipher_name_openssl = 'rc4-40';
|
||||
} else {
|
||||
switch (strlen($this->key)) {
|
||||
case 5:
|
||||
$this->cipher_name_openssl = 'rc4-40';
|
||||
|
|
@ -159,6 +161,7 @@ class RC4 extends Base
|
|||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return parent::isValidEngine($engine);
|
||||
|
|
|
|||
|
|
@ -182,6 +182,10 @@ class RSA
|
|||
* PKCS#8 formatted private key
|
||||
*/
|
||||
const PRIVATE_FORMAT_PKCS8 = 8;
|
||||
/**
|
||||
* OpenSSH formatted private key
|
||||
*/
|
||||
const PRIVATE_FORMAT_OPENSSH = 9;
|
||||
/**#@-*/
|
||||
|
||||
/**#@+
|
||||
|
|
@ -468,23 +472,27 @@ class RSA
|
|||
break;
|
||||
case extension_loaded('openssl') && file_exists($this->configFile):
|
||||
// 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();
|
||||
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];
|
||||
// avoid generating errors (even with suppression) when phpinfo() is disabled (common in production systems)
|
||||
if (strpos(ini_get('disable_functions'), 'phpinfo') === false) {
|
||||
ob_start();
|
||||
@phpinfo();
|
||||
$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];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -529,7 +537,7 @@ class RSA
|
|||
* @access public
|
||||
* @param int $bits
|
||||
* @param int $timeout
|
||||
* @param array $p
|
||||
* @param array $partial
|
||||
*/
|
||||
function createKey($bits = 1024, $timeout = false, $partial = array())
|
||||
{
|
||||
|
|
@ -708,7 +716,12 @@ class RSA
|
|||
*
|
||||
* @access private
|
||||
* @see self::setPrivateKeyFormat()
|
||||
* @param string $RSAPrivateKey
|
||||
* @param Math_BigInteger $n
|
||||
* @param Math_BigInteger $e
|
||||
* @param Math_BigInteger $d
|
||||
* @param array<int,Math_BigInteger> $primes
|
||||
* @param array<int,Math_BigInteger> $exponents
|
||||
* @param array<int,Math_BigInteger> $coefficients
|
||||
* @return string
|
||||
*/
|
||||
function _convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients)
|
||||
|
|
@ -816,6 +829,58 @@ class RSA
|
|||
$key.= 'Private-MAC: ' . bin2hex($hash->hash($source)) . "\r\n";
|
||||
|
||||
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-----\n" .
|
||||
chunk_split(base64_encode($key), 70, "\n") .
|
||||
"-----END OPENSSH PRIVATE KEY-----\n";
|
||||
default: // eg. self::PRIVATE_FORMAT_PKCS1
|
||||
$components = array();
|
||||
foreach ($raw as $name => $value) {
|
||||
|
|
@ -937,8 +1002,9 @@ class RSA
|
|||
*
|
||||
* @access private
|
||||
* @see self::setPublicKeyFormat()
|
||||
* @param string $RSAPrivateKey
|
||||
* @return string
|
||||
* @param Math_BigInteger $n
|
||||
* @param Math_BigInteger $e
|
||||
* @return string|array<string,Math_BigInteger>
|
||||
*/
|
||||
function _convertPublicKey($n, $e)
|
||||
{
|
||||
|
|
@ -1016,9 +1082,9 @@ class RSA
|
|||
* @access private
|
||||
* @see self::_convertPublicKey()
|
||||
* @see self::_convertPrivateKey()
|
||||
* @param string $key
|
||||
* @param string|array $key
|
||||
* @param int $type
|
||||
* @return array
|
||||
* @return array|bool
|
||||
*/
|
||||
function _parseKey($key, $type)
|
||||
{
|
||||
|
|
@ -1153,6 +1219,7 @@ class RSA
|
|||
$length = $this->_decodeLength($temp);
|
||||
switch ($this->_string_shift($temp, $length)) {
|
||||
case "\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01": // rsaEncryption
|
||||
case "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x0A": // rsaPSS
|
||||
break;
|
||||
case "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03": // pbeWithMD5AndDES-CBC
|
||||
/*
|
||||
|
|
@ -1329,9 +1396,14 @@ class RSA
|
|||
xml_set_character_data_handler($xml, '_data_handler');
|
||||
// add <xml></xml> to account for "dangling" tags like <BitStrength>...</BitStrength> that are sometimes added
|
||||
if (!xml_parse($xml, '<xml>' . $key . '</xml>')) {
|
||||
xml_parser_free($xml);
|
||||
unset($xml);
|
||||
return false;
|
||||
}
|
||||
|
||||
xml_parser_free($xml);
|
||||
unset($xml);
|
||||
|
||||
return isset($this->components['modulus']) && isset($this->components['publicExponent']) ? $this->components : false;
|
||||
// from PuTTY's SSHPUBK.C
|
||||
case self::PRIVATE_FORMAT_PUTTY:
|
||||
|
|
@ -1403,8 +1475,79 @@ class RSA
|
|||
}
|
||||
$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 false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1501,8 +1644,9 @@ class RSA
|
|||
* Returns true on success and false on failure (ie. an incorrect password was provided or the key was malformed)
|
||||
*
|
||||
* @access public
|
||||
* @param string $key
|
||||
* @param int $type optional
|
||||
* @param string|RSA|array $key
|
||||
* @param bool|int $type optional
|
||||
* @return bool
|
||||
*/
|
||||
function loadKey($key, $type = false)
|
||||
{
|
||||
|
|
@ -1559,7 +1703,8 @@ class RSA
|
|||
self::PRIVATE_FORMAT_PKCS1,
|
||||
self::PRIVATE_FORMAT_XML,
|
||||
self::PRIVATE_FORMAT_PUTTY,
|
||||
self::PUBLIC_FORMAT_OPENSSH
|
||||
self::PUBLIC_FORMAT_OPENSSH,
|
||||
self::PRIVATE_FORMAT_OPENSSH
|
||||
);
|
||||
foreach ($types as $type) {
|
||||
$components = $this->_parseKey($key, $type);
|
||||
|
|
@ -1572,6 +1717,15 @@ class RSA
|
|||
}
|
||||
|
||||
if ($components === false) {
|
||||
$this->comment = null;
|
||||
$this->modulus = null;
|
||||
$this->k = null;
|
||||
$this->exponent = null;
|
||||
$this->primes = null;
|
||||
$this->exponents = null;
|
||||
$this->coefficients = null;
|
||||
$this->publicExponent = null;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1733,7 +1887,6 @@ class RSA
|
|||
*
|
||||
* @see self::getPublicKey()
|
||||
* @access public
|
||||
* @param string $key
|
||||
* @param int $type optional
|
||||
*/
|
||||
function getPublicKey($type = self::PUBLIC_FORMAT_PKCS8)
|
||||
|
|
@ -1791,7 +1944,6 @@ class RSA
|
|||
*
|
||||
* @see self::getPublicKey()
|
||||
* @access public
|
||||
* @param string $key
|
||||
* @param int $type optional
|
||||
* @return mixed
|
||||
*/
|
||||
|
|
@ -1816,8 +1968,7 @@ class RSA
|
|||
*
|
||||
* @see self::getPrivateKey()
|
||||
* @access private
|
||||
* @param string $key
|
||||
* @param int $type optional
|
||||
* @param int $mode optional
|
||||
*/
|
||||
function _getPrivatePublicKey($mode = self::PUBLIC_FORMAT_PKCS8)
|
||||
{
|
||||
|
|
@ -2034,7 +2185,7 @@ class RSA
|
|||
* of the hash function Hash) and 0.
|
||||
*
|
||||
* @access public
|
||||
* @param int $format
|
||||
* @param int $sLen
|
||||
*/
|
||||
function setSaltLength($sLen)
|
||||
{
|
||||
|
|
@ -2067,7 +2218,7 @@ class RSA
|
|||
* See {@link http://tools.ietf.org/html/rfc3447#section-4.2 RFC3447#section-4.2}.
|
||||
*
|
||||
* @access private
|
||||
* @param string $x
|
||||
* @param int|string|resource $x
|
||||
* @return \phpseclib\Math\BigInteger
|
||||
*/
|
||||
function _os2ip($x)
|
||||
|
|
@ -2198,16 +2349,21 @@ class RSA
|
|||
*/
|
||||
function _equals($x, $y)
|
||||
{
|
||||
if (function_exists('hash_equals')) {
|
||||
return hash_equals($x, $y);
|
||||
}
|
||||
|
||||
if (strlen($x) != strlen($y)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = 0;
|
||||
$result = "\0";
|
||||
$x^= $y;
|
||||
for ($i = 0; $i < strlen($x); $i++) {
|
||||
$result |= ord($x[$i]) ^ ord($y[$i]);
|
||||
$result|= $x[$i];
|
||||
}
|
||||
|
||||
return $result == 0;
|
||||
return $result === "\0";
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2289,7 +2445,7 @@ class RSA
|
|||
*
|
||||
* @access private
|
||||
* @param string $mgfSeed
|
||||
* @param int $mgfLen
|
||||
* @param int $maskLen
|
||||
* @return string
|
||||
*/
|
||||
function _mgf1($mgfSeed, $maskLen)
|
||||
|
|
@ -2414,19 +2570,26 @@ class RSA
|
|||
$db = $maskedDB ^ $dbMask;
|
||||
$lHash2 = substr($db, 0, $this->hLen);
|
||||
$m = substr($db, $this->hLen);
|
||||
if ($lHash != $lHash2) {
|
||||
user_error('Decryption error');
|
||||
return false;
|
||||
$hashesMatch = $this->_equals($lHash, $lHash2);
|
||||
$leadingZeros = 1;
|
||||
$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');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Output the message M
|
||||
|
||||
return substr($m, 1);
|
||||
return substr($m, $offset + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2605,7 +2768,7 @@ class RSA
|
|||
// if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
|
||||
// be output.
|
||||
|
||||
$emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8);
|
||||
$emLen = ($emBits + 7) >> 3; // ie. ceil($emBits / 8);
|
||||
$sLen = $this->sLen !== null ? $this->sLen : $this->hLen;
|
||||
|
||||
$mHash = $this->hash->hash($m);
|
||||
|
|
@ -2683,7 +2846,7 @@ class RSA
|
|||
|
||||
// RSA verification
|
||||
|
||||
$modBits = 8 * $this->k;
|
||||
$modBits = strlen($this->modulus->toBits());
|
||||
|
||||
$s2 = $this->_os2ip($s);
|
||||
$m2 = $this->_rsavp1($s2);
|
||||
|
|
@ -2691,7 +2854,7 @@ class RSA
|
|||
user_error('Invalid signature');
|
||||
return false;
|
||||
}
|
||||
$em = $this->_i2osp($m2, $modBits >> 3);
|
||||
$em = $this->_i2osp($m2, $this->k);
|
||||
if ($em === false) {
|
||||
user_error('Invalid signature');
|
||||
return false;
|
||||
|
|
@ -2754,6 +2917,59 @@ class RSA
|
|||
return $em;
|
||||
}
|
||||
|
||||
/**
|
||||
* EMSA-PKCS1-V1_5-ENCODE (without NULL)
|
||||
*
|
||||
* Quoting https://tools.ietf.org/html/rfc8017#page-65,
|
||||
*
|
||||
* "The parameters field associated with id-sha1, id-sha224, id-sha256,
|
||||
* id-sha384, id-sha512, id-sha512/224, and id-sha512/256 should
|
||||
* generally be omitted, but if present, it shall have a value of type
|
||||
* NULL"
|
||||
*
|
||||
* @access private
|
||||
* @param string $m
|
||||
* @param int $emLen
|
||||
* @return string
|
||||
*/
|
||||
function _emsa_pkcs1_v1_5_encode_without_null($m, $emLen)
|
||||
{
|
||||
$h = $this->hash->hash($m);
|
||||
if ($h === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch ($this->hashName) {
|
||||
case 'sha1':
|
||||
$t = pack('H*', '301f300706052b0e03021a0414');
|
||||
break;
|
||||
case 'sha256':
|
||||
$t = pack('H*', '302f300b06096086480165030402010420');
|
||||
break;
|
||||
case 'sha384':
|
||||
$t = pack('H*', '303f300b06096086480165030402020430');
|
||||
break;
|
||||
case 'sha512':
|
||||
$t = pack('H*', '304f300b06096086480165030402030440');
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
$t.= $h;
|
||||
$tLen = strlen($t);
|
||||
|
||||
if ($emLen < $tLen + 11) {
|
||||
user_error('Intended encoded message length too short');
|
||||
return false;
|
||||
}
|
||||
|
||||
$ps = str_repeat(chr(0xFF), $emLen - $tLen - 3);
|
||||
|
||||
$em = "\0\1$ps\0$t";
|
||||
|
||||
return $em;
|
||||
}
|
||||
|
||||
/**
|
||||
* RSASSA-PKCS1-V1_5-SIGN
|
||||
*
|
||||
|
|
@ -2791,6 +3007,7 @@ class RSA
|
|||
*
|
||||
* @access private
|
||||
* @param string $m
|
||||
* @param string $s
|
||||
* @return string
|
||||
*/
|
||||
function _rsassa_pkcs1_v1_5_verify($m, $s)
|
||||
|
|
@ -2819,13 +3036,17 @@ class RSA
|
|||
// EMSA-PKCS1-v1_5 encoding
|
||||
|
||||
$em2 = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
|
||||
if ($em2 === false) {
|
||||
$em3 = $this->_emsa_pkcs1_v1_5_encode_without_null($m, $this->k);
|
||||
|
||||
if ($em2 === false && $em3 === false) {
|
||||
user_error('RSA modulus too short');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compare
|
||||
return $this->_equals($em, $em2);
|
||||
|
||||
return ($em2 !== false && $this->_equals($em, $em2)) ||
|
||||
($em3 !== false && $this->_equals($em, $em3));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2931,7 +3152,7 @@ class RSA
|
|||
*
|
||||
* @see self::encrypt()
|
||||
* @access public
|
||||
* @param string $plaintext
|
||||
* @param string $ciphertext
|
||||
* @return string
|
||||
*/
|
||||
function decrypt($ciphertext)
|
||||
|
|
|
|||
|
|
@ -45,6 +45,10 @@ class Random
|
|||
*/
|
||||
static function string($length)
|
||||
{
|
||||
if (!$length) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (version_compare(PHP_VERSION, '7.0.0', '>=')) {
|
||||
try {
|
||||
return \random_bytes($length);
|
||||
|
|
@ -62,7 +66,7 @@ class Random
|
|||
// method 1. prior to PHP 5.3 this would call rand() on windows hence the function_exists('class_alias') call.
|
||||
// ie. class_alias is a function that was introduced in PHP 5.3
|
||||
if (extension_loaded('mcrypt') && function_exists('class_alias')) {
|
||||
return mcrypt_create_iv($length);
|
||||
return @mcrypt_create_iv($length);
|
||||
}
|
||||
// method 2. openssl_random_pseudo_bytes was introduced in PHP 5.3.0 but prior to PHP 5.3.4 there was,
|
||||
// to quote <http://php.net/ChangeLog-5.php#5.3.4>, "possible blocking behavior". as of 5.3.4
|
||||
|
|
@ -93,7 +97,10 @@ class Random
|
|||
$fp = @fopen('/dev/urandom', 'rb');
|
||||
}
|
||||
if ($fp !== true && $fp !== false) { // surprisingly faster than !is_bool() or is_resource()
|
||||
return fread($fp, $length);
|
||||
$temp = fread($fp, $length);
|
||||
if (strlen($temp) == $length) {
|
||||
return $temp;
|
||||
}
|
||||
}
|
||||
// method 3. pretty much does the same thing as method 2 per the following url:
|
||||
// https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1391
|
||||
|
|
@ -101,7 +108,7 @@ class Random
|
|||
// not doing. regardless, this'll only be called if this PHP script couldn't open /dev/urandom due to open_basedir
|
||||
// restrictions or some such
|
||||
if (extension_loaded('mcrypt')) {
|
||||
return mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
|
||||
return @mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
|
||||
}
|
||||
}
|
||||
// at this point we have no choice but to use a pure-PHP CSPRNG
|
||||
|
|
|
|||
|
|
@ -432,8 +432,10 @@ class Twofish extends Base
|
|||
$m2[$q1[$q0[$j] ^ $key[15]] ^ $key[7]] ^
|
||||
$m3[$q1[$q1[$j] ^ $key[16]] ^ $key[8]];
|
||||
$B = ($B << 8) | ($B >> 24 & 0xff);
|
||||
$K[] = $A+= $B;
|
||||
$K[] = (($A+= $B) << 9 | $A >> 23 & 0x1ff);
|
||||
$A = $this->safe_intval($A + $B);
|
||||
$K[] = $A;
|
||||
$A = $this->safe_intval($A + $B);
|
||||
$K[] = ($A << 9 | $A >> 23 & 0x1ff);
|
||||
}
|
||||
for ($i = 0; $i < 256; ++$i) {
|
||||
$S0[$i] = $m0[$q0[$q0[$i] ^ $s4] ^ $s0];
|
||||
|
|
@ -456,8 +458,10 @@ class Twofish extends Base
|
|||
$m2[$q1[$q0[$q0[$j] ^ $key[23]] ^ $key[15]] ^ $key[7]] ^
|
||||
$m3[$q1[$q1[$q0[$j] ^ $key[24]] ^ $key[16]] ^ $key[8]];
|
||||
$B = ($B << 8) | ($B >> 24 & 0xff);
|
||||
$K[] = $A+= $B;
|
||||
$K[] = (($A+= $B) << 9 | $A >> 23 & 0x1ff);
|
||||
$A = $this->safe_intval($A + $B);
|
||||
$K[] = $A;
|
||||
$A = $this->safe_intval($A + $B);
|
||||
$K[] = ($A << 9 | $A >> 23 & 0x1ff);
|
||||
}
|
||||
for ($i = 0; $i < 256; ++$i) {
|
||||
$S0[$i] = $m0[$q0[$q0[$q1[$i] ^ $s8] ^ $s4] ^ $s0];
|
||||
|
|
@ -481,8 +485,10 @@ class Twofish extends Base
|
|||
$m2[$q1[$q0[$q0[$q0[$j] ^ $key[31]] ^ $key[23]] ^ $key[15]] ^ $key[7]] ^
|
||||
$m3[$q1[$q1[$q0[$q1[$j] ^ $key[32]] ^ $key[24]] ^ $key[16]] ^ $key[8]];
|
||||
$B = ($B << 8) | ($B >> 24 & 0xff);
|
||||
$K[] = $A+= $B;
|
||||
$K[] = (($A+= $B) << 9 | $A >> 23 & 0x1ff);
|
||||
$A = $this->safe_intval($A + $B);
|
||||
$K[] = $A;
|
||||
$A = $this->safe_intval($A + $B);
|
||||
$K[] = ($A << 9 | $A >> 23 & 0x1ff);
|
||||
}
|
||||
for ($i = 0; $i < 256; ++$i) {
|
||||
$S0[$i] = $m0[$q0[$q0[$q1[$q1[$i] ^ $sc] ^ $s8] ^ $s4] ^ $s0];
|
||||
|
|
@ -578,9 +584,9 @@ class Twofish extends Base
|
|||
$S1[ $R1 & 0xff] ^
|
||||
$S2[($R1 >> 8) & 0xff] ^
|
||||
$S3[($R1 >> 16) & 0xff];
|
||||
$R2^= $t0 + $t1 + $K[++$ki];
|
||||
$R2^= $this->safe_intval($t0 + $t1 + $K[++$ki]);
|
||||
$R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31);
|
||||
$R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ ($t0 + ($t1 << 1) + $K[++$ki]);
|
||||
$R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ $this->safe_intval($t0 + ($t1 << 1) + $K[++$ki]);
|
||||
|
||||
$t0 = $S0[ $R2 & 0xff] ^
|
||||
$S1[($R2 >> 8) & 0xff] ^
|
||||
|
|
@ -590,9 +596,9 @@ class Twofish extends Base
|
|||
$S1[ $R3 & 0xff] ^
|
||||
$S2[($R3 >> 8) & 0xff] ^
|
||||
$S3[($R3 >> 16) & 0xff];
|
||||
$R0^= ($t0 + $t1 + $K[++$ki]);
|
||||
$R0^= $this->safe_intval($t0 + $t1 + $K[++$ki]);
|
||||
$R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31);
|
||||
$R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ($t0 + ($t1 << 1) + $K[++$ki]);
|
||||
$R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ $this->safe_intval($t0 + ($t1 << 1) + $K[++$ki]);
|
||||
}
|
||||
|
||||
// @codingStandardsIgnoreStart
|
||||
|
|
@ -634,9 +640,9 @@ class Twofish extends Base
|
|||
$S1[$R1 & 0xff] ^
|
||||
$S2[$R1 >> 8 & 0xff] ^
|
||||
$S3[$R1 >> 16 & 0xff];
|
||||
$R3^= $t0 + ($t1 << 1) + $K[--$ki];
|
||||
$R3^= $this->safe_intval($t0 + ($t1 << 1) + $K[--$ki]);
|
||||
$R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31;
|
||||
$R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ ($t0 + $t1 + $K[--$ki]);
|
||||
$R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ $this->safe_intval($t0 + $t1 + $K[--$ki]);
|
||||
|
||||
$t0 = $S0[$R2 & 0xff] ^
|
||||
$S1[$R2 >> 8 & 0xff] ^
|
||||
|
|
@ -646,9 +652,9 @@ class Twofish extends Base
|
|||
$S1[$R3 & 0xff] ^
|
||||
$S2[$R3 >> 8 & 0xff] ^
|
||||
$S3[$R3 >> 16 & 0xff];
|
||||
$R1^= $t0 + ($t1 << 1) + $K[--$ki];
|
||||
$R1^= $this->safe_intval($t0 + ($t1 << 1) + $K[--$ki]);
|
||||
$R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31;
|
||||
$R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ($t0 + $t1 + $K[--$ki]);
|
||||
$R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ $this->safe_intval($t0 + $t1 + $K[--$ki]);
|
||||
}
|
||||
|
||||
// @codingStandardsIgnoreStart
|
||||
|
|
@ -679,6 +685,8 @@ class Twofish extends Base
|
|||
$code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key);
|
||||
}
|
||||
|
||||
$safeint = $this->safe_intval_inline();
|
||||
|
||||
if (!isset($lambda_functions[$code_hash])) {
|
||||
switch (true) {
|
||||
case $gen_hi_opt_code:
|
||||
|
|
@ -727,9 +735,9 @@ class Twofish extends Base
|
|||
$S1[ $R1 & 0xff] ^
|
||||
$S2[($R1 >> 8) & 0xff] ^
|
||||
$S3[($R1 >> 16) & 0xff];
|
||||
$R2^= ($t0 + $t1 + '.$K[++$ki].');
|
||||
$R2^= ' . sprintf($safeint, '$t0 + $t1 + ' . $K[++$ki]) . ';
|
||||
$R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31);
|
||||
$R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ ($t0 + ($t1 << 1) + '.$K[++$ki].');
|
||||
$R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ ' . sprintf($safeint, '($t0 + ($t1 << 1) + ' . $K[++$ki] . ')') . ';
|
||||
|
||||
$t0 = $S0[ $R2 & 0xff] ^
|
||||
$S1[($R2 >> 8) & 0xff] ^
|
||||
|
|
@ -739,16 +747,16 @@ class Twofish extends Base
|
|||
$S1[ $R3 & 0xff] ^
|
||||
$S2[($R3 >> 8) & 0xff] ^
|
||||
$S3[($R3 >> 16) & 0xff];
|
||||
$R0^= ($t0 + $t1 + '.$K[++$ki].');
|
||||
$R0^= ' . sprintf($safeint, '($t0 + $t1 + ' . $K[++$ki] . ')') . ';
|
||||
$R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31);
|
||||
$R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ($t0 + ($t1 << 1) + '.$K[++$ki].');
|
||||
$R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ' . sprintf($safeint, '($t0 + ($t1 << 1) + ' . $K[++$ki] . ')') . ';
|
||||
';
|
||||
}
|
||||
$encrypt_block.= '
|
||||
$in = pack("V4", '.$K[4].' ^ $R2,
|
||||
'.$K[5].' ^ $R3,
|
||||
'.$K[6].' ^ $R0,
|
||||
'.$K[7].' ^ $R1);
|
||||
$in = pack("V4", ' . $K[4] . ' ^ $R2,
|
||||
' . $K[5] . ' ^ $R3,
|
||||
' . $K[6] . ' ^ $R0,
|
||||
' . $K[7] . ' ^ $R1);
|
||||
';
|
||||
|
||||
// Generating decrypt code:
|
||||
|
|
@ -769,9 +777,9 @@ class Twofish extends Base
|
|||
$S1[$R1 & 0xff] ^
|
||||
$S2[$R1 >> 8 & 0xff] ^
|
||||
$S3[$R1 >> 16 & 0xff];
|
||||
$R3^= $t0 + ($t1 << 1) + '.$K[--$ki].';
|
||||
$R3^= ' . sprintf($safeint, '$t0 + ($t1 << 1) + ' . $K[--$ki]) . ';
|
||||
$R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31;
|
||||
$R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ ($t0 + $t1 + '.$K[--$ki].');
|
||||
$R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ ' . sprintf($safeint, '($t0 + $t1 + '.$K[--$ki] . ')') . ';
|
||||
|
||||
$t0 = $S0[$R2 & 0xff] ^
|
||||
$S1[$R2 >> 8 & 0xff] ^
|
||||
|
|
@ -781,16 +789,16 @@ class Twofish extends Base
|
|||
$S1[$R3 & 0xff] ^
|
||||
$S2[$R3 >> 8 & 0xff] ^
|
||||
$S3[$R3 >> 16 & 0xff];
|
||||
$R1^= $t0 + ($t1 << 1) + '.$K[--$ki].';
|
||||
$R1^= ' . sprintf($safeint, '$t0 + ($t1 << 1) + ' . $K[--$ki]) . ';
|
||||
$R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31;
|
||||
$R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ($t0 + $t1 + '.$K[--$ki].');
|
||||
$R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ' . sprintf($safeint, '($t0 + $t1 + '.$K[--$ki] . ')') . ';
|
||||
';
|
||||
}
|
||||
$decrypt_block.= '
|
||||
$in = pack("V4", '.$K[0].' ^ $R2,
|
||||
'.$K[1].' ^ $R3,
|
||||
'.$K[2].' ^ $R0,
|
||||
'.$K[3].' ^ $R1);
|
||||
$in = pack("V4", ' . $K[0] . ' ^ $R2,
|
||||
' . $K[1] . ' ^ $R3,
|
||||
' . $K[2] . ' ^ $R0,
|
||||
' . $K[3] . ' ^ $R1);
|
||||
';
|
||||
|
||||
$lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
|
||||
|
|
|
|||
|
|
@ -203,8 +203,7 @@ class ANSI
|
|||
/**
|
||||
* Set the number of lines that should be logged past the terminal height
|
||||
*
|
||||
* @param int $x
|
||||
* @param int $y
|
||||
* @param int $history
|
||||
* @access public
|
||||
*/
|
||||
function setHistory($history)
|
||||
|
|
@ -272,7 +271,7 @@ class ANSI
|
|||
case "\x1B[K": // Clear screen from cursor right
|
||||
$this->screen[$this->y] = substr($this->screen[$this->y], 0, $this->x);
|
||||
|
||||
array_splice($this->attrs[$this->y], $this->x + 1, $this->max_x - $this->x, array_fill($this->x, $this->max_x - $this->x - 1, $this->base_attr_cell));
|
||||
array_splice($this->attrs[$this->y], $this->x + 1, $this->max_x - $this->x, array_fill($this->x, $this->max_x - ($this->x - 1), $this->base_attr_cell));
|
||||
break;
|
||||
case "\x1B[2K": // Clear entire line
|
||||
$this->screen[$this->y] = str_repeat(' ', $this->x);
|
||||
|
|
@ -305,6 +304,9 @@ class ANSI
|
|||
case preg_match('#\x1B\[(\d+)D#', $this->ansi, $match): // Move cursor left n lines
|
||||
$this->old_x = $this->x;
|
||||
$this->x-= $match[1];
|
||||
if ($this->x < 0) {
|
||||
$this->x = 0;
|
||||
}
|
||||
break;
|
||||
case preg_match('#\x1B\[(\d+);(\d+)r#', $this->ansi, $match): // Set top and bottom lines of a window
|
||||
break;
|
||||
|
|
@ -313,19 +315,20 @@ class ANSI
|
|||
$mods = explode(';', $match[1]);
|
||||
foreach ($mods as $mod) {
|
||||
switch ($mod) {
|
||||
case 0: // Turn off character attributes
|
||||
case '':
|
||||
case '0': // Turn off character attributes
|
||||
$attr_cell = clone $this->base_attr_cell;
|
||||
break;
|
||||
case 1: // Turn bold mode on
|
||||
case '1': // Turn bold mode on
|
||||
$attr_cell->bold = true;
|
||||
break;
|
||||
case 4: // Turn underline mode on
|
||||
case '4': // Turn underline mode on
|
||||
$attr_cell->underline = true;
|
||||
break;
|
||||
case 5: // Turn blinking mode on
|
||||
case '5': // Turn blinking mode on
|
||||
$attr_cell->blink = true;
|
||||
break;
|
||||
case 7: // Turn reverse video on
|
||||
case '7': // Turn reverse video on
|
||||
$attr_cell->reverse = !$attr_cell->reverse;
|
||||
$temp = $attr_cell->background;
|
||||
$attr_cell->background = $attr_cell->foreground;
|
||||
|
|
@ -338,23 +341,23 @@ class ANSI
|
|||
$back = &$attr_cell->{ $attr_cell->reverse ? 'foreground' : 'background' };
|
||||
switch ($mod) {
|
||||
// @codingStandardsIgnoreStart
|
||||
case 30: $front = 'black'; break;
|
||||
case 31: $front = 'red'; break;
|
||||
case 32: $front = 'green'; break;
|
||||
case 33: $front = 'yellow'; break;
|
||||
case 34: $front = 'blue'; break;
|
||||
case 35: $front = 'magenta'; break;
|
||||
case 36: $front = 'cyan'; break;
|
||||
case 37: $front = 'white'; break;
|
||||
case '30': $front = 'black'; break;
|
||||
case '31': $front = 'red'; break;
|
||||
case '32': $front = 'green'; break;
|
||||
case '33': $front = 'yellow'; break;
|
||||
case '34': $front = 'blue'; break;
|
||||
case '35': $front = 'magenta'; break;
|
||||
case '36': $front = 'cyan'; break;
|
||||
case '37': $front = 'white'; break;
|
||||
|
||||
case 40: $back = 'black'; break;
|
||||
case 41: $back = 'red'; break;
|
||||
case 42: $back = 'green'; break;
|
||||
case 43: $back = 'yellow'; break;
|
||||
case 44: $back = 'blue'; break;
|
||||
case 45: $back = 'magenta'; break;
|
||||
case 46: $back = 'cyan'; break;
|
||||
case 47: $back = 'white'; break;
|
||||
case '40': $back = 'black'; break;
|
||||
case '41': $back = 'red'; break;
|
||||
case '42': $back = 'green'; break;
|
||||
case '43': $back = 'yellow'; break;
|
||||
case '44': $back = 'blue'; break;
|
||||
case '45': $back = 'magenta'; break;
|
||||
case '46': $back = 'cyan'; break;
|
||||
case '47': $back = 'white'; break;
|
||||
// @codingStandardsIgnoreEnd
|
||||
|
||||
default:
|
||||
|
|
@ -416,7 +419,7 @@ class ANSI
|
|||
|
||||
if ($this->x > $this->max_x) {
|
||||
$this->x = 0;
|
||||
$this->y++;
|
||||
$this->_newLine();
|
||||
} else {
|
||||
$this->x++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ namespace phpseclib\File;
|
|||
|
||||
use phpseclib\File\ASN1\Element;
|
||||
use phpseclib\Math\BigInteger;
|
||||
use DateTime;
|
||||
use DateTimeZone;
|
||||
|
||||
/**
|
||||
* Pure-PHP ASN.1 Parser
|
||||
|
|
@ -232,8 +234,11 @@ class ASN1
|
|||
{
|
||||
$current = array('start' => $start);
|
||||
|
||||
if (!isset($encoded[$encoded_pos])) {
|
||||
return false;
|
||||
}
|
||||
$type = ord($encoded[$encoded_pos++]);
|
||||
$start++;
|
||||
$startOffset = 1;
|
||||
|
||||
$constructed = ($type >> 5) & 1;
|
||||
|
||||
|
|
@ -242,14 +247,28 @@ class ASN1
|
|||
$tag = 0;
|
||||
// process septets (since the eighth bit is ignored, it's not an octet)
|
||||
do {
|
||||
$loop = ord($encoded[0]) >> 7;
|
||||
if (!isset($encoded[$encoded_pos])) {
|
||||
return false;
|
||||
}
|
||||
$temp = ord($encoded[$encoded_pos++]);
|
||||
$startOffset++;
|
||||
$loop = $temp >> 7;
|
||||
$tag <<= 7;
|
||||
$tag |= ord($encoded[$encoded_pos++]) & 0x7F;
|
||||
$start++;
|
||||
$temp &= 0x7F;
|
||||
// "bits 7 to 1 of the first subsequent octet shall not all be zero"
|
||||
if ($startOffset == 2 && $temp == 0) {
|
||||
return false;
|
||||
}
|
||||
$tag |= $temp;
|
||||
} while ($loop);
|
||||
}
|
||||
|
||||
$start+= $startOffset;
|
||||
|
||||
// Length, as discussed in paragraph 8.1.3 of X.690-0207.pdf#page=13
|
||||
if (!isset($encoded[$encoded_pos])) {
|
||||
return false;
|
||||
}
|
||||
$length = ord($encoded[$encoded_pos++]);
|
||||
$start++;
|
||||
if ($length == 0x80) { // indefinite length
|
||||
|
|
@ -306,6 +325,9 @@ class ASN1
|
|||
$remainingLength = $length;
|
||||
while ($remainingLength > 0) {
|
||||
$temp = $this->_decode_ber($content, $start, $content_pos);
|
||||
if ($temp === false) {
|
||||
break;
|
||||
}
|
||||
$length = $temp['length'];
|
||||
// end-of-content octets - see paragraph 8.1.5
|
||||
if (substr($content, $content_pos + $length, 2) == "\0\0") {
|
||||
|
|
@ -338,13 +360,16 @@ class ASN1
|
|||
switch ($tag) {
|
||||
case self::TYPE_BOOLEAN:
|
||||
// "The contents octets shall consist of a single octet." -- paragraph 8.2.1
|
||||
//if (strlen($content) != 1) {
|
||||
// return false;
|
||||
//}
|
||||
if ($constructed || strlen($content) != 1) {
|
||||
return false;
|
||||
}
|
||||
$current['content'] = (bool) ord($content[$content_pos]);
|
||||
break;
|
||||
case self::TYPE_INTEGER:
|
||||
case self::TYPE_ENUMERATED:
|
||||
if ($constructed) {
|
||||
return false;
|
||||
}
|
||||
$current['content'] = new BigInteger(substr($content, $content_pos), -256);
|
||||
break;
|
||||
case self::TYPE_REAL: // not currently supported
|
||||
|
|
@ -357,19 +382,22 @@ class ASN1
|
|||
$current['content'] = substr($content, $content_pos);
|
||||
} else {
|
||||
$temp = $this->_decode_ber($content, $start, $content_pos);
|
||||
if ($temp === false) {
|
||||
return false;
|
||||
}
|
||||
$length-= (strlen($content) - $content_pos);
|
||||
$last = count($temp) - 1;
|
||||
for ($i = 0; $i < $last; $i++) {
|
||||
// all subtags should be bit strings
|
||||
//if ($temp[$i]['type'] != self::TYPE_BIT_STRING) {
|
||||
// return false;
|
||||
//}
|
||||
if ($temp[$i]['type'] != self::TYPE_BIT_STRING) {
|
||||
return false;
|
||||
}
|
||||
$current['content'].= substr($temp[$i]['content'], 1);
|
||||
}
|
||||
// all subtags should be bit strings
|
||||
//if ($temp[$last]['type'] != self::TYPE_BIT_STRING) {
|
||||
// return false;
|
||||
//}
|
||||
if ($temp[$last]['type'] != self::TYPE_BIT_STRING) {
|
||||
return false;
|
||||
}
|
||||
$current['content'] = $temp[$last]['content'][0] . $current['content'] . substr($temp[$i]['content'], 1);
|
||||
}
|
||||
break;
|
||||
|
|
@ -381,11 +409,14 @@ class ASN1
|
|||
$length = 0;
|
||||
while (substr($content, $content_pos, 2) != "\0\0") {
|
||||
$temp = $this->_decode_ber($content, $length + $start, $content_pos);
|
||||
if ($temp === false) {
|
||||
return false;
|
||||
}
|
||||
$content_pos += $temp['length'];
|
||||
// all subtags should be octet strings
|
||||
//if ($temp['type'] != self::TYPE_OCTET_STRING) {
|
||||
// return false;
|
||||
//}
|
||||
if ($temp['type'] != self::TYPE_OCTET_STRING) {
|
||||
return false;
|
||||
}
|
||||
$current['content'].= $temp['content'];
|
||||
$length+= $temp['length'];
|
||||
}
|
||||
|
|
@ -396,12 +427,15 @@ class ASN1
|
|||
break;
|
||||
case self::TYPE_NULL:
|
||||
// "The contents octets shall not contain any octets." -- paragraph 8.8.2
|
||||
//if (strlen($content)) {
|
||||
// return false;
|
||||
//}
|
||||
if ($constructed || strlen($content)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case self::TYPE_SEQUENCE:
|
||||
case self::TYPE_SET:
|
||||
if (!$constructed) {
|
||||
return false;
|
||||
}
|
||||
$offset = 0;
|
||||
$current['content'] = array();
|
||||
$content_len = strlen($content);
|
||||
|
|
@ -413,30 +447,22 @@ class ASN1
|
|||
break 2;
|
||||
}
|
||||
$temp = $this->_decode_ber($content, $start + $offset, $content_pos);
|
||||
if ($temp === false) {
|
||||
return false;
|
||||
}
|
||||
$content_pos += $temp['length'];
|
||||
$current['content'][] = $temp;
|
||||
$offset+= $temp['length'];
|
||||
}
|
||||
break;
|
||||
case self::TYPE_OBJECT_IDENTIFIER:
|
||||
$temp = ord($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;
|
||||
}
|
||||
if ($constructed) {
|
||||
return false;
|
||||
}
|
||||
$current['content'] = $this->_decodeOID(substr($content, $content_pos));
|
||||
if ($current['content'] === false) {
|
||||
return false;
|
||||
}
|
||||
// the eighth bit of the last byte should not be 1
|
||||
//if ($temp >> 7) {
|
||||
// return false;
|
||||
//}
|
||||
break;
|
||||
/* Each character string type shall be encoded as if it had been declared:
|
||||
[UNIVERSAL x] IMPLICIT OCTET STRING
|
||||
|
|
@ -466,12 +492,20 @@ class ASN1
|
|||
case self::TYPE_UTF8_STRING:
|
||||
// ????
|
||||
case self::TYPE_BMP_STRING:
|
||||
if ($constructed) {
|
||||
return false;
|
||||
}
|
||||
$current['content'] = substr($content, $content_pos);
|
||||
break;
|
||||
case self::TYPE_UTC_TIME:
|
||||
case self::TYPE_GENERALIZED_TIME:
|
||||
if ($constructed) {
|
||||
return false;
|
||||
}
|
||||
$current['content'] = $this->_decodeTime(substr($content, $content_pos), $tag);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
$start+= $length;
|
||||
|
|
@ -495,6 +529,10 @@ class ASN1
|
|||
*/
|
||||
function asn1map($decoded, $mapping, $special = array())
|
||||
{
|
||||
if (!is_array($decoded)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($mapping['explicit']) && is_array($decoded['content'])) {
|
||||
$decoded = $decoded['content'][0];
|
||||
}
|
||||
|
|
@ -580,7 +618,7 @@ class ASN1
|
|||
$childClass = $tempClass = self::CLASS_UNIVERSAL;
|
||||
$constant = null;
|
||||
if (isset($temp['constant'])) {
|
||||
$tempClass = isset($temp['class']) ? $temp['class'] : self::CLASS_CONTEXT_SPECIFIC;
|
||||
$tempClass = $temp['type'];
|
||||
}
|
||||
if (isset($child['class'])) {
|
||||
$childClass = $child['class'];
|
||||
|
|
@ -643,7 +681,7 @@ class ASN1
|
|||
$temp = $decoded['content'][$i];
|
||||
$tempClass = self::CLASS_UNIVERSAL;
|
||||
if (isset($temp['constant'])) {
|
||||
$tempClass = isset($temp['class']) ? $temp['class'] : self::CLASS_CONTEXT_SPECIFIC;
|
||||
$tempClass = $temp['type'];
|
||||
}
|
||||
|
||||
foreach ($mapping['children'] as $key => $child) {
|
||||
|
|
@ -704,10 +742,17 @@ class ASN1
|
|||
return isset($this->oids[$decoded['content']]) ? $this->oids[$decoded['content']] : $decoded['content'];
|
||||
case self::TYPE_UTC_TIME:
|
||||
case self::TYPE_GENERALIZED_TIME:
|
||||
if (isset($mapping['implicit'])) {
|
||||
// for explicitly tagged optional stuff
|
||||
if (is_array($decoded['content'])) {
|
||||
$decoded['content'] = $decoded['content'][0]['content'];
|
||||
}
|
||||
// for implicitly tagged optional stuff
|
||||
// in theory, doing isset($mapping['implicit']) would work but malformed certs do exist
|
||||
// in the wild that OpenSSL decodes without issue so we'll support them as well
|
||||
if (!is_object($decoded['content'])) {
|
||||
$decoded['content'] = $this->_decodeTime($decoded['content'], $decoded['type']);
|
||||
}
|
||||
return @date($this->format, $decoded['content']);
|
||||
return $decoded['content'] ? $decoded['content']->format($this->format) : false;
|
||||
case self::TYPE_BIT_STRING:
|
||||
if (isset($mapping['mapping'])) {
|
||||
$offset = ord($decoded['content'][0]);
|
||||
|
|
@ -781,7 +826,7 @@ class ASN1
|
|||
*
|
||||
* @param string $source
|
||||
* @param string $mapping
|
||||
* @param int $idx
|
||||
* @param array $special
|
||||
* @return string
|
||||
* @access public
|
||||
*/
|
||||
|
|
@ -797,6 +842,7 @@ class ASN1
|
|||
* @param string $source
|
||||
* @param string $mapping
|
||||
* @param int $idx
|
||||
* @param array $special
|
||||
* @return string
|
||||
* @access private
|
||||
*/
|
||||
|
|
@ -845,7 +891,7 @@ class ASN1
|
|||
if ($mapping['type'] == self::TYPE_SET) {
|
||||
sort($value);
|
||||
}
|
||||
$value = implode($value, '');
|
||||
$value = implode('', $value);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -956,7 +1002,11 @@ class ASN1
|
|||
case self::TYPE_GENERALIZED_TIME:
|
||||
$format = $mapping['type'] == self::TYPE_UTC_TIME ? 'y' : 'Y';
|
||||
$format.= 'mdHis';
|
||||
$value = @gmdate($format, strtotime($source)) . 'Z';
|
||||
// if $source does _not_ include timezone information within it then assume that the timezone is GMT
|
||||
$date = new DateTime($source, new DateTimeZone('GMT'));
|
||||
// if $source _does_ include timezone information within it then convert the time to GMT
|
||||
$date->setTimezone(new DateTimeZone('GMT'));
|
||||
$value = $date->format($format) . 'Z';
|
||||
break;
|
||||
case self::TYPE_BIT_STRING:
|
||||
if (isset($mapping['mapping'])) {
|
||||
|
|
@ -998,27 +1048,7 @@ class ASN1
|
|||
$value = base64_decode($source);
|
||||
break;
|
||||
case self::TYPE_OBJECT_IDENTIFIER:
|
||||
$oid = preg_match('#(?:\d+\.)+#', $source) ? $source : array_search($source, $this->oids);
|
||||
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;
|
||||
}
|
||||
$value = $this->_encodeOID($source);
|
||||
break;
|
||||
case self::TYPE_ANY:
|
||||
$loc = $this->location;
|
||||
|
|
@ -1117,6 +1147,113 @@ class ASN1
|
|||
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);
|
||||
|
||||
if (ord($content[$len - 1]) & 0x80) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$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 $source
|
||||
* @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
|
||||
*
|
||||
|
|
@ -1137,33 +1274,32 @@ class ASN1
|
|||
http://tools.ietf.org/html/rfc5280#section-4.1.2.5.2
|
||||
http://www.obj-sys.com/asn1tutorial/node14.html */
|
||||
|
||||
$pattern = $tag == self::TYPE_UTC_TIME ?
|
||||
'#(..)(..)(..)(..)(..)(..)(.*)#' :
|
||||
'#(....)(..)(..)(..)(..)(..).*([Z+-].*)$#';
|
||||
|
||||
preg_match($pattern, $content, $matches);
|
||||
|
||||
list(, $year, $month, $day, $hour, $minute, $second, $timezone) = $matches;
|
||||
$format = 'YmdHis';
|
||||
|
||||
if ($tag == self::TYPE_UTC_TIME) {
|
||||
$year = $year >= 50 ? "19$year" : "20$year";
|
||||
}
|
||||
|
||||
if ($timezone == 'Z') {
|
||||
$mktime = 'gmmktime';
|
||||
$timezone = 0;
|
||||
} elseif (preg_match('#([+-])(\d\d)(\d\d)#', $timezone, $matches)) {
|
||||
$mktime = 'gmmktime';
|
||||
$timezone = 60 * $matches[3] + 3600 * $matches[2];
|
||||
if ($matches[1] == '-') {
|
||||
$timezone = -$timezone;
|
||||
// https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=28 says "the seconds
|
||||
// element shall always be present" but none-the-less I've seen X509 certs where it isn't and if the
|
||||
// browsers parse it phpseclib ought to too
|
||||
if (preg_match('#^(\d{10})(Z|[+-]\d{4})$#', $content, $matches)) {
|
||||
$content = $matches[1] . '00' . $matches[2];
|
||||
}
|
||||
} else {
|
||||
$mktime = 'mktime';
|
||||
$timezone = 0;
|
||||
$prefix = substr($content, 0, 2) >= 50 ? '19' : '20';
|
||||
$content = $prefix . $content;
|
||||
} elseif (strpos($content, '.') !== false) {
|
||||
$format.= '.u';
|
||||
}
|
||||
|
||||
return @$mktime($hour, $minute, $second, $month, $day, $year) + $timezone;
|
||||
if ($content[strlen($content) - 1] == 'Z') {
|
||||
$content = substr($content, 0, -1) . '+0000';
|
||||
}
|
||||
|
||||
if (strpos($content, '-') !== false || strpos($content, '+') !== false) {
|
||||
$format.= 'O';
|
||||
}
|
||||
|
||||
// error supression isn't necessary as of PHP 7.0:
|
||||
// http://php.net/manual/en/migration70.other-changes.php
|
||||
return @DateTime::createFromFormat($format, $content);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ use phpseclib\Crypt\Random;
|
|||
use phpseclib\Crypt\RSA;
|
||||
use phpseclib\File\ASN1\Element;
|
||||
use phpseclib\Math\BigInteger;
|
||||
use DateTime;
|
||||
use DateTimeZone;
|
||||
|
||||
/**
|
||||
* Pure-PHP X.509 Parser
|
||||
|
|
@ -303,6 +305,22 @@ class X509
|
|||
*/
|
||||
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.
|
||||
*
|
||||
|
|
@ -945,6 +963,13 @@ class X509
|
|||
'children' => $AccessDescription
|
||||
);
|
||||
|
||||
$this->SubjectInfoAccessSyntax = array(
|
||||
'type' => ASN1::TYPE_SEQUENCE,
|
||||
'min' => 1,
|
||||
'max' => -1,
|
||||
'children' => $AccessDescription
|
||||
);
|
||||
|
||||
$this->SubjectAltName = $GeneralNames;
|
||||
|
||||
$this->PrivateKeyUsagePeriod = array(
|
||||
|
|
@ -1583,7 +1608,7 @@ class X509
|
|||
* Map extension values from octet string to extension-specific internal
|
||||
* format.
|
||||
*
|
||||
* @param array ref $root
|
||||
* @param array $root (by reference)
|
||||
* @param string $path
|
||||
* @param object $asn1
|
||||
* @access private
|
||||
|
|
@ -1597,12 +1622,15 @@ class X509
|
|||
$id = $extensions[$i]['extnId'];
|
||||
$value = &$extensions[$i]['extnValue'];
|
||||
$value = base64_decode($value);
|
||||
$decoded = $asn1->decodeBER($value);
|
||||
/* [extnValue] contains the DER encoding of an ASN.1 value
|
||||
corresponding to the extension type identified by extnID */
|
||||
$map = $this->_getMapping($id);
|
||||
if (!is_bool($map)) {
|
||||
$mapped = $asn1->asn1map($decoded[0], $map, array('iPAddress' => array($this, '_decodeIP')));
|
||||
$decoder = $id == 'id-ce-nameConstraints' ?
|
||||
array($this, '_decodeNameConstraintIP') :
|
||||
array($this, '_decodeIP');
|
||||
$decoded = $asn1->decodeBER($value);
|
||||
$mapped = $asn1->asn1map($decoded[0], $map, array('iPAddress' => $decoder));
|
||||
$value = $mapped === false ? $decoded[0] : $mapped;
|
||||
|
||||
if ($id == 'id-ce-certificatePolicies') {
|
||||
|
|
@ -1633,7 +1661,7 @@ class X509
|
|||
* Map extension values from extension-specific internal format to
|
||||
* octet string.
|
||||
*
|
||||
* @param array ref $root
|
||||
* @param array $root (by reference)
|
||||
* @param string $path
|
||||
* @param object $asn1
|
||||
* @access private
|
||||
|
|
@ -1699,7 +1727,7 @@ class X509
|
|||
* Map attribute values from ANY type to attribute-specific internal
|
||||
* format.
|
||||
*
|
||||
* @param array ref $root
|
||||
* @param array $root (by reference)
|
||||
* @param string $path
|
||||
* @param object $asn1
|
||||
* @access private
|
||||
|
|
@ -1740,7 +1768,7 @@ class X509
|
|||
* Map attribute values from attribute-specific internal format to
|
||||
* ANY type.
|
||||
*
|
||||
* @param array ref $root
|
||||
* @param array $root (by reference)
|
||||
* @param string $path
|
||||
* @param object $asn1
|
||||
* @access private
|
||||
|
|
@ -1783,7 +1811,7 @@ class X509
|
|||
* Map DN values from ANY type to DN-specific internal
|
||||
* format.
|
||||
*
|
||||
* @param array ref $root
|
||||
* @param array $root (by reference)
|
||||
* @param string $path
|
||||
* @param object $asn1
|
||||
* @access private
|
||||
|
|
@ -1813,7 +1841,7 @@ class X509
|
|||
* Map DN values from DN-specific internal format to
|
||||
* ANY type.
|
||||
*
|
||||
* @param array ref $root
|
||||
* @param array $root (by reference)
|
||||
* @param string $path
|
||||
* @param object $asn1
|
||||
* @access private
|
||||
|
|
@ -1871,6 +1899,8 @@ class X509
|
|||
return $this->ExtKeyUsageSyntax;
|
||||
case 'id-pe-authorityInfoAccess':
|
||||
return $this->AuthorityInfoAccessSyntax;
|
||||
case 'id-pe-subjectInfoAccess':
|
||||
return $this->SubjectInfoAccessSyntax;
|
||||
case 'id-ce-subjectAltName':
|
||||
return $this->SubjectAltName;
|
||||
case 'id-ce-subjectDirectoryAttributes':
|
||||
|
|
@ -1907,6 +1937,12 @@ class X509
|
|||
// "SET Secure Electronic Transaction Specification"
|
||||
// http://www.maithean.com/docs/set_bk3.pdf
|
||||
case '2.23.42.7.0': // id-set-hashedRootKey
|
||||
// "Certificate Transparency"
|
||||
// https://tools.ietf.org/html/rfc6962
|
||||
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;
|
||||
|
||||
// CSR attributes
|
||||
|
|
@ -2027,30 +2063,32 @@ class X509
|
|||
}
|
||||
|
||||
if ($names = $this->getExtension('id-ce-subjectAltName')) {
|
||||
foreach ($names as $key => $value) {
|
||||
$value = str_replace(array('.', '*'), array('\.', '[^.]*'), $value);
|
||||
switch ($key) {
|
||||
case 'dNSName':
|
||||
/* From RFC2818 "HTTP over TLS":
|
||||
foreach ($names as $name) {
|
||||
foreach ($name as $key => $value) {
|
||||
$value = str_replace(array('.', '*'), array('\.', '[^.]*'), $value);
|
||||
switch ($key) {
|
||||
case 'dNSName':
|
||||
/* From RFC2818 "HTTP over TLS":
|
||||
|
||||
If a subjectAltName extension of type dNSName is present, that MUST
|
||||
be used as the identity. Otherwise, the (most specific) Common Name
|
||||
field in the Subject field of the certificate MUST be used. Although
|
||||
the use of the Common Name is existing practice, it is deprecated and
|
||||
Certification Authorities are encouraged to use the dNSName instead. */
|
||||
if (preg_match('#^' . $value . '$#', $components['host'])) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 'iPAddress':
|
||||
/* From RFC2818 "HTTP over TLS":
|
||||
If a subjectAltName extension of type dNSName is present, that MUST
|
||||
be used as the identity. Otherwise, the (most specific) Common Name
|
||||
field in the Subject field of the certificate MUST be used. Although
|
||||
the use of the Common Name is existing practice, it is deprecated and
|
||||
Certification Authorities are encouraged to use the dNSName instead. */
|
||||
if (preg_match('#^' . $value . '$#', $components['host'])) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 'iPAddress':
|
||||
/* From RFC2818 "HTTP over TLS":
|
||||
|
||||
In some cases, the URI is specified as an IP address rather than a
|
||||
hostname. In this case, the iPAddress subjectAltName must be present
|
||||
in the certificate and must exactly match the IP in the URI. */
|
||||
if (preg_match('#(?:\d{1-3}\.){4}#', $components['host'] . '.') && preg_match('#^' . $value . '$#', $components['host'])) {
|
||||
return true;
|
||||
}
|
||||
In some cases, the URI is specified as an IP address rather than a
|
||||
hostname. In this case, the iPAddress subjectAltName must be present
|
||||
in the certificate and must exactly match the IP in the URI. */
|
||||
if (preg_match('#(?:\d{1-3}\.){4}#', $components['host'] . '.') && preg_match('#^' . $value . '$#', $components['host'])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
@ -2069,7 +2107,7 @@ class X509
|
|||
*
|
||||
* If $date isn't defined it is assumed to be the current date.
|
||||
*
|
||||
* @param int $date optional
|
||||
* @param \DateTime|string $date optional
|
||||
* @access public
|
||||
*/
|
||||
function validateDate($date = null)
|
||||
|
|
@ -2079,7 +2117,7 @@ class X509
|
|||
}
|
||||
|
||||
if (!isset($date)) {
|
||||
$date = time();
|
||||
$date = new DateTime(null, new DateTimeZone(@date_default_timezone_get()));
|
||||
}
|
||||
|
||||
$notBefore = $this->currentCert['tbsCertificate']['validity']['notBefore'];
|
||||
|
|
@ -2088,15 +2126,137 @@ class X509
|
|||
$notAfter = $this->currentCert['tbsCertificate']['validity']['notAfter'];
|
||||
$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) {
|
||||
case $date < @strtotime($notBefore):
|
||||
case $date > @strtotime($notAfter):
|
||||
case $date < $notBefore:
|
||||
case $date > $notAfter:
|
||||
return false;
|
||||
}
|
||||
|
||||
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)) {
|
||||
$temp = fread($fsock, 1024);
|
||||
if ($temp === false) {
|
||||
return false;
|
||||
}
|
||||
$data.= $temp;
|
||||
}
|
||||
|
||||
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
|
||||
*
|
||||
|
|
@ -2113,11 +2273,30 @@ class X509
|
|||
* @return mixed
|
||||
*/
|
||||
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)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($count == self::$recur_limit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* TODO:
|
||||
"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
|
||||
|
|
@ -2134,7 +2313,8 @@ class X509
|
|||
$subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier');
|
||||
switch (true) {
|
||||
case !is_array($authorityKey):
|
||||
case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
|
||||
case !$subjectKeyID:
|
||||
case isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
|
||||
$signingCert = $this->currentCert; // working cert
|
||||
}
|
||||
}
|
||||
|
|
@ -2151,17 +2331,21 @@ class X509
|
|||
$subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
|
||||
switch (true) {
|
||||
case !is_array($authorityKey):
|
||||
case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
|
||||
case !$subjectKeyID:
|
||||
case isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
|
||||
if (is_array($authorityKey) && isset($authorityKey['authorityCertSerialNumber']) && !$authorityKey['authorityCertSerialNumber']->equals($ca['tbsCertificate']['serialNumber'])) {
|
||||
break 2; // serial mismatch - check other ca
|
||||
}
|
||||
$signingCert = $ca; // working cert
|
||||
break 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count($this->CAs) == $i && $caonly) {
|
||||
return false;
|
||||
return $this->_testForIntermediate($caonly, $count) && $this->validateSignature($caonly);
|
||||
}
|
||||
} elseif (!isset($signingCert) || $caonly) {
|
||||
return false;
|
||||
return $this->_testForIntermediate($caonly, $count) && $this->validateSignature($caonly);
|
||||
}
|
||||
return $this->_validateSignature(
|
||||
$signingCert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'],
|
||||
|
|
@ -2197,7 +2381,11 @@ class X509
|
|||
$subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
|
||||
switch (true) {
|
||||
case !is_array($authorityKey):
|
||||
case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
|
||||
case !$subjectKeyID:
|
||||
case isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
|
||||
if (is_array($authorityKey) && isset($authorityKey['authorityCertSerialNumber']) && !$authorityKey['authorityCertSerialNumber']->equals($ca['tbsCertificate']['serialNumber'])) {
|
||||
break 2; // serial mismatch - check other ca
|
||||
}
|
||||
$signingCert = $ca; // working cert
|
||||
break 3;
|
||||
}
|
||||
|
|
@ -2264,6 +2452,41 @@ class X509
|
|||
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
|
||||
*
|
||||
|
|
@ -2304,18 +2527,38 @@ class X509
|
|||
return inet_ntop(base64_decode($ip));
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes an IP address in a name constraints extension
|
||||
*
|
||||
* Takes in a base64 encoded "blob" and returns a human readable IP address / mask
|
||||
*
|
||||
* @param string $ip
|
||||
* @access private
|
||||
* @return array
|
||||
*/
|
||||
function _decodeNameConstraintIP($ip)
|
||||
{
|
||||
$ip = base64_decode($ip);
|
||||
$size = strlen($ip) >> 1;
|
||||
$mask = substr($ip, $size);
|
||||
$ip = substr($ip, 0, $size);
|
||||
return array(inet_ntop($ip), inet_ntop($mask));
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes an IP address
|
||||
*
|
||||
* Takes a human readable IP address into a base64-encoded "blob"
|
||||
*
|
||||
* @param string $ip
|
||||
* @param string|array $ip
|
||||
* @access private
|
||||
* @return string
|
||||
*/
|
||||
function _encodeIP($ip)
|
||||
{
|
||||
return base64_encode(inet_pton($ip));
|
||||
return is_string($ip) ?
|
||||
base64_encode(inet_pton($ip)) :
|
||||
base64_encode(inet_pton($ip[0]) . inet_pton($ip[1]));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2469,6 +2712,10 @@ class X509
|
|||
}
|
||||
|
||||
$dn = array_values($dn);
|
||||
// fix for https://bugs.php.net/75433 affecting PHP 7.2
|
||||
if (!isset($dn[0])) {
|
||||
$dn = array_splice($dn, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2712,12 +2959,14 @@ class X509
|
|||
$value = array_pop($value); // Always strip data type.
|
||||
}
|
||||
} elseif (is_object($value) && $value instanceof Element) {
|
||||
$callback = create_function('$x', 'return "\x" . bin2hex($x[0]);');
|
||||
$callback = function ($x) {
|
||||
return "\x" . bin2hex($x[0]);
|
||||
};
|
||||
$value = strtoupper(preg_replace_callback('#[^\x20-\x7E]#', $callback, $value->element));
|
||||
}
|
||||
$output.= $desc . '=' . $value;
|
||||
$result[$desc] = isset($result[$desc]) ?
|
||||
array_merge((array) $dn[$prop], array($value)) :
|
||||
array_merge((array) $result[$desc], array($value)) :
|
||||
$value;
|
||||
$start = false;
|
||||
}
|
||||
|
|
@ -2946,7 +3195,8 @@ class X509
|
|||
/**
|
||||
* Load a Certificate Signing Request
|
||||
*
|
||||
* @param string $csr
|
||||
* @param string|array $csr
|
||||
* @param int $mode
|
||||
* @access public
|
||||
* @return mixed
|
||||
*/
|
||||
|
|
@ -3083,7 +3333,7 @@ class X509
|
|||
*
|
||||
* https://developer.mozilla.org/en-US/docs/HTML/Element/keygen
|
||||
*
|
||||
* @param string $csr
|
||||
* @param string|array $spkac
|
||||
* @access public
|
||||
* @return mixed
|
||||
*/
|
||||
|
|
@ -3154,7 +3404,7 @@ class X509
|
|||
/**
|
||||
* Save a SPKAC CSR request
|
||||
*
|
||||
* @param array $csr
|
||||
* @param string|array $spkac
|
||||
* @param int $format optional
|
||||
* @access public
|
||||
* @return string
|
||||
|
|
@ -3198,6 +3448,7 @@ class X509
|
|||
* Load a Certificate Revocation List
|
||||
*
|
||||
* @param string $crl
|
||||
* @param int $mode
|
||||
* @access public
|
||||
* @return mixed
|
||||
*/
|
||||
|
|
@ -3335,7 +3586,11 @@ class X509
|
|||
*/
|
||||
function _timeField($date)
|
||||
{
|
||||
$year = @gmdate("Y", @strtotime($date)); // the same way ASN1.php parses this
|
||||
if ($date instanceof Element) {
|
||||
return $date;
|
||||
}
|
||||
$dateObj = new DateTime($date, new DateTimeZone('GMT'));
|
||||
$year = $dateObj->format('Y'); // the same way ASN1.php parses this
|
||||
if ($year < 2050) {
|
||||
return array('utcTime' => $date);
|
||||
} else {
|
||||
|
|
@ -3400,8 +3655,12 @@ class X509
|
|||
return false;
|
||||
}
|
||||
|
||||
$startDate = !empty($this->startDate) ? $this->startDate : @date('D, d M Y H:i:s O');
|
||||
$endDate = !empty($this->endDate) ? $this->endDate : @date('D, d M Y H:i:s O', strtotime('+1 year'));
|
||||
$startDate = new DateTime('now', new DateTimeZone(@date_default_timezone_get()));
|
||||
$startDate = !empty($this->startDate) ? $this->startDate : $startDate->format('D, d M Y H:i:s O');
|
||||
|
||||
$endDate = new DateTime('+1 year', new DateTimeZone(@date_default_timezone_get()));
|
||||
$endDate = !empty($this->endDate) ? $this->endDate : $endDate->format('D, d M Y H:i:s O');
|
||||
|
||||
/* "The serial number MUST be a positive integer"
|
||||
"Conforming CAs MUST NOT use serialNumber values longer than 20 octets."
|
||||
-- https://tools.ietf.org/html/rfc5280#section-4.1.2.2
|
||||
|
|
@ -3417,7 +3676,7 @@ class X509
|
|||
'tbsCertificate' =>
|
||||
array(
|
||||
'version' => 'v3',
|
||||
'serialNumber' => $serialNumber, // $this->setserialNumber()
|
||||
'serialNumber' => $serialNumber, // $this->setSerialNumber()
|
||||
'signature' => array('algorithm' => $signatureAlgorithm),
|
||||
'issuer' => false, // this is going to be overwritten later
|
||||
'validity' => array(
|
||||
|
|
@ -3463,8 +3722,8 @@ class X509
|
|||
|
||||
$altName = array();
|
||||
|
||||
if (isset($subject->domains) && count($subject->domains) > 1) {
|
||||
$altName = array_map(array('X509', '_dnsName'), $subject->domains);
|
||||
if (isset($subject->domains) && count($subject->domains)) {
|
||||
$altName = array_map(array('\phpseclib\File\X509', '_dnsName'), $subject->domains);
|
||||
}
|
||||
|
||||
if (isset($subject->ipAddresses) && count($subject->ipAddresses)) {
|
||||
|
|
@ -3669,7 +3928,9 @@ class X509
|
|||
|
||||
$currentCert = isset($this->currentCert) ? $this->currentCert : null;
|
||||
$signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject : null;
|
||||
$thisUpdate = !empty($this->startDate) ? $this->startDate : @date('D, d M Y H:i:s O');
|
||||
|
||||
$thisUpdate = new DateTime('now', new DateTimeZone(@date_default_timezone_get()));
|
||||
$thisUpdate = !empty($this->startDate) ? $this->startDate : $thisUpdate->format('D, d M Y H:i:s O');
|
||||
|
||||
if (isset($crl->currentCert) && is_array($crl->currentCert) && isset($crl->currentCert['tbsCertList'])) {
|
||||
$this->currentCert = $crl->currentCert;
|
||||
|
|
@ -3784,8 +4045,7 @@ class X509
|
|||
/**
|
||||
* X.509 certificate signing helper function.
|
||||
*
|
||||
* @param object $key
|
||||
* @param \phpseclib\File\X509 $subject
|
||||
* @param \phpseclib\File\X509 $key
|
||||
* @param string $signatureAlgorithm
|
||||
* @access public
|
||||
* @return mixed
|
||||
|
|
@ -3820,7 +4080,11 @@ class X509
|
|||
*/
|
||||
function setStartDate($date)
|
||||
{
|
||||
$this->startDate = @date('D, d M Y H:i:s O', @strtotime($date));
|
||||
if (!is_object($date) || !is_a($date, 'DateTime')) {
|
||||
$date = new DateTime($date, new DateTimeZone(@date_default_timezone_get()));
|
||||
}
|
||||
|
||||
$this->startDate = $date->format('D, d M Y H:i:s O');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -3844,7 +4108,11 @@ class X509
|
|||
$temp = chr(ASN1::TYPE_GENERALIZED_TIME) . $asn1->_encodeLength(strlen($temp)) . $temp;
|
||||
$this->endDate = new Element($temp);
|
||||
} else {
|
||||
$this->endDate = @date('D, d M Y H:i:s O', @strtotime($date));
|
||||
if (!is_object($date) || !is_a($date, 'DateTime')) {
|
||||
$date = new DateTime($date, new DateTimeZone(@date_default_timezone_get()));
|
||||
}
|
||||
|
||||
$this->endDate = $date->format('D, d M Y H:i:s O');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3852,7 +4120,7 @@ class X509
|
|||
* Set Serial Number
|
||||
*
|
||||
* @param string $serial
|
||||
* @param $base optional
|
||||
* @param int $base optional
|
||||
* @access public
|
||||
*/
|
||||
function setSerialNumber($serial, $base = -256)
|
||||
|
|
@ -4054,6 +4322,10 @@ class X509
|
|||
}
|
||||
|
||||
$extensions = array_values($extensions);
|
||||
// fix for https://bugs.php.net/75433 affecting PHP 7.2
|
||||
if (!isset($extensions[0])) {
|
||||
$extensions = array_splice($extensions, 0, 0);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
|
@ -4511,7 +4783,6 @@ class X509
|
|||
* Set the IP Addresses's which the cert is to be valid for
|
||||
*
|
||||
* @access public
|
||||
* @param string $ipAddress optional
|
||||
*/
|
||||
function setIPAddress()
|
||||
{
|
||||
|
|
@ -4574,8 +4845,9 @@ class X509
|
|||
}
|
||||
|
||||
$i = count($rclist);
|
||||
$revocationDate = new DateTime('now', new DateTimeZone(@date_default_timezone_get()));
|
||||
$rclist[] = array('userCertificate' => $serial,
|
||||
'revocationDate' => $this->_timeField(@date('D, d M Y H:i:s O')));
|
||||
'revocationDate' => $this->_timeField($revocationDate->format('D, d M Y H:i:s O')));
|
||||
return $i;
|
||||
}
|
||||
|
||||
|
|
@ -4782,11 +5054,16 @@ class X509
|
|||
* subject=/O=organization/OU=org unit/CN=common name
|
||||
* issuer=/O=organization/CN=common name
|
||||
*/
|
||||
$temp = preg_replace('#.*?^-+[^-]+-+[\r\n ]*$#ms', '', $str, 1);
|
||||
// remove the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- stuff
|
||||
$temp = preg_replace('#-+[^-]+-+#', '', $temp);
|
||||
if (strlen($str) > ini_get('pcre.backtrack_limit')) {
|
||||
$temp = $str;
|
||||
} else {
|
||||
$temp = preg_replace('#.*?^-+[^-]+-+[\r\n ]*$#ms', '', $str, 1);
|
||||
$temp = preg_replace('#-+END.*[\r\n ]*.*#ms', '', $temp, 1);
|
||||
}
|
||||
// remove new lines
|
||||
$temp = str_replace(array("\r", "\n", ' '), '', $temp);
|
||||
// remove the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- stuff
|
||||
$temp = preg_replace('#^-+[^-]+-+|-+[^-]+-+$#', '', $temp);
|
||||
$temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false;
|
||||
return $temp != false ? $temp : $str;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@
|
|||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2006 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://pear.php.net/package/Math_BigInteger
|
||||
*/
|
||||
|
||||
namespace phpseclib\Math;
|
||||
|
|
@ -244,7 +243,7 @@ class BigInteger
|
|||
* ?>
|
||||
* </code>
|
||||
*
|
||||
* @param $x base-10 number or base-$base number if $base set.
|
||||
* @param int|string|resource $x base-10 number or base-$base number if $base set.
|
||||
* @param int $base
|
||||
* @return \phpseclib\Math\BigInteger
|
||||
* @access public
|
||||
|
|
@ -266,23 +265,27 @@ class BigInteger
|
|||
|
||||
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
|
||||
ob_start();
|
||||
@phpinfo();
|
||||
$content = ob_get_contents();
|
||||
ob_end_clean();
|
||||
|
||||
preg_match_all('#OpenSSL (Header|Library) Version(.*)#im', $content, $matches);
|
||||
|
||||
$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
|
||||
if (!preg_match('/(\d+\.\d+\.\d+)/i', $fullVersion, $m)) {
|
||||
$versions[$matches[1][$i]] = $fullVersion;
|
||||
} else {
|
||||
$versions[$matches[1][$i]] = $m[0];
|
||||
// avoid generating errors (even with suppression) when phpinfo() is disabled (common in production systems)
|
||||
if (strpos(ini_get('disable_functions'), 'phpinfo') === false) {
|
||||
ob_start();
|
||||
@phpinfo();
|
||||
$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];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -360,8 +363,12 @@ class BigInteger
|
|||
case 256:
|
||||
switch (MATH_BIGINTEGER_MODE) {
|
||||
case self::MODE_GMP:
|
||||
$sign = $this->is_negative ? '-' : '';
|
||||
$this->value = gmp_init($sign . '0x' . bin2hex($x));
|
||||
$this->value = function_exists('gmp_import') ?
|
||||
gmp_import($x) :
|
||||
gmp_init('0x' . bin2hex($x));
|
||||
if ($this->is_negative) {
|
||||
$this->value = gmp_neg($this->value);
|
||||
}
|
||||
break;
|
||||
case self::MODE_BCMATH:
|
||||
// round $len to the nearest 4 (thanks, DavidMJ!)
|
||||
|
|
@ -438,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-9].*: find any non-numeric characters and then any characters that follow that
|
||||
$x = preg_replace('#(?<!^)(?:-).*|(?<=^|-)0*|[^-0-9].*#', '', $x);
|
||||
if (!strlen($x) || $x == '-') {
|
||||
$x = '0';
|
||||
}
|
||||
|
||||
switch (MATH_BIGINTEGER_MODE) {
|
||||
case self::MODE_GMP:
|
||||
|
|
@ -531,11 +541,11 @@ class BigInteger
|
|||
$temp = $comparison < 0 ? $this->add(new static(1)) : $this->copy();
|
||||
$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);
|
||||
}
|
||||
|
||||
if (ord($bytes[0]) & 0x80) {
|
||||
if ($this->precision <= 0 && (ord($bytes[0]) & 0x80)) {
|
||||
$bytes = chr(0) . $bytes;
|
||||
}
|
||||
|
||||
|
|
@ -548,9 +558,13 @@ class BigInteger
|
|||
return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
|
||||
}
|
||||
|
||||
$temp = gmp_strval(gmp_abs($this->value), 16);
|
||||
$temp = (strlen($temp) & 1) ? '0' . $temp : $temp;
|
||||
$temp = pack('H*', $temp);
|
||||
if (function_exists('gmp_export')) {
|
||||
$temp = gmp_export($this->value);
|
||||
} else {
|
||||
$temp = gmp_strval(gmp_abs($this->value), 16);
|
||||
$temp = (strlen($temp) & 1) ? '0' . $temp : $temp;
|
||||
$temp = pack('H*', $temp);
|
||||
}
|
||||
|
||||
return $this->precision > 0 ?
|
||||
substr(str_pad($temp, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
|
||||
|
|
@ -644,11 +658,11 @@ class BigInteger
|
|||
{
|
||||
$hex = $this->toHex($twos_compliment);
|
||||
$bits = '';
|
||||
for ($i = strlen($hex) - 8, $start = strlen($hex) & 7; $i >= $start; $i-=8) {
|
||||
$bits = str_pad(decbin(hexdec(substr($hex, $i, 8))), 32, '0', STR_PAD_LEFT) . $bits;
|
||||
for ($i = strlen($hex) - 6, $start = strlen($hex) % 6; $i >= $start; $i-=6) {
|
||||
$bits = str_pad(decbin(hexdec(substr($hex, $i, 6))), 24, '0', STR_PAD_LEFT) . $bits;
|
||||
}
|
||||
if ($start) { // hexdec('') == 0
|
||||
$bits = str_pad(decbin(hexdec(substr($hex, 0, $start))), 8, '0', STR_PAD_LEFT) . $bits;
|
||||
$bits = str_pad(decbin(hexdec(substr($hex, 0, $start))), 8 * $start, '0', STR_PAD_LEFT) . $bits;
|
||||
}
|
||||
$result = $this->precision > 0 ? substr($bits, -$this->precision) : ltrim($bits, '0');
|
||||
|
||||
|
|
@ -693,6 +707,7 @@ class BigInteger
|
|||
}
|
||||
|
||||
$temp = $this->copy();
|
||||
$temp->bitmask = false;
|
||||
$temp->is_negative = false;
|
||||
|
||||
$divisor = new static();
|
||||
|
|
@ -829,7 +844,7 @@ class BigInteger
|
|||
$opts[] = 'OpenSSL';
|
||||
}
|
||||
if (!empty($opts)) {
|
||||
$engine.= ' (' . implode($opts, ', ') . ')';
|
||||
$engine.= ' (' . implode('.', $opts) . ')';
|
||||
}
|
||||
return array(
|
||||
'value' => '0x' . $this->toHex(true),
|
||||
|
|
@ -1547,7 +1562,9 @@ class BigInteger
|
|||
$temp_value = array($quotient_value[$q_index]);
|
||||
$temp = $temp->multiply($y);
|
||||
$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);
|
||||
|
||||
|
|
@ -1977,7 +1994,7 @@ class BigInteger
|
|||
*
|
||||
* @see self::_slidingWindow()
|
||||
* @access private
|
||||
* @param \phpseclib\Math\BigInteger
|
||||
* @param \phpseclib\Math\BigInteger $n
|
||||
* @return \phpseclib\Math\BigInteger
|
||||
*/
|
||||
function _mod2($n)
|
||||
|
|
@ -2671,7 +2688,7 @@ class BigInteger
|
|||
* Note how the same comparison operator is used. If you want to test for equality, use $x->equals($y).
|
||||
*
|
||||
* @param \phpseclib\Math\BigInteger $y
|
||||
* @return int < 0 if $this is less than $y; > 0 if $this is greater than $y, and 0 if they are equal.
|
||||
* @return int that is < 0 if $this is less than $y; > 0 if $this is greater than $y, and 0 if they are equal.
|
||||
* @access public
|
||||
* @see self::equals()
|
||||
* @internal Could return $this->subtract($x), but that's not as fast as what we do do.
|
||||
|
|
@ -2680,7 +2697,14 @@ class BigInteger
|
|||
{
|
||||
switch (MATH_BIGINTEGER_MODE) {
|
||||
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:
|
||||
return bccomp($this->value, $y->value, 0);
|
||||
}
|
||||
|
|
@ -2860,8 +2884,7 @@ class BigInteger
|
|||
switch (MATH_BIGINTEGER_MODE) {
|
||||
case self::MODE_GMP:
|
||||
$temp = new static();
|
||||
$temp->value = gmp_xor($this->value, $x->value);
|
||||
|
||||
$temp->value = gmp_xor(gmp_abs($this->value), gmp_abs($x->value));
|
||||
return $this->_normalize($temp);
|
||||
case self::MODE_BCMATH:
|
||||
$left = $this->toBytes();
|
||||
|
|
@ -2877,6 +2900,7 @@ class BigInteger
|
|||
|
||||
$length = max(count($this->value), count($x->value));
|
||||
$result = $this->copy();
|
||||
$result->is_negative = false;
|
||||
$result->value = array_pad($result->value, $length, 0);
|
||||
$x->value = array_pad($x->value, $length, 0);
|
||||
|
||||
|
|
@ -2900,7 +2924,7 @@ class BigInteger
|
|||
// (will always result in a smaller number. ie. ~1 isn't 1111 1110 - it's 0)
|
||||
$temp = $this->toBytes();
|
||||
if ($temp == '') {
|
||||
return '';
|
||||
return $this->_normalize(new static());
|
||||
}
|
||||
$pre_msb = decbin(ord($temp[0]));
|
||||
$temp = ~$temp;
|
||||
|
|
@ -3066,7 +3090,7 @@ class BigInteger
|
|||
*
|
||||
* Byte length is equal to $length. Uses \phpseclib\Crypt\Random if it's loaded and mt_rand if it's not.
|
||||
*
|
||||
* @param int $length
|
||||
* @param int $size
|
||||
* @return \phpseclib\Math\BigInteger
|
||||
* @access private
|
||||
*/
|
||||
|
|
@ -3435,7 +3459,7 @@ class BigInteger
|
|||
break;
|
||||
}
|
||||
}
|
||||
$s = 26 * $i + $j - 1;
|
||||
$s = 26 * $i + $j;
|
||||
$r->_rshift($s);
|
||||
}
|
||||
|
||||
|
|
@ -3533,7 +3557,7 @@ class BigInteger
|
|||
*
|
||||
* Removes leading zeros and truncates (if necessary) to maintain the appropriate precision
|
||||
*
|
||||
* @param \phpseclib\Math\BigInteger
|
||||
* @param \phpseclib\Math\BigInteger $result
|
||||
* @return \phpseclib\Math\BigInteger
|
||||
* @see self::_trim()
|
||||
* @access private
|
||||
|
|
@ -3546,7 +3570,14 @@ class BigInteger
|
|||
switch (MATH_BIGINTEGER_MODE) {
|
||||
case self::MODE_GMP:
|
||||
if ($this->bitmask !== false) {
|
||||
$flip = gmp_cmp($result->value, gmp_init(0)) < 0;
|
||||
if ($flip) {
|
||||
$result->value = gmp_neg($result->value);
|
||||
}
|
||||
$result->value = gmp_and($result->value, $result->bitmask->value);
|
||||
if ($flip) {
|
||||
$result->value = gmp_neg($result->value);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
|
@ -3561,6 +3592,7 @@ class BigInteger
|
|||
$value = &$result->value;
|
||||
|
||||
if (!count($value)) {
|
||||
$result->is_negative = false;
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
|
@ -3602,8 +3634,8 @@ class BigInteger
|
|||
/**
|
||||
* Array Repeat
|
||||
*
|
||||
* @param $input Array
|
||||
* @param $multiplier mixed
|
||||
* @param array $input
|
||||
* @param mixed $multiplier
|
||||
* @return array
|
||||
* @access private
|
||||
*/
|
||||
|
|
@ -3617,8 +3649,8 @@ class BigInteger
|
|||
*
|
||||
* Shifts binary strings $shift bits, essentially multiplying by 2**$shift.
|
||||
*
|
||||
* @param $x String
|
||||
* @param $shift Integer
|
||||
* @param string $x (by reference)
|
||||
* @param int $shift
|
||||
* @return string
|
||||
* @access private
|
||||
*/
|
||||
|
|
@ -3646,8 +3678,8 @@ class BigInteger
|
|||
*
|
||||
* Shifts binary strings $shift bits, essentially dividing by 2**$shift and returning the remainder.
|
||||
*
|
||||
* @param $x String
|
||||
* @param $shift Integer
|
||||
* @param string $x (by referenc)
|
||||
* @param int $shift
|
||||
* @return string
|
||||
* @access private
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ class SCP
|
|||
*
|
||||
* Connects to an SSH server
|
||||
*
|
||||
* @param \phpseclib\Net\SSH1|\phpseclin\Net\SSH2 $ssh
|
||||
* @param \phpseclib\Net\SSH1|\phpseclib\Net\SSH2 $ssh
|
||||
* @return \phpseclib\Net\SCP
|
||||
* @access public
|
||||
*/
|
||||
|
|
@ -144,6 +144,11 @@ class SCP
|
|||
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
|
||||
return false;
|
||||
}
|
||||
|
|
@ -299,6 +304,9 @@ class SCP
|
|||
$response = $this->ssh->_get_binary_packet();
|
||||
switch ($response[SSH1::RESPONSE_TYPE]) {
|
||||
case NET_SSH1_SMSG_STDOUT_DATA:
|
||||
if (strlen($response[SSH1::RESPONSE_DATA]) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nlength', $response[SSH1::RESPONSE_DATA]));
|
||||
return $this->ssh->_string_shift($response[SSH1::RESPONSE_DATA], $length);
|
||||
case NET_SSH1_SMSG_STDERR_DATA:
|
||||
|
|
|
|||
|
|
@ -5,9 +5,7 @@
|
|||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* Currently only supports SFTPv2 and v3, which, according to wikipedia.org, "is the most widely used version,
|
||||
* implemented by the popular OpenSSH SFTP server". If you want SFTPv4/5/6 support, provide me with access
|
||||
* to an SFTPv4/5/6 server.
|
||||
* Supports SFTPv2/3/4/5/6. Defaults to v3.
|
||||
*
|
||||
* The API for this library is modeled after the API from PHP's {@link http://php.net/book.ftp FTP extension}.
|
||||
*
|
||||
|
|
@ -109,11 +107,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
|
||||
* concurrent actions, so it's somewhat academic, here.
|
||||
*
|
||||
* @var int
|
||||
* @var boolean
|
||||
* @see self::_send_sftp_packet()
|
||||
* @access private
|
||||
*/
|
||||
var $request_id = false;
|
||||
var $use_request_id = false;
|
||||
|
||||
/**
|
||||
* The Packet Type
|
||||
|
|
@ -154,11 +152,29 @@ class SFTP extends SSH2
|
|||
*/
|
||||
var $version;
|
||||
|
||||
/**
|
||||
* Default Server SFTP version
|
||||
*
|
||||
* @var int
|
||||
* @see self::_initChannel()
|
||||
* @access private
|
||||
*/
|
||||
var $defaultVersion;
|
||||
|
||||
/**
|
||||
* Preferred SFTP version
|
||||
*
|
||||
* @var int
|
||||
* @see self::_initChannel()
|
||||
* @access private
|
||||
*/
|
||||
var $preferredVersion = 3;
|
||||
|
||||
/**
|
||||
* Current working directory
|
||||
*
|
||||
* @var string
|
||||
* @see self::_realpath()
|
||||
* @see self::realpath()
|
||||
* @see self::chdir()
|
||||
* @access private
|
||||
*/
|
||||
|
|
@ -187,7 +203,7 @@ class SFTP extends SSH2
|
|||
*
|
||||
* @see self::getSFTPErrors()
|
||||
* @see self::getLastSFTPError()
|
||||
* @var string
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $sftp_errors = array();
|
||||
|
|
@ -236,6 +252,72 @@ class SFTP extends SSH2
|
|||
*/
|
||||
var $sortOptions = array();
|
||||
|
||||
/**
|
||||
* Canonicalization Flag
|
||||
*
|
||||
* Determines whether or not paths should be canonicalized before being
|
||||
* passed on to the remote server.
|
||||
*
|
||||
* @see self::enablePathCanonicalization()
|
||||
* @see self::disablePathCanonicalization()
|
||||
* @see self::realpath()
|
||||
* @var bool
|
||||
* @access private
|
||||
*/
|
||||
var $canonicalize_paths = true;
|
||||
|
||||
/**
|
||||
* Request Buffers
|
||||
*
|
||||
* @see self::_get_sftp_packet()
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $requestBuffer = array();
|
||||
|
||||
/**
|
||||
* Preserve timestamps on file downloads / uploads
|
||||
*
|
||||
* @see self::get()
|
||||
* @see self::put()
|
||||
* @var bool
|
||||
* @access private
|
||||
*/
|
||||
var $preserveTime = false;
|
||||
|
||||
/**
|
||||
* Arbitrary Length Packets Flag
|
||||
*
|
||||
* Determines whether or not packets of any length should be allowed,
|
||||
* in cases where the server chooses the packet length (such as
|
||||
* directory listings). By default, packets are only allowed to be
|
||||
* 256 * 1024 bytes (SFTP_MAX_MSG_LENGTH from OpenSSH's sftp-common.h)
|
||||
*
|
||||
* @see self::enableArbitraryLengthPackets()
|
||||
* @see self::_get_sftp_packet()
|
||||
* @var bool
|
||||
* @access private
|
||||
*/
|
||||
var $allow_arbitrary_length_packets = false;
|
||||
|
||||
/**
|
||||
* Was the last packet due to the channels being closed or not?
|
||||
*
|
||||
* @see self::get()
|
||||
* @see self::get_sftp_packet()
|
||||
* @var bool
|
||||
* @access private
|
||||
*/
|
||||
var $channel_close = false;
|
||||
|
||||
/**
|
||||
* Has the SFTP channel been partially negotiated?
|
||||
*
|
||||
* @var bool
|
||||
* @access private
|
||||
*/
|
||||
var $partial_init = false;
|
||||
|
||||
/**
|
||||
* Default Constructor.
|
||||
*
|
||||
|
|
@ -256,15 +338,13 @@ class SFTP extends SSH2
|
|||
$this->packet_types = array(
|
||||
1 => 'NET_SFTP_INIT',
|
||||
2 => 'NET_SFTP_VERSION',
|
||||
/* the format of SSH_FXP_OPEN changed between SFTPv4 and SFTPv5+:
|
||||
SFTPv5+: http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.1
|
||||
pre-SFTPv5 : http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.3 */
|
||||
3 => 'NET_SFTP_OPEN',
|
||||
4 => 'NET_SFTP_CLOSE',
|
||||
5 => 'NET_SFTP_READ',
|
||||
6 => 'NET_SFTP_WRITE',
|
||||
7 => 'NET_SFTP_LSTAT',
|
||||
9 => 'NET_SFTP_SETSTAT',
|
||||
10 => 'NET_SFTP_FSETSTAT',
|
||||
11 => 'NET_SFTP_OPENDIR',
|
||||
12 => 'NET_SFTP_READDIR',
|
||||
13 => 'NET_SFTP_REMOVE',
|
||||
|
|
@ -272,18 +352,13 @@ class SFTP extends SSH2
|
|||
15 => 'NET_SFTP_RMDIR',
|
||||
16 => 'NET_SFTP_REALPATH',
|
||||
17 => 'NET_SFTP_STAT',
|
||||
/* the format of SSH_FXP_RENAME changed between SFTPv4 and SFTPv5+:
|
||||
SFTPv5+: http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3
|
||||
pre-SFTPv5 : http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.5 */
|
||||
18 => 'NET_SFTP_RENAME',
|
||||
19 => 'NET_SFTP_READLINK',
|
||||
20 => 'NET_SFTP_SYMLINK',
|
||||
21 => 'NET_SFTP_LINK',
|
||||
|
||||
101=> 'NET_SFTP_STATUS',
|
||||
102=> 'NET_SFTP_HANDLE',
|
||||
/* the format of SSH_FXP_NAME changed between SFTPv3 and SFTPv4+:
|
||||
SFTPv4+: http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-9.4
|
||||
pre-SFTPv4 : http://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-7 */
|
||||
103=> 'NET_SFTP_DATA',
|
||||
104=> 'NET_SFTP_NAME',
|
||||
105=> 'NET_SFTP_ATTRS',
|
||||
|
|
@ -328,25 +403,59 @@ class SFTP extends SSH2
|
|||
// the order, in this case, matters quite a lot - see \phpseclib\Net\SFTP::_parseAttributes() to understand why
|
||||
$this->attributes = array(
|
||||
0x00000001 => 'NET_SFTP_ATTR_SIZE',
|
||||
0x00000002 => 'NET_SFTP_ATTR_UIDGID', // defined in SFTPv3, removed in SFTPv4+
|
||||
0x00000002 => 'NET_SFTP_ATTR_UIDGID', // defined in SFTPv3, removed in SFTPv4+
|
||||
0x00000080 => 'NET_SFTP_ATTR_OWNERGROUP', // defined in SFTPv4+
|
||||
0x00000004 => 'NET_SFTP_ATTR_PERMISSIONS',
|
||||
0x00000008 => 'NET_SFTP_ATTR_ACCESSTIME',
|
||||
0x00000010 => 'NET_SFTP_ATTR_CREATETIME', // SFTPv4+
|
||||
0x00000020 => 'NET_SFTP_ATTR_MODIFYTIME',
|
||||
0x00000040 => 'NET_SFTP_ATTR_ACL',
|
||||
0x00000100 => 'NET_SFTP_ATTR_SUBSECOND_TIMES',
|
||||
0x00000200 => 'NET_SFTP_ATTR_BITS', // SFTPv5+
|
||||
0x00000400 => 'NET_SFTP_ATTR_ALLOCATION_SIZE', // SFTPv6+
|
||||
0x00000800 => 'NET_SFTP_ATTR_TEXT_HINT',
|
||||
0x00001000 => 'NET_SFTP_ATTR_MIME_TYPE',
|
||||
0x00002000 => 'NET_SFTP_ATTR_LINK_COUNT',
|
||||
0x00004000 => 'NET_SFTP_ATTR_UNTRANSLATED_NAME',
|
||||
0x00008000 => 'NET_SFTP_ATTR_CTIME',
|
||||
// 0x80000000 will yield a floating point on 32-bit systems and converting floating points to integers
|
||||
// yields inconsistent behavior depending on how php is compiled. so we left shift -1 (which, in
|
||||
// two's compliment, consists of all 1 bits) by 31. on 64-bit systems this'll yield 0xFFFFFFFF80000000.
|
||||
// that's not a problem, however, and 'anded' and a 32-bit number, as all the leading 1 bits are ignored.
|
||||
-1 << 31 => 'NET_SFTP_ATTR_EXTENDED'
|
||||
(-1 << 31) & 0xFFFFFFFF => 'NET_SFTP_ATTR_EXTENDED'
|
||||
);
|
||||
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.3
|
||||
// the flag definitions change somewhat in SFTPv5+. if SFTPv5+ support is added to this library, maybe name
|
||||
// the array for that $this->open5_flags and similarly alter the constant names.
|
||||
$this->open_flags = array(
|
||||
0x00000001 => 'NET_SFTP_OPEN_READ',
|
||||
0x00000002 => 'NET_SFTP_OPEN_WRITE',
|
||||
0x00000004 => 'NET_SFTP_OPEN_APPEND',
|
||||
0x00000008 => 'NET_SFTP_OPEN_CREATE',
|
||||
0x00000010 => 'NET_SFTP_OPEN_TRUNCATE',
|
||||
0x00000020 => 'NET_SFTP_OPEN_EXCL'
|
||||
0x00000020 => 'NET_SFTP_OPEN_EXCL',
|
||||
0x00000040 => 'NET_SFTP_OPEN_TEXT' // defined in SFTPv4
|
||||
);
|
||||
// SFTPv5+ changed the flags up:
|
||||
// https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-8.1.1.3
|
||||
$this->open_flags5 = array(
|
||||
// when SSH_FXF_ACCESS_DISPOSITION is a 3 bit field that controls how the file is opened
|
||||
0x00000000 => 'NET_SFTP_OPEN_CREATE_NEW',
|
||||
0x00000001 => 'NET_SFTP_OPEN_CREATE_TRUNCATE',
|
||||
0x00000002 => 'NET_SFTP_OPEN_OPEN_EXISTING',
|
||||
0x00000003 => 'NET_SFTP_OPEN_OPEN_OR_CREATE',
|
||||
0x00000004 => 'NET_SFTP_OPEN_TRUNCATE_EXISTING',
|
||||
// the rest of the flags are not supported
|
||||
0x00000008 => 'NET_SFTP_OPEN_APPEND_DATA', // "the offset field of SS_FXP_WRITE requests is ignored"
|
||||
0x00000010 => 'NET_SFTP_OPEN_APPEND_DATA_ATOMIC',
|
||||
0x00000020 => 'NET_SFTP_OPEN_TEXT_MODE',
|
||||
0x00000040 => 'NET_SFTP_OPEN_BLOCK_READ',
|
||||
0x00000080 => 'NET_SFTP_OPEN_BLOCK_WRITE',
|
||||
0x00000100 => 'NET_SFTP_OPEN_BLOCK_DELETE',
|
||||
0x00000200 => 'NET_SFTP_OPEN_BLOCK_ADVISORY',
|
||||
0x00000400 => 'NET_SFTP_OPEN_NOFOLLOW',
|
||||
0x00000800 => 'NET_SFTP_OPEN_DELETE_ON_CLOSE',
|
||||
0x00001000 => 'NET_SFTP_OPEN_ACCESS_AUDIT_ALARM_INFO',
|
||||
0x00002000 => 'NET_SFTP_OPEN_ACCESS_BACKUP',
|
||||
0x00004000 => 'NET_SFTP_OPEN_BACKUP_STREAM',
|
||||
0x00008000 => 'NET_SFTP_OPEN_OVERRIDE_OWNER',
|
||||
);
|
||||
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-5.2
|
||||
// see \phpseclib\Net\SFTP::_parseLongname() for an explanation
|
||||
|
|
@ -368,29 +477,45 @@ class SFTP extends SSH2
|
|||
$this->status_codes,
|
||||
$this->attributes,
|
||||
$this->open_flags,
|
||||
$this->open_flags5,
|
||||
$this->file_types
|
||||
);
|
||||
|
||||
if (!defined('NET_SFTP_QUEUE_SIZE')) {
|
||||
define('NET_SFTP_QUEUE_SIZE', 50);
|
||||
define('NET_SFTP_QUEUE_SIZE', 32);
|
||||
}
|
||||
if (!defined('NET_SFTP_UPLOAD_QUEUE_SIZE')) {
|
||||
define('NET_SFTP_UPLOAD_QUEUE_SIZE', 1024);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Login
|
||||
* Check a few things before SFTP functions are called
|
||||
*
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @return bool
|
||||
* @access public
|
||||
*/
|
||||
function login($username)
|
||||
function _precheck()
|
||||
{
|
||||
$args = func_get_args();
|
||||
if (!call_user_func_array(array(&$this, '_login'), $args)) {
|
||||
if (!($this->bitmap & SSH2::MASK_LOGIN)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->pwd === false) {
|
||||
return $this->_init_sftp_connection();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Partially initialize an SFTP connection
|
||||
*
|
||||
* @return bool
|
||||
* @access public
|
||||
*/
|
||||
function _partial_init_sftp_connection()
|
||||
{
|
||||
$this->window_size_server_to_client[self::CHANNEL] = $this->window_size;
|
||||
|
||||
$packet = pack(
|
||||
|
|
@ -409,9 +534,11 @@ class SFTP extends SSH2
|
|||
|
||||
$this->channel_status[self::CHANNEL] = NET_SSH2_MSG_CHANNEL_OPEN;
|
||||
|
||||
$response = $this->_get_channel_packet(self::CHANNEL);
|
||||
$response = $this->_get_channel_packet(self::CHANNEL, true);
|
||||
if ($response === false) {
|
||||
return false;
|
||||
} elseif ($response === true && $this->isTimeout()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$packet = pack(
|
||||
|
|
@ -430,7 +557,7 @@ class SFTP extends SSH2
|
|||
|
||||
$this->channel_status[self::CHANNEL] = NET_SSH2_MSG_CHANNEL_REQUEST;
|
||||
|
||||
$response = $this->_get_channel_packet(self::CHANNEL);
|
||||
$response = $this->_get_channel_packet(self::CHANNEL, true);
|
||||
if ($response === false) {
|
||||
// from PuTTY's psftp.exe
|
||||
$command = "test -x /usr/lib/sftp-server && exec /usr/lib/sftp-server\n" .
|
||||
|
|
@ -454,10 +581,12 @@ class SFTP extends SSH2
|
|||
|
||||
$this->channel_status[self::CHANNEL] = NET_SSH2_MSG_CHANNEL_REQUEST;
|
||||
|
||||
$response = $this->_get_channel_packet(self::CHANNEL);
|
||||
$response = $this->_get_channel_packet(self::CHANNEL, true);
|
||||
if ($response === false) {
|
||||
return false;
|
||||
}
|
||||
} elseif ($response === true && $this->isTimeout()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->channel_status[self::CHANNEL] = NET_SSH2_MSG_CHANNEL_DATA;
|
||||
|
|
@ -472,31 +601,43 @@ class SFTP extends SSH2
|
|||
return false;
|
||||
}
|
||||
|
||||
$this->use_request_id = true;
|
||||
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nversion', $this->_string_shift($response, 4)));
|
||||
$this->version = $version;
|
||||
$this->defaultVersion = $version;
|
||||
while (!empty($response)) {
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
||||
$key = $this->_string_shift($response, $length);
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
||||
$value = $this->_string_shift($response, $length);
|
||||
$this->extensions[$key] = $value;
|
||||
}
|
||||
|
||||
/*
|
||||
SFTPv4+ defines a 'newline' extension. SFTPv3 seems to have unofficial support for it via 'newline@vandyke.com',
|
||||
however, I'm not sure what 'newline@vandyke.com' is supposed to do (the fact that it's unofficial means that it's
|
||||
not in the official SFTPv3 specs) and 'newline@vandyke.com' / 'newline' are likely not drop-in substitutes for
|
||||
one another due to the fact that 'newline' comes with a SSH_FXF_TEXT bitmask whereas it seems unlikely that
|
||||
'newline@vandyke.com' would.
|
||||
*/
|
||||
/*
|
||||
if (isset($this->extensions['newline@vandyke.com'])) {
|
||||
$this->extensions['newline'] = $this->extensions['newline@vandyke.com'];
|
||||
unset($this->extensions['newline@vandyke.com']);
|
||||
}
|
||||
*/
|
||||
$this->partial_init = true;
|
||||
|
||||
$this->request_id = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* (Re)initializes the SFTP channel
|
||||
*
|
||||
* @return bool
|
||||
* @access private
|
||||
*/
|
||||
function _init_sftp_connection()
|
||||
{
|
||||
if (!$this->partial_init && !$this->_partial_init_sftp_connection()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
A Note on SFTPv4/5/6 support:
|
||||
|
|
@ -521,12 +662,60 @@ class SFTP extends SSH2
|
|||
in draft-ietf-secsh-filexfer-13 would be quite impossible. As such, what \phpseclib\Net\SFTP would do is close the
|
||||
channel and reopen it with a new and updated SSH_FXP_INIT packet.
|
||||
*/
|
||||
switch ($this->version) {
|
||||
case 2:
|
||||
case 3:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
$this->version = $this->defaultVersion;
|
||||
if (isset($this->extensions['versions']) && (!$this->preferredVersion || $this->preferredVersion != $this->version)) {
|
||||
$versions = explode(',', $this->extensions['versions']);
|
||||
$supported = array(6, 5, 4);
|
||||
if ($this->preferredVersion) {
|
||||
$supported = array_diff($supported, array($this->preferredVersion));
|
||||
array_unshift($supported, $this->preferredVersion);
|
||||
}
|
||||
foreach ($supported as $ver) {
|
||||
if (in_array($ver, $versions)) {
|
||||
if ($ver === $this->version) {
|
||||
break;
|
||||
}
|
||||
$this->version = (int) $ver;
|
||||
$packet = pack('Na*Na*', strlen('version-select'), 'version-select', strlen($ver), $ver);
|
||||
if (!$this->_send_sftp_packet(NET_SFTP_EXTENDED, $packet)) {
|
||||
return false;
|
||||
}
|
||||
$response = $this->_get_sftp_packet();
|
||||
if ($this->packet_type != NET_SFTP_STATUS) {
|
||||
user_error('Expected SSH_FXP_STATUS');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
|
||||
if ($status != NET_SFTP_STATUS_OK) {
|
||||
$this->_logError($response, $status);
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
SFTPv4+ defines a 'newline' extension. SFTPv3 seems to have unofficial support for it via 'newline@vandyke.com',
|
||||
however, I'm not sure what 'newline@vandyke.com' is supposed to do (the fact that it's unofficial means that it's
|
||||
not in the official SFTPv3 specs) and 'newline@vandyke.com' / 'newline' are likely not drop-in substitutes for
|
||||
one another due to the fact that 'newline' comes with a SSH_FXF_TEXT bitmask whereas it seems unlikely that
|
||||
'newline@vandyke.com' would.
|
||||
*/
|
||||
/*
|
||||
if (isset($this->extensions['newline@vandyke.com'])) {
|
||||
$this->extensions['newline'] = $this->extensions['newline@vandyke.com'];
|
||||
unset($this->extensions['newline@vandyke.com']);
|
||||
}
|
||||
*/
|
||||
|
||||
if ($this->version < 2 || $this->version > 6) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->pwd = $this->_realpath('.');
|
||||
|
|
@ -566,6 +755,46 @@ class SFTP extends SSH2
|
|||
$this->stat_cache = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable path canonicalization
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
function enablePathCanonicalization()
|
||||
{
|
||||
$this->canonicalize_paths = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable path canonicalization
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
function disablePathCanonicalization()
|
||||
{
|
||||
$this->canonicalize_paths = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable arbitrary length packets
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
function enableArbitraryLengthPackets()
|
||||
{
|
||||
$this->allow_arbitrary_length_packets = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable arbitrary length packets
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
function disableArbitraryLengthPackets()
|
||||
{
|
||||
$this->allow_arbitrary_length_packets = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current directory name
|
||||
*
|
||||
|
|
@ -574,6 +803,10 @@ class SFTP extends SSH2
|
|||
*/
|
||||
function pwd()
|
||||
{
|
||||
if (!$this->_precheck()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->pwd;
|
||||
}
|
||||
|
||||
|
|
@ -587,12 +820,15 @@ class SFTP extends SSH2
|
|||
function _logError($response, $status = -1)
|
||||
{
|
||||
if ($status == -1) {
|
||||
if (strlen($response) < 4) {
|
||||
return;
|
||||
}
|
||||
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
|
||||
}
|
||||
|
||||
$error = $this->status_codes[$status];
|
||||
|
||||
if ($this->version > 2) {
|
||||
if ($this->version > 2 || strlen($response) < 4) {
|
||||
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
||||
$this->sftp_errors[] = $error . ': ' . $this->_string_shift($response, $length);
|
||||
} else {
|
||||
|
|
@ -612,6 +848,10 @@ class SFTP extends SSH2
|
|||
*/
|
||||
function realpath($path)
|
||||
{
|
||||
if (!$this->_precheck()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->_realpath($path);
|
||||
}
|
||||
|
||||
|
|
@ -621,13 +861,20 @@ class SFTP extends SSH2
|
|||
* SFTP doesn't provide a mechanism by which the current working directory can be changed, so we'll emulate it. Returns
|
||||
* the absolute (canonicalized) path.
|
||||
*
|
||||
* If canonicalize_paths has been disabled using disablePathCanonicalization(), $path is returned as-is.
|
||||
*
|
||||
* @see self::chdir()
|
||||
* @see self::disablePathCanonicalization()
|
||||
* @param string $path
|
||||
* @return mixed
|
||||
* @access private
|
||||
*/
|
||||
function _realpath($path)
|
||||
{
|
||||
if (!$this->canonicalize_paths) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
if ($this->pwd === false) {
|
||||
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.9
|
||||
if (!$this->_send_sftp_packet(NET_SFTP_REALPATH, pack('Na*', strlen($path), $path))) {
|
||||
|
|
@ -641,6 +888,9 @@ class SFTP extends SSH2
|
|||
// should work on all SFTP versions since the only part of the SSH_FXP_NAME packet the following looks
|
||||
// at is the first part and that part is defined the same in SFTP versions 3 through 6.
|
||||
$this->_string_shift($response, 4); // skip over the count - it should be 1, anyway
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
||||
return $this->_string_shift($response, $length);
|
||||
case NET_SFTP_STATUS:
|
||||
|
|
@ -652,7 +902,7 @@ class SFTP extends SSH2
|
|||
}
|
||||
}
|
||||
|
||||
if ($path[0] != '/') {
|
||||
if (!strlen($path) || $path[0] != '/') {
|
||||
$path = $this->pwd . '/' . $path;
|
||||
}
|
||||
|
||||
|
|
@ -684,7 +934,7 @@ class SFTP extends SSH2
|
|||
*/
|
||||
function chdir($dir)
|
||||
{
|
||||
if (!($this->bitmap & SSH2::MASK_LOGIN)) {
|
||||
if (!$this->_precheck()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -777,6 +1027,7 @@ class SFTP extends SSH2
|
|||
}
|
||||
if (is_array($this->_query_stat_cache($this->_realpath($dir . '/' . $value)))) {
|
||||
$temp = $this->_nlist_helper($dir . '/' . $value, true, $relativeDir . $value . '/');
|
||||
$temp = is_array($temp) ? $temp : array();
|
||||
$result = array_merge($result, $temp);
|
||||
} else {
|
||||
$result[] = $relativeDir . $value;
|
||||
|
|
@ -808,7 +1059,17 @@ class SFTP extends SSH2
|
|||
unset($files[$key]);
|
||||
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++;
|
||||
$files[$key] = $this->rawlist($dir . '/' . $key, true);
|
||||
$depth--;
|
||||
|
|
@ -830,7 +1091,7 @@ class SFTP extends SSH2
|
|||
*/
|
||||
function _list($dir, $raw = true)
|
||||
{
|
||||
if (!($this->bitmap & SSH2::MASK_LOGIN)) {
|
||||
if (!$this->_precheck()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -875,14 +1136,27 @@ class SFTP extends SSH2
|
|||
$response = $this->_get_sftp_packet();
|
||||
switch ($this->packet_type) {
|
||||
case NET_SFTP_NAME:
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Ncount', $this->_string_shift($response, 4)));
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
||||
$shortname = $this->_string_shift($response, $length);
|
||||
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
||||
$longname = $this->_string_shift($response, $length);
|
||||
// SFTPv4 "removed the long filename from the names structure-- it can now be
|
||||
// built from information available in the attrs structure."
|
||||
if ($this->version < 4) {
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
||||
$longname = $this->_string_shift($response, $length);
|
||||
}
|
||||
$attributes = $this->_parseAttributes($response);
|
||||
if (!isset($attributes['type'])) {
|
||||
if (!isset($attributes['type']) && $this->version < 4) {
|
||||
$fileType = $this->_parseLongname($longname);
|
||||
if ($fileType) {
|
||||
$attributes['type'] = $fileType;
|
||||
|
|
@ -905,6 +1179,9 @@ class SFTP extends SSH2
|
|||
}
|
||||
break;
|
||||
case NET_SFTP_STATUS:
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
|
||||
if ($status != NET_SFTP_STATUS_EOF) {
|
||||
$this->_logError($response, $status);
|
||||
|
|
@ -925,7 +1202,7 @@ class SFTP extends SSH2
|
|||
uasort($contents, array(&$this, '_comparator'));
|
||||
}
|
||||
|
||||
return $raw ? $contents : array_keys($contents);
|
||||
return $raw ? $contents : array_map('strval', array_keys($contents));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1039,10 +1316,6 @@ class SFTP extends SSH2
|
|||
*/
|
||||
function size($filename)
|
||||
{
|
||||
if (!($this->bitmap & SSH2::MASK_LOGIN)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = $this->stat($filename);
|
||||
if ($result === false) {
|
||||
return false;
|
||||
|
|
@ -1079,7 +1352,7 @@ class SFTP extends SSH2
|
|||
$temp[$dir] = array();
|
||||
}
|
||||
if ($i === $max) {
|
||||
if (is_object($temp[$dir])) {
|
||||
if (is_object($temp[$dir]) && is_object($value)) {
|
||||
if (!isset($value->stat) && isset($temp[$dir]->stat)) {
|
||||
$value->stat = $temp[$dir]->stat;
|
||||
}
|
||||
|
|
@ -1108,6 +1381,9 @@ class SFTP extends SSH2
|
|||
$temp = &$this->stat_cache;
|
||||
$max = count($dirs) - 1;
|
||||
foreach ($dirs as $i => $dir) {
|
||||
if (!is_array($temp)) {
|
||||
return false;
|
||||
}
|
||||
if ($i === $max) {
|
||||
unset($temp[$dir]);
|
||||
return true;
|
||||
|
|
@ -1124,7 +1400,7 @@ class SFTP extends SSH2
|
|||
*
|
||||
* Mainly used by file_exists
|
||||
*
|
||||
* @param string $dir
|
||||
* @param string $path
|
||||
* @return mixed
|
||||
* @access private
|
||||
*/
|
||||
|
|
@ -1134,6 +1410,9 @@ class SFTP extends SSH2
|
|||
|
||||
$temp = &$this->stat_cache;
|
||||
foreach ($dirs as $dir) {
|
||||
if (!is_array($temp)) {
|
||||
return null;
|
||||
}
|
||||
if (!isset($temp[$dir])) {
|
||||
return null;
|
||||
}
|
||||
|
|
@ -1153,7 +1432,7 @@ class SFTP extends SSH2
|
|||
*/
|
||||
function stat($filename)
|
||||
{
|
||||
if (!($this->bitmap & SSH2::MASK_LOGIN)) {
|
||||
if (!$this->_precheck()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1210,7 +1489,7 @@ class SFTP extends SSH2
|
|||
*/
|
||||
function lstat($filename)
|
||||
{
|
||||
if (!($this->bitmap & SSH2::MASK_LOGIN)) {
|
||||
if (!$this->_precheck()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1267,7 +1546,7 @@ class SFTP extends SSH2
|
|||
/**
|
||||
* Returns general information about a file or symbolic link
|
||||
*
|
||||
* Determines information without calling \phpseclib\Net\SFTP::_realpath().
|
||||
* Determines information without calling \phpseclib\Net\SFTP::realpath().
|
||||
* The second parameter can be either NET_SFTP_STAT or NET_SFTP_LSTAT.
|
||||
*
|
||||
* @param string $filename
|
||||
|
|
@ -1324,7 +1603,7 @@ class SFTP extends SSH2
|
|||
*/
|
||||
function touch($filename, $time = null, $atime = null)
|
||||
{
|
||||
if (!($this->bitmap & SSH2::MASK_LOGIN)) {
|
||||
if (!$this->_precheck()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1340,9 +1619,25 @@ class SFTP extends SSH2
|
|||
$atime = $time;
|
||||
}
|
||||
|
||||
$flags = NET_SFTP_OPEN_WRITE | NET_SFTP_OPEN_CREATE | NET_SFTP_OPEN_EXCL;
|
||||
$attr = pack('N3', NET_SFTP_ATTR_ACCESSTIME, $time, $atime);
|
||||
$packet = pack('Na*Na*', strlen($filename), $filename, $flags, $attr);
|
||||
if ($this->version < 4) {
|
||||
$attr = pack('N3', NET_SFTP_ATTR_ACCESSTIME, $atime, $time);
|
||||
} else {
|
||||
$attr = pack(
|
||||
'N5',
|
||||
NET_SFTP_ATTR_ACCESSTIME | NET_SFTP_ATTR_MODIFYTIME,
|
||||
$atime / 4294967296,
|
||||
$atime,
|
||||
$time / 4294967296,
|
||||
$time
|
||||
);
|
||||
}
|
||||
|
||||
$packet = pack('Na*', strlen($filename), $filename);
|
||||
$packet.= $this->version >= 5 ?
|
||||
pack('N2', 0, NET_SFTP_OPEN_OPEN_EXISTING) :
|
||||
pack('N', NET_SFTP_OPEN_WRITE | NET_SFTP_OPEN_CREATE | NET_SFTP_OPEN_EXCL);
|
||||
$packet.= $attr;
|
||||
|
||||
if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1365,19 +1660,47 @@ class SFTP extends SSH2
|
|||
/**
|
||||
* Changes file or directory owner
|
||||
*
|
||||
* $uid should be an int for SFTPv3 and a string for SFTPv4+. Ideally the string
|
||||
* would be of the form "user@dns_domain" but it does not need to be.
|
||||
* `$sftp->getSupportedVersions()['version']` will return the specific version
|
||||
* that's being used.
|
||||
*
|
||||
* Returns true on success or false on error.
|
||||
*
|
||||
* @param string $filename
|
||||
* @param int $uid
|
||||
* @param int|string $uid
|
||||
* @param bool $recursive
|
||||
* @return bool
|
||||
* @access public
|
||||
*/
|
||||
function chown($filename, $uid, $recursive = false)
|
||||
{
|
||||
// quoting from <http://www.kernel.org/doc/man-pages/online/pages/man2/chown.2.html>,
|
||||
// "if the owner or group is specified as -1, then that ID is not changed"
|
||||
$attr = pack('N3', NET_SFTP_ATTR_UIDGID, $uid, -1);
|
||||
/*
|
||||
quoting <https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-7.5>,
|
||||
|
||||
"To avoid a representation that is tied to a particular underlying
|
||||
implementation at the client or server, the use of UTF-8 strings has
|
||||
been chosen. The string should be of the form "user@dns_domain".
|
||||
This will allow for a client and server that do not use the same
|
||||
local representation the ability to translate to a common syntax that
|
||||
can be interpreted by both. In the case where there is no
|
||||
translation available to the client or server, the attribute value
|
||||
must be constructed without the "@"."
|
||||
|
||||
phpseclib _could_ auto append the dns_domain to $uid BUT what if it shouldn't
|
||||
have one? phpseclib would have no way of knowing so rather than guess phpseclib
|
||||
will just use whatever value the user provided
|
||||
*/
|
||||
|
||||
$attr = $this->version < 4 ?
|
||||
// quoting <http://www.kernel.org/doc/man-pages/online/pages/man2/chown.2.html>,
|
||||
// "if the owner or group is specified as -1, then that ID is not changed"
|
||||
pack('N3', NET_SFTP_ATTR_UIDGID, $uid, -1) :
|
||||
// quoting <https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-7.5>,
|
||||
// "If either the owner or group field is zero length, the field should be
|
||||
// considered absent, and no change should be made to that specific field
|
||||
// during a modification operation"
|
||||
pack('NNa*Na*', NET_SFTP_ATTR_OWNERGROUP, strlen($uid), $uid, 0, '');
|
||||
|
||||
return $this->_setstat($filename, $attr, $recursive);
|
||||
}
|
||||
|
|
@ -1385,17 +1708,24 @@ class SFTP extends SSH2
|
|||
/**
|
||||
* Changes file or directory group
|
||||
*
|
||||
* $gid should be an int for SFTPv3 and a string for SFTPv4+. Ideally the string
|
||||
* would be of the form "user@dns_domain" but it does not need to be.
|
||||
* `$sftp->getSupportedVersions()['version']` will return the specific version
|
||||
* that's being used.
|
||||
*
|
||||
* Returns true on success or false on error.
|
||||
*
|
||||
* @param string $filename
|
||||
* @param int $gid
|
||||
* @param int|string $gid
|
||||
* @param bool $recursive
|
||||
* @return bool
|
||||
* @access public
|
||||
*/
|
||||
function chgrp($filename, $gid, $recursive = false)
|
||||
{
|
||||
$attr = pack('N3', NET_SFTP_ATTR_UIDGID, -1, $gid);
|
||||
$attr = $this->version < 4 ?
|
||||
pack('N3', NET_SFTP_ATTR_UIDGID, $gid, -1) :
|
||||
pack('NNa*Na*', NET_SFTP_ATTR_OWNERGROUP, 0, '', strlen($gid), $gid);
|
||||
|
||||
return $this->_setstat($filename, $attr, $recursive);
|
||||
}
|
||||
|
|
@ -1428,7 +1758,7 @@ class SFTP extends SSH2
|
|||
return true;
|
||||
}
|
||||
|
||||
$filename = $this->_realPath($filename);
|
||||
$filename = $this->realpath($filename);
|
||||
// rather than return what the permissions *should* be, we'll return what they actually are. this will also
|
||||
// tell us if the file actually exists.
|
||||
// incidentally, SFTPv4+ adds an additional 32-bit integer field - flags - to the following:
|
||||
|
|
@ -1462,7 +1792,7 @@ class SFTP extends SSH2
|
|||
*/
|
||||
function _setstat($filename, $attr, $recursive)
|
||||
{
|
||||
if (!($this->bitmap & SSH2::MASK_LOGIN)) {
|
||||
if (!$this->_precheck()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1480,9 +1810,10 @@ class SFTP extends SSH2
|
|||
return $result;
|
||||
}
|
||||
|
||||
// SFTPv4+ has an additional byte field - type - that would need to be sent, as well. setting it to
|
||||
// SSH_FILEXFER_TYPE_UNKNOWN might work. if not, we'd have to do an SSH_FXP_STAT before doing an SSH_FXP_SETSTAT.
|
||||
if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, pack('Na*a*', strlen($filename), $filename, $attr))) {
|
||||
$packet = $this->version >= 4 ?
|
||||
pack('Na*a*Ca*', strlen($filename), $filename, substr($attr, 0, 4), NET_SFTP_TYPE_UNKNOWN, substr($attr, 4)) :
|
||||
pack('Na*a*', strlen($filename), $filename, $attr);
|
||||
if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, $packet)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1499,6 +1830,9 @@ class SFTP extends SSH2
|
|||
return false;
|
||||
}
|
||||
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
|
||||
if ($status != NET_SFTP_STATUS_OK) {
|
||||
$this->_logError($response, $status);
|
||||
|
|
@ -1549,7 +1883,10 @@ class SFTP extends SSH2
|
|||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, pack('Na*a*', strlen($temp), $temp, $attr))) {
|
||||
$packet = $this->version >= 4 ?
|
||||
pack('Na*Ca*', strlen($temp), $temp, NET_SFTP_TYPE_UNKNOWN, $attr) :
|
||||
pack('Na*a*', strlen($temp), $temp, $attr);
|
||||
if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, $packet)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1564,7 +1901,10 @@ class SFTP extends SSH2
|
|||
}
|
||||
}
|
||||
|
||||
if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, pack('Na*a*', strlen($path), $path, $attr))) {
|
||||
$packet = $this->version >= 4 ?
|
||||
pack('Na*Ca*', strlen($temp), $temp, NET_SFTP_TYPE_UNKNOWN, $attr) :
|
||||
pack('Na*a*', strlen($temp), $temp, $attr);
|
||||
if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, $packet)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1589,7 +1929,7 @@ class SFTP extends SSH2
|
|||
*/
|
||||
function readlink($link)
|
||||
{
|
||||
if (!($this->bitmap & SSH2::MASK_LOGIN)) {
|
||||
if (!$this->_precheck()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1611,12 +1951,18 @@ class SFTP extends SSH2
|
|||
return false;
|
||||
}
|
||||
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Ncount', $this->_string_shift($response, 4)));
|
||||
// the file isn't a symlink
|
||||
if (!$count) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
||||
return $this->_string_shift($response, $length);
|
||||
}
|
||||
|
|
@ -1633,15 +1979,44 @@ class SFTP extends SSH2
|
|||
*/
|
||||
function symlink($target, $link)
|
||||
{
|
||||
if (!($this->bitmap & SSH2::MASK_LOGIN)) {
|
||||
if (!$this->_precheck()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//$target = $this->_realpath($target);
|
||||
$link = $this->_realpath($link);
|
||||
|
||||
$packet = pack('Na*Na*', strlen($target), $target, strlen($link), $link);
|
||||
if (!$this->_send_sftp_packet(NET_SFTP_SYMLINK, $packet)) {
|
||||
/* quoting https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-09#section-12.1 :
|
||||
|
||||
Changed the SYMLINK packet to be LINK and give it the ability to
|
||||
create hard links. Also change it's packet number because many
|
||||
implementation implemented SYMLINK with the arguments reversed.
|
||||
Hopefully the new argument names make it clear which way is which.
|
||||
*/
|
||||
if ($this->version == 6) {
|
||||
$type = NET_SFTP_LINK;
|
||||
$packet = pack('Na*Na*C', strlen($link), $link, strlen($target), $target, 1);
|
||||
} else {
|
||||
$type = NET_SFTP_SYMLINK;
|
||||
/* quoting http://bxr.su/OpenBSD/usr.bin/ssh/PROTOCOL#347 :
|
||||
|
||||
3.1. sftp: Reversal of arguments to SSH_FXP_SYMLINK
|
||||
|
||||
When OpenSSH's sftp-server was implemented, the order of the arguments
|
||||
to the SSH_FXP_SYMLINK method was inadvertently reversed. Unfortunately,
|
||||
the reversal was not noticed until the server was widely deployed. Since
|
||||
fixing this to follow the specification would cause incompatibility, the
|
||||
current order was retained. For correct operation, clients should send
|
||||
SSH_FXP_SYMLINK as follows:
|
||||
|
||||
uint32 id
|
||||
string targetpath
|
||||
string linkpath */
|
||||
$packet = substr($this->server_identifier, 0, 15) == 'SSH-2.0-OpenSSH' ?
|
||||
pack('Na*Na*', strlen($target), $target, strlen($link), $link) :
|
||||
pack('Na*Na*', strlen($link), $link, strlen($target), $target);
|
||||
}
|
||||
if (!$this->_send_sftp_packet($type, $packet)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1651,6 +2026,9 @@ class SFTP extends SSH2
|
|||
return false;
|
||||
}
|
||||
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
|
||||
if ($status != NET_SFTP_STATUS_OK) {
|
||||
$this->_logError($response, $status);
|
||||
|
|
@ -1664,19 +2042,18 @@ class SFTP extends SSH2
|
|||
* Creates a directory.
|
||||
*
|
||||
* @param string $dir
|
||||
* @param int $mode
|
||||
* @param bool $recursive
|
||||
* @return bool
|
||||
* @access public
|
||||
*/
|
||||
function mkdir($dir, $mode = -1, $recursive = false)
|
||||
{
|
||||
if (!($this->bitmap & SSH2::MASK_LOGIN)) {
|
||||
if (!$this->_precheck()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$dir = $this->_realpath($dir);
|
||||
// by not providing any permissions, hopefully the server will use the logged in users umask - their
|
||||
// default permissions.
|
||||
$attr = $mode == -1 ? "\0\0\0\0" : pack('N2', NET_SFTP_ATTR_PERMISSIONS, $mode & 07777);
|
||||
|
||||
if ($recursive) {
|
||||
$dirs = explode('/', preg_replace('#/(?=/)|/$#', '', $dir));
|
||||
|
|
@ -1687,24 +2064,26 @@ class SFTP extends SSH2
|
|||
for ($i = 0; $i < count($dirs); $i++) {
|
||||
$temp = array_slice($dirs, 0, $i + 1);
|
||||
$temp = implode('/', $temp);
|
||||
$result = $this->_mkdir_helper($temp, $attr);
|
||||
$result = $this->_mkdir_helper($temp, $mode);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $this->_mkdir_helper($dir, $attr);
|
||||
return $this->_mkdir_helper($dir, $mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for directory creation
|
||||
*
|
||||
* @param string $dir
|
||||
* @param int $mode
|
||||
* @return bool
|
||||
* @access private
|
||||
*/
|
||||
function _mkdir_helper($dir, $attr)
|
||||
function _mkdir_helper($dir, $mode)
|
||||
{
|
||||
if (!$this->_send_sftp_packet(NET_SFTP_MKDIR, pack('Na*a*', strlen($dir), $dir, $attr))) {
|
||||
// send SSH_FXP_MKDIR without any attributes (that's what the \0\0\0\0 is doing)
|
||||
if (!$this->_send_sftp_packet(NET_SFTP_MKDIR, pack('Na*a*', strlen($dir), $dir, "\0\0\0\0"))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1714,12 +2093,19 @@ class SFTP extends SSH2
|
|||
return false;
|
||||
}
|
||||
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
|
||||
if ($status != NET_SFTP_STATUS_OK) {
|
||||
$this->_logError($response, $status);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($mode !== -1) {
|
||||
$this->chmod($mode, $dir);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1732,7 +2118,7 @@ class SFTP extends SSH2
|
|||
*/
|
||||
function rmdir($dir)
|
||||
{
|
||||
if (!($this->bitmap & SSH2::MASK_LOGIN)) {
|
||||
if (!$this->_precheck()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1751,6 +2137,9 @@ class SFTP extends SSH2
|
|||
return false;
|
||||
}
|
||||
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
|
||||
if ($status != NET_SFTP_STATUS_OK) {
|
||||
// presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED?
|
||||
|
|
@ -1778,7 +2167,8 @@ class SFTP extends SSH2
|
|||
* contain as many bytes as filename.ext does on your local filesystem. If your filename.ext is 1MB then that is how
|
||||
* large $remote_file will be, as well.
|
||||
*
|
||||
* Setting $mode to self::SOURCE_CALLBACK will use $data as callback function, which gets only one parameter -- number of bytes to return, and returns a string if there is some data or null if there is no more data
|
||||
* Setting $mode to self::SOURCE_CALLBACK will use $data as callback function, which gets only one parameter -- number
|
||||
* of bytes to return, and returns a string if there is some data or null if there is no more data
|
||||
*
|
||||
* If $data is a resource then it'll be used as a resource instead.
|
||||
*
|
||||
|
|
@ -1814,7 +2204,7 @@ class SFTP extends SSH2
|
|||
*/
|
||||
function put($remote_file, $data, $mode = self::SOURCE_STRING, $start = -1, $local_start = -1, $progressCallback = null)
|
||||
{
|
||||
if (!($this->bitmap & SSH2::MASK_LOGIN)) {
|
||||
if (!$this->_precheck()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1825,10 +2215,14 @@ class SFTP extends SSH2
|
|||
|
||||
$this->_remove_from_stat_cache($remote_file);
|
||||
|
||||
$flags = NET_SFTP_OPEN_WRITE | NET_SFTP_OPEN_CREATE;
|
||||
// according to the SFTP specs, NET_SFTP_OPEN_APPEND should "force all writes to append data at the end of the file."
|
||||
// in practice, it doesn't seem to do that.
|
||||
//$flags|= ($mode & self::RESUME) ? NET_SFTP_OPEN_APPEND : NET_SFTP_OPEN_TRUNCATE;
|
||||
if ($this->version >= 5) {
|
||||
$flags = NET_SFTP_OPEN_OPEN_OR_CREATE;
|
||||
} else {
|
||||
$flags = NET_SFTP_OPEN_WRITE | NET_SFTP_OPEN_CREATE;
|
||||
// according to the SFTP specs, NET_SFTP_OPEN_APPEND should "force all writes to append data at the end of the file."
|
||||
// in practice, it doesn't seem to do that.
|
||||
//$flags|= ($mode & SFTP::RESUME) ? NET_SFTP_OPEN_APPEND : NET_SFTP_OPEN_TRUNCATE;
|
||||
}
|
||||
|
||||
if ($start >= 0) {
|
||||
$offset = $start;
|
||||
|
|
@ -1838,10 +2232,17 @@ class SFTP extends SSH2
|
|||
$offset = $size !== false ? $size : 0;
|
||||
} else {
|
||||
$offset = 0;
|
||||
$flags|= NET_SFTP_OPEN_TRUNCATE;
|
||||
if ($this->version >= 5) {
|
||||
$flags = NET_SFTP_OPEN_CREATE_TRUNCATE;
|
||||
} else {
|
||||
$flags|= NET_SFTP_OPEN_TRUNCATE;
|
||||
}
|
||||
}
|
||||
|
||||
$packet = pack('Na*N2', strlen($remote_file), $remote_file, $flags, 0);
|
||||
$packet = pack('Na*', strlen($remote_file), $remote_file);
|
||||
$packet.= $this->version >= 5 ?
|
||||
pack('N3', 0, $flags, 0) :
|
||||
pack('N2', $flags, 0);
|
||||
if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1871,7 +2272,14 @@ class SFTP extends SSH2
|
|||
break;
|
||||
case is_resource($data):
|
||||
$mode = $mode & ~self::SOURCE_LOCAL_FILE;
|
||||
$fp = $data;
|
||||
$info = stream_get_meta_data($data);
|
||||
if ($info['wrapper_type'] == 'PHP' && $info['stream_type'] == 'Input') {
|
||||
$fp = fopen('php://memory', 'w+');
|
||||
stream_copy_to_stream($data, $fp);
|
||||
rewind($fp);
|
||||
} else {
|
||||
$fp = $data;
|
||||
}
|
||||
break;
|
||||
case $mode & self::SOURCE_LOCAL_FILE:
|
||||
if (!is_file($data)) {
|
||||
|
|
@ -1886,7 +2294,7 @@ class SFTP extends SSH2
|
|||
|
||||
if (isset($fp)) {
|
||||
$stat = fstat($fp);
|
||||
$size = $stat['size'];
|
||||
$size = !empty($stat) ? $stat['size'] : 0;
|
||||
|
||||
if ($local_start >= 0) {
|
||||
fseek($fp, $local_start);
|
||||
|
|
@ -1901,10 +2309,10 @@ class SFTP extends SSH2
|
|||
$sent = 0;
|
||||
$size = $size < 0 ? ($size & 0x7FFFFFFF) + 0x80000000 : $size;
|
||||
|
||||
$sftp_packet_size = 4096; // PuTTY uses 4096
|
||||
// make the SFTP packet be exactly 4096 bytes by including the bytes in the NET_SFTP_WRITE packets "header"
|
||||
$sftp_packet_size = $this->max_sftp_packet;
|
||||
// make the SFTP packet be exactly the SFTP packet size by including the bytes in the NET_SFTP_WRITE packets "header"
|
||||
$sftp_packet_size-= strlen($handle) + 25;
|
||||
$i = 0;
|
||||
$i = $j = 0;
|
||||
while ($dataCallback || ($size === 0 || $sent < $size)) {
|
||||
if ($dataCallback) {
|
||||
$temp = call_user_func($dataCallback, $sftp_packet_size);
|
||||
|
|
@ -1920,7 +2328,7 @@ class SFTP extends SSH2
|
|||
|
||||
$subtemp = $offset + $sent;
|
||||
$packet = pack('Na*N3a*', strlen($handle), $handle, $subtemp / 4294967296, $subtemp, strlen($temp), $temp);
|
||||
if (!$this->_send_sftp_packet(NET_SFTP_WRITE, $packet)) {
|
||||
if (!$this->_send_sftp_packet(NET_SFTP_WRITE, $packet, $j)) {
|
||||
if ($mode & self::SOURCE_LOCAL_FILE) {
|
||||
fclose($fp);
|
||||
}
|
||||
|
|
@ -1932,8 +2340,9 @@ class SFTP extends SSH2
|
|||
}
|
||||
|
||||
$i++;
|
||||
$j++;
|
||||
|
||||
if ($i == NET_SFTP_QUEUE_SIZE) {
|
||||
if ($i == NET_SFTP_UPLOAD_QUEUE_SIZE) {
|
||||
if (!$this->_read_put_responses($i)) {
|
||||
$i = 0;
|
||||
break;
|
||||
|
|
@ -1942,6 +2351,8 @@ class SFTP extends SSH2
|
|||
}
|
||||
}
|
||||
|
||||
$result = $this->_close_handle($handle);
|
||||
|
||||
if (!$this->_read_put_responses($i)) {
|
||||
if ($mode & self::SOURCE_LOCAL_FILE) {
|
||||
fclose($fp);
|
||||
|
|
@ -1950,11 +2361,33 @@ class SFTP extends SSH2
|
|||
return false;
|
||||
}
|
||||
|
||||
if ($mode & self::SOURCE_LOCAL_FILE) {
|
||||
fclose($fp);
|
||||
if ($mode & SFTP::SOURCE_LOCAL_FILE) {
|
||||
if (isset($fp) && is_resource($fp)) {
|
||||
fclose($fp);
|
||||
}
|
||||
|
||||
if ($this->preserveTime) {
|
||||
$stat = stat($data);
|
||||
if ($this->version < 4) {
|
||||
$attr = pack('N3', NET_SFTP_ATTR_ACCESSTIME, $stat['atime'], $stat['mtime']);
|
||||
} else {
|
||||
$attr = pack(
|
||||
'N5',
|
||||
NET_SFTP_ATTR_ACCESSTIME | NET_SFTP_ATTR_MODIFYTIME,
|
||||
$stat['atime'] / 4294967296,
|
||||
$stat['atime'],
|
||||
$stat['mtime'] / 4294967296,
|
||||
$stat['mtime']
|
||||
);
|
||||
}
|
||||
|
||||
if (!$this->_setstat($remote_file, $attr, false)) {
|
||||
user_error('Error setting file time');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_close_handle($handle);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1976,6 +2409,9 @@ class SFTP extends SSH2
|
|||
return false;
|
||||
}
|
||||
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
|
||||
if ($status != NET_SFTP_STATUS_OK) {
|
||||
$this->_logError($response, $status);
|
||||
|
|
@ -2007,6 +2443,9 @@ class SFTP extends SSH2
|
|||
return false;
|
||||
}
|
||||
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
|
||||
if ($status != NET_SFTP_STATUS_OK) {
|
||||
$this->_logError($response, $status);
|
||||
|
|
@ -2029,12 +2468,13 @@ class SFTP extends SSH2
|
|||
* @param string $local_file
|
||||
* @param int $offset
|
||||
* @param int $length
|
||||
* @param callable|null $progressCallback
|
||||
* @return mixed
|
||||
* @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->_precheck()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -2043,7 +2483,10 @@ class SFTP extends SSH2
|
|||
return false;
|
||||
}
|
||||
|
||||
$packet = pack('Na*N2', strlen($remote_file), $remote_file, NET_SFTP_OPEN_READ, 0);
|
||||
$packet = pack('Na*', strlen($remote_file), $remote_file);
|
||||
$packet.= $this->version >= 5 ?
|
||||
pack('N3', 0, NET_SFTP_OPEN_OPEN_EXISTING, 0) :
|
||||
pack('N2', NET_SFTP_OPEN_READ, 0);
|
||||
if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -2067,7 +2510,7 @@ class SFTP extends SSH2
|
|||
$res_offset = $stat['size'];
|
||||
} else {
|
||||
$res_offset = 0;
|
||||
if ($local_file !== false) {
|
||||
if ($local_file !== false && !is_callable($local_file)) {
|
||||
$fp = fopen($local_file, 'wb');
|
||||
if (!$fp) {
|
||||
return false;
|
||||
|
|
@ -2077,7 +2520,7 @@ class SFTP extends SSH2
|
|||
}
|
||||
}
|
||||
|
||||
$fclose_check = $local_file !== false && !is_resource($local_file);
|
||||
$fclose_check = $local_file !== false && !is_callable($local_file) && !is_resource($local_file);
|
||||
|
||||
$start = $offset;
|
||||
$read = 0;
|
||||
|
|
@ -2090,7 +2533,7 @@ class SFTP extends SSH2
|
|||
$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);
|
||||
if (!$this->_send_sftp_packet(NET_SFTP_READ, $packet)) {
|
||||
if (!$this->_send_sftp_packet(NET_SFTP_READ, $packet, $i)) {
|
||||
if ($fclose_check) {
|
||||
fclose($fp);
|
||||
}
|
||||
|
|
@ -2105,15 +2548,17 @@ class SFTP extends SSH2
|
|||
break;
|
||||
}
|
||||
|
||||
$packets_sent = $i - 1;
|
||||
|
||||
$clear_responses = false;
|
||||
while ($i > 0) {
|
||||
$i--;
|
||||
|
||||
if ($clear_responses) {
|
||||
$this->_get_sftp_packet();
|
||||
$this->_get_sftp_packet($packets_sent - $i);
|
||||
continue;
|
||||
} else {
|
||||
$response = $this->_get_sftp_packet();
|
||||
$response = $this->_get_sftp_packet($packets_sent - $i);
|
||||
}
|
||||
|
||||
switch ($this->packet_type) {
|
||||
|
|
@ -2122,9 +2567,14 @@ class SFTP extends SSH2
|
|||
$offset+= strlen($temp);
|
||||
if ($local_file === false) {
|
||||
$content.= $temp;
|
||||
} elseif (is_callable($local_file)) {
|
||||
$local_file($temp);
|
||||
} else {
|
||||
fputs($fp, $temp);
|
||||
}
|
||||
if (is_callable($progressCallback)) {
|
||||
call_user_func($progressCallback, $offset);
|
||||
}
|
||||
$temp = null;
|
||||
break;
|
||||
case NET_SFTP_STATUS:
|
||||
|
|
@ -2136,7 +2586,14 @@ class SFTP extends SSH2
|
|||
if ($fclose_check) {
|
||||
fclose($fp);
|
||||
}
|
||||
user_error('Expected SSH_FX_DATA or SSH_FXP_STATUS');
|
||||
// maybe the file was successfully transferred, maybe it wasn't
|
||||
if ($this->channel_close) {
|
||||
$this->partial_init = false;
|
||||
$this->_init_sftp_connection();
|
||||
return false;
|
||||
} else {
|
||||
user_error('Expected SSH_FX_DATA or SSH_FXP_STATUS');
|
||||
}
|
||||
}
|
||||
$response = null;
|
||||
}
|
||||
|
|
@ -2156,6 +2613,11 @@ class SFTP extends SSH2
|
|||
|
||||
if ($fclose_check) {
|
||||
fclose($fp);
|
||||
|
||||
if ($this->preserveTime) {
|
||||
$stat = $this->stat($remote_file);
|
||||
touch($local_file, $stat['mtime'], $stat['atime']);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->_close_handle($handle)) {
|
||||
|
|
@ -2176,7 +2638,16 @@ class SFTP extends SSH2
|
|||
*/
|
||||
function delete($path, $recursive = true)
|
||||
{
|
||||
if (!($this->bitmap & SSH2::MASK_LOGIN)) {
|
||||
if (!$this->_precheck()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_object($path)) {
|
||||
// It's an object. Cast it as string before we check anything else.
|
||||
$path = (string) $path;
|
||||
}
|
||||
|
||||
if (!is_string($path) || $path == '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -2197,6 +2668,9 @@ class SFTP extends SSH2
|
|||
}
|
||||
|
||||
// if $status isn't SSH_FX_OK it's probably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
|
||||
if ($status != NET_SFTP_STATUS_OK) {
|
||||
$this->_logError($response, $status);
|
||||
|
|
@ -2293,6 +2767,10 @@ class SFTP extends SSH2
|
|||
function file_exists($path)
|
||||
{
|
||||
if ($this->use_stat_cache) {
|
||||
if (!$this->_precheck()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$path = $this->_realpath($path);
|
||||
|
||||
$result = $this->_query_stat_cache($path);
|
||||
|
|
@ -2363,6 +2841,10 @@ class SFTP extends SSH2
|
|||
*/
|
||||
function is_readable($path)
|
||||
{
|
||||
if (!$this->_precheck()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$path = $this->_realpath($path);
|
||||
|
||||
$packet = pack('Na*N2', strlen($path), $path, NET_SFTP_OPEN_READ, 0);
|
||||
|
|
@ -2391,6 +2873,10 @@ class SFTP extends SSH2
|
|||
*/
|
||||
function is_writable($path)
|
||||
{
|
||||
if (!$this->_precheck()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$path = $this->_realpath($path);
|
||||
|
||||
$packet = pack('Na*N2', strlen($path), $path, NET_SFTP_OPEN_WRITE, 0);
|
||||
|
|
@ -2565,11 +3051,16 @@ class SFTP extends SSH2
|
|||
*
|
||||
* @param string $path
|
||||
* @param string $prop
|
||||
* @param mixed $type
|
||||
* @return mixed
|
||||
* @access private
|
||||
*/
|
||||
function _get_xstat_cache_prop($path, $prop, $type)
|
||||
{
|
||||
if (!$this->_precheck()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->use_stat_cache) {
|
||||
$path = $this->_realpath($path);
|
||||
|
||||
|
|
@ -2590,7 +3081,9 @@ class SFTP extends SSH2
|
|||
}
|
||||
|
||||
/**
|
||||
* Renames a file or a directory on the SFTP server
|
||||
* Renames a file or a directory on the SFTP server.
|
||||
*
|
||||
* If the file already exists this will return false
|
||||
*
|
||||
* @param string $oldname
|
||||
* @param string $newname
|
||||
|
|
@ -2599,7 +3092,7 @@ class SFTP extends SSH2
|
|||
*/
|
||||
function rename($oldname, $newname)
|
||||
{
|
||||
if (!($this->bitmap & SSH2::MASK_LOGIN)) {
|
||||
if (!$this->_precheck()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -2611,6 +3104,18 @@ class SFTP extends SSH2
|
|||
|
||||
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3
|
||||
$packet = pack('Na*Na*', strlen($oldname), $oldname, strlen($newname), $newname);
|
||||
if ($this->version >= 5) {
|
||||
/* quoting https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-05#section-6.5 ,
|
||||
|
||||
'flags' is 0 or a combination of:
|
||||
|
||||
SSH_FXP_RENAME_OVERWRITE 0x00000001
|
||||
SSH_FXP_RENAME_ATOMIC 0x00000002
|
||||
SSH_FXP_RENAME_NATIVE 0x00000004
|
||||
|
||||
(none of these are currently supported) */
|
||||
$packet.= "\0\0\0\0";
|
||||
}
|
||||
if (!$this->_send_sftp_packet(NET_SFTP_RENAME, $packet)) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -2622,6 +3127,9 @@ class SFTP extends SSH2
|
|||
}
|
||||
|
||||
// if $status isn't SSH_FX_OK it's probably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
|
||||
if ($status != NET_SFTP_STATUS_OK) {
|
||||
$this->_logError($response, $status);
|
||||
|
|
@ -2637,6 +3145,31 @@ class SFTP extends SSH2
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse Time
|
||||
*
|
||||
* See '7.7. Times' of draft-ietf-secsh-filexfer-13 for more info.
|
||||
*
|
||||
* @param string $key
|
||||
* @param int $flags
|
||||
* @param string $response
|
||||
* @return array
|
||||
* @access private
|
||||
*/
|
||||
function _parseTime($key, $flags, &$response)
|
||||
{
|
||||
if (strlen($response) < 8) {
|
||||
user_error('Malformed file attributes');
|
||||
return array();
|
||||
}
|
||||
$attr = array();
|
||||
$attr[$key] = hexdec(bin2hex($this->_string_shift($response, 8)));
|
||||
if ($flags & NET_SFTP_ATTR_SUBSECOND_TIMES) {
|
||||
$attr+= extract(unpack('N' . $key . '_nseconds', $this->_string_shift($response, 4)));
|
||||
}
|
||||
return $attr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse Attributes
|
||||
*
|
||||
|
|
@ -2648,12 +3181,26 @@ class SFTP extends SSH2
|
|||
*/
|
||||
function _parseAttributes(&$response)
|
||||
{
|
||||
if ($this->version >= 4) {
|
||||
$length = 5;
|
||||
$format = 'Nflags/Ctype';
|
||||
} else {
|
||||
$length = 4;
|
||||
$format = 'Nflags';
|
||||
}
|
||||
|
||||
$attr = array();
|
||||
extract(unpack('Nflags', $this->_string_shift($response, 4)));
|
||||
// SFTPv4+ have a type field (a byte) that follows the above flag field
|
||||
if (strlen($response) < $length) {
|
||||
user_error('Malformed file attributes');
|
||||
return array();
|
||||
}
|
||||
extract(unpack($format, $this->_string_shift($response, $length)));
|
||||
if (isset($type)) {
|
||||
$attr['type'] = $type;
|
||||
}
|
||||
foreach ($this->attributes as $key => $value) {
|
||||
switch ($flags & $key) {
|
||||
case NET_SFTP_ATTR_SIZE: // 0x00000001
|
||||
case NET_SFTP_ATTR_SIZE: // 0x00000001
|
||||
// The size attribute is defined as an unsigned 64-bit integer.
|
||||
// The following will use floats on 32-bit platforms, if necessary.
|
||||
// As can be seen in the BigInteger class, floats are generally
|
||||
|
|
@ -2662,10 +3209,18 @@ class SFTP extends SSH2
|
|||
// of precision. Interpreted in filesize, 2^50 bytes = 1024 TiB.
|
||||
$attr['size'] = hexdec(bin2hex($this->_string_shift($response, 8)));
|
||||
break;
|
||||
case NET_SFTP_ATTR_UIDGID: // 0x00000002 (SFTPv3 only)
|
||||
case NET_SFTP_ATTR_UIDGID: // 0x00000002 (SFTPv3 or earlier)
|
||||
if (strlen($response) < 8) {
|
||||
user_error('Malformed file attributes');
|
||||
return $attr;
|
||||
}
|
||||
$attr+= unpack('Nuid/Ngid', $this->_string_shift($response, 8));
|
||||
break;
|
||||
case NET_SFTP_ATTR_PERMISSIONS: // 0x00000004
|
||||
case NET_SFTP_ATTR_PERMISSIONS: // 0x00000004
|
||||
if (strlen($response) < 4) {
|
||||
user_error('Malformed file attributes');
|
||||
return $attr;
|
||||
}
|
||||
$attr+= unpack('Npermissions', $this->_string_shift($response, 4));
|
||||
// mode == permissions; permissions was the original array key and is retained for bc purposes.
|
||||
// mode was added because that's the more industry standard terminology
|
||||
|
|
@ -2675,14 +3230,150 @@ class SFTP extends SSH2
|
|||
$attr+= array('type' => $fileType);
|
||||
}
|
||||
break;
|
||||
case NET_SFTP_ATTR_ACCESSTIME: // 0x00000008
|
||||
case NET_SFTP_ATTR_ACCESSTIME: // 0x00000008
|
||||
if ($this->version >= 4) {
|
||||
$attr+= $this->_parseTime('atime', $flags, $response);
|
||||
break;
|
||||
}
|
||||
if (strlen($response) < 8) {
|
||||
user_error('Malformed file attributes');
|
||||
return $attr;
|
||||
}
|
||||
$attr+= unpack('Natime/Nmtime', $this->_string_shift($response, 8));
|
||||
break;
|
||||
case NET_SFTP_ATTR_EXTENDED: // 0x80000000
|
||||
case NET_SFTP_ATTR_CREATETIME: // 0x00000010 (SFTPv4+)
|
||||
$attr+= $this->_parseTime('createtime', $flags, $response);
|
||||
break;
|
||||
case NET_SFTP_ATTR_MODIFYTIME: // 0x00000020
|
||||
$attr+= $this->_parseTime('mtime', $flags, $response);
|
||||
break;
|
||||
case NET_SFTP_ATTR_ACL: // 0x00000040
|
||||
// access control list
|
||||
// see https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-04#section-5.7
|
||||
// currently unsupported
|
||||
if (strlen($response) < 4) {
|
||||
user_error('Malformed file attributes');
|
||||
return $attr;
|
||||
}
|
||||
extract(unpack('Ncount', $this->_string_shift($response, 4)));
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
if (strlen($response) < 16) {
|
||||
user_error('Malformed file attributes');
|
||||
return $attr;
|
||||
}
|
||||
extract(unpack('Ntype/Nflag/Nmask/Nlength', $this->_string_shift($response, 16)));
|
||||
if (strlen($response) < $length) {
|
||||
user_error('Malformed file attributes');
|
||||
return $attr;
|
||||
}
|
||||
$this->_string_shift($response, $length); // who
|
||||
}
|
||||
break;
|
||||
case NET_SFTP_ATTR_OWNERGROUP: // 0x00000080
|
||||
if (strlen($response) < 4) {
|
||||
user_error('Malformed file attributes');
|
||||
return $attr;
|
||||
}
|
||||
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
||||
if (strlen($response) < $length) {
|
||||
user_error('Malformed file attributes');
|
||||
return $attr;
|
||||
}
|
||||
$attr['owner'] = $this->_string_shift($response, $length);
|
||||
|
||||
if (strlen($response) < 4) {
|
||||
user_error('Malformed file attributes');
|
||||
return $attr;
|
||||
}
|
||||
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
||||
if (strlen($response) < $length) {
|
||||
user_error('Malformed file attributes');
|
||||
return $attr;
|
||||
}
|
||||
$attr['group'] = $this->_string_shift($response, $length);
|
||||
break;
|
||||
case NET_SFTP_ATTR_SUBSECOND_TIMES: // 0x00000100
|
||||
break;
|
||||
case NET_SFTP_ATTR_BITS: // 0x00000200 (SFTPv5+)
|
||||
// see https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-05#section-5.8
|
||||
// currently unsupported
|
||||
// tells if you file is:
|
||||
// readonly, system, hidden, case inensitive, archive, encrypted, compressed, sparse
|
||||
// append only, immutable, sync
|
||||
if (strlen($response) < 8) {
|
||||
user_error('Malformed file attributes');
|
||||
return $attr;
|
||||
}
|
||||
extract(unpack('Nattrib-bits/Nattrib-bits-valid', $this->_string_shift($response, 8)));
|
||||
break;
|
||||
case NET_SFTP_ATTR_ALLOCATION_SIZE: // 0x00000400 (SFTPv6+)
|
||||
// see https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-7.4
|
||||
// represents the number of bytes htat the file consumes on the disk. will
|
||||
// usually be larger than the 'size' field
|
||||
$attr['allocation-size'] = hexdec(bin2hex($this->_string_shift($response, 8)));
|
||||
break;
|
||||
case NET_SFTP_ATTR_TEXT_HINT: // 0x00000800
|
||||
// https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-7.10
|
||||
// currently unsupported
|
||||
// tells if file is "known text", "guessed text", "known binary", "guessed binary"
|
||||
extract(unpack('Ctext-hint', $this->_string_shift($response)));
|
||||
break;
|
||||
case NET_SFTP_ATTR_MIME_TYPE: // 0x00001000
|
||||
// see https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-7.11
|
||||
if (strlen($response) < 4) {
|
||||
user_error('Malformed file attributes');
|
||||
return $attr;
|
||||
}
|
||||
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
||||
if (strlen($response) < $length) {
|
||||
user_error('Malformed file attributes');
|
||||
return $attr;
|
||||
}
|
||||
$attr['mime-type'] = $this->_string_shift($response, $length);
|
||||
break;
|
||||
case NET_SFTP_ATTR_LINK_COUNT: // 0x00002000
|
||||
// see https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-7.12
|
||||
if (strlen($response) < 4) {
|
||||
user_error('Malformed file attributes');
|
||||
return $attr;
|
||||
}
|
||||
$attr+= unpack('Nlink-count', $this->_string_shift($response, 4));
|
||||
break;
|
||||
case NET_SFTP_ATTR_UNTRANSLATED_NAME:// 0x00004000
|
||||
// see https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-7.13
|
||||
if (strlen($response) < 4) {
|
||||
user_error('Malformed file attributes');
|
||||
return $attr;
|
||||
}
|
||||
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
||||
if (strlen($response) < $length) {
|
||||
user_error('Malformed file attributes');
|
||||
return $attr;
|
||||
}
|
||||
$attr['untranslated-name'] = $this->_string_shift($response, $length);
|
||||
break;
|
||||
case NET_SFTP_ATTR_CTIME: // 0x00008000
|
||||
// 'ctime' contains the last time the file attributes were changed. The
|
||||
// exact meaning of this field depends on the server.
|
||||
$attr+= $this->_parseTime('ctime', $flags, $response);
|
||||
break;
|
||||
case NET_SFTP_ATTR_EXTENDED: // 0x80000000
|
||||
if (strlen($response) < 4) {
|
||||
user_error('Malformed file attributes');
|
||||
return $attr;
|
||||
}
|
||||
extract(unpack('Ncount', $this->_string_shift($response, 4)));
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
if (strlen($response) < 4) {
|
||||
user_error('Malformed file attributes');
|
||||
return $attr;
|
||||
}
|
||||
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
||||
$key = $this->_string_shift($response, $length);
|
||||
if (strlen($response) < 4) {
|
||||
user_error('Malformed file attributes');
|
||||
return $attr;
|
||||
}
|
||||
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
||||
$attr[$key] = $this->_string_shift($response, $length);
|
||||
}
|
||||
|
|
@ -2774,15 +3465,20 @@ class SFTP extends SSH2
|
|||
*
|
||||
* @param int $type
|
||||
* @param string $data
|
||||
* @param int $request_id
|
||||
* @see self::_get_sftp_packet()
|
||||
* @see self::_send_channel_packet()
|
||||
* @return bool
|
||||
* @access private
|
||||
*/
|
||||
function _send_sftp_packet($type, $data)
|
||||
function _send_sftp_packet($type, $data, $request_id = 1)
|
||||
{
|
||||
$packet = $this->request_id !== false ?
|
||||
pack('NCNa*', strlen($data) + 5, $type, $this->request_id, $data) :
|
||||
// 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;
|
||||
|
||||
$packet = $this->use_request_id ?
|
||||
pack('NCNa*', strlen($data) + 5, $type, $request_id, $data) :
|
||||
pack('NCa*', strlen($data) + 1, $type, $data);
|
||||
|
||||
$start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
|
||||
|
|
@ -2792,13 +3488,21 @@ class SFTP extends SSH2
|
|||
if (defined('NET_SFTP_LOGGING')) {
|
||||
$packet_type = '-> ' . $this->packet_types[$type] .
|
||||
' (' . round($stop - $start, 4) . 's)';
|
||||
if (NET_SFTP_LOGGING == NET_SFTP_LOG_REALTIME) {
|
||||
echo "<pre>\r\n" . $this->_format_log(array($data), array($packet_type)) . "\r\n</pre>\r\n";
|
||||
flush();
|
||||
ob_flush();
|
||||
if (NET_SFTP_LOGGING == self::LOG_REALTIME) {
|
||||
switch (PHP_SAPI) {
|
||||
case 'cli':
|
||||
$start = $stop = "\r\n";
|
||||
break;
|
||||
default:
|
||||
$start = '<pre>';
|
||||
$stop = '</pre>';
|
||||
}
|
||||
echo $start . $this->_format_log(array($data), array($packet_type)) . $stop;
|
||||
@flush();
|
||||
@ob_flush();
|
||||
} else {
|
||||
$this->packet_type_log[] = $packet_type;
|
||||
if (NET_SFTP_LOGGING == NET_SFTP_LOG_COMPLEX) {
|
||||
if (NET_SFTP_LOGGING == self::LOG_COMPLEX) {
|
||||
$this->packet_log[] = $data;
|
||||
}
|
||||
}
|
||||
|
|
@ -2807,6 +3511,20 @@ class SFTP extends SSH2
|
|||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets a connection for re-use
|
||||
*
|
||||
* @param int $reason
|
||||
* @access private
|
||||
*/
|
||||
function _reset_connection($reason)
|
||||
{
|
||||
parent::_reset_connection($reason);
|
||||
$this->use_request_id = false;
|
||||
$this->pwd = false;
|
||||
$this->requestBuffer = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Receives SFTP Packets
|
||||
*
|
||||
|
|
@ -2820,29 +3538,55 @@ class SFTP extends SSH2
|
|||
* @return string
|
||||
* @access private
|
||||
*/
|
||||
function _get_sftp_packet()
|
||||
function _get_sftp_packet($request_id = null)
|
||||
{
|
||||
$this->curTimeout = false;
|
||||
$this->channel_close = 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
|
||||
|
||||
// SFTP packet length
|
||||
while (strlen($this->packet_buffer) < 4) {
|
||||
$temp = $this->_get_channel_packet(self::CHANNEL);
|
||||
if (is_bool($temp)) {
|
||||
$temp = $this->_get_channel_packet(self::CHANNEL, true);
|
||||
if ($temp === true) {
|
||||
if ($this->channel_status[self::CHANNEL] === NET_SSH2_MSG_CHANNEL_CLOSE) {
|
||||
$this->channel_close = true;
|
||||
}
|
||||
$this->packet_type = false;
|
||||
$this->packet_buffer = '';
|
||||
return false;
|
||||
}
|
||||
if ($temp === false) {
|
||||
return false;
|
||||
}
|
||||
$this->packet_buffer.= $temp;
|
||||
}
|
||||
if (strlen($this->packet_buffer) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nlength', $this->_string_shift($this->packet_buffer, 4)));
|
||||
$tempLength = $length;
|
||||
$tempLength-= strlen($this->packet_buffer);
|
||||
|
||||
// 256 * 1024 is what SFTP_MAX_MSG_LENGTH is set to in OpenSSH's sftp-common.h
|
||||
if (!$this->allow_arbitrary_length_packets && !$this->use_request_id && $tempLength > 256 * 1024) {
|
||||
user_error('Invalid SFTP packet size');
|
||||
return false;
|
||||
}
|
||||
|
||||
// SFTP packet type and data payload
|
||||
while ($tempLength > 0) {
|
||||
$temp = $this->_get_channel_packet(self::CHANNEL);
|
||||
$temp = $this->_get_channel_packet(self::CHANNEL, true);
|
||||
if (is_bool($temp)) {
|
||||
$this->packet_type = false;
|
||||
$this->packet_buffer = '';
|
||||
|
|
@ -2856,8 +3600,8 @@ class SFTP extends SSH2
|
|||
|
||||
$this->packet_type = ord($this->_string_shift($this->packet_buffer));
|
||||
|
||||
if ($this->request_id !== false) {
|
||||
$this->_string_shift($this->packet_buffer, 4); // remove the request id
|
||||
if ($this->use_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
|
||||
} else {
|
||||
$length-= 1; // account for the packet type
|
||||
|
|
@ -2868,18 +3612,34 @@ class SFTP extends SSH2
|
|||
if (defined('NET_SFTP_LOGGING')) {
|
||||
$packet_type = '<- ' . $this->packet_types[$this->packet_type] .
|
||||
' (' . round($stop - $start, 4) . 's)';
|
||||
if (NET_SFTP_LOGGING == NET_SFTP_LOG_REALTIME) {
|
||||
echo "<pre>\r\n" . $this->_format_log(array($packet), array($packet_type)) . "\r\n</pre>\r\n";
|
||||
flush();
|
||||
ob_flush();
|
||||
if (NET_SFTP_LOGGING == self::LOG_REALTIME) {
|
||||
switch (PHP_SAPI) {
|
||||
case 'cli':
|
||||
$start = $stop = "\r\n";
|
||||
break;
|
||||
default:
|
||||
$start = '<pre>';
|
||||
$stop = '</pre>';
|
||||
}
|
||||
echo $start . $this->_format_log(array($packet), array($packet_type)) . $stop;
|
||||
@flush();
|
||||
@ob_flush();
|
||||
} else {
|
||||
$this->packet_type_log[] = $packet_type;
|
||||
if (NET_SFTP_LOGGING == NET_SFTP_LOG_COMPLEX) {
|
||||
if (NET_SFTP_LOGGING == self::LOG_COMPLEX) {
|
||||
$this->packet_log[] = $packet;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -2898,10 +3658,10 @@ class SFTP extends SSH2
|
|||
}
|
||||
|
||||
switch (NET_SFTP_LOGGING) {
|
||||
case NET_SFTP_LOG_COMPLEX:
|
||||
case self::LOG_COMPLEX:
|
||||
return $this->_format_log($this->packet_log, $this->packet_type_log);
|
||||
break;
|
||||
//case NET_SFTP_LOG_SIMPLE:
|
||||
//case self::LOG_SIMPLE:
|
||||
default:
|
||||
return $this->packet_type_log;
|
||||
}
|
||||
|
|
@ -2910,7 +3670,7 @@ class SFTP extends SSH2
|
|||
/**
|
||||
* Returns all errors
|
||||
*
|
||||
* @return string
|
||||
* @return array
|
||||
* @access public
|
||||
*/
|
||||
function getSFTPErrors()
|
||||
|
|
@ -2937,13 +3697,51 @@ class SFTP extends SSH2
|
|||
*/
|
||||
function getSupportedVersions()
|
||||
{
|
||||
$temp = array('version' => $this->version);
|
||||
if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->partial_init) {
|
||||
$this->_partial_init_sftp_connection();
|
||||
}
|
||||
|
||||
$temp = array('version' => $this->defaultVersion);
|
||||
if (isset($this->extensions['versions'])) {
|
||||
$temp['extensions'] = $this->extensions['versions'];
|
||||
}
|
||||
return $temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get supported SFTP versions
|
||||
*
|
||||
* @return array
|
||||
* @access public
|
||||
*/
|
||||
function getNegotiatedVersion()
|
||||
{
|
||||
if (!$this->_precheck()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set preferred version
|
||||
*
|
||||
* If you're preferred version isn't supported then the highest supported
|
||||
* version of SFTP will be utilized. Set to null or false or int(0) to
|
||||
* unset the preferred version
|
||||
*
|
||||
* @param int $version
|
||||
* @access public
|
||||
*/
|
||||
function setPreferredVersion($version)
|
||||
{
|
||||
$this->preferredVersion = $version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect
|
||||
*
|
||||
|
|
@ -2956,4 +3754,24 @@ class SFTP extends SSH2
|
|||
$this->pwd = false;
|
||||
parent::_disconnect($reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable Date Preservation
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
function enableDatePreservation()
|
||||
{
|
||||
$this->preserveTime = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable Date Preservation
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
function disableDatePreservation()
|
||||
{
|
||||
$this->preserveTime = false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ class Stream
|
|||
|
||||
if ($host[0] == '$') {
|
||||
$host = substr($host, 1);
|
||||
global $$host;
|
||||
global ${$host};
|
||||
if (($$host instanceof SFTP) === false) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -410,7 +410,7 @@ class Stream
|
|||
{
|
||||
switch ($whence) {
|
||||
case SEEK_SET:
|
||||
if ($offset >= $this->size || $offset < 0) {
|
||||
if ($offset < 0) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
|
@ -447,7 +447,9 @@ class Stream
|
|||
// and https://github.com/php/php-src/blob/master/main/php_streams.h#L592
|
||||
switch ($option) {
|
||||
case 1: // PHP_STREAM_META_TOUCH
|
||||
return $this->sftp->touch($path, $var[0], $var[1]);
|
||||
$time = isset($var[0]) ? $var[0] : null;
|
||||
$atime = isset($var[1]) ? $var[1] : null;
|
||||
return $this->sftp->touch($path, $time, $atime);
|
||||
case 2: // PHP_STREAM_OWNER_NAME
|
||||
case 3: // PHP_STREAM_GROUP_NAME
|
||||
return false;
|
||||
|
|
@ -626,7 +628,6 @@ class Stream
|
|||
* $options. What does 8 correspond to?
|
||||
*
|
||||
* @param string $path
|
||||
* @param int $mode
|
||||
* @param int $options
|
||||
* @return bool
|
||||
* @access public
|
||||
|
|
@ -768,8 +769,8 @@ class Stream
|
|||
* If NET_SFTP_STREAM_LOGGING is defined all calls will be output on the screen and then (regardless of whether or not
|
||||
* NET_SFTP_STREAM_LOGGING is enabled) the parameters will be passed through to the appropriate method.
|
||||
*
|
||||
* @param string
|
||||
* @param array
|
||||
* @param string $name
|
||||
* @param array $arguments
|
||||
* @return mixed
|
||||
* @access public
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -575,28 +575,46 @@ class SSH1
|
|||
|
||||
$this->_string_shift($response[self::RESPONSE_DATA], 4);
|
||||
|
||||
if (strlen($response[self::RESPONSE_DATA]) < 2) {
|
||||
return false;
|
||||
}
|
||||
$temp = unpack('nlen', $this->_string_shift($response[self::RESPONSE_DATA], 2));
|
||||
$server_key_public_exponent = new BigInteger($this->_string_shift($response[self::RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
|
||||
$this->server_key_public_exponent = $server_key_public_exponent;
|
||||
|
||||
if (strlen($response[self::RESPONSE_DATA]) < 2) {
|
||||
return false;
|
||||
}
|
||||
$temp = unpack('nlen', $this->_string_shift($response[self::RESPONSE_DATA], 2));
|
||||
$server_key_public_modulus = new BigInteger($this->_string_shift($response[self::RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
|
||||
|
||||
$this->server_key_public_modulus = $server_key_public_modulus;
|
||||
|
||||
$this->_string_shift($response[self::RESPONSE_DATA], 4);
|
||||
|
||||
if (strlen($response[self::RESPONSE_DATA]) < 2) {
|
||||
return false;
|
||||
}
|
||||
$temp = unpack('nlen', $this->_string_shift($response[self::RESPONSE_DATA], 2));
|
||||
$host_key_public_exponent = new BigInteger($this->_string_shift($response[self::RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
|
||||
$this->host_key_public_exponent = $host_key_public_exponent;
|
||||
|
||||
if (strlen($response[self::RESPONSE_DATA]) < 2) {
|
||||
return false;
|
||||
}
|
||||
$temp = unpack('nlen', $this->_string_shift($response[self::RESPONSE_DATA], 2));
|
||||
$host_key_public_modulus = new BigInteger($this->_string_shift($response[self::RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
|
||||
|
||||
$this->host_key_public_modulus = $host_key_public_modulus;
|
||||
|
||||
$this->_string_shift($response[self::RESPONSE_DATA], 4);
|
||||
|
||||
// get a list of the supported ciphers
|
||||
if (strlen($response[self::RESPONSE_DATA]) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nsupported_ciphers_mask', $this->_string_shift($response[self::RESPONSE_DATA], 4)));
|
||||
|
||||
foreach ($this->supported_ciphers as $mask => $name) {
|
||||
if (($supported_ciphers_mask & (1 << $mask)) == 0) {
|
||||
unset($this->supported_ciphers[$mask]);
|
||||
|
|
@ -604,6 +622,9 @@ class SSH1
|
|||
}
|
||||
|
||||
// get a list of the supported authentications
|
||||
if (strlen($response[self::RESPONSE_DATA]) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nsupported_authentications_mask', $this->_string_shift($response[self::RESPONSE_DATA], 4)));
|
||||
foreach ($this->supported_authentications as $mask => $name) {
|
||||
if (($supported_authentications_mask & (1 << $mask)) == 0) {
|
||||
|
|
@ -791,6 +812,7 @@ class SSH1
|
|||
* @see self::interactiveRead()
|
||||
* @see self::interactiveWrite()
|
||||
* @param string $cmd
|
||||
* @param bool $block
|
||||
* @return mixed
|
||||
* @access public
|
||||
*/
|
||||
|
|
@ -895,7 +917,7 @@ class SSH1
|
|||
/**
|
||||
* Returns the output of an interactive shell when there's a match for $expect
|
||||
*
|
||||
* $expect can take the form of a string literal or, if $mode == self::READ__REGEX,
|
||||
* $expect can take the form of a string literal or, if $mode == self::READ_REGEX,
|
||||
* a regular expression.
|
||||
*
|
||||
* @see self::write()
|
||||
|
|
@ -904,7 +926,7 @@ class SSH1
|
|||
* @return bool
|
||||
* @access public
|
||||
*/
|
||||
function read($expect, $mode = self::READ__SIMPLE)
|
||||
function read($expect, $mode = self::READ_SIMPLE)
|
||||
{
|
||||
if (!($this->bitmap & self::MASK_LOGIN)) {
|
||||
user_error('Operation disallowed prior to login()');
|
||||
|
|
@ -918,7 +940,7 @@ class SSH1
|
|||
|
||||
$match = $expect;
|
||||
while (true) {
|
||||
if ($mode == self::READ__REGEX) {
|
||||
if ($mode == self::READ_REGEX) {
|
||||
preg_match($expect, $this->interactiveBuffer, $matches);
|
||||
$match = isset($matches[0]) ? $matches[0] : '';
|
||||
}
|
||||
|
|
@ -1091,7 +1113,11 @@ class SSH1
|
|||
}
|
||||
|
||||
$start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
|
||||
$temp = unpack('Nlength', fread($this->fsock, 4));
|
||||
$data = fread($this->fsock, 4);
|
||||
if (strlen($data) < 4) {
|
||||
return false;
|
||||
}
|
||||
$temp = unpack('Nlength', $data);
|
||||
|
||||
$padding_length = 8 - ($temp['length'] & 7);
|
||||
$length = $temp['length'] + $padding_length;
|
||||
|
|
@ -1099,6 +1125,9 @@ class SSH1
|
|||
|
||||
while ($length > 0) {
|
||||
$temp = fread($this->fsock, $length);
|
||||
if (strlen($temp) != $length) {
|
||||
return false;
|
||||
}
|
||||
$raw.= $temp;
|
||||
$length-= strlen($temp);
|
||||
}
|
||||
|
|
@ -1112,6 +1141,9 @@ class SSH1
|
|||
$type = $raw[$padding_length];
|
||||
$data = substr($raw, $padding_length + 1, -4);
|
||||
|
||||
if (strlen($raw) < 4) {
|
||||
return false;
|
||||
}
|
||||
$temp = unpack('Ncrc', substr($raw, -4));
|
||||
|
||||
//if ( $temp['crc'] != $this->_crc($padding . $type . $data) ) {
|
||||
|
|
@ -1354,7 +1386,6 @@ class SSH1
|
|||
* named constants from it, using the value as the name of the constant and the index as the value of the constant.
|
||||
* If any of the constants that would be defined already exists, none of the constants will be defined.
|
||||
*
|
||||
* @param array $array
|
||||
* @access private
|
||||
*/
|
||||
function _define_array()
|
||||
|
|
@ -1553,7 +1584,8 @@ class SSH1
|
|||
*
|
||||
* Makes sure that only the last 1MB worth of packets will be logged
|
||||
*
|
||||
* @param string $data
|
||||
* @param int $protocol_flags
|
||||
* @param string $message
|
||||
* @access private
|
||||
*/
|
||||
function _append_log($protocol_flags, $message)
|
||||
|
|
|
|||
|
|
@ -61,6 +61,23 @@ use phpseclib\Crypt\Twofish;
|
|||
use phpseclib\Math\BigInteger; // Used to do Diffie-Hellman key exchange and DSA/RSA signature verification.
|
||||
use phpseclib\System\SSH\Agent;
|
||||
|
||||
/**#@+
|
||||
* @access private
|
||||
*/
|
||||
/**
|
||||
* No compression
|
||||
*/
|
||||
define('NET_SSH2_COMPRESSION_NONE', 1);
|
||||
/**
|
||||
* zlib compression
|
||||
*/
|
||||
define('NET_SSH2_COMPRESSION_ZLIB', 2);
|
||||
/**
|
||||
* zlib@openssh.com
|
||||
*/
|
||||
define('NET_SSH2_COMPRESSION_ZLIB_AT_OPENSSH', 3);
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
* Pure-PHP implementation of SSHv2.
|
||||
*
|
||||
|
|
@ -100,10 +117,11 @@ class SSH2
|
|||
* @see \phpseclib\Net\SSH2::_get_channel_packet()
|
||||
* @access private
|
||||
*/
|
||||
const CHANNEL_EXEC = 0; // PuTTy uses 0x100
|
||||
const CHANNEL_SHELL = 1;
|
||||
const CHANNEL_SUBSYSTEM = 2;
|
||||
const CHANNEL_AGENT_FORWARD = 3;
|
||||
const CHANNEL_EXEC = 1; // PuTTy uses 0x100
|
||||
const CHANNEL_SHELL = 2;
|
||||
const CHANNEL_SUBSYSTEM = 3;
|
||||
const CHANNEL_AGENT_FORWARD = 4;
|
||||
const CHANNEL_KEEP_ALIVE = 5;
|
||||
/**#@-*/
|
||||
|
||||
/**#@+
|
||||
|
|
@ -126,6 +144,10 @@ class SSH2
|
|||
* Dumps the content real-time to a file
|
||||
*/
|
||||
const LOG_REALTIME_FILE = 4;
|
||||
/**
|
||||
* Make sure that the log never gets larger than this
|
||||
*/
|
||||
const LOG_MAX_SIZE = 1048576; // 1024 * 1024
|
||||
/**#@-*/
|
||||
|
||||
/**#@+
|
||||
|
|
@ -141,9 +163,12 @@ class SSH2
|
|||
*/
|
||||
const READ_REGEX = 2;
|
||||
/**
|
||||
* Make sure that the log never gets larger than this
|
||||
* 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 LOG_MAX_SIZE = 1048576; // 1024 * 1024
|
||||
const READ_NEXT = 3;
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
|
|
@ -201,6 +226,15 @@ class SSH2
|
|||
*/
|
||||
var $kex_algorithms = false;
|
||||
|
||||
/**
|
||||
* Key Exchange Algorithm
|
||||
*
|
||||
* @see self::getMethodsNegotiated()
|
||||
* @var string|false
|
||||
* @access private
|
||||
*/
|
||||
var $kex_algorithm = false;
|
||||
|
||||
/**
|
||||
* Minimum Diffie-Hellman Group Bit Size in RFC 4419 Key Exchange Methods
|
||||
*
|
||||
|
|
@ -309,6 +343,15 @@ class SSH2
|
|||
*/
|
||||
var $languages_client_to_server = false;
|
||||
|
||||
/**
|
||||
* Preferred Algorithms
|
||||
*
|
||||
* @see self::setPreferredAlgorithms()
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $preferred = array();
|
||||
|
||||
/**
|
||||
* Block Size for Server to Client Encryption
|
||||
*
|
||||
|
|
@ -566,6 +609,20 @@ class SSH2
|
|||
*/
|
||||
var $window_size = 0x7FFFFFFF;
|
||||
|
||||
/**
|
||||
* What we resize the window to
|
||||
*
|
||||
* When PuTTY resizes the window it doesn't add an additional 0x7FFFFFFF bytes - it adds 0x40000000 bytes.
|
||||
* Some SFTP clients (GoAnywhere) don't support adding 0x7FFFFFFF to the window size after the fact so
|
||||
* we'll just do what PuTTY does
|
||||
*
|
||||
* @var int
|
||||
* @see self::_send_channel_packet()
|
||||
* @see self::exec()
|
||||
* @access private
|
||||
*/
|
||||
var $window_resize = 0x40000000;
|
||||
|
||||
/**
|
||||
* Window size, server to client
|
||||
*
|
||||
|
|
@ -647,6 +704,14 @@ class SSH2
|
|||
*/
|
||||
var $curTimeout;
|
||||
|
||||
/**
|
||||
* Keep Alive Interval
|
||||
*
|
||||
* @see self::setKeepAlive()
|
||||
* @access private
|
||||
*/
|
||||
var $keepAlive;
|
||||
|
||||
/**
|
||||
* Real-time log file pointer
|
||||
*
|
||||
|
|
@ -866,6 +931,119 @@ class SSH2
|
|||
*/
|
||||
var $agent;
|
||||
|
||||
/**
|
||||
* Send the identification string first?
|
||||
*
|
||||
* @var bool
|
||||
* @access private
|
||||
*/
|
||||
var $send_id_string_first = true;
|
||||
|
||||
/**
|
||||
* Send the key exchange initiation packet first?
|
||||
*
|
||||
* @var bool
|
||||
* @access private
|
||||
*/
|
||||
var $send_kex_first = true;
|
||||
|
||||
/**
|
||||
* Some versions of OpenSSH incorrectly calculate the key size
|
||||
*
|
||||
* @var bool
|
||||
* @access private
|
||||
*/
|
||||
var $bad_key_size_fix = false;
|
||||
|
||||
/**
|
||||
* Should we try to re-connect to re-establish keys?
|
||||
*
|
||||
* @var bool
|
||||
* @access private
|
||||
*/
|
||||
var $retry_connect = false;
|
||||
|
||||
/**
|
||||
* Binary Packet Buffer
|
||||
*
|
||||
* @var string|false
|
||||
* @access private
|
||||
*/
|
||||
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();
|
||||
|
||||
/**
|
||||
* The authentication methods that may productively continue authentication.
|
||||
*
|
||||
* @see https://tools.ietf.org/html/rfc4252#section-5.1
|
||||
* @var array|null
|
||||
* @access private
|
||||
*/
|
||||
var $auth_methods_to_continue = null;
|
||||
|
||||
/**
|
||||
* Compression method
|
||||
*
|
||||
* @var int
|
||||
* @access private
|
||||
*/
|
||||
var $compress = NET_SSH2_COMPRESSION_NONE;
|
||||
|
||||
/**
|
||||
* Decompression method
|
||||
*
|
||||
* @var resource|object
|
||||
* @access private
|
||||
*/
|
||||
var $decompress = NET_SSH2_COMPRESSION_NONE;
|
||||
|
||||
/**
|
||||
* Compression context
|
||||
*
|
||||
* @var int
|
||||
* @access private
|
||||
*/
|
||||
var $compress_context;
|
||||
|
||||
/**
|
||||
* Decompression context
|
||||
*
|
||||
* @var resource|object
|
||||
* @access private
|
||||
*/
|
||||
var $decompress_context;
|
||||
|
||||
/**
|
||||
* Regenerate Compression Context
|
||||
*
|
||||
* @var bool
|
||||
* @access private
|
||||
*/
|
||||
var $regenerate_compression_context = false;
|
||||
|
||||
/**
|
||||
* Regenerate Decompression Context
|
||||
*
|
||||
* @var bool
|
||||
* @access private
|
||||
*/
|
||||
var $regenerate_decompression_context = false;
|
||||
|
||||
/**
|
||||
* Default Constructor.
|
||||
*
|
||||
|
|
@ -978,13 +1156,69 @@ class SSH2
|
|||
* CRYPT_MODE_INTERNAL, CRYPT_MODE_MCRYPT
|
||||
*
|
||||
* @param int $engine
|
||||
* @access private
|
||||
* @access public
|
||||
*/
|
||||
function setCryptoEngine($engine)
|
||||
{
|
||||
$this->crypto_engine = $engine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send Identification String First
|
||||
*
|
||||
* https://tools.ietf.org/html/rfc4253#section-4.2 says "when the connection has been established,
|
||||
* both sides MUST send an identification string". It does not say which side sends it first. In
|
||||
* theory it shouldn't matter but it is a fact of life that some SSH servers are simply buggy
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
function sendIdentificationStringFirst()
|
||||
{
|
||||
$this->send_id_string_first = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send Identification String Last
|
||||
*
|
||||
* https://tools.ietf.org/html/rfc4253#section-4.2 says "when the connection has been established,
|
||||
* both sides MUST send an identification string". It does not say which side sends it first. In
|
||||
* theory it shouldn't matter but it is a fact of life that some SSH servers are simply buggy
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
function sendIdentificationStringLast()
|
||||
{
|
||||
$this->send_id_string_first = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send SSH_MSG_KEXINIT First
|
||||
*
|
||||
* https://tools.ietf.org/html/rfc4253#section-7.1 says "key exchange begins by each sending
|
||||
* sending the [SSH_MSG_KEXINIT] packet". It does not say which side sends it first. In theory
|
||||
* it shouldn't matter but it is a fact of life that some SSH servers are simply buggy
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
function sendKEXINITFirst()
|
||||
{
|
||||
$this->send_kex_first = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send SSH_MSG_KEXINIT Last
|
||||
*
|
||||
* https://tools.ietf.org/html/rfc4253#section-7.1 says "key exchange begins by each sending
|
||||
* sending the [SSH_MSG_KEXINIT] packet". It does not say which side sends it first. In theory
|
||||
* it shouldn't matter but it is a fact of life that some SSH servers are simply buggy
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
function sendKEXINITLast()
|
||||
{
|
||||
$this->send_kex_first = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to an SSHv2 server
|
||||
*
|
||||
|
|
@ -1005,7 +1239,10 @@ class SSH2
|
|||
|
||||
if (!is_resource($this->fsock)) {
|
||||
$start = microtime(true);
|
||||
$this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $this->curTimeout);
|
||||
// with stream_select a timeout of 0 means that no timeout takes place;
|
||||
// with fsockopen a timeout of 0 means that you instantly timeout
|
||||
// to resolve this incompatibility a timeout of 100,000 will be used for fsockopen if timeout is 0
|
||||
$this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $this->curTimeout == 0 ? 100000 : $this->curTimeout);
|
||||
if (!$this->fsock) {
|
||||
$host = $this->host . ':' . $this->port;
|
||||
user_error(rtrim("Cannot connect to $host. Error $errno. $errstr"));
|
||||
|
|
@ -1013,14 +1250,21 @@ class SSH2
|
|||
}
|
||||
$elapsed = microtime(true) - $start;
|
||||
|
||||
$this->curTimeout-= $elapsed;
|
||||
|
||||
if ($this->curTimeout <= 0) {
|
||||
$this->is_timeout = true;
|
||||
return false;
|
||||
if ($this->curTimeout) {
|
||||
$this->curTimeout-= $elapsed;
|
||||
if ($this->curTimeout < 0) {
|
||||
$this->is_timeout = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->identifier = $this->_generate_identifier();
|
||||
|
||||
if ($this->send_id_string_first) {
|
||||
fputs($this->fsock, $this->identifier . "\r\n");
|
||||
}
|
||||
|
||||
/* According to the SSH2 specs,
|
||||
|
||||
"The server MAY send other lines of data before sending the version
|
||||
|
|
@ -1056,6 +1300,9 @@ class SSH2
|
|||
if (strlen($temp) == 255) {
|
||||
continue;
|
||||
}
|
||||
if ($temp === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$line.= "$temp\n";
|
||||
|
||||
|
|
@ -1076,14 +1323,13 @@ class SSH2
|
|||
}
|
||||
|
||||
if (feof($this->fsock)) {
|
||||
$this->bitmap = 0;
|
||||
user_error('Connection closed by server');
|
||||
return false;
|
||||
}
|
||||
|
||||
$extra = $matches[1];
|
||||
|
||||
$this->identifier = $this->_generate_identifier();
|
||||
|
||||
if (defined('NET_SSH2_LOGGING')) {
|
||||
$this->_append_log('<-', $matches[0]);
|
||||
$this->_append_log('->', $this->identifier . "\r\n");
|
||||
|
|
@ -1091,28 +1337,37 @@ class SSH2
|
|||
|
||||
$this->server_identifier = trim($temp, "\r\n");
|
||||
if (strlen($extra)) {
|
||||
$this->errors[] = utf8_decode($data);
|
||||
$this->errors[] = $data;
|
||||
}
|
||||
|
||||
if ($matches[3] != '1.99' && $matches[3] != '2.0') {
|
||||
if (version_compare($matches[3], '1.99', '<')) {
|
||||
user_error("Cannot connect to SSH $matches[3] servers");
|
||||
return false;
|
||||
}
|
||||
|
||||
fputs($this->fsock, $this->identifier . "\r\n");
|
||||
|
||||
$response = $this->_get_binary_packet();
|
||||
if ($response === false) {
|
||||
user_error('Connection closed by server');
|
||||
return false;
|
||||
if (!$this->send_id_string_first) {
|
||||
fputs($this->fsock, $this->identifier . "\r\n");
|
||||
}
|
||||
|
||||
if (ord($response[0]) != NET_SSH2_MSG_KEXINIT) {
|
||||
user_error('Expected SSH_MSG_KEXINIT');
|
||||
return false;
|
||||
if (!$this->send_kex_first) {
|
||||
$response = $this->_get_binary_packet();
|
||||
if ($response === false) {
|
||||
$this->bitmap = 0;
|
||||
user_error('Connection closed by server');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!strlen($response) || ord($response[0]) != NET_SSH2_MSG_KEXINIT) {
|
||||
user_error('Expected SSH_MSG_KEXINIT');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->_key_exchange($response)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->_key_exchange($response)) {
|
||||
if ($this->send_kex_first && !$this->_key_exchange()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1134,7 +1389,7 @@ class SSH2
|
|||
$identifier = 'SSH-2.0-phpseclib_2.0';
|
||||
|
||||
$ext = array();
|
||||
if (extension_loaded('libsodium')) {
|
||||
if (function_exists('sodium_crypto_box_publickey_from_secretkey')) {
|
||||
$ext[] = 'libsodium';
|
||||
}
|
||||
|
||||
|
|
@ -1160,184 +1415,68 @@ class SSH2
|
|||
/**
|
||||
* Key Exchange
|
||||
*
|
||||
* @param string $kexinit_payload_server
|
||||
* @param string $kexinit_payload_server optional
|
||||
* @access private
|
||||
*/
|
||||
function _key_exchange($kexinit_payload_server)
|
||||
function _key_exchange($kexinit_payload_server = false)
|
||||
{
|
||||
$kex_algorithms = array(
|
||||
// Elliptic Curve Diffie-Hellman Key Agreement (ECDH) using
|
||||
// Curve25519. See doc/curve25519-sha256@libssh.org.txt in the
|
||||
// libssh repository for more information.
|
||||
'curve25519-sha256@libssh.org',
|
||||
$preferred = $this->preferred;
|
||||
$send_kex = true;
|
||||
|
||||
// Diffie-Hellman Key Agreement (DH) using integer modulo prime
|
||||
// groups.
|
||||
'diffie-hellman-group1-sha1', // REQUIRED
|
||||
'diffie-hellman-group14-sha1', // REQUIRED
|
||||
'diffie-hellman-group-exchange-sha1', // RFC 4419
|
||||
'diffie-hellman-group-exchange-sha256', // RFC 4419
|
||||
);
|
||||
if (!function_exists('\\Sodium\\library_version_major')) {
|
||||
$kex_algorithms = array_diff(
|
||||
$kex_algorithms,
|
||||
array('curve25519-sha256@libssh.org')
|
||||
);
|
||||
}
|
||||
|
||||
$server_host_key_algorithms = array(
|
||||
'ssh-rsa', // RECOMMENDED sign Raw RSA Key
|
||||
'ssh-dss' // REQUIRED sign Raw DSS Key
|
||||
);
|
||||
|
||||
$encryption_algorithms = array(
|
||||
// from <http://tools.ietf.org/html/rfc4345#section-4>:
|
||||
'arcfour256',
|
||||
'arcfour128',
|
||||
|
||||
//'arcfour', // OPTIONAL the ARCFOUR stream cipher with a 128-bit key
|
||||
|
||||
// CTR modes from <http://tools.ietf.org/html/rfc4344#section-4>:
|
||||
'aes128-ctr', // RECOMMENDED AES (Rijndael) in SDCTR mode, with 128-bit key
|
||||
'aes192-ctr', // RECOMMENDED AES with 192-bit key
|
||||
'aes256-ctr', // RECOMMENDED AES with 256-bit key
|
||||
|
||||
'twofish128-ctr', // OPTIONAL Twofish in SDCTR mode, with 128-bit key
|
||||
'twofish192-ctr', // OPTIONAL Twofish with 192-bit key
|
||||
'twofish256-ctr', // OPTIONAL Twofish with 256-bit key
|
||||
|
||||
'aes128-cbc', // RECOMMENDED AES with a 128-bit key
|
||||
'aes192-cbc', // OPTIONAL AES with a 192-bit key
|
||||
'aes256-cbc', // OPTIONAL AES in CBC mode, with a 256-bit key
|
||||
|
||||
'twofish128-cbc', // OPTIONAL Twofish with a 128-bit key
|
||||
'twofish192-cbc', // OPTIONAL Twofish with a 192-bit key
|
||||
'twofish256-cbc',
|
||||
'twofish-cbc', // OPTIONAL alias for "twofish256-cbc"
|
||||
// (this is being retained for historical reasons)
|
||||
|
||||
'blowfish-ctr', // OPTIONAL Blowfish in SDCTR mode
|
||||
|
||||
'blowfish-cbc', // OPTIONAL Blowfish in CBC mode
|
||||
|
||||
'3des-ctr', // RECOMMENDED Three-key 3DES in SDCTR mode
|
||||
|
||||
'3des-cbc', // REQUIRED three-key 3DES in CBC mode
|
||||
//'none' // OPTIONAL no encryption; NOT RECOMMENDED
|
||||
);
|
||||
|
||||
if (extension_loaded('openssl') && !extension_loaded('mcrypt')) {
|
||||
// OpenSSL does not support arcfour256 in any capacity and arcfour128 / arcfour support is limited to
|
||||
// instances that do not use continuous buffers
|
||||
$encryption_algorithms = array_diff(
|
||||
$encryption_algorithms,
|
||||
array('arcfour256', 'arcfour128', 'arcfour')
|
||||
);
|
||||
}
|
||||
|
||||
if (class_exists('\phpseclib\Crypt\RC4') === false) {
|
||||
$encryption_algorithms = array_diff(
|
||||
$encryption_algorithms,
|
||||
array('arcfour256', 'arcfour128', 'arcfour')
|
||||
);
|
||||
}
|
||||
if (class_exists('\phpseclib\Crypt\Rijndael') === false) {
|
||||
$encryption_algorithms = array_diff(
|
||||
$encryption_algorithms,
|
||||
array('aes128-ctr', 'aes192-ctr', 'aes256-ctr', 'aes128-cbc', 'aes192-cbc', 'aes256-cbc')
|
||||
);
|
||||
}
|
||||
if (class_exists('\phpseclib\Crypt\Twofish') === false) {
|
||||
$encryption_algorithms = array_diff(
|
||||
$encryption_algorithms,
|
||||
array('twofish128-ctr', 'twofish192-ctr', 'twofish256-ctr', 'twofish128-cbc', 'twofish192-cbc', 'twofish256-cbc', 'twofish-cbc')
|
||||
);
|
||||
}
|
||||
if (class_exists('\phpseclib\Crypt\Blowfish') === false) {
|
||||
$encryption_algorithms = array_diff(
|
||||
$encryption_algorithms,
|
||||
array('blowfish-ctr', 'blowfish-cbc')
|
||||
);
|
||||
}
|
||||
if (class_exists('\phpseclib\Crypt\TripleDES') === false) {
|
||||
$encryption_algorithms = array_diff(
|
||||
$encryption_algorithms,
|
||||
array('3des-ctr', '3des-cbc')
|
||||
);
|
||||
}
|
||||
$encryption_algorithms = array_values($encryption_algorithms);
|
||||
|
||||
$mac_algorithms = array(
|
||||
// from <http://www.ietf.org/rfc/rfc6668.txt>:
|
||||
'hmac-sha2-256',// RECOMMENDED HMAC-SHA256 (digest length = key length = 32)
|
||||
|
||||
'hmac-sha1-96', // RECOMMENDED first 96 bits of HMAC-SHA1 (digest length = 12, key length = 20)
|
||||
'hmac-sha1', // REQUIRED HMAC-SHA1 (digest length = key length = 20)
|
||||
'hmac-md5-96', // OPTIONAL first 96 bits of HMAC-MD5 (digest length = 12, key length = 16)
|
||||
'hmac-md5', // OPTIONAL HMAC-MD5 (digest length = key length = 16)
|
||||
//'none' // OPTIONAL no MAC; NOT RECOMMENDED
|
||||
);
|
||||
|
||||
$compression_algorithms = array(
|
||||
'none' // REQUIRED no compression
|
||||
//'zlib' // OPTIONAL ZLIB (LZ77) compression
|
||||
);
|
||||
$kex_algorithms = isset($preferred['kex']) ?
|
||||
$preferred['kex'] :
|
||||
$this->getSupportedKEXAlgorithms();
|
||||
$server_host_key_algorithms = isset($preferred['hostkey']) ?
|
||||
$preferred['hostkey'] :
|
||||
$this->getSupportedHostKeyAlgorithms();
|
||||
$s2c_encryption_algorithms = isset($preferred['server_to_client']['crypt']) ?
|
||||
$preferred['server_to_client']['crypt'] :
|
||||
$this->getSupportedEncryptionAlgorithms();
|
||||
$c2s_encryption_algorithms = isset($preferred['client_to_server']['crypt']) ?
|
||||
$preferred['client_to_server']['crypt'] :
|
||||
$this->getSupportedEncryptionAlgorithms();
|
||||
$s2c_mac_algorithms = isset($preferred['server_to_client']['mac']) ?
|
||||
$preferred['server_to_client']['mac'] :
|
||||
$this->getSupportedMACAlgorithms();
|
||||
$c2s_mac_algorithms = isset($preferred['client_to_server']['mac']) ?
|
||||
$preferred['client_to_server']['mac'] :
|
||||
$this->getSupportedMACAlgorithms();
|
||||
$s2c_compression_algorithms = isset($preferred['server_to_client']['comp']) ?
|
||||
$preferred['server_to_client']['comp'] :
|
||||
$this->getSupportedCompressionAlgorithms();
|
||||
$c2s_compression_algorithms = isset($preferred['client_to_server']['comp']) ?
|
||||
$preferred['client_to_server']['comp'] :
|
||||
$this->getSupportedCompressionAlgorithms();
|
||||
|
||||
// some SSH servers have buggy implementations of some of the above algorithms
|
||||
switch ($this->server_identifier) {
|
||||
case 'SSH-2.0-SSHD':
|
||||
$mac_algorithms = array_values(array_diff(
|
||||
$mac_algorithms,
|
||||
array('hmac-sha1-96', 'hmac-md5-96')
|
||||
));
|
||||
switch (true) {
|
||||
case $this->server_identifier == 'SSH-2.0-SSHD':
|
||||
case substr($this->server_identifier, 0, 13) == 'SSH-2.0-DLINK':
|
||||
if (!isset($preferred['server_to_client']['mac'])) {
|
||||
$s2c_mac_algorithms = array_values(array_diff(
|
||||
$s2c_mac_algorithms,
|
||||
array('hmac-sha1-96', 'hmac-md5-96')
|
||||
));
|
||||
}
|
||||
if (!isset($preferred['client_to_server']['mac'])) {
|
||||
$c2s_mac_algorithms = array_values(array_diff(
|
||||
$c2s_mac_algorithms,
|
||||
array('hmac-sha1-96', 'hmac-md5-96')
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
$str_kex_algorithms = implode(',', $kex_algorithms);
|
||||
$str_server_host_key_algorithms = implode(',', $server_host_key_algorithms);
|
||||
$encryption_algorithms_server_to_client = $encryption_algorithms_client_to_server = implode(',', $encryption_algorithms);
|
||||
$mac_algorithms_server_to_client = $mac_algorithms_client_to_server = implode(',', $mac_algorithms);
|
||||
$compression_algorithms_server_to_client = $compression_algorithms_client_to_server = implode(',', $compression_algorithms);
|
||||
$encryption_algorithms_server_to_client = implode(',', $s2c_encryption_algorithms);
|
||||
$encryption_algorithms_client_to_server = implode(',', $c2s_encryption_algorithms);
|
||||
$mac_algorithms_server_to_client = implode(',', $s2c_mac_algorithms);
|
||||
$mac_algorithms_client_to_server = implode(',', $c2s_mac_algorithms);
|
||||
$compression_algorithms_server_to_client = implode(',', $s2c_compression_algorithms);
|
||||
$compression_algorithms_client_to_server = implode(',', $c2s_compression_algorithms);
|
||||
|
||||
$client_cookie = Random::string(16);
|
||||
|
||||
$response = $kexinit_payload_server;
|
||||
$this->_string_shift($response, 1); // skip past the message number (it should be SSH_MSG_KEXINIT)
|
||||
$server_cookie = $this->_string_shift($response, 16);
|
||||
|
||||
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
||||
$this->kex_algorithms = explode(',', $this->_string_shift($response, $temp['length']));
|
||||
|
||||
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
||||
$this->server_host_key_algorithms = explode(',', $this->_string_shift($response, $temp['length']));
|
||||
|
||||
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
||||
$this->encryption_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
|
||||
|
||||
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
||||
$this->encryption_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
|
||||
|
||||
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
||||
$this->mac_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
|
||||
|
||||
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
||||
$this->mac_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
|
||||
|
||||
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
||||
$this->compression_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
|
||||
|
||||
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
||||
$this->compression_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
|
||||
|
||||
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
||||
$this->languages_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
|
||||
|
||||
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
||||
$this->languages_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
|
||||
|
||||
extract(unpack('Cfirst_kex_packet_follows', $this->_string_shift($response, 1)));
|
||||
$first_kex_packet_follows = $first_kex_packet_follows != 0;
|
||||
|
||||
// the sending of SSH2_MSG_KEXINIT could go in one of two places. this is the second place.
|
||||
$kexinit_payload_client = pack(
|
||||
'Ca*Na*Na*Na*Na*Na*Na*Na*Na*Na*Na*CN',
|
||||
NET_SSH2_MSG_KEXINIT,
|
||||
|
|
@ -1366,22 +1505,111 @@ class SSH2
|
|||
0
|
||||
);
|
||||
|
||||
if (!$this->_send_binary_packet($kexinit_payload_client)) {
|
||||
if ($kexinit_payload_server === false) {
|
||||
if (!$this->_send_binary_packet($kexinit_payload_client)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$kexinit_payload_server = $this->_get_binary_packet();
|
||||
if ($kexinit_payload_server === false) {
|
||||
$this->bitmap = 0;
|
||||
user_error('Connection closed by server');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!strlen($kexinit_payload_server) || ord($kexinit_payload_server[0]) != NET_SSH2_MSG_KEXINIT) {
|
||||
user_error('Expected SSH_MSG_KEXINIT');
|
||||
return false;
|
||||
}
|
||||
|
||||
$send_kex = false;
|
||||
}
|
||||
|
||||
$response = $kexinit_payload_server;
|
||||
$this->_string_shift($response, 1); // skip past the message number (it should be SSH_MSG_KEXINIT)
|
||||
$server_cookie = $this->_string_shift($response, 16);
|
||||
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
||||
$this->kex_algorithms = explode(',', $this->_string_shift($response, $temp['length']));
|
||||
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
||||
$this->server_host_key_algorithms = explode(',', $this->_string_shift($response, $temp['length']));
|
||||
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
||||
$this->encryption_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
|
||||
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
||||
$this->encryption_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
|
||||
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
||||
$this->mac_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
|
||||
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
||||
$this->mac_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
|
||||
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
||||
$this->compression_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
|
||||
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
||||
$this->compression_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
|
||||
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
||||
$this->languages_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
|
||||
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
||||
$this->languages_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
|
||||
|
||||
if (!strlen($response)) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Cfirst_kex_packet_follows', $this->_string_shift($response, 1)));
|
||||
$first_kex_packet_follows = $first_kex_packet_follows != 0;
|
||||
|
||||
if ($send_kex && !$this->_send_binary_packet($kexinit_payload_client)) {
|
||||
return false;
|
||||
}
|
||||
// here ends the second place.
|
||||
|
||||
// we need to decide upon the symmetric encryption algorithms before we do the diffie-hellman key exchange
|
||||
// we don't initialize any crypto-objects, yet - we do that, later. for now, we need the lengths to make the
|
||||
// diffie-hellman key exchange as fast as possible
|
||||
$decrypt = $this->_array_intersect_first($encryption_algorithms, $this->encryption_algorithms_server_to_client);
|
||||
$decrypt = $this->_array_intersect_first($s2c_encryption_algorithms, $this->encryption_algorithms_server_to_client);
|
||||
$decryptKeyLength = $this->_encryption_algorithm_to_key_size($decrypt);
|
||||
if ($decryptKeyLength === null) {
|
||||
user_error('No compatible server to client encryption algorithms found');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
||||
}
|
||||
|
||||
$encrypt = $this->_array_intersect_first($encryption_algorithms, $this->encryption_algorithms_client_to_server);
|
||||
$encrypt = $this->_array_intersect_first($c2s_encryption_algorithms, $this->encryption_algorithms_client_to_server);
|
||||
$encryptKeyLength = $this->_encryption_algorithm_to_key_size($encrypt);
|
||||
if ($encryptKeyLength === null) {
|
||||
user_error('No compatible client to server encryption algorithms found');
|
||||
|
|
@ -1389,20 +1617,52 @@ class SSH2
|
|||
}
|
||||
|
||||
// through diffie-hellman key exchange a symmetric key is obtained
|
||||
$kex_algorithm = $this->_array_intersect_first($kex_algorithms, $this->kex_algorithms);
|
||||
$this->kex_algorithm = $kex_algorithm = $this->_array_intersect_first($kex_algorithms, $this->kex_algorithms);
|
||||
if ($kex_algorithm === false) {
|
||||
user_error('No compatible key exchange algorithms found');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
||||
}
|
||||
|
||||
$server_host_key_algorithm = $this->_array_intersect_first($server_host_key_algorithms, $this->server_host_key_algorithms);
|
||||
if ($server_host_key_algorithm === false) {
|
||||
user_error('No compatible server host key algorithms found');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
||||
}
|
||||
|
||||
$mac_algorithm_in = $this->_array_intersect_first($s2c_mac_algorithms, $this->mac_algorithms_server_to_client);
|
||||
if ($mac_algorithm_in === false) {
|
||||
user_error('No compatible server to client message authentication algorithms found');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
||||
}
|
||||
|
||||
$compression_map = array(
|
||||
'none' => NET_SSH2_COMPRESSION_NONE,
|
||||
'zlib' => NET_SSH2_COMPRESSION_ZLIB,
|
||||
'zlib@openssh.com' => NET_SSH2_COMPRESSION_ZLIB_AT_OPENSSH
|
||||
);
|
||||
|
||||
$compression_algorithm_out = $this->_array_intersect_first($c2s_compression_algorithms, $this->compression_algorithms_client_to_server);
|
||||
if ($compression_algorithm_out === false) {
|
||||
user_error('No compatible client to server compression algorithms found');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
||||
}
|
||||
$this->compress = $compression_map[$compression_algorithm_out];
|
||||
|
||||
$compression_algorithm_in = $this->_array_intersect_first($s2c_compression_algorithms, $this->compression_algorithms_server_to_client);
|
||||
if ($compression_algorithm_in === false) {
|
||||
user_error('No compatible server to client compression algorithms found');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
||||
}
|
||||
$this->decompress = $compression_map[$compression_algorithm_in];
|
||||
|
||||
// Only relevant in diffie-hellman-group-exchange-sha{1,256}, otherwise empty.
|
||||
$exchange_hash_rfc4419 = '';
|
||||
|
||||
if ($kex_algorithm === 'curve25519-sha256@libssh.org') {
|
||||
$x = Random::string(32);
|
||||
$eBytes = \Sodium\crypto_box_publickey_from_secretkey($x);
|
||||
$clientKexInitMessage = NET_SSH2_MSG_KEX_ECDH_INIT;
|
||||
$serverKexReplyMessage = NET_SSH2_MSG_KEX_ECDH_REPLY;
|
||||
$eBytes = sodium_crypto_box_publickey_from_secretkey($x);
|
||||
$clientKexInitMessage = 'NET_SSH2_MSG_KEX_ECDH_INIT';
|
||||
$serverKexReplyMessage = 'NET_SSH2_MSG_KEX_ECDH_REPLY';
|
||||
$kexHash = new Hash('sha256');
|
||||
} else {
|
||||
if (strpos($kex_algorithm, 'diffie-hellman-group-exchange') === 0) {
|
||||
|
|
@ -1420,9 +1680,11 @@ class SSH2
|
|||
if (!$this->_send_binary_packet($packet)) {
|
||||
return false;
|
||||
}
|
||||
$this->_updateLogHistory('UNKNOWN (34)', 'NET_SSH2_MSG_KEXDH_GEX_REQUEST');
|
||||
|
||||
$response = $this->_get_binary_packet();
|
||||
if ($response === false) {
|
||||
$this->bitmap = 0;
|
||||
user_error('Connection closed by server');
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1431,11 +1693,18 @@ class SSH2
|
|||
user_error('Expected SSH_MSG_KEX_DH_GEX_GROUP');
|
||||
return false;
|
||||
}
|
||||
$this->_updateLogHistory('NET_SSH2_MSG_KEXDH_REPLY', 'NET_SSH2_MSG_KEXDH_GEX_GROUP');
|
||||
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('NprimeLength', $this->_string_shift($response, 4)));
|
||||
$primeBytes = $this->_string_shift($response, $primeLength);
|
||||
$prime = new BigInteger($primeBytes, -256);
|
||||
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('NgLength', $this->_string_shift($response, 4)));
|
||||
$gBytes = $this->_string_shift($response, $gLength);
|
||||
$g = new BigInteger($gBytes, -256);
|
||||
|
|
@ -1449,8 +1718,8 @@ class SSH2
|
|||
$gBytes
|
||||
);
|
||||
|
||||
$clientKexInitMessage = NET_SSH2_MSG_KEXDH_GEX_INIT;
|
||||
$serverKexReplyMessage = NET_SSH2_MSG_KEXDH_GEX_REPLY;
|
||||
$clientKexInitMessage = 'NET_SSH2_MSG_KEXDH_GEX_INIT';
|
||||
$serverKexReplyMessage = 'NET_SSH2_MSG_KEXDH_GEX_REPLY';
|
||||
} else {
|
||||
switch ($kex_algorithm) {
|
||||
// see http://tools.ietf.org/html/rfc2409#section-6.2 and
|
||||
|
|
@ -1477,8 +1746,8 @@ class SSH2
|
|||
// the generator field element is 2 (decimal) and the hash function is sha1.
|
||||
$g = new BigInteger(2);
|
||||
$prime = new BigInteger($prime, 16);
|
||||
$clientKexInitMessage = NET_SSH2_MSG_KEXDH_INIT;
|
||||
$serverKexReplyMessage = NET_SSH2_MSG_KEXDH_REPLY;
|
||||
$clientKexInitMessage = 'NET_SSH2_MSG_KEXDH_INIT';
|
||||
$serverKexReplyMessage = 'NET_SSH2_MSG_KEXDH_REPLY';
|
||||
}
|
||||
|
||||
switch ($kex_algorithm) {
|
||||
|
|
@ -1506,37 +1775,71 @@ class SSH2
|
|||
|
||||
$eBytes = $e->toBytes(true);
|
||||
}
|
||||
$data = pack('CNa*', $clientKexInitMessage, strlen($eBytes), $eBytes);
|
||||
$data = pack('CNa*', constant($clientKexInitMessage), strlen($eBytes), $eBytes);
|
||||
|
||||
if (!$this->_send_binary_packet($data)) {
|
||||
$this->bitmap = 0;
|
||||
user_error('Connection closed by server');
|
||||
return false;
|
||||
}
|
||||
switch ($clientKexInitMessage) {
|
||||
case 'NET_SSH2_MSG_KEX_ECDH_INIT':
|
||||
$this->_updateLogHistory('NET_SSH2_MSG_KEXDH_INIT', 'NET_SSH2_MSG_KEX_ECDH_INIT');
|
||||
break;
|
||||
case 'NET_SSH2_MSG_KEXDH_GEX_INIT':
|
||||
$this->_updateLogHistory('UNKNOWN (32)', 'NET_SSH2_MSG_KEXDH_GEX_INIT');
|
||||
}
|
||||
|
||||
$response = $this->_get_binary_packet();
|
||||
if ($response === false) {
|
||||
$this->bitmap = 0;
|
||||
user_error('Connection closed by server');
|
||||
return false;
|
||||
}
|
||||
if (!strlen($response)) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Ctype', $this->_string_shift($response, 1)));
|
||||
|
||||
if ($type != $serverKexReplyMessage) {
|
||||
user_error('Expected SSH_MSG_KEXDH_REPLY');
|
||||
if ($type != constant($serverKexReplyMessage)) {
|
||||
user_error("Expected $serverKexReplyMessage");
|
||||
return false;
|
||||
}
|
||||
switch ($serverKexReplyMessage) {
|
||||
case 'NET_SSH2_MSG_KEX_ECDH_REPLY':
|
||||
$this->_updateLogHistory('NET_SSH2_MSG_KEXDH_REPLY', 'NET_SSH2_MSG_KEX_ECDH_REPLY');
|
||||
break;
|
||||
case 'NET_SSH2_MSG_KEXDH_GEX_REPLY':
|
||||
$this->_updateLogHistory('UNKNOWN (33)', 'NET_SSH2_MSG_KEXDH_GEX_REPLY');
|
||||
}
|
||||
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
||||
$this->server_public_host_key = $server_public_host_key = $this->_string_shift($response, $temp['length']);
|
||||
|
||||
if (strlen($server_public_host_key) < 4) {
|
||||
return false;
|
||||
}
|
||||
$temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
|
||||
$public_key_format = $this->_string_shift($server_public_host_key, $temp['length']);
|
||||
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
||||
$fBytes = $this->_string_shift($response, $temp['length']);
|
||||
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
||||
$this->signature = $this->_string_shift($response, $temp['length']);
|
||||
|
||||
if (strlen($this->signature) < 4) {
|
||||
return false;
|
||||
}
|
||||
$temp = unpack('Nlength', $this->_string_shift($this->signature, 4));
|
||||
$this->signature_format = $this->_string_shift($this->signature, $temp['length']);
|
||||
|
||||
|
|
@ -1545,8 +1848,15 @@ class SSH2
|
|||
user_error('Received curve25519 public key of invalid length.');
|
||||
return false;
|
||||
}
|
||||
$key = new BigInteger(\Sodium\crypto_scalarmult($x, $fBytes), 256);
|
||||
\Sodium\memzero($x);
|
||||
$key = new BigInteger(sodium_crypto_scalarmult($x, $fBytes), 256);
|
||||
// sodium_compat doesn't emulate sodium_memzero
|
||||
// also, with v1 of libsodium API the extension identifies itself as
|
||||
// libsodium whereas v2 of the libsodium API (what PHP 7.2+ includes)
|
||||
// identifies itself as sodium. sodium_compat uses the v1 API to
|
||||
// emulate the v2 API if it's the v1 API that's available
|
||||
if (extension_loaded('sodium') || extension_loaded('libsodium')) {
|
||||
sodium_memzero($x);
|
||||
}
|
||||
} else {
|
||||
$f = new BigInteger($fBytes, -256);
|
||||
$key = $f->modPow($x, $prime);
|
||||
|
|
@ -1580,15 +1890,25 @@ class SSH2
|
|||
$this->session_id = $this->exchange_hash;
|
||||
}
|
||||
|
||||
$server_host_key_algorithm = $this->_array_intersect_first($server_host_key_algorithms, $this->server_host_key_algorithms);
|
||||
if ($server_host_key_algorithm === false) {
|
||||
user_error('No compatible server host key algorithms found');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
||||
switch ($server_host_key_algorithm) {
|
||||
case 'ssh-dss':
|
||||
$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 != $server_host_key_algorithm || $this->signature_format != $server_host_key_algorithm) {
|
||||
user_error('Server Host Key Algorithm Mismatch');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
||||
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(
|
||||
|
|
@ -1603,10 +1923,14 @@ class SSH2
|
|||
$response = $this->_get_binary_packet();
|
||||
|
||||
if ($response === false) {
|
||||
$this->bitmap = 0;
|
||||
user_error('Connection closed by server');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!strlen($response)) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Ctype', $this->_string_shift($response, 1)));
|
||||
|
||||
if ($type != NET_SSH2_MSG_NEWKEYS) {
|
||||
|
|
@ -1619,7 +1943,7 @@ class SSH2
|
|||
$this->encrypt = $this->_encryption_algorithm_to_crypt_instance($encrypt);
|
||||
if ($this->encrypt) {
|
||||
if ($this->crypto_engine) {
|
||||
$this->encrypt->setEngine($this->crypto_engine);
|
||||
$this->encrypt->setPreferredEngine($this->crypto_engine);
|
||||
}
|
||||
if ($this->encrypt->block_size) {
|
||||
$this->encrypt_block_size = $this->encrypt->block_size;
|
||||
|
|
@ -1627,6 +1951,10 @@ class SSH2
|
|||
$this->encrypt->enableContinuousBuffer();
|
||||
$this->encrypt->disablePadding();
|
||||
|
||||
if ($this->encrypt->getBlockLength()) {
|
||||
$this->encrypt_block_size = $this->encrypt->getBlockLength() >> 3;
|
||||
}
|
||||
|
||||
$iv = $kexHash->hash($keyBytes . $this->exchange_hash . 'A' . $this->session_id);
|
||||
while ($this->encrypt_block_size > strlen($iv)) {
|
||||
$iv.= $kexHash->hash($keyBytes . $this->exchange_hash . $iv);
|
||||
|
|
@ -1638,12 +1966,14 @@ class SSH2
|
|||
$key.= $kexHash->hash($keyBytes . $this->exchange_hash . $key);
|
||||
}
|
||||
$this->encrypt->setKey(substr($key, 0, $encryptKeyLength));
|
||||
|
||||
$this->encrypt->name = $decrypt;
|
||||
}
|
||||
|
||||
$this->decrypt = $this->_encryption_algorithm_to_crypt_instance($decrypt);
|
||||
if ($this->decrypt) {
|
||||
if ($this->crypto_engine) {
|
||||
$this->decrypt->setEngine($this->crypto_engine);
|
||||
$this->decrypt->setPreferredEngine($this->crypto_engine);
|
||||
}
|
||||
if ($this->decrypt->block_size) {
|
||||
$this->decrypt_block_size = $this->decrypt->block_size;
|
||||
|
|
@ -1651,6 +1981,10 @@ class SSH2
|
|||
$this->decrypt->enableContinuousBuffer();
|
||||
$this->decrypt->disablePadding();
|
||||
|
||||
if ($this->decrypt->getBlockLength()) {
|
||||
$this->decrypt_block_size = $this->decrypt->getBlockLength() >> 3;
|
||||
}
|
||||
|
||||
$iv = $kexHash->hash($keyBytes . $this->exchange_hash . 'B' . $this->session_id);
|
||||
while ($this->decrypt_block_size > strlen($iv)) {
|
||||
$iv.= $kexHash->hash($keyBytes . $this->exchange_hash . $iv);
|
||||
|
|
@ -1662,6 +1996,8 @@ class SSH2
|
|||
$key.= $kexHash->hash($keyBytes . $this->exchange_hash . $key);
|
||||
}
|
||||
$this->decrypt->setKey(substr($key, 0, $decryptKeyLength));
|
||||
|
||||
$this->decrypt->name = $decrypt;
|
||||
}
|
||||
|
||||
/* The "arcfour128" algorithm is the RC4 cipher, as described in
|
||||
|
|
@ -1678,14 +2014,14 @@ class SSH2
|
|||
$this->decrypt->decrypt(str_repeat("\0", 1536));
|
||||
}
|
||||
|
||||
$mac_algorithm = $this->_array_intersect_first($mac_algorithms, $this->mac_algorithms_client_to_server);
|
||||
if ($mac_algorithm === false) {
|
||||
$mac_algorithm_out = $this->_array_intersect_first($c2s_mac_algorithms, $this->mac_algorithms_client_to_server);
|
||||
if ($mac_algorithm_out === false) {
|
||||
user_error('No compatible client to server message authentication algorithms found');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
||||
}
|
||||
|
||||
$createKeyLength = 0; // ie. $mac_algorithm == 'none'
|
||||
switch ($mac_algorithm) {
|
||||
switch ($mac_algorithm_out) {
|
||||
case 'hmac-sha2-256':
|
||||
$this->hmac_create = new Hash('sha256');
|
||||
$createKeyLength = 32;
|
||||
|
|
@ -1706,16 +2042,11 @@ class SSH2
|
|||
$this->hmac_create = new Hash('md5-96');
|
||||
$createKeyLength = 16;
|
||||
}
|
||||
|
||||
$mac_algorithm = $this->_array_intersect_first($mac_algorithms, $this->mac_algorithms_server_to_client);
|
||||
if ($mac_algorithm === false) {
|
||||
user_error('No compatible server to client message authentication algorithms found');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
||||
}
|
||||
$this->hmac_create->name = $mac_algorithm_out;
|
||||
|
||||
$checkKeyLength = 0;
|
||||
$this->hmac_size = 0;
|
||||
switch ($mac_algorithm) {
|
||||
switch ($mac_algorithm_in) {
|
||||
case 'hmac-sha2-256':
|
||||
$this->hmac_check = new Hash('sha256');
|
||||
$checkKeyLength = 32;
|
||||
|
|
@ -1741,6 +2072,7 @@ class SSH2
|
|||
$checkKeyLength = 16;
|
||||
$this->hmac_size = 12;
|
||||
}
|
||||
$this->hmac_check->name = $mac_algorithm_in;
|
||||
|
||||
$key = $kexHash->hash($keyBytes . $this->exchange_hash . 'E' . $this->session_id);
|
||||
while ($createKeyLength > strlen($key)) {
|
||||
|
|
@ -1754,19 +2086,7 @@ class SSH2
|
|||
}
|
||||
$this->hmac_check->setKey(substr($key, 0, $checkKeyLength));
|
||||
|
||||
$compression_algorithm = $this->_array_intersect_first($compression_algorithms, $this->compression_algorithms_server_to_client);
|
||||
if ($compression_algorithm === false) {
|
||||
user_error('No compatible server to client compression algorithms found');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
||||
}
|
||||
$this->decompress = $compression_algorithm == 'zlib';
|
||||
|
||||
$compression_algorithm = $this->_array_intersect_first($compression_algorithms, $this->compression_algorithms_client_to_server);
|
||||
if ($compression_algorithm === false) {
|
||||
user_error('No compatible client to server compression algorithms found');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
||||
}
|
||||
$this->compress = $compression_algorithm == 'zlib';
|
||||
$this->regenerate_compression_context = $this->regenerate_decompression_context = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1780,6 +2100,10 @@ class SSH2
|
|||
*/
|
||||
function _encryption_algorithm_to_key_size($algorithm)
|
||||
{
|
||||
if ($this->bad_key_size_fix && $this->_bad_algorithm_candidate($algorithm)) {
|
||||
return 16;
|
||||
}
|
||||
|
||||
switch ($algorithm) {
|
||||
case 'none':
|
||||
return 0;
|
||||
|
|
@ -1854,14 +2178,33 @@ class SSH2
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether or not proposed algorithm has a potential for issues
|
||||
*
|
||||
* @link https://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/ssh2-aesctr-openssh.html
|
||||
* @link https://bugzilla.mindrot.org/show_bug.cgi?id=1291
|
||||
* @param string $algorithm Name of the encryption algorithm
|
||||
* @return bool
|
||||
* @access private
|
||||
*/
|
||||
function _bad_algorithm_candidate($algorithm)
|
||||
{
|
||||
switch ($algorithm) {
|
||||
case 'arcfour256':
|
||||
case 'aes192-ctr':
|
||||
case 'aes256-ctr':
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Login
|
||||
*
|
||||
* The $password parameter can be a plaintext password, a \phpseclib\Crypt\RSA object or an array
|
||||
*
|
||||
* @param string $username
|
||||
* @param mixed $password
|
||||
* @param mixed $...
|
||||
* @return bool
|
||||
* @see self::_login()
|
||||
* @access public
|
||||
|
|
@ -1869,6 +2212,18 @@ class SSH2
|
|||
function login($username)
|
||||
{
|
||||
$args = func_get_args();
|
||||
$this->auth[] = $args;
|
||||
|
||||
// try logging with 'none' as an authentication method first since that's what
|
||||
// PuTTY does
|
||||
if (substr($this->server_identifier, 0, 15) != 'SSH-2.0-CoreFTP' && $this->auth_methods_to_continue === null) {
|
||||
if ($this->_login($username)) {
|
||||
return true;
|
||||
}
|
||||
if (count($args) == 1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return call_user_func_array(array(&$this, '_login'), $args);
|
||||
}
|
||||
|
||||
|
|
@ -1876,8 +2231,6 @@ class SSH2
|
|||
* Login Helper
|
||||
*
|
||||
* @param string $username
|
||||
* @param mixed $password
|
||||
* @param mixed $...
|
||||
* @return bool
|
||||
* @see self::_login_helper()
|
||||
* @access private
|
||||
|
|
@ -1933,10 +2286,21 @@ class SSH2
|
|||
|
||||
$response = $this->_get_binary_packet();
|
||||
if ($response === false) {
|
||||
if ($this->retry_connect) {
|
||||
$this->retry_connect = false;
|
||||
if (!$this->_connect()) {
|
||||
return false;
|
||||
}
|
||||
return $this->_login_helper($username, $password);
|
||||
}
|
||||
$this->bitmap = 0;
|
||||
user_error('Connection closed by server');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Ctype', $this->_string_shift($response, 1)));
|
||||
|
||||
if ($type != NET_SSH2_MSG_SERVICE_ACCEPT) {
|
||||
|
|
@ -1982,17 +2346,23 @@ class SSH2
|
|||
|
||||
$response = $this->_get_binary_packet();
|
||||
if ($response === false) {
|
||||
$this->bitmap = 0;
|
||||
user_error('Connection closed by server');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!strlen($response)) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Ctype', $this->_string_shift($response, 1)));
|
||||
|
||||
switch ($type) {
|
||||
case NET_SSH2_MSG_USERAUTH_SUCCESS:
|
||||
$this->bitmap |= self::MASK_LOGIN;
|
||||
return true;
|
||||
//case NET_SSH2_MSG_USERAUTH_FAILURE:
|
||||
case NET_SSH2_MSG_USERAUTH_FAILURE:
|
||||
extract(unpack('Nmethodlistlen', $this->_string_shift($response, 4)));
|
||||
$this->auth_methods_to_continue = explode(',', $this->_string_shift($response, $methodlistlen));
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
@ -2037,25 +2407,37 @@ class SSH2
|
|||
|
||||
$response = $this->_get_binary_packet();
|
||||
if ($response === false) {
|
||||
$this->bitmap = 0;
|
||||
user_error('Connection closed by server');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!strlen($response)) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Ctype', $this->_string_shift($response, 1)));
|
||||
|
||||
switch ($type) {
|
||||
case NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ: // in theory, the password can be changed
|
||||
if (defined('NET_SSH2_LOGGING')) {
|
||||
$this->message_number_log[count($this->message_number_log) - 1] = 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ';
|
||||
$this->_updateLogHistory('UNKNOWN (60)', 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ');
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
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);
|
||||
case NET_SSH2_MSG_USERAUTH_FAILURE:
|
||||
// can we use keyboard-interactive authentication? if not then either the login is bad or the server employees
|
||||
// multi-factor authentication
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
||||
$auth_methods = explode(',', $this->_string_shift($response, $length));
|
||||
$this->auth_methods_to_continue = $auth_methods;
|
||||
if (!strlen($response)) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Cpartial_success', $this->_string_shift($response, 1)));
|
||||
$partial_success = $partial_success != 0;
|
||||
|
||||
|
|
@ -2112,7 +2494,6 @@ class SSH2
|
|||
/**
|
||||
* Handle the keyboard-interactive requests / responses.
|
||||
*
|
||||
* @param string $responses...
|
||||
* @return bool
|
||||
* @access private
|
||||
*/
|
||||
|
|
@ -2125,21 +2506,37 @@ class SSH2
|
|||
} else {
|
||||
$orig = $response = $this->_get_binary_packet();
|
||||
if ($response === false) {
|
||||
$this->bitmap = 0;
|
||||
user_error('Connection closed by server');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!strlen($response)) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Ctype', $this->_string_shift($response, 1)));
|
||||
|
||||
switch ($type) {
|
||||
case NET_SSH2_MSG_USERAUTH_INFO_REQUEST:
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
||||
$this->_string_shift($response, $length); // name; may be empty
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
||||
$this->_string_shift($response, $length); // instruction; may be empty
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
||||
$this->_string_shift($response, $length); // language tag; may be empty
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nnum_prompts', $this->_string_shift($response, 4)));
|
||||
|
||||
for ($i = 0; $i < count($responses); $i++) {
|
||||
|
|
@ -2154,6 +2551,9 @@ class SSH2
|
|||
|
||||
if (isset($this->keyboard_requests_responses)) {
|
||||
for ($i = 0; $i < $num_prompts; $i++) {
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
||||
// prompt - ie. "Password: "; must not be empty
|
||||
$prompt = $this->_string_shift($response, $length);
|
||||
|
|
@ -2170,12 +2570,8 @@ class SSH2
|
|||
// see http://tools.ietf.org/html/rfc4256#section-3.2
|
||||
if (strlen($this->last_interactive_response)) {
|
||||
$this->last_interactive_response = '';
|
||||
} elseif (defined('NET_SSH2_LOGGING')) {
|
||||
$this->message_number_log[count($this->message_number_log) - 1] = str_replace(
|
||||
'UNKNOWN',
|
||||
'NET_SSH2_MSG_USERAUTH_INFO_REQUEST',
|
||||
$this->message_number_log[count($this->message_number_log) - 1]
|
||||
);
|
||||
} else {
|
||||
$this->_updateLogHistory('UNKNOWN (60)', 'NET_SSH2_MSG_USERAUTH_INFO_REQUEST');
|
||||
}
|
||||
|
||||
if (!count($responses) && $num_prompts) {
|
||||
|
|
@ -2198,13 +2594,7 @@ class SSH2
|
|||
return false;
|
||||
}
|
||||
|
||||
if (defined('NET_SSH2_LOGGING') && NET_SSH2_LOGGING == self::LOG_COMPLEX) {
|
||||
$this->message_number_log[count($this->message_number_log) - 1] = str_replace(
|
||||
'UNKNOWN',
|
||||
'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE',
|
||||
$this->message_number_log[count($this->message_number_log) - 1]
|
||||
);
|
||||
}
|
||||
$this->_updateLogHistory('UNKNOWN (61)', 'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE');
|
||||
|
||||
/*
|
||||
After receiving the response, the server MUST send either an
|
||||
|
|
@ -2217,6 +2607,8 @@ class SSH2
|
|||
case NET_SSH2_MSG_USERAUTH_SUCCESS:
|
||||
return true;
|
||||
case NET_SSH2_MSG_USERAUTH_FAILURE:
|
||||
extract(unpack('Nmethodlistlen', $this->_string_shift($response, 4)));
|
||||
$this->auth_methods_to_continue = explode(',', $this->_string_shift($response, $methodlistlen));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -2248,7 +2640,7 @@ class SSH2
|
|||
* Login with an RSA private key
|
||||
*
|
||||
* @param string $username
|
||||
* @param \phpseclib\Crypt\RSA $password
|
||||
* @param \phpseclib\Crypt\RSA $privatekey
|
||||
* @return bool
|
||||
* @access private
|
||||
* @internal It might be worthwhile, at some point, to protect against {@link http://tools.ietf.org/html/rfc4251#section-9.3.9 traffic analysis}
|
||||
|
|
@ -2276,6 +2668,21 @@ class SSH2
|
|||
$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(
|
||||
'CNa*Na*Na*',
|
||||
NET_SSH2_MSG_USERAUTH_REQUEST,
|
||||
|
|
@ -2286,7 +2693,7 @@ class SSH2
|
|||
strlen('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;
|
||||
if (!$this->_send_binary_packet($packet)) {
|
||||
|
|
@ -2295,33 +2702,43 @@ class SSH2
|
|||
|
||||
$response = $this->_get_binary_packet();
|
||||
if ($response === false) {
|
||||
$this->bitmap = 0;
|
||||
user_error('Connection closed by server');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!strlen($response)) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Ctype', $this->_string_shift($response, 1)));
|
||||
|
||||
switch ($type) {
|
||||
case NET_SSH2_MSG_USERAUTH_FAILURE:
|
||||
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
||||
$this->errors[] = 'SSH_MSG_USERAUTH_FAILURE: ' . $this->_string_shift($response, $length);
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nmethodlistlen', $this->_string_shift($response, 4)));
|
||||
$this->auth_methods_to_continue = explode(',', $this->_string_shift($response, $methodlistlen));
|
||||
$this->errors[] = 'SSH_MSG_USERAUTH_FAILURE';
|
||||
return false;
|
||||
case NET_SSH2_MSG_USERAUTH_PK_OK:
|
||||
// we'll just take it on faith that the public key blob and the public key algorithm name are as
|
||||
// they should be
|
||||
if (defined('NET_SSH2_LOGGING') && NET_SSH2_LOGGING == self::LOG_COMPLEX) {
|
||||
$this->message_number_log[count($this->message_number_log) - 1] = str_replace(
|
||||
'UNKNOWN',
|
||||
'NET_SSH2_MSG_USERAUTH_PK_OK',
|
||||
$this->message_number_log[count($this->message_number_log) - 1]
|
||||
);
|
||||
}
|
||||
$this->_updateLogHistory('UNKNOWN (60)', 'NET_SSH2_MSG_USERAUTH_PK_OK');
|
||||
break;
|
||||
case NET_SSH2_MSG_USERAUTH_SUCCESS:
|
||||
$this->bitmap |= self::MASK_LOGIN;
|
||||
return true;
|
||||
default:
|
||||
user_error('Unexpected response to publickey authentication pt 1');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
|
||||
}
|
||||
|
||||
$packet = $part1 . chr(1) . $part2;
|
||||
$privatekey->setSignatureMode(RSA::SIGNATURE_PKCS1);
|
||||
$privatekey->setHash($hash);
|
||||
$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);
|
||||
|
||||
if (!$this->_send_binary_packet($packet)) {
|
||||
|
|
@ -2330,22 +2747,29 @@ class SSH2
|
|||
|
||||
$response = $this->_get_binary_packet();
|
||||
if ($response === false) {
|
||||
$this->bitmap = 0;
|
||||
user_error('Connection closed by server');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!strlen($response)) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Ctype', $this->_string_shift($response, 1)));
|
||||
|
||||
switch ($type) {
|
||||
case NET_SSH2_MSG_USERAUTH_FAILURE:
|
||||
// either the login is bad or the server employs multi-factor authentication
|
||||
extract(unpack('Nmethodlistlen', $this->_string_shift($response, 4)));
|
||||
$this->auth_methods_to_continue = explode(',', $this->_string_shift($response, $methodlistlen));
|
||||
return false;
|
||||
case NET_SSH2_MSG_USERAUTH_SUCCESS:
|
||||
$this->bitmap |= self::MASK_LOGIN;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
user_error('Unexpected response to publickey authentication pt 2');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2362,6 +2786,19 @@ class SSH2
|
|||
$this->timeout = $this->curTimeout = $timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Keep Alive
|
||||
*
|
||||
* Sends an SSH2_MSG_IGNORE message every x seconds, if x is a positive non-zero number.
|
||||
*
|
||||
* @param int $interval
|
||||
* @access public
|
||||
*/
|
||||
function setKeepAlive($interval)
|
||||
{
|
||||
$this->keepAlive = $interval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the output from stdError
|
||||
*
|
||||
|
|
@ -2389,7 +2826,12 @@ class SSH2
|
|||
$this->is_timeout = false;
|
||||
$this->stdErrorLog = '';
|
||||
|
||||
if (!($this->bitmap & self::MASK_LOGIN)) {
|
||||
if (!$this->isAuthenticated()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->in_request_pty_exec) {
|
||||
user_error('If you want to run multiple exec()\'s you will need to disable (and re-enable if appropriate) a PTY for each one.');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -2446,22 +2888,12 @@ class SSH2
|
|||
return false;
|
||||
}
|
||||
|
||||
$response = $this->_get_binary_packet();
|
||||
if ($response === false) {
|
||||
user_error('Connection closed by server');
|
||||
return false;
|
||||
$this->channel_status[self::CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_REQUEST;
|
||||
if (!$this->_get_channel_packet(self::CHANNEL_EXEC)) {
|
||||
user_error('Unable to request pseudo-terminal');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
|
||||
}
|
||||
|
||||
list(, $type) = unpack('C', $this->_string_shift($response, 1));
|
||||
|
||||
switch ($type) {
|
||||
case NET_SSH2_MSG_CHANNEL_SUCCESS:
|
||||
break;
|
||||
case NET_SSH2_MSG_CHANNEL_FAILURE:
|
||||
default:
|
||||
user_error('Unable to request pseudo-terminal');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
|
||||
}
|
||||
$this->in_request_pty_exec = true;
|
||||
}
|
||||
|
||||
|
|
@ -2582,22 +3014,11 @@ class SSH2
|
|||
return false;
|
||||
}
|
||||
|
||||
$response = $this->_get_binary_packet();
|
||||
if ($response === false) {
|
||||
user_error('Connection closed by server');
|
||||
return false;
|
||||
}
|
||||
$this->channel_status[self::CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_REQUEST;
|
||||
|
||||
list(, $type) = unpack('C', $this->_string_shift($response, 1));
|
||||
|
||||
switch ($type) {
|
||||
case NET_SSH2_MSG_CHANNEL_SUCCESS:
|
||||
// if a pty can't be opened maybe commands can still be executed
|
||||
case NET_SSH2_MSG_CHANNEL_FAILURE:
|
||||
break;
|
||||
default:
|
||||
user_error('Unable to request pseudo-terminal');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
|
||||
if (!$this->_get_channel_packet(self::CHANNEL_SHELL)) {
|
||||
user_error('Unable to request pseudo-terminal');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
|
||||
}
|
||||
|
||||
$packet = pack(
|
||||
|
|
@ -2612,8 +3033,6 @@ class SSH2
|
|||
return false;
|
||||
}
|
||||
|
||||
$this->channel_status[self::CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_REQUEST;
|
||||
|
||||
$response = $this->_get_channel_packet(self::CHANNEL_SHELL);
|
||||
if ($response === false) {
|
||||
return false;
|
||||
|
|
@ -2673,7 +3092,7 @@ class SSH2
|
|||
* @see self::write()
|
||||
* @param string $expect
|
||||
* @param int $mode
|
||||
* @return string
|
||||
* @return string|bool
|
||||
* @access public
|
||||
*/
|
||||
function read($expect = '', $mode = self::READ_SIMPLE)
|
||||
|
|
@ -2681,7 +3100,7 @@ class SSH2
|
|||
$this->curTimeout = $this->timeout;
|
||||
$this->is_timeout = false;
|
||||
|
||||
if (!($this->bitmap & self::MASK_LOGIN)) {
|
||||
if (!$this->isAuthenticated()) {
|
||||
user_error('Operation disallowed prior to login()');
|
||||
return false;
|
||||
}
|
||||
|
|
@ -2693,6 +3112,10 @@ class SSH2
|
|||
|
||||
$channel = $this->_get_interactive_channel();
|
||||
|
||||
if ($mode == self::READ_NEXT) {
|
||||
return $this->_get_channel_packet($channel);
|
||||
}
|
||||
|
||||
$match = $expect;
|
||||
while (true) {
|
||||
if ($mode == self::READ_REGEX) {
|
||||
|
|
@ -2723,7 +3146,7 @@ class SSH2
|
|||
*/
|
||||
function write($cmd)
|
||||
{
|
||||
if (!($this->bitmap & self::MASK_LOGIN)) {
|
||||
if (!$this->isAuthenticated()) {
|
||||
user_error('Operation disallowed prior to login()');
|
||||
return false;
|
||||
}
|
||||
|
|
@ -2891,6 +3314,87 @@ class SSH2
|
|||
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()) {
|
||||
if (!empty($this->auth)) {
|
||||
return $this->_reconnect();
|
||||
}
|
||||
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
|
||||
*
|
||||
* @param int $reason
|
||||
* @access private
|
||||
*/
|
||||
function _reset_connection($reason)
|
||||
{
|
||||
$this->_disconnect($reason);
|
||||
$this->decrypt = $this->encrypt = false;
|
||||
$this->decrypt_block_size = $this->encrypt_block_size = 8;
|
||||
$this->hmac_check = $this->hmac_create = false;
|
||||
$this->hmac_size = false;
|
||||
$this->session_id = false;
|
||||
$this->retry_connect = true;
|
||||
$this->get_seq_no = $this->send_seq_no = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets Binary Packets
|
||||
*
|
||||
|
|
@ -2900,11 +3404,59 @@ class SSH2
|
|||
* @return string
|
||||
* @access private
|
||||
*/
|
||||
function _get_binary_packet()
|
||||
function _get_binary_packet($skip_channel_filter = false)
|
||||
{
|
||||
if ($skip_channel_filter) {
|
||||
$read = array($this->fsock);
|
||||
$write = $except = null;
|
||||
|
||||
if (!$this->curTimeout) {
|
||||
if ($this->keepAlive <= 0) {
|
||||
@stream_select($read, $write, $except, null);
|
||||
} else {
|
||||
if (!@stream_select($read, $write, $except, $this->keepAlive) && !count($read)) {
|
||||
$this->_send_binary_packet(pack('CN', NET_SSH2_MSG_IGNORE, 0));
|
||||
return $this->_get_binary_packet(true);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($this->curTimeout < 0) {
|
||||
$this->is_timeout = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
$read = array($this->fsock);
|
||||
$write = $except = null;
|
||||
|
||||
$start = microtime(true);
|
||||
|
||||
if ($this->keepAlive > 0 && $this->keepAlive < $this->curTimeout) {
|
||||
if (!@stream_select($read, $write, $except, $this->keepAlive) && !count($read)) {
|
||||
$this->_send_binary_packet(pack('CN', NET_SSH2_MSG_IGNORE, 0));
|
||||
$elapsed = microtime(true) - $start;
|
||||
$this->curTimeout-= $elapsed;
|
||||
return $this->_get_binary_packet(true);
|
||||
}
|
||||
$elapsed = microtime(true) - $start;
|
||||
$this->curTimeout-= $elapsed;
|
||||
}
|
||||
|
||||
$sec = floor($this->curTimeout);
|
||||
$usec = 1000000 * ($this->curTimeout - $sec);
|
||||
|
||||
// on windows this returns a "Warning: Invalid CRT parameters detected" error
|
||||
if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {
|
||||
$this->is_timeout = true;
|
||||
return true;
|
||||
}
|
||||
$elapsed = microtime(true) - $start;
|
||||
$this->curTimeout-= $elapsed;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_resource($this->fsock) || feof($this->fsock)) {
|
||||
user_error('Connection closed prematurely');
|
||||
$this->bitmap = 0;
|
||||
user_error('Connection closed (by server) prematurely ' . $elapsed . 's');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -2923,6 +3475,9 @@ class SSH2
|
|||
return false;
|
||||
}
|
||||
|
||||
if (strlen($raw) < 5) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Npacket_length/Cpadding_length', $this->_string_shift($raw, 5)));
|
||||
|
||||
$remaining_length = $packet_length + 4 - $this->decrypt_block_size;
|
||||
|
|
@ -2931,6 +3486,11 @@ class SSH2
|
|||
// "implementations SHOULD check that the packet length is reasonable"
|
||||
// PuTTY uses 0x9000 as the actual max packet size and so to shall we
|
||||
if ($remaining_length < -$this->decrypt_block_size || $remaining_length > 0x9000 || $remaining_length % $this->decrypt_block_size != 0) {
|
||||
if (!$this->bad_key_size_fix && $this->_bad_algorithm_candidate($this->decrypt->name) && !($this->bitmap & SSH2::MASK_LOGIN)) {
|
||||
$this->bad_key_size_fix = true;
|
||||
$this->_reset_connection(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
||||
return false;
|
||||
}
|
||||
user_error('Invalid size');
|
||||
return false;
|
||||
}
|
||||
|
|
@ -2939,13 +3499,14 @@ class SSH2
|
|||
while ($remaining_length > 0) {
|
||||
$temp = stream_get_contents($this->fsock, $remaining_length);
|
||||
if ($temp === false || feof($this->fsock)) {
|
||||
user_error('Error reading from socket');
|
||||
$this->bitmap = 0;
|
||||
user_error('Error reading from socket');
|
||||
return false;
|
||||
}
|
||||
$buffer.= $temp;
|
||||
$remaining_length-= strlen($temp);
|
||||
}
|
||||
|
||||
$stop = microtime(true);
|
||||
if (strlen($buffer)) {
|
||||
$raw.= $this->decrypt !== false ? $this->decrypt->decrypt($buffer) : $buffer;
|
||||
|
|
@ -2957,8 +3518,8 @@ class SSH2
|
|||
if ($this->hmac_check !== false) {
|
||||
$hmac = stream_get_contents($this->fsock, $this->hmac_size);
|
||||
if ($hmac === false || strlen($hmac) != $this->hmac_size) {
|
||||
user_error('Error reading socket');
|
||||
$this->bitmap = 0;
|
||||
user_error('Error reading socket');
|
||||
return false;
|
||||
} elseif ($hmac != $this->hmac_check->hash(pack('NNCa*', $this->get_seq_no, $packet_length, $padding_length, $payload . $padding))) {
|
||||
user_error('Invalid HMAC');
|
||||
|
|
@ -2966,9 +3527,41 @@ class SSH2
|
|||
}
|
||||
}
|
||||
|
||||
//if ($this->decompress) {
|
||||
// $payload = gzinflate(substr($payload, 2));
|
||||
//}
|
||||
switch ($this->decompress) {
|
||||
case NET_SSH2_COMPRESSION_ZLIB_AT_OPENSSH:
|
||||
if (!$this->isAuthenticated()) {
|
||||
break;
|
||||
}
|
||||
case NET_SSH2_COMPRESSION_ZLIB:
|
||||
if ($this->regenerate_decompression_context) {
|
||||
$this->regenerate_decompression_context = false;
|
||||
|
||||
$cmf = ord($payload[0]);
|
||||
$cm = $cmf & 0x0F;
|
||||
if ($cm != 8) { // deflate
|
||||
user_error("Only CM = 8 ('deflate') is supported ($cm)");
|
||||
}
|
||||
$cinfo = ($cmf & 0xF0) >> 4;
|
||||
if ($cinfo > 7) {
|
||||
user_error("CINFO above 7 is not allowed ($cinfo)");
|
||||
}
|
||||
$windowSize = 1 << ($cinfo + 8);
|
||||
|
||||
$flg = ord($payload[1]);
|
||||
//$fcheck = $flg && 0x0F;
|
||||
if ((($cmf << 8) | $flg) % 31) {
|
||||
user_error('fcheck failed');
|
||||
}
|
||||
$fdict = boolval($flg & 0x20);
|
||||
$flevel = ($flg & 0xC0) >> 6;
|
||||
|
||||
$this->decompress_context = inflate_init(ZLIB_ENCODING_RAW, ['window' => $cinfo + 8]);
|
||||
$payload = substr($payload, 2);
|
||||
}
|
||||
if ($this->decompress_context) {
|
||||
$payload = inflate_add($this->decompress_context, $payload, ZLIB_PARTIAL_FLUSH);
|
||||
}
|
||||
}
|
||||
|
||||
$this->get_seq_no++;
|
||||
|
||||
|
|
@ -2981,7 +3574,7 @@ class SSH2
|
|||
$this->last_packet = $current;
|
||||
}
|
||||
|
||||
return $this->_filter($payload);
|
||||
return $this->_filter($payload, $skip_channel_filter);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2993,48 +3586,86 @@ class SSH2
|
|||
* @return string
|
||||
* @access private
|
||||
*/
|
||||
function _filter($payload)
|
||||
function _filter($payload, $skip_channel_filter)
|
||||
{
|
||||
switch (ord($payload[0])) {
|
||||
case NET_SSH2_MSG_DISCONNECT:
|
||||
$this->_string_shift($payload, 1);
|
||||
if (strlen($payload) < 8) {
|
||||
return false;
|
||||
}
|
||||
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;
|
||||
return false;
|
||||
case NET_SSH2_MSG_IGNORE:
|
||||
$payload = $this->_get_binary_packet();
|
||||
$payload = $this->_get_binary_packet($skip_channel_filter);
|
||||
break;
|
||||
case NET_SSH2_MSG_DEBUG:
|
||||
$this->_string_shift($payload, 2);
|
||||
if (strlen($payload) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nlength', $this->_string_shift($payload, 4)));
|
||||
$this->errors[] = 'SSH_MSG_DEBUG: ' . utf8_decode($this->_string_shift($payload, $length));
|
||||
$payload = $this->_get_binary_packet();
|
||||
$this->errors[] = 'SSH_MSG_DEBUG: ' . $this->_string_shift($payload, $length);
|
||||
$payload = $this->_get_binary_packet($skip_channel_filter);
|
||||
break;
|
||||
case NET_SSH2_MSG_UNIMPLEMENTED:
|
||||
return false;
|
||||
case NET_SSH2_MSG_KEXINIT:
|
||||
if ($this->session_id !== false) {
|
||||
$this->send_kex_first = false;
|
||||
if (!$this->_key_exchange($payload)) {
|
||||
$this->bitmap = 0;
|
||||
return false;
|
||||
}
|
||||
$payload = $this->_get_binary_packet();
|
||||
$payload = $this->_get_binary_packet($skip_channel_filter);
|
||||
}
|
||||
}
|
||||
|
||||
// see http://tools.ietf.org/html/rfc4252#section-5.4; only called when the encryption has been activated and when we haven't already logged in
|
||||
if (($this->bitmap & self::MASK_CONNECTED) && !($this->bitmap & self::MASK_LOGIN) && ord($payload[0]) == NET_SSH2_MSG_USERAUTH_BANNER) {
|
||||
if (($this->bitmap & self::MASK_CONNECTED) && !$this->isAuthenticated() && ord($payload[0]) == NET_SSH2_MSG_USERAUTH_BANNER) {
|
||||
$this->_string_shift($payload, 1);
|
||||
if (strlen($payload) < 4) {
|
||||
return false;
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
// only called when we've already logged in
|
||||
if (($this->bitmap & self::MASK_CONNECTED) && ($this->bitmap & self::MASK_LOGIN)) {
|
||||
if (($this->bitmap & self::MASK_CONNECTED) && $this->isAuthenticated()) {
|
||||
if (is_bool($payload)) {
|
||||
return $payload;
|
||||
}
|
||||
|
||||
switch (ord($payload[0])) {
|
||||
case NET_SSH2_MSG_CHANNEL_REQUEST:
|
||||
if (strlen($payload) == 31) {
|
||||
extract(unpack('cpacket_type/Nchannel/Nlength', $payload));
|
||||
if (substr($payload, 9, $length) == 'keepalive@openssh.com' && isset($this->server_channels[$channel])) {
|
||||
if (ord(substr($payload, 9 + $length))) { // want reply
|
||||
$this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_SUCCESS, $this->server_channels[$channel]));
|
||||
}
|
||||
$payload = $this->_get_binary_packet($skip_channel_filter);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NET_SSH2_MSG_CHANNEL_DATA:
|
||||
case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA:
|
||||
case NET_SSH2_MSG_CHANNEL_CLOSE:
|
||||
case NET_SSH2_MSG_CHANNEL_EOF:
|
||||
if (!$skip_channel_filter && !empty($this->server_channels)) {
|
||||
$this->binary_packet_buffer = $payload;
|
||||
$this->_get_channel_packet(true);
|
||||
$payload = $this->_get_binary_packet();
|
||||
}
|
||||
break;
|
||||
case NET_SSH2_MSG_GLOBAL_REQUEST: // see http://tools.ietf.org/html/rfc4254#section-4
|
||||
if (strlen($payload) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nlength', $this->_string_shift($payload, 4)));
|
||||
$this->errors[] = 'SSH_MSG_GLOBAL_REQUEST: ' . $this->_string_shift($payload, $length);
|
||||
|
||||
|
|
@ -3042,12 +3673,18 @@ class SSH2
|
|||
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
|
||||
}
|
||||
|
||||
$payload = $this->_get_binary_packet();
|
||||
$payload = $this->_get_binary_packet($skip_channel_filter);
|
||||
break;
|
||||
case NET_SSH2_MSG_CHANNEL_OPEN: // see http://tools.ietf.org/html/rfc4254#section-5.1
|
||||
$this->_string_shift($payload, 1);
|
||||
if (strlen($payload) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nlength', $this->_string_shift($payload, 4)));
|
||||
$data = $this->_string_shift($payload, $length);
|
||||
if (strlen($payload) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nserver_channel', $this->_string_shift($payload, 4)));
|
||||
switch ($data) {
|
||||
case 'auth-agent':
|
||||
|
|
@ -3055,6 +3692,9 @@ class SSH2
|
|||
if (isset($this->agent)) {
|
||||
$new_channel = self::CHANNEL_AGENT_FORWARD;
|
||||
|
||||
if (strlen($payload) < 8) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nremote_window_size', $this->_string_shift($payload, 4)));
|
||||
extract(unpack('Nremote_maximum_packet_size', $this->_string_shift($payload, 4)));
|
||||
|
||||
|
|
@ -3096,15 +3736,18 @@ class SSH2
|
|||
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
|
||||
}
|
||||
}
|
||||
$payload = $this->_get_binary_packet();
|
||||
$payload = $this->_get_binary_packet($skip_channel_filter);
|
||||
break;
|
||||
case NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST:
|
||||
$this->_string_shift($payload, 1);
|
||||
if (strlen($payload) < 8) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nchannel', $this->_string_shift($payload, 4)));
|
||||
extract(unpack('Nwindow_size', $this->_string_shift($payload, 4)));
|
||||
$this->window_size_client_to_server[$channel]+= $window_size;
|
||||
|
||||
$payload = ($this->bitmap & self::MASK_WINDOW_ADJUST) ? true : $this->_get_binary_packet();
|
||||
$payload = ($this->bitmap & self::MASK_WINDOW_ADJUST) ? true : $this->_get_binary_packet($skip_channel_filter);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3165,6 +3808,10 @@ class SSH2
|
|||
*/
|
||||
function disablePTY()
|
||||
{
|
||||
if ($this->in_request_pty_exec) {
|
||||
$this->_close_channel(self::CHANNEL_EXEC);
|
||||
$this->in_request_pty_exec = false;
|
||||
}
|
||||
$this->request_pty = false;
|
||||
}
|
||||
|
||||
|
|
@ -3186,52 +3833,60 @@ class SSH2
|
|||
*
|
||||
* Returns the data as a string if it's available and false if not.
|
||||
*
|
||||
* @param $client_channel
|
||||
* @return mixed
|
||||
* @param int $client_channel
|
||||
* @param bool $skip_extended
|
||||
* @return mixed|bool
|
||||
* @access private
|
||||
*/
|
||||
function _get_channel_packet($client_channel, $skip_extended = false)
|
||||
{
|
||||
if (!empty($this->channel_buffers[$client_channel])) {
|
||||
return array_shift($this->channel_buffers[$client_channel]);
|
||||
switch ($this->channel_status[$client_channel]) {
|
||||
case NET_SSH2_MSG_CHANNEL_REQUEST:
|
||||
foreach ($this->channel_buffers[$client_channel] as $i => $packet) {
|
||||
switch (ord($packet[0])) {
|
||||
case NET_SSH2_MSG_CHANNEL_SUCCESS:
|
||||
case NET_SSH2_MSG_CHANNEL_FAILURE:
|
||||
unset($this->channel_buffers[$client_channel][$i]);
|
||||
return substr($packet, 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return substr(array_shift($this->channel_buffers[$client_channel]), 1);
|
||||
}
|
||||
}
|
||||
|
||||
while (true) {
|
||||
if ($this->curTimeout) {
|
||||
if ($this->curTimeout < 0) {
|
||||
$this->is_timeout = true;
|
||||
if ($this->binary_packet_buffer !== false) {
|
||||
$response = $this->binary_packet_buffer;
|
||||
$this->binary_packet_buffer = false;
|
||||
} else {
|
||||
$response = $this->_get_binary_packet(true);
|
||||
if ($response === true && $this->is_timeout) {
|
||||
if ($client_channel == self::CHANNEL_EXEC && !$this->request_pty) {
|
||||
$this->_close_channel($client_channel);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
$read = array($this->fsock);
|
||||
$write = $except = null;
|
||||
|
||||
$start = microtime(true);
|
||||
$sec = floor($this->curTimeout);
|
||||
$usec = 1000000 * ($this->curTimeout - $sec);
|
||||
// on windows this returns a "Warning: Invalid CRT parameters detected" error
|
||||
if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {
|
||||
$this->is_timeout = true;
|
||||
return true;
|
||||
if ($response === false) {
|
||||
$this->bitmap = 0;
|
||||
user_error('Connection closed by server');
|
||||
return false;
|
||||
}
|
||||
$elapsed = microtime(true) - $start;
|
||||
$this->curTimeout-= $elapsed;
|
||||
}
|
||||
|
||||
$response = $this->_get_binary_packet();
|
||||
if ($response === false) {
|
||||
user_error('Connection closed by server');
|
||||
return false;
|
||||
}
|
||||
if ($client_channel == -1 && $response === true) {
|
||||
return true;
|
||||
}
|
||||
if (!strlen($response)) {
|
||||
return '';
|
||||
return false;
|
||||
}
|
||||
|
||||
extract(unpack('Ctype', $this->_string_shift($response, 1)));
|
||||
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
if ($type == NET_SSH2_MSG_CHANNEL_OPEN) {
|
||||
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
||||
} else {
|
||||
|
|
@ -3244,34 +3899,123 @@ class SSH2
|
|||
|
||||
// resize the window, if appropriate
|
||||
if ($this->window_size_server_to_client[$channel] < 0) {
|
||||
$packet = pack('CNN', NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST, $this->server_channels[$channel], $this->window_size);
|
||||
// PuTTY does something more analogous to the following:
|
||||
//if ($this->window_size_server_to_client[$channel] < 0x3FFFFFFF) {
|
||||
$packet = pack('CNN', NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST, $this->server_channels[$channel], $this->window_resize);
|
||||
if (!$this->_send_binary_packet($packet)) {
|
||||
return false;
|
||||
}
|
||||
$this->window_size_server_to_client[$channel]+= $this->window_size;
|
||||
$this->window_size_server_to_client[$channel]+= $this->window_resize;
|
||||
}
|
||||
|
||||
switch ($type) {
|
||||
case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA:
|
||||
/*
|
||||
if ($client_channel == self::CHANNEL_EXEC) {
|
||||
$this->_send_channel_packet($client_channel, chr(0));
|
||||
}
|
||||
*/
|
||||
// currently, there's only one possible value for $data_type_code: NET_SSH2_EXTENDED_DATA_STDERR
|
||||
if (strlen($response) < 8) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Ndata_type_code/Nlength', $this->_string_shift($response, 8)));
|
||||
$data = $this->_string_shift($response, $length);
|
||||
$this->stdErrorLog.= $data;
|
||||
if ($skip_extended || $this->quiet_mode) {
|
||||
continue 2;
|
||||
}
|
||||
if ($client_channel == $channel && $this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_DATA) {
|
||||
return $data;
|
||||
}
|
||||
$this->channel_buffers[$channel][] = chr($type) . $data;
|
||||
|
||||
continue 2;
|
||||
case NET_SSH2_MSG_CHANNEL_REQUEST:
|
||||
if ($this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_CLOSE) {
|
||||
continue 2;
|
||||
}
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
||||
$value = $this->_string_shift($response, $length);
|
||||
switch ($value) {
|
||||
case 'exit-signal':
|
||||
$this->_string_shift($response, 1);
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
||||
$this->errors[] = 'SSH_MSG_CHANNEL_REQUEST (exit-signal): ' . $this->_string_shift($response, $length);
|
||||
$this->_string_shift($response, 1);
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
||||
if ($length) {
|
||||
$this->errors[count($this->errors)].= "\r\n" . $this->_string_shift($response, $length);
|
||||
}
|
||||
|
||||
$this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$client_channel]));
|
||||
$this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel]));
|
||||
|
||||
$this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_EOF;
|
||||
|
||||
continue 3;
|
||||
case 'exit-status':
|
||||
if (strlen($response) < 5) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Cfalse/Nexit_status', $this->_string_shift($response, 5)));
|
||||
$this->exit_status = $exit_status;
|
||||
|
||||
// "The client MAY ignore these messages."
|
||||
// -- http://tools.ietf.org/html/rfc4254#section-6.10
|
||||
|
||||
continue 3;
|
||||
default:
|
||||
// "Some systems may not implement signals, in which case they SHOULD ignore this message."
|
||||
// -- http://tools.ietf.org/html/rfc4254#section-6.9
|
||||
continue 3;
|
||||
}
|
||||
}
|
||||
|
||||
switch ($this->channel_status[$channel]) {
|
||||
case NET_SSH2_MSG_CHANNEL_OPEN:
|
||||
switch ($type) {
|
||||
case NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION:
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nserver_channel', $this->_string_shift($response, 4)));
|
||||
$this->server_channels[$channel] = $server_channel;
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nwindow_size', $this->_string_shift($response, 4)));
|
||||
if ($window_size < 0) {
|
||||
$window_size&= 0x7FFFFFFF;
|
||||
$window_size+= 0x80000000;
|
||||
}
|
||||
$this->window_size_client_to_server[$channel] = $window_size;
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
$temp = unpack('Npacket_size_client_to_server', $this->_string_shift($response, 4));
|
||||
$this->packet_size_client_to_server[$channel] = $temp['packet_size_client_to_server'];
|
||||
$result = $client_channel == $channel ? true : $this->_get_channel_packet($client_channel, $skip_extended);
|
||||
$this->_on_channel_open();
|
||||
return $result;
|
||||
//case NET_SSH2_MSG_CHANNEL_OPEN_FAILURE:
|
||||
default:
|
||||
case NET_SSH2_MSG_CHANNEL_OPEN_FAILURE:
|
||||
user_error('Unable to open channel');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
|
||||
default:
|
||||
if ($client_channel == $channel) {
|
||||
user_error('Unexpected response to open request');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
|
||||
}
|
||||
return $this->_get_channel_packet($client_channel, $skip_extended);
|
||||
}
|
||||
break;
|
||||
case NET_SSH2_MSG_CHANNEL_REQUEST:
|
||||
|
|
@ -3280,6 +4024,14 @@ class SSH2
|
|||
return true;
|
||||
case NET_SSH2_MSG_CHANNEL_FAILURE:
|
||||
return false;
|
||||
case NET_SSH2_MSG_CHANNEL_DATA:
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
||||
$data = $this->_string_shift($response, $length);
|
||||
$this->channel_buffers[$channel][] = chr($type) . $data;
|
||||
return $this->_get_channel_packet($client_channel, $skip_extended);
|
||||
default:
|
||||
user_error('Unable to fulfill channel request');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
|
||||
|
|
@ -3302,6 +4054,9 @@ class SSH2
|
|||
$this->_send_channel_packet($channel, chr(0));
|
||||
}
|
||||
*/
|
||||
if (strlen($response) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
||||
$data = $this->_string_shift($response, $length);
|
||||
|
||||
|
|
@ -3316,68 +4071,10 @@ class SSH2
|
|||
if ($client_channel == $channel) {
|
||||
return $data;
|
||||
}
|
||||
if (!isset($this->channel_buffers[$channel])) {
|
||||
$this->channel_buffers[$channel] = array();
|
||||
}
|
||||
$this->channel_buffers[$channel][] = $data;
|
||||
break;
|
||||
case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA:
|
||||
/*
|
||||
if ($client_channel == self::CHANNEL_EXEC) {
|
||||
$this->_send_channel_packet($client_channel, chr(0));
|
||||
}
|
||||
*/
|
||||
// currently, there's only one possible value for $data_type_code: NET_SSH2_EXTENDED_DATA_STDERR
|
||||
extract(unpack('Ndata_type_code/Nlength', $this->_string_shift($response, 8)));
|
||||
$data = $this->_string_shift($response, $length);
|
||||
$this->stdErrorLog.= $data;
|
||||
if ($skip_extended || $this->quiet_mode) {
|
||||
break;
|
||||
}
|
||||
if ($client_channel == $channel) {
|
||||
return $data;
|
||||
}
|
||||
if (!isset($this->channel_buffers[$channel])) {
|
||||
$this->channel_buffers[$channel] = array();
|
||||
}
|
||||
$this->channel_buffers[$channel][] = $data;
|
||||
break;
|
||||
case NET_SSH2_MSG_CHANNEL_REQUEST:
|
||||
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
||||
$value = $this->_string_shift($response, $length);
|
||||
switch ($value) {
|
||||
case 'exit-signal':
|
||||
$this->_string_shift($response, 1);
|
||||
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
||||
$this->errors[] = 'SSH_MSG_CHANNEL_REQUEST (exit-signal): ' . $this->_string_shift($response, $length);
|
||||
$this->_string_shift($response, 1);
|
||||
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
||||
if ($length) {
|
||||
$this->errors[count($this->errors)].= "\r\n" . $this->_string_shift($response, $length);
|
||||
}
|
||||
|
||||
$this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$client_channel]));
|
||||
$this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel]));
|
||||
|
||||
$this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_EOF;
|
||||
|
||||
break;
|
||||
case 'exit-status':
|
||||
extract(unpack('Cfalse/Nexit_status', $this->_string_shift($response, 5)));
|
||||
$this->exit_status = $exit_status;
|
||||
|
||||
// "The client MAY ignore these messages."
|
||||
// -- http://tools.ietf.org/html/rfc4254#section-6.10
|
||||
|
||||
break;
|
||||
default:
|
||||
// "Some systems may not implement signals, in which case they SHOULD ignore this message."
|
||||
// -- http://tools.ietf.org/html/rfc4254#section-6.9
|
||||
break;
|
||||
}
|
||||
$this->channel_buffers[$channel][] = chr($type) . $data;
|
||||
break;
|
||||
case NET_SSH2_MSG_CHANNEL_CLOSE:
|
||||
$this->curTimeout = 0;
|
||||
$this->curTimeout = 5;
|
||||
|
||||
if ($this->bitmap & self::MASK_SHELL) {
|
||||
$this->bitmap&= ~self::MASK_SHELL;
|
||||
|
|
@ -3393,7 +4090,7 @@ class SSH2
|
|||
case NET_SSH2_MSG_CHANNEL_EOF:
|
||||
break;
|
||||
default:
|
||||
user_error('Error reading channel data');
|
||||
user_error("Error reading channel data ($type)");
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
|
||||
}
|
||||
}
|
||||
|
|
@ -3413,16 +4110,32 @@ class SSH2
|
|||
function _send_binary_packet($data, $logged = null)
|
||||
{
|
||||
if (!is_resource($this->fsock) || feof($this->fsock)) {
|
||||
user_error('Connection closed prematurely');
|
||||
$this->bitmap = 0;
|
||||
user_error('Connection closed prematurely');
|
||||
return false;
|
||||
}
|
||||
|
||||
//if ($this->compress) {
|
||||
// // the -4 removes the checksum:
|
||||
// // http://php.net/function.gzcompress#57710
|
||||
// $data = substr(gzcompress($data), 0, -4);
|
||||
//}
|
||||
if (!isset($logged)) {
|
||||
$logged = $data;
|
||||
}
|
||||
|
||||
switch ($this->compress) {
|
||||
case NET_SSH2_COMPRESSION_ZLIB_AT_OPENSSH:
|
||||
if (!$this->isAuthenticated()) {
|
||||
break;
|
||||
}
|
||||
case NET_SSH2_COMPRESSION_ZLIB:
|
||||
if (!$this->regenerate_compression_context) {
|
||||
$header = '';
|
||||
} else {
|
||||
$this->regenerate_compression_context = false;
|
||||
$this->compress_context = deflate_init(ZLIB_ENCODING_RAW, ['window' => 15]);
|
||||
$header = "\x78\x9C";
|
||||
}
|
||||
if ($this->compress_context) {
|
||||
$data = $header . deflate_add($this->compress_context, $data, ZLIB_PARTIAL_FLUSH);
|
||||
}
|
||||
}
|
||||
|
||||
// 4 (packet length) + 1 (padding length) + 4 (minimal padding amount) == 9
|
||||
$packet_length = strlen($data) + 9;
|
||||
|
|
@ -3445,15 +4158,15 @@ class SSH2
|
|||
$packet.= $hmac;
|
||||
|
||||
$start = microtime(true);
|
||||
$result = strlen($packet) == fputs($this->fsock, $packet);
|
||||
$result = strlen($packet) == @fputs($this->fsock, $packet);
|
||||
$stop = microtime(true);
|
||||
|
||||
if (defined('NET_SSH2_LOGGING')) {
|
||||
$current = microtime(true);
|
||||
$message_number = isset($this->message_numbers[ord($data[0])]) ? $this->message_numbers[ord($data[0])] : 'UNKNOWN (' . ord($data[0]) . ')';
|
||||
$message_number = isset($this->message_numbers[ord($logged[0])]) ? $this->message_numbers[ord($logged[0])] : 'UNKNOWN (' . ord($logged[0]) . ')';
|
||||
$message_number = '-> ' . $message_number .
|
||||
' (since last: ' . round($current - $this->last_packet, 4) . ', network: ' . round($stop - $start, 4) . 's)';
|
||||
$this->_append_log($message_number, isset($logged) ? $logged : $data);
|
||||
$this->_append_log($message_number, $logged);
|
||||
$this->last_packet = $current;
|
||||
}
|
||||
|
||||
|
|
@ -3465,7 +4178,8 @@ class SSH2
|
|||
*
|
||||
* Makes sure that only the last 1MB worth of packets will be logged
|
||||
*
|
||||
* @param string $data
|
||||
* @param string $message_number
|
||||
* @param string $message
|
||||
* @access private
|
||||
*/
|
||||
function _append_log($message_number, $message)
|
||||
|
|
@ -3606,11 +4320,15 @@ class SSH2
|
|||
|
||||
$this->channel_status[$client_channel] = NET_SSH2_MSG_CHANNEL_CLOSE;
|
||||
|
||||
$this->curTimeout = 0;
|
||||
$this->curTimeout = 5;
|
||||
|
||||
while (!is_bool($this->_get_channel_packet($client_channel))) {
|
||||
}
|
||||
|
||||
if ($this->is_timeout) {
|
||||
$this->disconnect();
|
||||
}
|
||||
|
||||
if ($want_reply) {
|
||||
$this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$client_channel]));
|
||||
}
|
||||
|
|
@ -3632,10 +4350,14 @@ class SSH2
|
|||
if ($this->bitmap & self::MASK_CONNECTED) {
|
||||
$data = pack('CNNa*Na*', NET_SSH2_MSG_DISCONNECT, $reason, 0, '', 0, '');
|
||||
$this->_send_binary_packet($data);
|
||||
$this->bitmap = 0;
|
||||
fclose($this->fsock);
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->bitmap = 0;
|
||||
if (is_resource($this->fsock) && get_resource_type($this->fsock) == 'stream') {
|
||||
fclose($this->fsock);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -3662,7 +4384,6 @@ class SSH2
|
|||
* named constants from it, using the value as the name of the constant and the index as the value of the constant.
|
||||
* If any of the constants that would be defined already exists, none of the constants will be defined.
|
||||
*
|
||||
* @param array $array
|
||||
* @access private
|
||||
*/
|
||||
function _define_array()
|
||||
|
|
@ -3696,10 +4417,9 @@ class SSH2
|
|||
switch (NET_SSH2_LOGGING) {
|
||||
case self::LOG_SIMPLE:
|
||||
return $this->message_number_log;
|
||||
break;
|
||||
case self::LOG_COMPLEX:
|
||||
return $this->_format_log($this->message_log, $this->message_number_log);
|
||||
break;
|
||||
$log = $this->_format_log($this->message_log, $this->message_number_log);
|
||||
return PHP_SAPI == 'cli' ? $log : '<pre>' . $log . '</pre>';
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
@ -3957,6 +4677,318 @@ class SSH2
|
|||
return $this->languages_client_to_server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of algorithms the server supports
|
||||
*
|
||||
* @return array
|
||||
* @access public
|
||||
*/
|
||||
function getServerAlgorithms()
|
||||
{
|
||||
$this->_connect();
|
||||
|
||||
return array(
|
||||
'kex' => $this->kex_algorithms,
|
||||
'hostkey' => $this->server_host_key_algorithms,
|
||||
'client_to_server' => array(
|
||||
'crypt' => $this->encryption_algorithms_client_to_server,
|
||||
'mac' => $this->mac_algorithms_client_to_server,
|
||||
'comp' => $this->compression_algorithms_client_to_server,
|
||||
'lang' => $this->languages_client_to_server
|
||||
),
|
||||
'server_to_client' => array(
|
||||
'crypt' => $this->encryption_algorithms_server_to_client,
|
||||
'mac' => $this->mac_algorithms_server_to_client,
|
||||
'comp' => $this->compression_algorithms_server_to_client,
|
||||
'lang' => $this->languages_server_to_client
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of KEX algorithms that phpseclib supports
|
||||
*
|
||||
* @return array
|
||||
* @access public
|
||||
*/
|
||||
function getSupportedKEXAlgorithms()
|
||||
{
|
||||
$kex_algorithms = array(
|
||||
// Elliptic Curve Diffie-Hellman Key Agreement (ECDH) using
|
||||
// Curve25519. See doc/curve25519-sha256@libssh.org.txt in the
|
||||
// libssh repository for more information.
|
||||
'curve25519-sha256@libssh.org',
|
||||
|
||||
'diffie-hellman-group-exchange-sha256',// RFC 4419
|
||||
'diffie-hellman-group-exchange-sha1', // RFC 4419
|
||||
|
||||
// Diffie-Hellman Key Agreement (DH) using integer modulo prime
|
||||
// groups.
|
||||
'diffie-hellman-group14-sha1', // REQUIRED
|
||||
'diffie-hellman-group1-sha1', // REQUIRED
|
||||
);
|
||||
|
||||
if (!function_exists('sodium_crypto_box_publickey_from_secretkey')) {
|
||||
$kex_algorithms = array_diff(
|
||||
$kex_algorithms,
|
||||
array('curve25519-sha256@libssh.org')
|
||||
);
|
||||
}
|
||||
|
||||
return $kex_algorithms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of host key algorithms that phpseclib supports
|
||||
*
|
||||
* @return array
|
||||
* @access public
|
||||
*/
|
||||
function getSupportedHostKeyAlgorithms()
|
||||
{
|
||||
return array(
|
||||
'rsa-sha2-256', // RFC 8332
|
||||
'rsa-sha2-512', // RFC 8332
|
||||
'ssh-rsa', // RECOMMENDED sign Raw RSA Key
|
||||
'ssh-dss' // REQUIRED sign Raw DSS Key
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of symmetric key algorithms that phpseclib supports
|
||||
*
|
||||
* @return array
|
||||
* @access public
|
||||
*/
|
||||
function getSupportedEncryptionAlgorithms()
|
||||
{
|
||||
$algos = array(
|
||||
// from <http://tools.ietf.org/html/rfc4345#section-4>:
|
||||
'arcfour256',
|
||||
'arcfour128',
|
||||
|
||||
//'arcfour', // OPTIONAL the ARCFOUR stream cipher with a 128-bit key
|
||||
|
||||
// CTR modes from <http://tools.ietf.org/html/rfc4344#section-4>:
|
||||
'aes128-ctr', // RECOMMENDED AES (Rijndael) in SDCTR mode, with 128-bit key
|
||||
'aes192-ctr', // RECOMMENDED AES with 192-bit key
|
||||
'aes256-ctr', // RECOMMENDED AES with 256-bit key
|
||||
|
||||
'twofish128-ctr', // OPTIONAL Twofish in SDCTR mode, with 128-bit key
|
||||
'twofish192-ctr', // OPTIONAL Twofish with 192-bit key
|
||||
'twofish256-ctr', // OPTIONAL Twofish with 256-bit key
|
||||
|
||||
'aes128-cbc', // RECOMMENDED AES with a 128-bit key
|
||||
'aes192-cbc', // OPTIONAL AES with a 192-bit key
|
||||
'aes256-cbc', // OPTIONAL AES in CBC mode, with a 256-bit key
|
||||
|
||||
'twofish128-cbc', // OPTIONAL Twofish with a 128-bit key
|
||||
'twofish192-cbc', // OPTIONAL Twofish with a 192-bit key
|
||||
'twofish256-cbc',
|
||||
'twofish-cbc', // OPTIONAL alias for "twofish256-cbc"
|
||||
// (this is being retained for historical reasons)
|
||||
|
||||
'blowfish-ctr', // OPTIONAL Blowfish in SDCTR mode
|
||||
|
||||
'blowfish-cbc', // OPTIONAL Blowfish in CBC mode
|
||||
|
||||
'3des-ctr', // RECOMMENDED Three-key 3DES in SDCTR mode
|
||||
|
||||
'3des-cbc', // REQUIRED three-key 3DES in CBC mode
|
||||
|
||||
//'none' // OPTIONAL no encryption; NOT RECOMMENDED
|
||||
);
|
||||
|
||||
if ($this->crypto_engine) {
|
||||
$engines = array($this->crypto_engine);
|
||||
} else {
|
||||
$engines = array(
|
||||
Base::ENGINE_OPENSSL,
|
||||
Base::ENGINE_MCRYPT,
|
||||
Base::ENGINE_INTERNAL
|
||||
);
|
||||
}
|
||||
|
||||
$ciphers = array();
|
||||
foreach ($engines as $engine) {
|
||||
foreach ($algos as $algo) {
|
||||
$obj = $this->_encryption_algorithm_to_crypt_instance($algo);
|
||||
if ($obj instanceof Rijndael) {
|
||||
$obj->setKeyLength(preg_replace('#[^\d]#', '', $algo));
|
||||
}
|
||||
switch ($algo) {
|
||||
case 'arcfour128':
|
||||
case 'arcfour256':
|
||||
if ($engine != Base::ENGINE_INTERNAL) {
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
if ($obj->isValidEngine($engine)) {
|
||||
$algos = array_diff($algos, array($algo));
|
||||
$ciphers[] = $algo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $ciphers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of MAC algorithms that phpseclib supports
|
||||
*
|
||||
* @return array
|
||||
* @access public
|
||||
*/
|
||||
function getSupportedMACAlgorithms()
|
||||
{
|
||||
return array(
|
||||
// from <http://www.ietf.org/rfc/rfc6668.txt>:
|
||||
'hmac-sha2-256',// RECOMMENDED HMAC-SHA256 (digest length = key length = 32)
|
||||
|
||||
'hmac-sha1-96', // RECOMMENDED first 96 bits of HMAC-SHA1 (digest length = 12, key length = 20)
|
||||
'hmac-sha1', // REQUIRED HMAC-SHA1 (digest length = key length = 20)
|
||||
'hmac-md5-96', // OPTIONAL first 96 bits of HMAC-MD5 (digest length = 12, key length = 16)
|
||||
'hmac-md5', // OPTIONAL HMAC-MD5 (digest length = key length = 16)
|
||||
//'none' // OPTIONAL no MAC; NOT RECOMMENDED
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of compression algorithms that phpseclib supports
|
||||
*
|
||||
* @return array
|
||||
* @access public
|
||||
*/
|
||||
function getSupportedCompressionAlgorithms()
|
||||
{
|
||||
$algos = array('none'); // REQUIRED no compression
|
||||
if (function_exists('deflate_init')) {
|
||||
$algos[] = 'zlib@openssh.com'; // https://datatracker.ietf.org/doc/html/draft-miller-secsh-compression-delayed
|
||||
$algos[] = 'zlib';
|
||||
}
|
||||
return $algos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return list of negotiated algorithms
|
||||
*
|
||||
* Uses the same format as https://www.php.net/ssh2-methods-negotiated
|
||||
*
|
||||
* @return array
|
||||
* @access public
|
||||
*/
|
||||
function getAlgorithmsNegotiated()
|
||||
{
|
||||
$this->_connect();
|
||||
|
||||
$compression_map = array(
|
||||
NET_SSH2_COMPRESSION_NONE => 'none',
|
||||
NET_SSH2_COMPRESSION_ZLIB => 'zlib',
|
||||
NET_SSH2_COMPRESSION_ZLIB_AT_OPENSSH => 'zlib@openssh.com'
|
||||
);
|
||||
|
||||
return array(
|
||||
'kex' => $this->kex_algorithm,
|
||||
'hostkey' => $this->signature_format,
|
||||
'client_to_server' => array(
|
||||
'crypt' => $this->encrypt->name,
|
||||
'mac' => $this->hmac_create->name,
|
||||
'comp' => $compression_map[$this->compress],
|
||||
),
|
||||
'server_to_client' => array(
|
||||
'crypt' => $this->decrypt->name,
|
||||
'mac' => $this->hmac_check->name,
|
||||
'comp' => $compression_map[$this->decompress],
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts an associative array with up to four parameters as described at
|
||||
* <https://www.php.net/manual/en/function.ssh2-connect.php>
|
||||
*
|
||||
* @param array $methods
|
||||
* @access public
|
||||
*/
|
||||
function setPreferredAlgorithms($methods)
|
||||
{
|
||||
$preferred = $methods;
|
||||
|
||||
if (isset($preferred['kex'])) {
|
||||
$preferred['kex'] = array_intersect(
|
||||
$preferred['kex'],
|
||||
$this->getSupportedKEXAlgorithms()
|
||||
);
|
||||
}
|
||||
|
||||
if (isset($preferred['hostkey'])) {
|
||||
$preferred['hostkey'] = array_intersect(
|
||||
$preferred['hostkey'],
|
||||
$this->getSupportedHostKeyAlgorithms()
|
||||
);
|
||||
}
|
||||
|
||||
$keys = array('client_to_server', 'server_to_client');
|
||||
foreach ($keys as $key) {
|
||||
if (isset($preferred[$key])) {
|
||||
$a = &$preferred[$key];
|
||||
if (isset($a['crypt'])) {
|
||||
$a['crypt'] = array_intersect(
|
||||
$a['crypt'],
|
||||
$this->getSupportedEncryptionAlgorithms()
|
||||
);
|
||||
}
|
||||
if (isset($a['comp'])) {
|
||||
$a['comp'] = array_intersect(
|
||||
$a['comp'],
|
||||
$this->getSupportedCompressionAlgorithms()
|
||||
);
|
||||
}
|
||||
if (isset($a['mac'])) {
|
||||
$a['mac'] = array_intersect(
|
||||
$a['mac'],
|
||||
$this->getSupportedMACAlgorithms()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$keys = array(
|
||||
'kex',
|
||||
'hostkey',
|
||||
'client_to_server/crypt',
|
||||
'client_to_server/comp',
|
||||
'client_to_server/mac',
|
||||
'server_to_client/crypt',
|
||||
'server_to_client/comp',
|
||||
'server_to_client/mac',
|
||||
);
|
||||
foreach ($keys as $key) {
|
||||
$p = $preferred;
|
||||
$m = $methods;
|
||||
|
||||
$subkeys = explode('/', $key);
|
||||
foreach ($subkeys as $subkey) {
|
||||
if (!isset($p[$subkey])) {
|
||||
continue 2;
|
||||
}
|
||||
$p = $p[$subkey];
|
||||
$m = $m[$subkey];
|
||||
}
|
||||
|
||||
if (count($p) != count($m)) {
|
||||
$diff = array_diff($m, $p);
|
||||
$msg = count($diff) == 1 ?
|
||||
' is not a supported algorithm' :
|
||||
' are not supported algorithms';
|
||||
user_error(implode(', ', $diff) . $msg);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$this->preferred = $preferred;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the banner message.
|
||||
*
|
||||
|
|
@ -3991,6 +5023,9 @@ class SSH2
|
|||
$signature = $this->signature;
|
||||
$server_public_host_key = $this->server_public_host_key;
|
||||
|
||||
if (strlen($server_public_host_key) < 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nlength', $this->_string_shift($server_public_host_key, 4)));
|
||||
$this->_string_shift($server_public_host_key, $length);
|
||||
|
||||
|
|
@ -4006,15 +5041,27 @@ class SSH2
|
|||
case 'ssh-dss':
|
||||
$zero = new BigInteger();
|
||||
|
||||
if (strlen($server_public_host_key) < 4) {
|
||||
return false;
|
||||
}
|
||||
$temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
|
||||
$p = new BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
|
||||
|
||||
if (strlen($server_public_host_key) < 4) {
|
||||
return false;
|
||||
}
|
||||
$temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
|
||||
$q = new BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
|
||||
|
||||
if (strlen($server_public_host_key) < 4) {
|
||||
return false;
|
||||
}
|
||||
$temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
|
||||
$g = new BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
|
||||
|
||||
if (strlen($server_public_host_key) < 4) {
|
||||
return false;
|
||||
}
|
||||
$temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
|
||||
$y = new BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
|
||||
|
||||
|
|
@ -4061,27 +5108,54 @@ class SSH2
|
|||
|
||||
break;
|
||||
case 'ssh-rsa':
|
||||
case 'rsa-sha2-256':
|
||||
case 'rsa-sha2-512':
|
||||
if (strlen($server_public_host_key) < 4) {
|
||||
return false;
|
||||
}
|
||||
$temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
|
||||
$e = new BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
|
||||
|
||||
if (strlen($server_public_host_key) < 4) {
|
||||
return false;
|
||||
}
|
||||
$temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
|
||||
$rawN = $this->_string_shift($server_public_host_key, $temp['length']);
|
||||
$n = new BigInteger($rawN, -256);
|
||||
$nLength = strlen(ltrim($rawN, "\0"));
|
||||
|
||||
/*
|
||||
if (strlen($signature) < 4) {
|
||||
return false;
|
||||
}
|
||||
$temp = unpack('Nlength', $this->_string_shift($signature, 4));
|
||||
$signature = $this->_string_shift($signature, $temp['length']);
|
||||
|
||||
$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->loadKey(array('e' => $e, 'n' => $n), RSA::PUBLIC_FORMAT_RAW);
|
||||
|
||||
if (!$rsa->verify($this->exchange_hash, $signature)) {
|
||||
user_error('Bad server signature');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
|
||||
}
|
||||
*/
|
||||
|
||||
if (strlen($signature) < 4) {
|
||||
return false;
|
||||
}
|
||||
$temp = unpack('Nlength', $this->_string_shift($signature, 4));
|
||||
$s = new BigInteger($this->_string_shift($signature, $temp['length']), 256);
|
||||
|
||||
|
|
@ -4099,7 +5173,30 @@ class SSH2
|
|||
$s = $s->modPow($e, $n);
|
||||
$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;
|
||||
|
||||
if ($s != $h) {
|
||||
|
|
@ -4185,4 +5282,33 @@ class SSH2
|
|||
$this->windowColumns = $columns;
|
||||
$this->windowRows = $rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update packet types in log history
|
||||
*
|
||||
* @param string $old
|
||||
* @param string $new
|
||||
* @access private
|
||||
*/
|
||||
function _updateLogHistory($old, $new)
|
||||
{
|
||||
if (defined('NET_SSH2_LOGGING') && NET_SSH2_LOGGING == self::LOG_COMPLEX) {
|
||||
$this->message_number_log[count($this->message_number_log) - 1] = str_replace(
|
||||
$old,
|
||||
$new,
|
||||
$this->message_number_log[count($this->message_number_log) - 1]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of authentication methods that may productively continue authentication.
|
||||
*
|
||||
* @see https://tools.ietf.org/html/rfc4252#section-5.1
|
||||
* @return array|null
|
||||
*/
|
||||
function getAuthMethodsToContinue()
|
||||
{
|
||||
return $this->auth_methods_to_continue;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ use phpseclib\System\SSH\Agent\Identity;
|
|||
*
|
||||
* @package SSH\Agent
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access internal
|
||||
* @access public
|
||||
*/
|
||||
class Agent
|
||||
{
|
||||
|
|
@ -117,18 +117,20 @@ class Agent
|
|||
* @return \phpseclib\System\SSH\Agent
|
||||
* @access public
|
||||
*/
|
||||
function __construct()
|
||||
function __construct($address = null)
|
||||
{
|
||||
switch (true) {
|
||||
case isset($_SERVER['SSH_AUTH_SOCK']):
|
||||
$address = $_SERVER['SSH_AUTH_SOCK'];
|
||||
break;
|
||||
case isset($_ENV['SSH_AUTH_SOCK']):
|
||||
$address = $_ENV['SSH_AUTH_SOCK'];
|
||||
break;
|
||||
default:
|
||||
user_error('SSH_AUTH_SOCK not found');
|
||||
return false;
|
||||
if (!$address) {
|
||||
switch (true) {
|
||||
case isset($_SERVER['SSH_AUTH_SOCK']):
|
||||
$address = $_SERVER['SSH_AUTH_SOCK'];
|
||||
break;
|
||||
case isset($_ENV['SSH_AUTH_SOCK']):
|
||||
$address = $_ENV['SSH_AUTH_SOCK'];
|
||||
break;
|
||||
default:
|
||||
user_error('SSH_AUTH_SOCK not found');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$this->fsock = fsockopen('unix://' . $address, 0, $errno, $errstr);
|
||||
|
|
@ -155,23 +157,54 @@ class Agent
|
|||
$packet = pack('NC', 1, self::SSH_AGENTC_REQUEST_IDENTITIES);
|
||||
if (strlen($packet) != fputs($this->fsock, $packet)) {
|
||||
user_error('Connection closed while requesting identities');
|
||||
return array();
|
||||
}
|
||||
|
||||
$length = current(unpack('N', fread($this->fsock, 4)));
|
||||
$temp = fread($this->fsock, 4);
|
||||
if (strlen($temp) != 4) {
|
||||
user_error('Connection closed while requesting identities');
|
||||
return array();
|
||||
}
|
||||
$length = current(unpack('N', $temp));
|
||||
$type = ord(fread($this->fsock, 1));
|
||||
if ($type != self::SSH_AGENT_IDENTITIES_ANSWER) {
|
||||
user_error('Unable to request identities');
|
||||
return array();
|
||||
}
|
||||
|
||||
$identities = array();
|
||||
$keyCount = current(unpack('N', fread($this->fsock, 4)));
|
||||
$temp = fread($this->fsock, 4);
|
||||
if (strlen($temp) != 4) {
|
||||
user_error('Connection closed while requesting identities');
|
||||
return array();
|
||||
}
|
||||
$keyCount = current(unpack('N', $temp));
|
||||
for ($i = 0; $i < $keyCount; $i++) {
|
||||
$length = current(unpack('N', fread($this->fsock, 4)));
|
||||
$temp = fread($this->fsock, 4);
|
||||
if (strlen($temp) != 4) {
|
||||
user_error('Connection closed while requesting identities');
|
||||
return array();
|
||||
}
|
||||
$length = current(unpack('N', $temp));
|
||||
$key_blob = fread($this->fsock, $length);
|
||||
if (strlen($key_blob) != $length) {
|
||||
user_error('Connection closed while requesting identities');
|
||||
return array();
|
||||
}
|
||||
$key_str = 'ssh-rsa ' . base64_encode($key_blob);
|
||||
$length = current(unpack('N', fread($this->fsock, 4)));
|
||||
$temp = fread($this->fsock, 4);
|
||||
if (strlen($temp) != 4) {
|
||||
user_error('Connection closed while requesting identities');
|
||||
return array();
|
||||
}
|
||||
$length = current(unpack('N', $temp));
|
||||
if ($length) {
|
||||
$key_str.= ' ' . fread($this->fsock, $length);
|
||||
$temp = fread($this->fsock, $length);
|
||||
if (strlen($temp) != $length) {
|
||||
user_error('Connection closed while requesting identities');
|
||||
return array();
|
||||
}
|
||||
$key_str.= ' ' . $temp;
|
||||
}
|
||||
$length = current(unpack('N', substr($key_blob, 0, 4)));
|
||||
$key_type = substr($key_blob, 4, $length);
|
||||
|
|
@ -293,14 +326,24 @@ class Agent
|
|||
|
||||
if (strlen($this->socket_buffer) != fwrite($this->fsock, $this->socket_buffer)) {
|
||||
user_error('Connection closed attempting to forward data to SSH agent');
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->socket_buffer = '';
|
||||
$this->expected_bytes = 0;
|
||||
|
||||
$agent_reply_bytes = current(unpack('N', fread($this->fsock, 4)));
|
||||
$temp = fread($this->fsock, 4);
|
||||
if (strlen($temp) != 4) {
|
||||
user_error('Connection closed while reading data response');
|
||||
return false;
|
||||
}
|
||||
$agent_reply_bytes = current(unpack('N', $temp));
|
||||
|
||||
$agent_reply_data = fread($this->fsock, $agent_reply_bytes);
|
||||
if (strlen($agent_reply_data) != $agent_reply_bytes) {
|
||||
user_error('Connection closed while reading data response');
|
||||
return false;
|
||||
}
|
||||
$agent_reply_data = current(unpack('a*', $agent_reply_data));
|
||||
|
||||
return pack('Na*', $agent_reply_bytes, $agent_reply_data);
|
||||
|
|
|
|||
|
|
@ -32,6 +32,17 @@ use phpseclib\System\SSH\Agent;
|
|||
*/
|
||||
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
|
||||
*
|
||||
|
|
@ -59,6 +70,16 @@ class Identity
|
|||
*/
|
||||
var $fsock;
|
||||
|
||||
/**
|
||||
* Signature flags
|
||||
*
|
||||
* @var int
|
||||
* @access private
|
||||
* @see self::sign()
|
||||
* @see self::setHash()
|
||||
*/
|
||||
var $flags = 0;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
|
|
@ -138,21 +184,58 @@ class Identity
|
|||
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
|
||||
$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);
|
||||
if (strlen($packet) != fputs($this->fsock, $packet)) {
|
||||
user_error('Connection closed during signing');
|
||||
return false;
|
||||
}
|
||||
|
||||
$length = current(unpack('N', fread($this->fsock, 4)));
|
||||
$temp = fread($this->fsock, 4);
|
||||
if (strlen($temp) != 4) {
|
||||
user_error('Connection closed during signing');
|
||||
return false;
|
||||
}
|
||||
$length = current(unpack('N', $temp));
|
||||
$type = ord(fread($this->fsock, 1));
|
||||
if ($type != Agent::SSH_AGENT_SIGN_RESPONSE) {
|
||||
user_error('Unable to retrieve signature');
|
||||
return false;
|
||||
}
|
||||
|
||||
$signature_blob = fread($this->fsock, $length - 1);
|
||||
// the only other signature format defined - ssh-dss - is the same length as ssh-rsa
|
||||
// the + 12 is for the other various SSH added length fields
|
||||
return substr($signature_blob, strlen('ssh-rsa') + 12);
|
||||
if (strlen($signature_blob) != $length - 1) {
|
||||
user_error('Connection closed during signing');
|
||||
return false;
|
||||
}
|
||||
$length = current(unpack('N', $this->_string_shift($signature_blob, 4)));
|
||||
if ($length != strlen($signature_blob)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
3
securemail/vendor/singpolyma/openpgp-php/.github/FUNDING.yml
vendored
Normal file
3
securemail/vendor/singpolyma/openpgp-php/.github/FUNDING.yml
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
github: singpolyma
|
||||
liberapay: singpolyma
|
||||
patreon: singpolyma
|
||||
30
securemail/vendor/singpolyma/openpgp-php/.travis.dhall
vendored
Normal file
30
securemail/vendor/singpolyma/openpgp-php/.travis.dhall
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
let Prelude = https://prelude.dhall-lang.org/v17.0.0/package.dhall
|
||||
let phpseclib = \(max: Natural) -> \(filter: (Natural -> Bool)) ->
|
||||
Prelude.List.map Natural Text
|
||||
(\(m: Natural) -> "PHPSECLIB='2.0.${Prelude.Natural.show m}'")
|
||||
(Prelude.List.filter Natural filter (Prelude.Natural.enumerate max))
|
||||
let Exclusion = { php: Text, env: Text }
|
||||
in
|
||||
{
|
||||
language = "php",
|
||||
php = [
|
||||
"7.3",
|
||||
"7.4",
|
||||
"8.0"
|
||||
],
|
||||
dist = "xenial",
|
||||
env = [
|
||||
"PHPSECLIB='^2.0 !=2.0.8'"
|
||||
] # (phpseclib 28 (\(m: Natural) -> Prelude.Bool.not (Prelude.Natural.equal m 8))
|
||||
),
|
||||
matrix = {
|
||||
exclude = Prelude.List.concatMap Text Exclusion (\(php: Text) ->
|
||||
Prelude.List.map Text Exclusion (\(env: Text) ->
|
||||
{ php = php, env = env }
|
||||
) (phpseclib 7 (\(_: Natural) -> True))
|
||||
) ["7.3", "7.4", "8.0"],
|
||||
fast_finish = True
|
||||
},
|
||||
before_script = ''
|
||||
sed -i "s/\"phpseclib\/phpseclib\": \"[^\"]*/\"phpseclib\/phpseclib\": \"$PHPSECLIB/" composer.json && composer install --prefer-source''
|
||||
}
|
||||
|
|
@ -1,18 +1,82 @@
|
|||
language: php
|
||||
php:
|
||||
- 5.3
|
||||
- 5.4
|
||||
- 5.5
|
||||
- 5.6
|
||||
- 7.0
|
||||
- hhvm
|
||||
# - nightly
|
||||
|
||||
# Code generated by dhall-to-yaml. DO NOT EDIT.
|
||||
before_script: "sed -i \"s/\\\"phpseclib\\/phpseclib\\\": \\\"[^\\\"]*/\\\"phpseclib\\/phpseclib\\\": \\\"$PHPSECLIB/\" composer.json && composer install --prefer-source"
|
||||
dist: xenial
|
||||
env:
|
||||
- PHPSECLIB="2.0.0"
|
||||
- PHPSECLIB="2.0.1"
|
||||
- PHPSECLIB="2.0.2"
|
||||
- PHPSECLIB="2.0.3"
|
||||
- PHPSECLIB="2.0.4"
|
||||
|
||||
before_script: 'sed -i "s/\"phpseclib\/phpseclib\": \"[^\"]*/\"phpseclib\/phpseclib\": \"$PHPSECLIB/" composer.json && composer install --prefer-source --dev'
|
||||
- "PHPSECLIB='^2.0 !=2.0.8'"
|
||||
- "PHPSECLIB='2.0.0'"
|
||||
- "PHPSECLIB='2.0.1'"
|
||||
- "PHPSECLIB='2.0.2'"
|
||||
- "PHPSECLIB='2.0.3'"
|
||||
- "PHPSECLIB='2.0.4'"
|
||||
- "PHPSECLIB='2.0.5'"
|
||||
- "PHPSECLIB='2.0.6'"
|
||||
- "PHPSECLIB='2.0.7'"
|
||||
- "PHPSECLIB='2.0.9'"
|
||||
- "PHPSECLIB='2.0.10'"
|
||||
- "PHPSECLIB='2.0.11'"
|
||||
- "PHPSECLIB='2.0.12'"
|
||||
- "PHPSECLIB='2.0.13'"
|
||||
- "PHPSECLIB='2.0.14'"
|
||||
- "PHPSECLIB='2.0.15'"
|
||||
- "PHPSECLIB='2.0.16'"
|
||||
- "PHPSECLIB='2.0.17'"
|
||||
- "PHPSECLIB='2.0.18'"
|
||||
- "PHPSECLIB='2.0.19'"
|
||||
- "PHPSECLIB='2.0.20'"
|
||||
- "PHPSECLIB='2.0.21'"
|
||||
- "PHPSECLIB='2.0.22'"
|
||||
- "PHPSECLIB='2.0.23'"
|
||||
- "PHPSECLIB='2.0.24'"
|
||||
- "PHPSECLIB='2.0.25'"
|
||||
- "PHPSECLIB='2.0.26'"
|
||||
- "PHPSECLIB='2.0.27'"
|
||||
language: php
|
||||
matrix:
|
||||
exclude:
|
||||
- env: "PHPSECLIB='2.0.0'"
|
||||
php: '7.3'
|
||||
- env: "PHPSECLIB='2.0.1'"
|
||||
php: '7.3'
|
||||
- env: "PHPSECLIB='2.0.2'"
|
||||
php: '7.3'
|
||||
- env: "PHPSECLIB='2.0.3'"
|
||||
php: '7.3'
|
||||
- env: "PHPSECLIB='2.0.4'"
|
||||
php: '7.3'
|
||||
- env: "PHPSECLIB='2.0.5'"
|
||||
php: '7.3'
|
||||
- env: "PHPSECLIB='2.0.6'"
|
||||
php: '7.3'
|
||||
- env: "PHPSECLIB='2.0.0'"
|
||||
php: '7.4'
|
||||
- env: "PHPSECLIB='2.0.1'"
|
||||
php: '7.4'
|
||||
- env: "PHPSECLIB='2.0.2'"
|
||||
php: '7.4'
|
||||
- env: "PHPSECLIB='2.0.3'"
|
||||
php: '7.4'
|
||||
- env: "PHPSECLIB='2.0.4'"
|
||||
php: '7.4'
|
||||
- env: "PHPSECLIB='2.0.5'"
|
||||
php: '7.4'
|
||||
- env: "PHPSECLIB='2.0.6'"
|
||||
php: '7.4'
|
||||
- env: "PHPSECLIB='2.0.0'"
|
||||
php: '8.0'
|
||||
- env: "PHPSECLIB='2.0.1'"
|
||||
php: '8.0'
|
||||
- env: "PHPSECLIB='2.0.2'"
|
||||
php: '8.0'
|
||||
- env: "PHPSECLIB='2.0.3'"
|
||||
php: '8.0'
|
||||
- env: "PHPSECLIB='2.0.4'"
|
||||
php: '8.0'
|
||||
- env: "PHPSECLIB='2.0.5'"
|
||||
php: '8.0'
|
||||
- env: "PHPSECLIB='2.0.6'"
|
||||
php: '8.0'
|
||||
fast_finish: true
|
||||
php:
|
||||
- '7.3'
|
||||
- '7.4'
|
||||
- '8.0'
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
[](https://travis-ci.org/singpolyma/openpgp-php)
|
||||
|
||||
OpenPGP.php: OpenPGP for PHP
|
||||
============================
|
||||
|
||||
This is a pure-PHP implementation of the OpenPGP Message Format (RFC 4880).
|
||||
|
||||
* <http://github.com/bendiken/openpgp-php>
|
||||
* <https://github.com/singpolyma/openpgp-php>
|
||||
|
||||
### About OpenPGP
|
||||
About OpenPGP
|
||||
-------------
|
||||
|
||||
OpenPGP is the most widely-used e-mail encryption standard in the world. It
|
||||
is defined by the OpenPGP Working Group of the Internet Engineering Task
|
||||
|
|
@ -13,8 +16,8 @@ Force (IETF) Proposed Standard RFC 4880. The OpenPGP standard was originally
|
|||
derived from PGP (Pretty Good Privacy), first created by Phil Zimmermann in
|
||||
1991.
|
||||
|
||||
* <http://tools.ietf.org/html/rfc4880>
|
||||
* <http://www.openpgp.org/>
|
||||
* <https://tools.ietf.org/html/rfc4880>
|
||||
* <https://www.openpgp.org/>
|
||||
|
||||
Features
|
||||
--------
|
||||
|
|
@ -22,15 +25,26 @@ Features
|
|||
* Encodes and decodes ASCII-armored OpenPGP messages.
|
||||
* Parses OpenPGP messages into their constituent packets.
|
||||
* Supports both old-format (PGP 2.6.x) and new-format (RFC 4880) packets.
|
||||
* Helper class for verifying, signing, encrypting, and decrypting messages using Crypt_RSA from <http://phpseclib.sourceforge.net>
|
||||
* Helper class for encrypting and decrypting messages and keys using Crypt_AES and Crypt_TripleDES from <http://phpseclib.sourceforge.net>
|
||||
* Helper class for verifying, signing, encrypting, and decrypting messages <http://phpseclib.sourceforge.net>
|
||||
* Helper class for encrypting and decrypting messages and keys using <http://phpseclib.sourceforge.net>
|
||||
* openssl or mcrypt required for CAST5 encryption and decryption
|
||||
|
||||
Bugs, Feature Requests, Patches
|
||||
-------------------------------
|
||||
|
||||
This project is primarily maintained by a single volunteer with many other
|
||||
things vying for their attention, please be patient.
|
||||
|
||||
Bugs, feature request, pull requests, patches, and general discussion may
|
||||
be submitted publicly via email to: dev@singpolyma.net
|
||||
|
||||
Github users may alternately submit on the web there.
|
||||
|
||||
Users
|
||||
-----
|
||||
|
||||
OpenPGP.php is currently being used in the following projects:
|
||||
|
||||
* <https://drupal.org/project/openpgp>
|
||||
* <https://wordpress.org/plugins/wp-pgp-encrypted-emails/>
|
||||
|
||||
Download
|
||||
|
|
@ -38,21 +52,21 @@ Download
|
|||
|
||||
To get a local working copy of the development repository, do:
|
||||
|
||||
% git clone git://github.com/bendiken/openpgp-php.git
|
||||
git clone https://github.com/singpolyma/openpgp-php.git
|
||||
|
||||
Alternatively, you can download the latest development version as a tarball
|
||||
as follows:
|
||||
|
||||
% wget http://github.com/bendiken/openpgp-php/tarball/master
|
||||
wget https://github.com/singpolyma/openpgp-php/tarball/master
|
||||
|
||||
Authors
|
||||
-------
|
||||
|
||||
* [Arto Bendiken](mailto:arto.bendiken@gmail.com) - <http://ar.to/>
|
||||
* [Stephen Paul Weber](mailto:singpolyma@singpolyma.net) - <http://singpolyma.net/>
|
||||
* [Arto Bendiken](mailto:arto.bendiken@gmail.com) (Original author) - <http://ar.to/>
|
||||
* [Stephen Paul Weber](mailto:singpolyma@singpolyma.net) (Maintainer) - <https://singpolyma.net/>
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
OpenPGP.php is free and unencumbered public domain software. For more
|
||||
information, see <http://unlicense.org/> or the accompanying UNLICENSE file.
|
||||
information, see <https://unlicense.org/> or the accompanying UNLICENSE file.
|
||||
|
|
|
|||
|
|
@ -13,10 +13,14 @@
|
|||
}
|
||||
],
|
||||
"require": {
|
||||
"phpseclib/phpseclib": ">=2.0.0 <=2.0.4"
|
||||
"php": "^5.6 || ^7.0 || ^8.0",
|
||||
"phpseclib/phpseclib": "^2.0 !=2.0.8"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.0"
|
||||
"phpunit/phpunit": "^9.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-mcrypt": "required if you use encryption cast5"
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": ["lib/"]
|
||||
|
|
|
|||
22
securemail/vendor/singpolyma/openpgp-php/examples/README.md
vendored
Normal file
22
securemail/vendor/singpolyma/openpgp-php/examples/README.md
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
OpenPGP.php Examples
|
||||
====================
|
||||
|
||||
The scripts in this folder show how to use this library to perform various tasks
|
||||
such as [generating a new key](keygen.php), [signing a message](sign.php), and
|
||||
[verifying a message](verify.php) that has been signed.
|
||||
|
||||
To use these examples, make sure [`phpseclib`](http://phpseclib.sourceforge.net/) is available. You can install it
|
||||
using [Composer](https://getcomposer.org/):
|
||||
|
||||
```sh
|
||||
git clone https://github.com/singpolyma/openpgp-php.git # Clone the repository.
|
||||
cd openpgp-php
|
||||
composer install # Use Composer to install the requirements.
|
||||
```
|
||||
|
||||
Once Composer has installed the requirements, run the examples using PHP:
|
||||
|
||||
```sh
|
||||
# Generate a new OpenPGP key; see the `keygen.php` file for parameters.
|
||||
php ./examples/keygen.php > mykey.gpg
|
||||
```
|
||||
21
securemail/vendor/singpolyma/openpgp-php/examples/armorEncryptSignCompress.php
vendored
Normal file
21
securemail/vendor/singpolyma/openpgp-php/examples/armorEncryptSignCompress.php
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
@include_once dirname(__FILE__).'/../vendor/autoload.php';
|
||||
require_once dirname(__FILE__).'/../lib/openpgp.php';
|
||||
require_once dirname(__FILE__).'/../lib/openpgp_crypt_rsa.php';
|
||||
|
||||
$recipientPublicKey = OpenPGP_Message::parse(OpenPGP::unarmor(file_get_contents('public.asc'), 'PGP PUBLIC KEY BLOCK'));
|
||||
|
||||
$encryptedPrivateKey = OpenPGP_Message::parse(OpenPGP::unarmor(file_get_contents('sekret.asc'), 'PGP PRIVATE KEY BLOCK'));
|
||||
$privateKeyPassphrase = 'test';
|
||||
$key = OpenPGP_Crypt_Symmetric::decryptSecretKey($privateKeyPassphrase, $encryptedPrivateKey[0]);
|
||||
|
||||
$signer = new OpenPGP_Crypt_RSA($key);
|
||||
$data = new OpenPGP_LiteralDataPacket("some text\n", ['format' => 'u']);
|
||||
$signed = $signer->sign($data);
|
||||
|
||||
$compressed = new OpenPGP_CompressedDataPacket($signed);
|
||||
$encrypted = OpenPGP_Crypt_Symmetric::encrypt([$recipientPublicKey, $key], new OpenPGP_Message([$compressed]));
|
||||
|
||||
echo OpenPGP::enarmor($encrypted->to_bytes(), 'PGP MESSAGE');
|
||||
|
||||
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
<?php
|
||||
|
||||
@include_once dirname(__FILE__).'/../vendor/autoload.php';
|
||||
require_once dirname(__FILE__).'/../lib/openpgp.php';
|
||||
require_once dirname(__FILE__).'/../lib/openpgp_crypt_rsa.php';
|
||||
|
||||
|
|
@ -27,5 +28,3 @@ echo "-----BEGIN PGP SIGNED MESSAGE-----\nHash: SHA256\n\n";
|
|||
// trailing whitespace to lines.
|
||||
echo preg_replace("/^-/", "- -", $packets[0]->data)."\n";
|
||||
echo OpenPGP::enarmor($packets[1][0]->to_bytes(), "PGP SIGNATURE");
|
||||
|
||||
?>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
// USAGE: php examples/deASCIIdeCrypt.php secretkey.asc password message.asc
|
||||
// This will fail if the algo on key or message is not 3DES or AES
|
||||
|
||||
@include_once dirname(__FILE__).'/../vendor/autoload.php';
|
||||
require_once dirname(__FILE__).'/../lib/openpgp.php';
|
||||
require_once dirname(__FILE__).'/../lib/openpgp_crypt_rsa.php';
|
||||
require_once dirname(__FILE__).'/../lib/openpgp_crypt_symmetric.php';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<?php
|
||||
|
||||
@include_once dirname(__FILE__).'/../vendor/autoload.php';
|
||||
require_once dirname(__FILE__).'/../lib/openpgp.php';
|
||||
require_once dirname(__FILE__).'/../lib/openpgp_crypt_rsa.php';
|
||||
require_once dirname(__FILE__).'/../lib/openpgp_crypt_symmetric.php';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<?php
|
||||
|
||||
@include_once dirname(__FILE__).'/../vendor/autoload.php';
|
||||
require_once dirname(__FILE__).'/../lib/openpgp.php';
|
||||
require_once dirname(__FILE__).'/../lib/openpgp_crypt_rsa.php';
|
||||
|
||||
|
|
|
|||
28
securemail/vendor/singpolyma/openpgp-php/examples/keygenEncrypted.php
vendored
Normal file
28
securemail/vendor/singpolyma/openpgp-php/examples/keygenEncrypted.php
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
@include_once dirname(__FILE__).'/../vendor/autoload.php';
|
||||
require_once dirname(__FILE__).'/../lib/openpgp.php';
|
||||
require_once dirname(__FILE__).'/../lib/openpgp_crypt_rsa.php';
|
||||
require_once dirname(__FILE__).'/../lib/openpgp_crypt_symmetric.php';
|
||||
|
||||
$rsa = new \phpseclib\Crypt\RSA();
|
||||
$k = $rsa->createKey(512);
|
||||
$rsa->loadKey($k['privatekey']);
|
||||
|
||||
$nkey = new OpenPGP_SecretKeyPacket(array(
|
||||
'n' => $rsa->modulus->toBytes(),
|
||||
'e' => $rsa->publicExponent->toBytes(),
|
||||
'd' => $rsa->exponent->toBytes(),
|
||||
'p' => $rsa->primes[2]->toBytes(),
|
||||
'q' => $rsa->primes[1]->toBytes(),
|
||||
'u' => $rsa->coefficients[2]->toBytes()
|
||||
));
|
||||
|
||||
$uid = new OpenPGP_UserIDPacket('Test <test@example.com>');
|
||||
|
||||
$wkey = new OpenPGP_Crypt_RSA($nkey);
|
||||
$m = $wkey->sign_key_userid(array($nkey, $uid));
|
||||
$m[0] = OpenPGP_Crypt_Symmetric::encryptSecretKey("password", $nkey);
|
||||
|
||||
// Serialize encrypted private key
|
||||
print $m->to_bytes();
|
||||
116
securemail/vendor/singpolyma/openpgp-php/examples/keygenSubkeys.php
vendored
Normal file
116
securemail/vendor/singpolyma/openpgp-php/examples/keygenSubkeys.php
vendored
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
<?php
|
||||
|
||||
@include_once dirname(__FILE__).'/../vendor/autoload.php';
|
||||
require_once dirname(__FILE__).'/../lib/openpgp.php';
|
||||
require_once dirname(__FILE__).'/../lib/openpgp_crypt_rsa.php';
|
||||
|
||||
// Key length: 512, 1024, 2048, 3072, 4096
|
||||
$key_length = 512;
|
||||
|
||||
// Generate a master signing key
|
||||
|
||||
$rsa = new \phpseclib\Crypt\RSA();
|
||||
$k = $rsa->createKey($key_length);
|
||||
$rsa->loadKey($k['privatekey']);
|
||||
|
||||
$nkey = new OpenPGP_SecretKeyPacket(array(
|
||||
'n' => $rsa->modulus->toBytes(),
|
||||
'e' => $rsa->publicExponent->toBytes(),
|
||||
'd' => $rsa->exponent->toBytes(),
|
||||
'p' => $rsa->primes[2]->toBytes(),
|
||||
'q' => $rsa->primes[1]->toBytes(),
|
||||
'u' => $rsa->coefficients[2]->toBytes()
|
||||
));
|
||||
|
||||
// Start assembling packets for our eventual OpenPGP_Message
|
||||
$packets = array($nkey);
|
||||
|
||||
$wkey = new OpenPGP_Crypt_RSA($nkey);
|
||||
$fingerprint = $wkey->key()->fingerprint;
|
||||
$key = $wkey->private_key();
|
||||
$key->setHash('sha256');
|
||||
$keyid = substr($fingerprint, -16);
|
||||
|
||||
// Add multiple UID packets and signatures
|
||||
|
||||
$uids = array(
|
||||
new OpenPGP_UserIDPacket('Support', '', 'support@example.com'),
|
||||
new OpenPGP_UserIDPacket('Security', '', 'security@example.com'),
|
||||
);
|
||||
|
||||
foreach($uids as $uid) {
|
||||
// Append the UID packet
|
||||
$packets[] = $uid;
|
||||
|
||||
$sig = new OpenPGP_SignaturePacket(new OpenPGP_Message(array($nkey, $uid)), 'RSA', 'SHA256');
|
||||
$sig->signature_type = 0x13;
|
||||
$sig->hashed_subpackets[] = new OpenPGP_SignaturePacket_KeyFlagsPacket(array(0x01 | 0x02)); // Certify + sign bits
|
||||
$sig->hashed_subpackets[] = new OpenPGP_SignaturePacket_IssuerPacket($keyid);
|
||||
$m = $wkey->sign_key_userid(array($nkey, $uid, $sig));
|
||||
|
||||
// Append the UID signature from the master key
|
||||
$packets[] = $m->packets[2];
|
||||
}
|
||||
|
||||
// Generate an encryption subkey
|
||||
|
||||
$rsa_subkey = new \phpseclib\Crypt\RSA();
|
||||
$sub_k = $rsa_subkey->createKey($key_length);
|
||||
$rsa_subkey->loadKey($sub_k['privatekey']);
|
||||
|
||||
$subkey = new OpenPGP_SecretSubkeyPacket(array(
|
||||
'n' => $rsa_subkey->modulus->toBytes(),
|
||||
'e' => $rsa_subkey->publicExponent->toBytes(),
|
||||
'd' => $rsa_subkey->exponent->toBytes(),
|
||||
'p' => $rsa_subkey->primes[2]->toBytes(),
|
||||
'q' => $rsa_subkey->primes[1]->toBytes(),
|
||||
'u' => $rsa_subkey->coefficients[2]->toBytes()
|
||||
));
|
||||
|
||||
// Append the encryption subkey
|
||||
$packets[] = $subkey;
|
||||
|
||||
$sub_wkey = new OpenPGP_Crypt_RSA($subkey);
|
||||
|
||||
/*
|
||||
* Sign the encryption subkey with the master key
|
||||
*
|
||||
* OpenPGP_SignaturePacket assumes any message starting with an
|
||||
* OpenPGP_PublicKeyPacket is followed by a OpenPGP_UserIDPacket. We need
|
||||
* to pass `null` in the constructor and generate the `->data` ourselves.
|
||||
*/
|
||||
$sub_sig = new OpenPGP_SignaturePacket(null, 'RSA', 'SHA256');
|
||||
$sub_sig->signature_type = 0x18;
|
||||
$sub_sig->hashed_subpackets[] = new OpenPGP_SignaturePacket_SignatureCreationTimePacket(time());
|
||||
$sub_sig->hashed_subpackets[] = new OpenPGP_SignaturePacket_KeyFlagsPacket(array(0x0C)); // Encrypt bits
|
||||
$sub_sig->hashed_subpackets[] = new OpenPGP_SignaturePacket_IssuerPacket($keyid);
|
||||
$sub_sig->data = implode('', $nkey->fingerprint_material()) . implode('', $subkey->fingerprint_material());
|
||||
$sub_sig->sign_data(array('RSA' => array('SHA256' => function($data) use($key) {return array($key->sign($data));})));
|
||||
|
||||
// Append the subkey signature
|
||||
$packets[] = $sub_sig;
|
||||
|
||||
// Build the OpenPGP_Message for the secret key from our packets
|
||||
$m = new OpenPGP_Message($packets);
|
||||
|
||||
// Serialize the private key
|
||||
print $m->to_bytes();
|
||||
|
||||
// Clone a public key message from the secret key
|
||||
$pubm = clone($m);
|
||||
|
||||
// Convert the private key packets to public so we only export public data
|
||||
// (n+e in RSA)
|
||||
foreach($pubm as $idx => $p) {
|
||||
if($p instanceof OpenPGP_SecretSubkeyPacket) {
|
||||
$pubm[$idx] = new OpenPGP_PublicSubkeyPacket($p);
|
||||
} else if($p instanceof OpenPGP_SecretKeyPacket) {
|
||||
$pubm[$idx] = new OpenPGP_PublicKeyPacket($p);
|
||||
}
|
||||
}
|
||||
|
||||
// Serialize the public key
|
||||
$public_bytes = $pubm->to_bytes();
|
||||
|
||||
// Note: If using PHP 7.4 CLI, disable deprecated warnings:
|
||||
// php -d error_reporting="E_ALL & ~E_DEPRECATED" examples/keygenSubkeys.php > mykey.gpg
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
<?php
|
||||
|
||||
@include_once dirname(__FILE__).'/../vendor/autoload.php';
|
||||
require_once dirname(__FILE__).'/../lib/openpgp.php';
|
||||
require_once dirname(__FILE__).'/../lib/openpgp_crypt_rsa.php';
|
||||
|
||||
|
|
@ -18,5 +19,3 @@ $m = $sign->sign($data);
|
|||
|
||||
/* Output the raw message bytes to STDOUT */
|
||||
echo $m->to_bytes();
|
||||
|
||||
?>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<?php
|
||||
|
||||
@include_once dirname(__FILE__).'/../vendor/autoload.php';
|
||||
require_once dirname(__FILE__).'/../lib/openpgp.php';
|
||||
require_once dirname(__FILE__).'/../lib/openpgp_crypt_rsa.php';
|
||||
|
||||
|
|
@ -14,5 +15,3 @@ $verify = new OpenPGP_Crypt_RSA($wkey);
|
|||
|
||||
/* Dump verification information to STDOUT */
|
||||
var_dump($verify->verify($m));
|
||||
|
||||
?>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
* (RFC 4880).
|
||||
*
|
||||
* @package OpenPGP
|
||||
* @version 0.3.0
|
||||
* @version 0.5.0
|
||||
* @author Arto Bendiken <arto.bendiken@gmail.com>
|
||||
* @author Stephen Paul Weber <singpolyma@singpolyma.net>
|
||||
* @see http://github.com/bendiken/openpgp-php
|
||||
|
|
@ -18,6 +18,8 @@
|
|||
* @see http://tools.ietf.org/html/rfc4880
|
||||
*/
|
||||
class OpenPGP {
|
||||
const VERSION = array(0, 5, 0);
|
||||
|
||||
/**
|
||||
* @see http://tools.ietf.org/html/rfc4880#section-6
|
||||
* @see http://tools.ietf.org/html/rfc4880#section-6.2
|
||||
|
|
@ -28,7 +30,7 @@ class OpenPGP {
|
|||
foreach ($headers as $key => $value) {
|
||||
$text .= $key . ': ' . (string)$value . "\n";
|
||||
}
|
||||
$text .= "\n" . base64_encode($data);
|
||||
$text .= "\n" . wordwrap(base64_encode($data), 76, "\n", true);
|
||||
$text .= "\n".'=' . base64_encode(substr(pack('N', self::crc24($data)), 1)) . "\n";
|
||||
$text .= self::footer($marker) . "\n";
|
||||
return $text;
|
||||
|
|
@ -42,8 +44,13 @@ class OpenPGP {
|
|||
$header = self::header($header);
|
||||
$text = str_replace(array("\r\n", "\r"), array("\n", ''), $text);
|
||||
if (($pos1 = strpos($text, $header)) !== FALSE &&
|
||||
($pos1 = strpos($text, "\n\n", $pos1 += strlen($header))) !== FALSE &&
|
||||
($pos2 = strpos($text, "\n=", $pos1 += 2)) !== FALSE) {
|
||||
($pos1 = strpos($text, "\n\n", $pos1 += strlen($header))) !== FALSE) {
|
||||
$pos2 = strpos($text, "\n=", $pos1 += 2);
|
||||
if ($pos2 === FALSE) {
|
||||
trigger_error("Invalid ASCII armor, missing CRC");
|
||||
$pos2 = strpos($text, "-----END");
|
||||
if ($pos2 === FALSE) return NULL;
|
||||
}
|
||||
return base64_decode($text = substr($text, $pos1, $pos2 - $pos1));
|
||||
}
|
||||
}
|
||||
|
|
@ -122,20 +129,20 @@ class OpenPGP_S2K {
|
|||
|
||||
static function parse(&$input) {
|
||||
$s2k = new OpenPGP_S2k();
|
||||
switch($s2k->type = ord($input{0})) {
|
||||
switch($s2k->type = ord($input[0])) {
|
||||
case 0:
|
||||
$s2k->hash_algorithm = ord($input{1});
|
||||
$s2k->hash_algorithm = ord($input[1]);
|
||||
$input = substr($input, 2);
|
||||
break;
|
||||
case 1:
|
||||
$s2k->hash_algorithm = ord($input{1});
|
||||
$s2k->hash_algorithm = ord($input[1]);
|
||||
$s2k->salt = substr($input, 2, 8);
|
||||
$input = substr($input, 10);
|
||||
break;
|
||||
case 3:
|
||||
$s2k->hash_algorithm = ord($input{1});
|
||||
$s2k->hash_algorithm = ord($input[1]);
|
||||
$s2k->salt = substr($input, 2, 8);
|
||||
$s2k->count = OpenPGP::decode_s2k_count(ord($input{10}));
|
||||
$s2k->count = OpenPGP::decode_s2k_count(ord($input[10]));
|
||||
$input = substr($input, 11);
|
||||
break;
|
||||
}
|
||||
|
|
@ -150,10 +157,12 @@ class OpenPGP_S2K {
|
|||
$bytes .= chr($this->hash_algorithm);
|
||||
break;
|
||||
case 1:
|
||||
if(strlen($this->salt) != 8) throw new Exception("Invalid salt length");
|
||||
$bytes .= chr($this->hash_algorithm);
|
||||
$bytes .= $this->salt;
|
||||
break;
|
||||
case 3:
|
||||
if(strlen($this->salt) != 8) throw new Exception("Invalid salt length");
|
||||
$bytes .= chr($this->hash_algorithm);
|
||||
$bytes .= $this->salt;
|
||||
$bytes .= chr(OpenPGP::encode_s2k_count($this->count));
|
||||
|
|
@ -553,7 +562,7 @@ class OpenPGP_Packet {
|
|||
}
|
||||
|
||||
function read_byte() {
|
||||
return ($bytes = $this->read_bytes()) ? $bytes[0] : NULL;
|
||||
return !is_null($bytes = $this->read_bytes()) ? $bytes[0] : NULL;
|
||||
}
|
||||
|
||||
function read_bytes($count = 1) {
|
||||
|
|
@ -609,7 +618,7 @@ class OpenPGP_AsymmetricSessionKeyPacket extends OpenPGP_Packet {
|
|||
$rawkeyid = $this->read_bytes(8);
|
||||
$this->keyid = '';
|
||||
for($i = 0; $i < strlen($rawkeyid); $i++) { // Store KeyID in Hex
|
||||
$this->keyid .= sprintf('%02X',ord($rawkeyid{$i}));
|
||||
$this->keyid .= sprintf('%02X',ord($rawkeyid[$i]));
|
||||
}
|
||||
|
||||
$this->key_algorithm = ord($this->read_byte());
|
||||
|
|
@ -625,7 +634,7 @@ class OpenPGP_AsymmetricSessionKeyPacket extends OpenPGP_Packet {
|
|||
$bytes = chr($this->version);
|
||||
|
||||
for($i = 0; $i < strlen($this->keyid); $i += 2) {
|
||||
$bytes .= chr(hexdec($this->keyid{$i}.$this->keyid{$i+1}));
|
||||
$bytes .= chr(hexdec($this->keyid[$i].$this->keyid[$i+1]));
|
||||
}
|
||||
|
||||
$bytes .= chr($this->key_algorithm);
|
||||
|
|
@ -685,13 +694,15 @@ class OpenPGP_SignaturePacket extends OpenPGP_Packet {
|
|||
switch($this->version = ord($this->read_byte())) {
|
||||
case 2:
|
||||
case 3:
|
||||
assert(ord($this->read_byte()) == 5);
|
||||
if(ord($this->read_byte()) != 5) {
|
||||
throw new Exception("Invalid version 2 or 3 SignaturePacket");
|
||||
}
|
||||
$this->signature_type = ord($this->read_byte());
|
||||
$creation_time = $this->read_timestamp();
|
||||
$keyid = $this->read_bytes(8);
|
||||
$keyidHex = '';
|
||||
for($i = 0; $i < strlen($keyid); $i++) { // Store KeyID in Hex
|
||||
$keyidHex .= sprintf('%02X',ord($keyid{$i}));
|
||||
$keyidHex .= sprintf('%02X',ord($keyid[$i]));
|
||||
}
|
||||
|
||||
$this->hashed_subpackets = array();
|
||||
|
|
@ -768,7 +779,7 @@ class OpenPGP_SignaturePacket extends OpenPGP_Packet {
|
|||
foreach((array)$this->unhashed_subpackets as $p) {
|
||||
if($p instanceof OpenPGP_SignaturePacket_IssuerPacket) {
|
||||
for($i = 0; $i < strlen($p->data); $i += 2) {
|
||||
$body .= chr(hexdec($p->data{$i}.$p->data{$i+1}));
|
||||
$body .= chr(hexdec($p->data[$i].$p->data[$i+1]));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -975,8 +986,8 @@ class OpenPGP_SignaturePacket_ExportableCertificationPacket extends OpenPGP_Sign
|
|||
|
||||
class OpenPGP_SignaturePacket_TrustSignaturePacket extends OpenPGP_SignaturePacket_Subpacket {
|
||||
function read() {
|
||||
$this->depth = ord($this->input{0});
|
||||
$this->trust = ord($this->input{1});
|
||||
$this->depth = ord($this->input[0]);
|
||||
$this->trust = ord($this->input[1]);
|
||||
}
|
||||
|
||||
function body() {
|
||||
|
|
@ -1052,7 +1063,7 @@ class OpenPGP_SignaturePacket_RevocationKeyPacket extends OpenPGP_SignaturePacke
|
|||
$bytes .= chr($this->key_algorithm);
|
||||
|
||||
for($i = 0; $i < strlen($this->fingerprint); $i += 2) {
|
||||
$bytes .= chr(hexdec($this->fingerprint{$i}.$this->fingerprint{$i+1}));
|
||||
$bytes .= chr(hexdec($this->fingerprint[$i].$this->fingerprint[$i+1]));
|
||||
}
|
||||
|
||||
return $bytes;
|
||||
|
|
@ -1072,7 +1083,7 @@ class OpenPGP_SignaturePacket_IssuerPacket extends OpenPGP_SignaturePacket_Subpa
|
|||
function body() {
|
||||
$bytes = '';
|
||||
for($i = 0; $i < strlen($this->data); $i += 2) {
|
||||
$bytes .= chr(hexdec($this->data{$i}.$this->data{$i+1}));
|
||||
$bytes .= chr(hexdec($this->data[$i].$this->data[$i+1]));
|
||||
}
|
||||
return $bytes;
|
||||
}
|
||||
|
|
@ -1305,7 +1316,7 @@ class OpenPGP_OnePassSignaturePacket extends OpenPGP_Packet {
|
|||
function body() {
|
||||
$body = chr($this->version).chr($this->signature_type).chr($this->hash_algorithm).chr($this->key_algorithm);
|
||||
for($i = 0; $i < strlen($this->key_id); $i += 2) {
|
||||
$body .= chr(hexdec($this->key_id{$i}.$this->key_id{$i+1}));
|
||||
$body .= chr(hexdec($this->key_id[$i].$this->key_id[$i+1]));
|
||||
}
|
||||
$body .= chr((int)$this->nested);
|
||||
return $body;
|
||||
|
|
@ -1594,6 +1605,13 @@ class OpenPGP_CompressedDataPacket extends OpenPGP_Packet implements IteratorAgg
|
|||
public $algorithm;
|
||||
/* see http://tools.ietf.org/html/rfc4880#section-9.3 */
|
||||
static $algorithms = array(0 => 'Uncompressed', 1 => 'ZIP', 2 => 'ZLIB', 3 => 'BZip2');
|
||||
|
||||
function __construct($m=NULL, $algorithm=1) {
|
||||
parent::__construct();
|
||||
$this->algorithm = $algorithm;
|
||||
$this->data = $m ? $m : new OpenPGP_Message();
|
||||
}
|
||||
|
||||
function read() {
|
||||
$this->algorithm = ord($this->read_byte());
|
||||
$this->data = $this->read_bytes($this->length);
|
||||
|
|
|
|||
|
|
@ -182,8 +182,10 @@ class OpenPGP_Crypt_RSA {
|
|||
$keys = new self($keys);
|
||||
}
|
||||
|
||||
$session_key = NULL;
|
||||
foreach($message as $p) {
|
||||
if($p instanceof OpenPGP_AsymmetricSessionKeyPacket) {
|
||||
$session_key = $p;
|
||||
if($keys instanceof Crypt_RSA) {
|
||||
$sk = self::try_decrypt_session($keys, substr($p->encrypted_data, 2));
|
||||
} else if(strlen(str_replace('0', '', $p->keyid)) < 1) {
|
||||
|
|
@ -203,23 +205,26 @@ class OpenPGP_Crypt_RSA {
|
|||
}
|
||||
}
|
||||
|
||||
if (!$session_key) throw new Exception("Not an asymmetrically encrypted message");
|
||||
|
||||
return NULL; /* Failed */
|
||||
}
|
||||
|
||||
static function try_decrypt_session($key, $edata) {
|
||||
$key->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
|
||||
$data = $key->decrypt($edata);
|
||||
$data = @$key->decrypt($edata);
|
||||
if(!$data) return NULL;
|
||||
$sk = substr($data, 1, strlen($data)-3);
|
||||
$chk = unpack('n', substr($data, -2));
|
||||
$chk = reset($chk);
|
||||
|
||||
$sk_chk = 0;
|
||||
for($i = 0; $i < strlen($sk); $i++) {
|
||||
$sk_chk = ($sk_chk + ord($sk{$i})) % 65536;
|
||||
$sk_chk = ($sk_chk + ord($sk[$i])) % 65536;
|
||||
}
|
||||
|
||||
if($sk_chk != $chk) return NULL;
|
||||
return array(ord($data{0}), $sk);
|
||||
return array(ord($data[0]), $sk);
|
||||
}
|
||||
|
||||
static function crypt_rsa_key($mod, $exp, $hash='SHA256') {
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
<?php
|
||||
|
||||
use phpseclib\Crypt\TripleDES as Crypt_TripleDES;
|
||||
use phpseclib\Crypt\AES as Crypt_AES;
|
||||
use phpseclib\Crypt\Blowfish as Crypt_Blowfish;
|
||||
use phpseclib\Crypt\TripleDES as Crypt_TripleDES;
|
||||
use phpseclib\Crypt\Twofish as Crypt_Twofish;
|
||||
use phpseclib\Crypt\Random;
|
||||
|
||||
define('CRYPT_DES_MODE_CFB', Crypt_TripleDES::MODE_CFB);
|
||||
define('CRYPT_AES_MODE_CFB', Crypt_AES::MODE_CFB);
|
||||
|
||||
require_once dirname(__FILE__).'/openpgp.php';
|
||||
@include_once dirname(__FILE__).'/openpgp_crypt_rsa.php';
|
||||
@include_once dirname(__FILE__).'/openpgp_mcrypt_wrapper.php';
|
||||
@include_once dirname(__FILE__).'/openpgp_openssl_wrapper.php';
|
||||
|
||||
class OpenPGP_Crypt_Symmetric {
|
||||
public static function encrypt($passphrases_and_keys, $message, $symmetric_algorithm=9) {
|
||||
|
|
@ -40,7 +40,7 @@ class OpenPGP_Crypt_Symmetric {
|
|||
$esk = pack('n', OpenPGP::bitlength($esk)) . $esk;
|
||||
array_unshift($encrypted, new OpenPGP_AsymmetricSessionKeyPacket($pass->algorithm, $pass->fingerprint(), $esk));
|
||||
} else if(is_string($pass)) {
|
||||
$s2k = new OpenPGP_S2K(Random::string(10));
|
||||
$s2k = new OpenPGP_S2K(Random::string(8));
|
||||
$cipher->setKey($s2k->make_key($pass, $key_bytes));
|
||||
$esk = $cipher->encrypt(chr($symmetric_algorithm) . $key);
|
||||
array_unshift($encrypted, new OpenPGP_SymmetricSessionKeyPacket($s2k, $esk, $symmetric_algorithm));
|
||||
|
|
@ -62,7 +62,7 @@ class OpenPGP_Crypt_Symmetric {
|
|||
|
||||
$padAmount = $key_block_bytes - (strlen($p->encrypted_data) % $key_block_bytes);
|
||||
$data = substr($cipher->decrypt($p->encrypted_data . str_repeat("\0", $padAmount)), 0, strlen($p->encrypted_data));
|
||||
$decrypted = self::decryptPacket($epacket, ord($data{0}), substr($data, 1));
|
||||
$decrypted = self::decryptPacket($epacket, ord($data[0]), substr($data, 1));
|
||||
} else {
|
||||
list($cipher, $key_bytes, $key_block_bytes) = self::getCipher($p->symmetric_algorithm);
|
||||
$decrypted = self::decryptPacket($epacket, $p->symmetric_algorithm, $p->s2k->make_key($pass, $key_bytes));
|
||||
|
|
@ -75,6 +75,31 @@ class OpenPGP_Crypt_Symmetric {
|
|||
return NULL; /* If we get here, we failed */
|
||||
}
|
||||
|
||||
public static function encryptSecretKey($pass, $packet, $symmetric_algorithm=9) {
|
||||
$packet = clone $packet; // Do not mutate original
|
||||
$packet->s2k_useage = 254;
|
||||
$packet->symmetric_algorithm = $symmetric_algorithm;
|
||||
|
||||
list($cipher, $key_bytes, $key_block_bytes) = self::getCipher($packet->symmetric_algorithm);
|
||||
if(!$cipher) throw new Exception("Unsupported cipher");
|
||||
|
||||
$material = '';
|
||||
foreach(OpenPGP_SecretKeyPacket::$secret_key_fields[$packet->algorithm] as $field) {
|
||||
$f = $packet->key[$field];
|
||||
$material .= pack('n', OpenPGP::bitlength($f)) . $f;
|
||||
unset($packet->key[$field]);
|
||||
}
|
||||
$material .= hash('sha1', $material, true);
|
||||
|
||||
$iv = Random::string($key_block_bytes);
|
||||
if(!$packet->s2k) $packet->s2k = new OpenPGP_S2K(Random::string(8));
|
||||
$cipher->setKey($packet->s2k->make_key($pass, $key_bytes));
|
||||
$cipher->setIV($iv);
|
||||
$packet->encrypted_data = $iv . $cipher->encrypt($material);
|
||||
|
||||
return $packet;
|
||||
}
|
||||
|
||||
public static function decryptSecretKey($pass, $packet) {
|
||||
$packet = clone $packet; // Do not mutate orinigal
|
||||
|
||||
|
|
@ -97,6 +122,7 @@ class OpenPGP_Crypt_Symmetric {
|
|||
if($chk != $mkChk) return NULL;
|
||||
}
|
||||
|
||||
$packet->s2k = NULL;
|
||||
$packet->s2k_useage = 0;
|
||||
$packet->symmetric_algorithm = 0;
|
||||
$packet->encrypted_data = NULL;
|
||||
|
|
@ -146,29 +172,45 @@ class OpenPGP_Crypt_Symmetric {
|
|||
public static function getCipher($algo) {
|
||||
$cipher = NULL;
|
||||
switch($algo) {
|
||||
case NULL:
|
||||
case 0:
|
||||
throw new Exception("Data is already unencrypted");
|
||||
case 2:
|
||||
$cipher = new Crypt_TripleDES(CRYPT_DES_MODE_CFB);
|
||||
$key_bytes = 24;
|
||||
$key_block_bytes = 8;
|
||||
$cipher = new Crypt_TripleDES(Crypt_TripleDES::MODE_CFB);
|
||||
$key_bytes = 24;
|
||||
$key_block_bytes = 8;
|
||||
break;
|
||||
case 3:
|
||||
if(defined('MCRYPT_CAST_128')) {
|
||||
if(class_exists('OpenSSLWrapper')) {
|
||||
$cipher = new OpenSSLWrapper("CAST5-CFB");
|
||||
} else if(defined('MCRYPT_CAST_128')) {
|
||||
$cipher = new MCryptWrapper(MCRYPT_CAST_128);
|
||||
} else {
|
||||
throw new Exception("Unsupported cipher: you must have mcrypt installed to use CAST5");
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
$cipher = new Crypt_Blowfish(Crypt_Blowfish::MODE_CFB);
|
||||
$key_bytes = 16;
|
||||
$key_block_bytes = 8;
|
||||
break;
|
||||
case 7:
|
||||
$cipher = new Crypt_AES(CRYPT_AES_MODE_CFB);
|
||||
$cipher->setKeyLength(128);
|
||||
$cipher = new Crypt_AES(Crypt_AES::MODE_CFB);
|
||||
$cipher->setKeyLength(128);
|
||||
break;
|
||||
case 8:
|
||||
$cipher = new Crypt_AES(CRYPT_AES_MODE_CFB);
|
||||
$cipher->setKeyLength(192);
|
||||
$cipher = new Crypt_AES(Crypt_AES::MODE_CFB);
|
||||
$cipher->setKeyLength(192);
|
||||
break;
|
||||
case 9:
|
||||
$cipher = new Crypt_AES(CRYPT_AES_MODE_CFB);
|
||||
$cipher = new Crypt_AES(Crypt_AES::MODE_CFB);
|
||||
$cipher->setKeyLength(256);
|
||||
break;
|
||||
case 10:
|
||||
$cipher = new Crypt_Twofish(Crypt_Twofish::MODE_CFB);
|
||||
if(method_exists($cipher, 'setKeyLength')) {
|
||||
$cipher->setKeyLength(256);
|
||||
} else {
|
||||
$cipher = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(!$cipher) return array(NULL, NULL, NULL); // Unsupported cipher
|
||||
|
|
@ -187,7 +229,7 @@ class OpenPGP_Crypt_Symmetric {
|
|||
public static function checksum($s) {
|
||||
$mkChk = 0;
|
||||
for($i = 0; $i < strlen($s); $i++) {
|
||||
$mkChk = ($mkChk + ord($s{$i})) % 65536;
|
||||
$mkChk = ($mkChk + ord($s[$i])) % 65536;
|
||||
}
|
||||
return $mkChk;
|
||||
}
|
||||
|
|
|
|||
33
securemail/vendor/singpolyma/openpgp-php/lib/openpgp_openssl_wrapper.php
vendored
Normal file
33
securemail/vendor/singpolyma/openpgp-php/lib/openpgp_openssl_wrapper.php
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
if(function_exists('openssl_encrypt')) {
|
||||
class OpenSSLWrapper {
|
||||
public $cipher, $key, $iv, $key_size, $block_size;
|
||||
|
||||
|
||||
function __construct($cipher) {
|
||||
if($cipher != "CAST5-CFB") throw Exception("OpenSSLWrapper is only used for CAST5 right now");
|
||||
|
||||
$this->cipher = $cipher;
|
||||
$this->key_size = 16;
|
||||
$this->block_size = 8;
|
||||
$this->iv = str_repeat("\0", 8);
|
||||
}
|
||||
|
||||
function setKey($key) {
|
||||
$this->key = $key;
|
||||
}
|
||||
|
||||
function setIV($iv) {
|
||||
$this->iv = $iv;
|
||||
}
|
||||
|
||||
function encrypt($data) {
|
||||
return openssl_encrypt($data, $this->cipher, $this->key, OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING, $this->iv);
|
||||
}
|
||||
|
||||
function decrypt($data) {
|
||||
return openssl_decrypt($data, $this->cipher, $this->key, OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING, $this->iv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,10 @@
|
|||
<file>tests/suite.php</file>
|
||||
</testsuite>
|
||||
|
||||
<testsuite name="Signature">
|
||||
<file>tests/suite.php</file>
|
||||
</testsuite>
|
||||
|
||||
<testsuite name="MessageVerification">
|
||||
<file>tests/phpseclib_suite.php</file>
|
||||
</testsuite>
|
||||
|
|
|
|||
BIN
securemail/vendor/singpolyma/openpgp-php/tests/data/000079-002.sig
vendored
Normal file
BIN
securemail/vendor/singpolyma/openpgp-php/tests/data/000079-002.sig
vendored
Normal file
Binary file not shown.
BIN
securemail/vendor/singpolyma/openpgp-php/tests/data/000080-006.public_key
vendored
Normal file
BIN
securemail/vendor/singpolyma/openpgp-php/tests/data/000080-006.public_key
vendored
Normal file
Binary file not shown.
BIN
securemail/vendor/singpolyma/openpgp-php/tests/data/000081-002.sig
vendored
Normal file
BIN
securemail/vendor/singpolyma/openpgp-php/tests/data/000081-002.sig
vendored
Normal file
Binary file not shown.
BIN
securemail/vendor/singpolyma/openpgp-php/tests/data/000082-006.public_key
vendored
Normal file
BIN
securemail/vendor/singpolyma/openpgp-php/tests/data/000082-006.public_key
vendored
Normal file
Binary file not shown.
BIN
securemail/vendor/singpolyma/openpgp-php/tests/data/000083-002.sig
vendored
Normal file
BIN
securemail/vendor/singpolyma/openpgp-php/tests/data/000083-002.sig
vendored
Normal file
Binary file not shown.
1
securemail/vendor/singpolyma/openpgp-php/tests/data/symmetric-blowfish.gpg
vendored
Normal file
1
securemail/vendor/singpolyma/openpgp-php/tests/data/symmetric-blowfish.gpg
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
<EFBFBD>
σθΆh<CE86>±Ο³ΦΙfuάhθ‚ύ’sΕώ®Ωψ°Όώ_VF•4Σ
|
||||
3
securemail/vendor/singpolyma/openpgp-php/tests/data/symmetric-twofish.gpg
vendored
Normal file
3
securemail/vendor/singpolyma/openpgp-php/tests/data/symmetric-twofish.gpg
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
Œ
|
||||
cýІèÑÔÖÒ9=õÇâ]¼TföA¼c«vìåeøkº€Èʲõ¡©n}%.<16>lòëuÛ?\êåI
|
||||
ð[øõblÊ
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
<?php
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/* The tests which require phpseclib */
|
||||
|
||||
|
|
@ -6,7 +7,7 @@ require_once dirname(__FILE__).'/../lib/openpgp.php';
|
|||
require_once dirname(__FILE__).'/../lib/openpgp_crypt_rsa.php';
|
||||
require_once dirname(__FILE__).'/../lib/openpgp_crypt_symmetric.php';
|
||||
|
||||
class MessageVerification extends PHPUnit_Framework_TestCase {
|
||||
class MessageVerification extends TestCase {
|
||||
public function oneMessageRSA($pkey, $path) {
|
||||
$pkeyM = OpenPGP_Message::parse(file_get_contents(dirname(__FILE__) . '/data/' . $pkey));
|
||||
$m = OpenPGP_Message::parse(file_get_contents(dirname(__FILE__) . '/data/' . $path));
|
||||
|
|
@ -51,7 +52,7 @@ class MessageVerification extends PHPUnit_Framework_TestCase {
|
|||
}
|
||||
|
||||
|
||||
class KeyVerification extends PHPUnit_Framework_TestCase {
|
||||
class KeyVerification extends TestCase {
|
||||
public function oneKeyRSA($path) {
|
||||
$m = OpenPGP_Message::parse(file_get_contents(dirname(__FILE__) . '/data/' . $path));
|
||||
$verify = new OpenPGP_Crypt_RSA($m);
|
||||
|
|
@ -64,7 +65,7 @@ class KeyVerification extends PHPUnit_Framework_TestCase {
|
|||
}
|
||||
|
||||
|
||||
class Decryption extends PHPUnit_Framework_TestCase {
|
||||
class Decryption extends TestCase {
|
||||
public function oneSymmetric($pass, $cnt, $path) {
|
||||
$m = OpenPGP_Message::parse(file_get_contents(dirname(__FILE__) . '/data/' . $path));
|
||||
$m2 = OpenPGP_Crypt_Symmetric::decryptSymmetric($pass, $m);
|
||||
|
|
@ -76,18 +77,28 @@ class Decryption extends PHPUnit_Framework_TestCase {
|
|||
}
|
||||
}
|
||||
|
||||
public function testDecryptAES() {
|
||||
$this->oneSymmetric("hello", "PGP\n", "symmetric-aes.gpg");
|
||||
}
|
||||
|
||||
public function testDecrypt3DES() {
|
||||
$this->oneSymmetric("hello", "PGP\n", "symmetric-3des.gpg");
|
||||
}
|
||||
|
||||
public function testDecryptCAST5() { // Requires mcrypt
|
||||
public function testDecryptCAST5() { // Requires mcrypt or openssl
|
||||
$this->oneSymmetric("hello", "PGP\n", "symmetric-cast5.gpg");
|
||||
}
|
||||
|
||||
public function testDecryptBlowfish() {
|
||||
$this->oneSymmetric("hello", "PGP\n", "symmetric-blowfish.gpg");
|
||||
}
|
||||
|
||||
public function testDecryptAES() {
|
||||
$this->oneSymmetric("hello", "PGP\n", "symmetric-aes.gpg");
|
||||
}
|
||||
|
||||
public function testDecryptTwofish() {
|
||||
if(OpenPGP_Crypt_Symmetric::getCipher(10)[0]) {
|
||||
$this->oneSymmetric("hello", "PGP\n", "symmetric-twofish.gpg");
|
||||
}
|
||||
}
|
||||
|
||||
public function testDecryptSessionKey() {
|
||||
$this->oneSymmetric("hello", "PGP\n", "symmetric-with-session-key.gpg");
|
||||
}
|
||||
|
|
@ -109,25 +120,89 @@ class Decryption extends PHPUnit_Framework_TestCase {
|
|||
}
|
||||
}
|
||||
|
||||
public function testDecryptRoundtrip() {
|
||||
$m = new OpenPGP_Message(array(new OpenPGP_LiteralDataPacket("hello\n")));
|
||||
$key = OpenPGP_Message::parse(file_get_contents(dirname(__FILE__) . '/data/helloKey.gpg'));
|
||||
$em = OpenPGP_Crypt_Symmetric::encrypt($key, $m);
|
||||
|
||||
foreach($key as $packet) {
|
||||
if(!($packet instanceof OpenPGP_SecretKeyPacket)) continue;
|
||||
$decryptor = new OpenPGP_Crypt_RSA($packet);
|
||||
$m2 = $decryptor->decrypt($em);
|
||||
|
||||
foreach($m2 as $p) {
|
||||
if($p instanceof OpenPGP_LiteralDataPacket) {
|
||||
$this->assertEquals($p->data, "hello\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function testDecryptSecretKey() {
|
||||
$key = OpenPGP_Message::parse(file_get_contents(dirname(__FILE__) . '/data/encryptedSecretKey.gpg'));
|
||||
$skey = OpenPGP_Crypt_Symmetric::decryptSecretKey("hello", $key[0]);
|
||||
$this->assertSame(!!$skey, true);
|
||||
}
|
||||
|
||||
public function testEncryptSecretKeyRoundtrip() {
|
||||
$key = OpenPGP_Message::parse(file_get_contents(dirname(__FILE__) . '/data/helloKey.gpg'));
|
||||
$enkey = OpenPGP_Crypt_Symmetric::encryptSecretKey("password", $key[0]);
|
||||
$skey = OpenPGP_Crypt_Symmetric::decryptSecretKey("password", $enkey);
|
||||
$this->assertEquals($key[0], $skey);
|
||||
}
|
||||
|
||||
public function testAlreadyDecryptedSecretKey() {
|
||||
$this->expectException(Exception::class);
|
||||
$this->expectExceptionMessage("Data is already unencrypted");
|
||||
$key = OpenPGP_Message::parse(file_get_contents(dirname(__FILE__) . '/data/helloKey.gpg'));
|
||||
OpenPGP_Crypt_Symmetric::decryptSecretKey("hello", $key[0]);
|
||||
}
|
||||
}
|
||||
|
||||
class Encryption extends PHPUnit_Framework_TestCase {
|
||||
public function testEncryptSymmetric() {
|
||||
class Encryption extends TestCase {
|
||||
public function oneSymmetric($algorithm) {
|
||||
$data = new OpenPGP_LiteralDataPacket('This is text.', array('format' => 'u', 'filename' => 'stuff.txt'));
|
||||
$encrypted = OpenPGP_Crypt_Symmetric::encrypt('secret', new OpenPGP_Message(array($data)));
|
||||
$encrypted = OpenPGP_Crypt_Symmetric::encrypt('secret', new OpenPGP_Message(array($data)), $algorithm);
|
||||
$encrypted = OpenPGP_Message::parse($encrypted->to_bytes());
|
||||
$decrypted = OpenPGP_Crypt_Symmetric::decryptSymmetric('secret', $encrypted);
|
||||
$this->assertEquals($decrypted[0]->data, 'This is text.');
|
||||
}
|
||||
|
||||
public function testEncryptSymmetric3DES() {
|
||||
$this->oneSymmetric(2);
|
||||
}
|
||||
|
||||
public function testEncryptSymmetricCAST5() {
|
||||
$this->oneSymmetric(3);
|
||||
}
|
||||
|
||||
public function testEncryptSymmetricBlowfish() {
|
||||
$this->oneSymmetric(4);
|
||||
}
|
||||
|
||||
public function testEncryptSymmetricAES128() {
|
||||
$this->oneSymmetric(7);
|
||||
}
|
||||
|
||||
public function testEncryptSymmetricAES192() {
|
||||
$this->oneSymmetric(8);
|
||||
}
|
||||
|
||||
public function testEncryptSymmetricAES256() {
|
||||
$this->oneSymmetric(9);
|
||||
}
|
||||
|
||||
public function testEncryptSymmetricTwofish() {
|
||||
if(OpenPGP_Crypt_Symmetric::getCipher(10)[0]) {
|
||||
$this->oneSymmetric(10);
|
||||
}
|
||||
}
|
||||
|
||||
public function testEncryptAsymmetric() {
|
||||
$key = OpenPGP_Message::parse(file_get_contents(dirname(__FILE__) . '/data/helloKey.gpg'));
|
||||
$data = new OpenPGP_LiteralDataPacket('This is text.', array('format' => 'u', 'filename' => 'stuff.txt'));
|
||||
$encrypted = OpenPGP_Crypt_Symmetric::encrypt($key, new OpenPGP_Message(array($data)));
|
||||
$encrypted = OpenPGP_Message::parse($encrypted->to_bytes());
|
||||
$decryptor = new OpenPGP_Crypt_RSA($key);
|
||||
$decrypted = $decryptor->decrypt($encrypted);
|
||||
$this->assertEquals($decrypted[0]->data, 'This is text.');
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
<?php
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
require_once dirname(__FILE__).'/../lib/openpgp.php';
|
||||
|
||||
class Serialization extends PHPUnit_Framework_TestCase {
|
||||
class Serialization extends TestCase {
|
||||
public function oneSerialization($path) {
|
||||
$in = OpenPGP_Message::parse(file_get_contents(dirname(__FILE__) . '/data/' . $path));
|
||||
$mid = $in->to_bytes();
|
||||
|
|
@ -14,355 +15,354 @@ class Serialization extends PHPUnit_Framework_TestCase {
|
|||
$this->oneSerialization("000001-006.public_key");
|
||||
}
|
||||
|
||||
|
||||
public function test000002013user_id() {
|
||||
$this->oneSerialization("000002-013.user_id");
|
||||
}
|
||||
|
||||
|
||||
public function test000003002sig() {
|
||||
$this->oneSerialization("000003-002.sig");
|
||||
}
|
||||
|
||||
|
||||
public function test000004012ring_trust() {
|
||||
$this->oneSerialization("000004-012.ring_trust");
|
||||
}
|
||||
|
||||
|
||||
public function test000005002sig() {
|
||||
$this->oneSerialization("000005-002.sig");
|
||||
}
|
||||
|
||||
|
||||
public function test000006012ring_trust() {
|
||||
$this->oneSerialization("000006-012.ring_trust");
|
||||
}
|
||||
|
||||
|
||||
public function test000007002sig() {
|
||||
$this->oneSerialization("000007-002.sig");
|
||||
}
|
||||
|
||||
|
||||
public function test000008012ring_trust() {
|
||||
$this->oneSerialization("000008-012.ring_trust");
|
||||
}
|
||||
|
||||
|
||||
public function test000009002sig() {
|
||||
$this->oneSerialization("000009-002.sig");
|
||||
}
|
||||
|
||||
|
||||
public function test000010012ring_trust() {
|
||||
$this->oneSerialization("000010-012.ring_trust");
|
||||
}
|
||||
|
||||
|
||||
public function test000011002sig() {
|
||||
$this->oneSerialization("000011-002.sig");
|
||||
}
|
||||
|
||||
|
||||
public function test000012012ring_trust() {
|
||||
$this->oneSerialization("000012-012.ring_trust");
|
||||
}
|
||||
|
||||
|
||||
public function test000013014public_subkey() {
|
||||
$this->oneSerialization("000013-014.public_subkey");
|
||||
}
|
||||
|
||||
|
||||
public function test000014002sig() {
|
||||
$this->oneSerialization("000014-002.sig");
|
||||
}
|
||||
|
||||
|
||||
public function test000015012ring_trust() {
|
||||
$this->oneSerialization("000015-012.ring_trust");
|
||||
}
|
||||
|
||||
|
||||
public function test000016006public_key() {
|
||||
$this->oneSerialization("000016-006.public_key");
|
||||
}
|
||||
|
||||
|
||||
public function test000017002sig() {
|
||||
$this->oneSerialization("000017-002.sig");
|
||||
}
|
||||
|
||||
|
||||
public function test000018012ring_trust() {
|
||||
$this->oneSerialization("000018-012.ring_trust");
|
||||
}
|
||||
|
||||
|
||||
public function test000019013user_id() {
|
||||
$this->oneSerialization("000019-013.user_id");
|
||||
}
|
||||
|
||||
|
||||
public function test000020002sig() {
|
||||
$this->oneSerialization("000020-002.sig");
|
||||
}
|
||||
|
||||
|
||||
public function test000021012ring_trust() {
|
||||
$this->oneSerialization("000021-012.ring_trust");
|
||||
}
|
||||
|
||||
|
||||
public function test000022002sig() {
|
||||
$this->oneSerialization("000022-002.sig");
|
||||
}
|
||||
|
||||
|
||||
public function test000023012ring_trust() {
|
||||
$this->oneSerialization("000023-012.ring_trust");
|
||||
}
|
||||
|
||||
|
||||
public function test000024014public_subkey() {
|
||||
$this->oneSerialization("000024-014.public_subkey");
|
||||
}
|
||||
|
||||
|
||||
public function test000025002sig() {
|
||||
$this->oneSerialization("000025-002.sig");
|
||||
}
|
||||
|
||||
|
||||
public function test000026012ring_trust() {
|
||||
$this->oneSerialization("000026-012.ring_trust");
|
||||
}
|
||||
|
||||
|
||||
public function test000027006public_key() {
|
||||
$this->oneSerialization("000027-006.public_key");
|
||||
}
|
||||
|
||||
|
||||
public function test000028002sig() {
|
||||
$this->oneSerialization("000028-002.sig");
|
||||
}
|
||||
|
||||
|
||||
public function test000029012ring_trust() {
|
||||
$this->oneSerialization("000029-012.ring_trust");
|
||||
}
|
||||
|
||||
|
||||
public function test000030013user_id() {
|
||||
$this->oneSerialization("000030-013.user_id");
|
||||
}
|
||||
|
||||
|
||||
public function test000031002sig() {
|
||||
$this->oneSerialization("000031-002.sig");
|
||||
}
|
||||
|
||||
|
||||
public function test000032012ring_trust() {
|
||||
$this->oneSerialization("000032-012.ring_trust");
|
||||
}
|
||||
|
||||
|
||||
public function test000033002sig() {
|
||||
$this->oneSerialization("000033-002.sig");
|
||||
}
|
||||
|
||||
|
||||
public function test000034012ring_trust() {
|
||||
$this->oneSerialization("000034-012.ring_trust");
|
||||
}
|
||||
|
||||
|
||||
public function test000035006public_key() {
|
||||
$this->oneSerialization("000035-006.public_key");
|
||||
}
|
||||
|
||||
|
||||
public function test000036013user_id() {
|
||||
$this->oneSerialization("000036-013.user_id");
|
||||
}
|
||||
|
||||
|
||||
public function test000037002sig() {
|
||||
$this->oneSerialization("000037-002.sig");
|
||||
}
|
||||
|
||||
|
||||
public function test000038012ring_trust() {
|
||||
$this->oneSerialization("000038-012.ring_trust");
|
||||
}
|
||||
|
||||
|
||||
public function test000039002sig() {
|
||||
$this->oneSerialization("000039-002.sig");
|
||||
}
|
||||
|
||||
|
||||
public function test000040012ring_trust() {
|
||||
$this->oneSerialization("000040-012.ring_trust");
|
||||
}
|
||||
|
||||
|
||||
public function test000041017attribute() {
|
||||
$this->oneSerialization("000041-017.attribute");
|
||||
}
|
||||
|
||||
|
||||
public function test000042002sig() {
|
||||
$this->oneSerialization("000042-002.sig");
|
||||
}
|
||||
|
||||
|
||||
public function test000043012ring_trust() {
|
||||
$this->oneSerialization("000043-012.ring_trust");
|
||||
}
|
||||
|
||||
|
||||
public function test000044014public_subkey() {
|
||||
$this->oneSerialization("000044-014.public_subkey");
|
||||
}
|
||||
|
||||
|
||||
public function test000045002sig() {
|
||||
$this->oneSerialization("000045-002.sig");
|
||||
}
|
||||
|
||||
|
||||
public function test000046012ring_trust() {
|
||||
$this->oneSerialization("000046-012.ring_trust");
|
||||
}
|
||||
|
||||
|
||||
public function test000047005secret_key() {
|
||||
$this->oneSerialization("000047-005.secret_key");
|
||||
}
|
||||
|
||||
|
||||
public function test000048013user_id() {
|
||||
$this->oneSerialization("000048-013.user_id");
|
||||
}
|
||||
|
||||
|
||||
public function test000049002sig() {
|
||||
$this->oneSerialization("000049-002.sig");
|
||||
}
|
||||
|
||||
|
||||
public function test000050012ring_trust() {
|
||||
$this->oneSerialization("000050-012.ring_trust");
|
||||
}
|
||||
|
||||
|
||||
public function test000051007secret_subkey() {
|
||||
$this->oneSerialization("000051-007.secret_subkey");
|
||||
}
|
||||
|
||||
|
||||
public function test000052002sig() {
|
||||
$this->oneSerialization("000052-002.sig");
|
||||
}
|
||||
|
||||
|
||||
public function test000053012ring_trust() {
|
||||
$this->oneSerialization("000053-012.ring_trust");
|
||||
}
|
||||
|
||||
|
||||
public function test000054005secret_key() {
|
||||
$this->oneSerialization("000054-005.secret_key");
|
||||
}
|
||||
|
||||
|
||||
public function test000055002sig() {
|
||||
$this->oneSerialization("000055-002.sig");
|
||||
}
|
||||
|
||||
|
||||
public function test000056012ring_trust() {
|
||||
$this->oneSerialization("000056-012.ring_trust");
|
||||
}
|
||||
|
||||
|
||||
public function test000057013user_id() {
|
||||
$this->oneSerialization("000057-013.user_id");
|
||||
}
|
||||
|
||||
|
||||
public function test000058002sig() {
|
||||
$this->oneSerialization("000058-002.sig");
|
||||
}
|
||||
|
||||
|
||||
public function test000059012ring_trust() {
|
||||
$this->oneSerialization("000059-012.ring_trust");
|
||||
}
|
||||
|
||||
|
||||
public function test000060007secret_subkey() {
|
||||
$this->oneSerialization("000060-007.secret_subkey");
|
||||
}
|
||||
|
||||
|
||||
public function test000061002sig() {
|
||||
$this->oneSerialization("000061-002.sig");
|
||||
}
|
||||
|
||||
|
||||
public function test000062012ring_trust() {
|
||||
$this->oneSerialization("000062-012.ring_trust");
|
||||
}
|
||||
|
||||
|
||||
public function test000063005secret_key() {
|
||||
$this->oneSerialization("000063-005.secret_key");
|
||||
}
|
||||
|
||||
|
||||
public function test000064002sig() {
|
||||
$this->oneSerialization("000064-002.sig");
|
||||
}
|
||||
|
||||
|
||||
public function test000065012ring_trust() {
|
||||
$this->oneSerialization("000065-012.ring_trust");
|
||||
}
|
||||
|
||||
|
||||
public function test000066013user_id() {
|
||||
$this->oneSerialization("000066-013.user_id");
|
||||
}
|
||||
|
||||
|
||||
public function test000067002sig() {
|
||||
$this->oneSerialization("000067-002.sig");
|
||||
}
|
||||
|
||||
|
||||
public function test000068012ring_trust() {
|
||||
$this->oneSerialization("000068-012.ring_trust");
|
||||
}
|
||||
|
||||
|
||||
public function test000069005secret_key() {
|
||||
$this->oneSerialization("000069-005.secret_key");
|
||||
}
|
||||
|
||||
|
||||
public function test000070013user_id() {
|
||||
$this->oneSerialization("000070-013.user_id");
|
||||
}
|
||||
|
||||
|
||||
public function test000071002sig() {
|
||||
$this->oneSerialization("000071-002.sig");
|
||||
}
|
||||
|
||||
|
||||
public function test000072012ring_trust() {
|
||||
$this->oneSerialization("000072-012.ring_trust");
|
||||
}
|
||||
|
||||
|
||||
public function test000073017attribute() {
|
||||
$this->oneSerialization("000073-017.attribute");
|
||||
}
|
||||
|
||||
|
||||
public function test000074002sig() {
|
||||
$this->oneSerialization("000074-002.sig");
|
||||
}
|
||||
|
||||
|
||||
public function test000075012ring_trust() {
|
||||
$this->oneSerialization("000075-012.ring_trust");
|
||||
}
|
||||
|
||||
|
||||
public function test000076007secret_subkey() {
|
||||
$this->oneSerialization("000076-007.secret_subkey");
|
||||
}
|
||||
|
||||
|
||||
public function test000077002sig() {
|
||||
$this->oneSerialization("000077-002.sig");
|
||||
}
|
||||
|
||||
|
||||
public function test000078012ring_trust() {
|
||||
$this->oneSerialization("000078-012.ring_trust");
|
||||
}
|
||||
|
||||
|
||||
public function test002182002sig() {
|
||||
$this->oneSerialization("002182-002.sig");
|
||||
}
|
||||
|
||||
|
||||
public function testpubringgpg() {
|
||||
$this->oneSerialization("pubring.gpg");
|
||||
}
|
||||
|
||||
|
||||
public function testsecringgpg() {
|
||||
$this->oneSerialization("secring.gpg");
|
||||
}
|
||||
|
||||
|
||||
public function testcompressedsiggpg() {
|
||||
$this->oneSerialization("compressedsig.gpg");
|
||||
}
|
||||
|
||||
|
||||
public function testcompressedsigzlibgpg() {
|
||||
$this->oneSerialization("compressedsig-zlib.gpg");
|
||||
}
|
||||
|
||||
|
||||
public function testcompressedsigbzip2gpg() {
|
||||
$this->oneSerialization("compressedsig-bzip2.gpg");
|
||||
}
|
||||
|
||||
|
||||
public function testonepass_sig() {
|
||||
$this->oneSerialization("onepass_sig");
|
||||
}
|
||||
|
||||
|
||||
public function testsymmetrically_encrypted() {
|
||||
$this->oneSerialization("symmetrically_encrypted");
|
||||
}
|
||||
|
||||
|
||||
public function testuncompressedopsdsagpg() {
|
||||
$this->oneSerialization("uncompressed-ops-dsa.gpg");
|
||||
}
|
||||
|
||||
|
||||
public function testuncompressedopsdsasha384txtgpg() {
|
||||
$this->oneSerialization("uncompressed-ops-dsa-sha384.txt.gpg");
|
||||
}
|
||||
|
||||
|
||||
public function testuncompressedopsrsagpg() {
|
||||
$this->oneSerialization("uncompressed-ops-rsa.gpg");
|
||||
}
|
||||
|
|
@ -376,7 +376,7 @@ class Serialization extends PHPUnit_Framework_TestCase {
|
|||
}
|
||||
}
|
||||
|
||||
class Fingerprint extends PHPUnit_Framework_TestCase {
|
||||
class Fingerprint extends TestCase {
|
||||
public function oneFingerprint($path, $kf) {
|
||||
$m = OpenPGP_Message::parse(file_get_contents(dirname(__FILE__) . '/data/' . $path));
|
||||
$this->assertEquals($m[0]->fingerprint(), $kf);
|
||||
|
|
@ -397,4 +397,31 @@ class Fingerprint extends PHPUnit_Framework_TestCase {
|
|||
public function test000035006public_key() {
|
||||
$this->oneFingerprint("000035-006.public_key", "CB7933459F59C70DF1C3FBEEDEDC3ECF689AF56D");
|
||||
}
|
||||
|
||||
public function test000080006public_key() {
|
||||
$this->oneFingerprint("000080-006.public_key", "AEDA0C4468AE265E8B7CCA1C3047D4A7B15467AB");
|
||||
}
|
||||
|
||||
public function test000082006public_key() {
|
||||
$this->oneFingerprint("000082-006.public_key", "589D7E6884A9235BBE821D35BD7BA7BC5547FD09");
|
||||
}
|
||||
}
|
||||
|
||||
class Signature extends TestCase {
|
||||
public function oneIssuer($path, $kf) {
|
||||
$m = OpenPGP_Message::parse(file_get_contents(dirname(__FILE__) . '/data/' . $path));
|
||||
$this->assertEquals($m[0]->issuer(), $kf);
|
||||
}
|
||||
|
||||
public function test000079002sig() {
|
||||
$this->oneIssuer("000079-002.sig", "C25059FA8730BC38");
|
||||
}
|
||||
|
||||
public function test000081002sig() {
|
||||
$this->oneIssuer("000081-002.sig", "6B799484725130FE");
|
||||
}
|
||||
|
||||
public function test000083002sig() {
|
||||
$this->oneIssuer("000083-002.sig", "BD7BA7BC5547FD09");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue