mirror of
https://github.com/phpseclib/phpseclib.git
synced 2024-12-25 03:16:02 +00:00
Revert "undo merging of master to 2.0 branch"
This reverts commit 8fb4c3363d
.
This commit is contained in:
parent
8fb4c3363d
commit
398a795e1f
@ -1,6 +1,6 @@
|
||||
# phpseclib - PHP Secure Communications Library
|
||||
|
||||
[![Build Status](https://travis-ci.org/phpseclib/phpseclib.svg?branch=2.0)](https://travis-ci.org/phpseclib/phpseclib)
|
||||
[![Build Status](https://travis-ci.org/phpseclib/phpseclib.svg?branch=master)](https://travis-ci.org/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,
|
||||
@ -8,7 +8,7 @@ AES, Blowfish, Twofish, SSH-1, SSH-2, SFTP, and X.509
|
||||
|
||||
* [Download (1.0.1)](http://sourceforge.net/projects/phpseclib/files/phpseclib1.0.1.zip/download)
|
||||
* [Browse Git](https://github.com/phpseclib/phpseclib)
|
||||
* [Code Coverage Report](http://phpseclib.bantux.org/code_coverage/2.0/latest/)
|
||||
* [Code Coverage Report](http://phpseclib.bantux.org/code_coverage/master/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)
|
||||
@ -16,7 +16,7 @@ PEAR Channel: [phpseclib.sourceforge.net](http://phpseclib.sourceforge.net/pear.
|
||||
## Documentation
|
||||
|
||||
* [Documentation / Manual](http://phpseclib.sourceforge.net/)
|
||||
* [API Documentation](http://phpseclib.bantux.org/api/2.0/) (generated by Sami)
|
||||
* [API Documentation](http://phpseclib.bantux.org/api/master/) (generated by Sami)
|
||||
|
||||
## Support
|
||||
|
||||
|
@ -51,6 +51,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"paragonie/random_compat": "^1.4|^2.0",
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
|
55
composer.lock
generated
55
composer.lock
generated
@ -4,9 +4,58 @@
|
||||
"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": [],
|
||||
"hash": "deb73cf7e6004dbc2550a38c4082df2d",
|
||||
"content-hash": "39f9dd8d2c209ff69eebbb83e367257e",
|
||||
"packages": [
|
||||
{
|
||||
"name": "paragonie/random_compat",
|
||||
"version": "v2.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/paragonie/random_compat.git",
|
||||
"reference": "088c04e2f261c33bed6ca5245491cfca69195ccf"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/088c04e2f261c33bed6ca5245491cfca69195ccf",
|
||||
"reference": "088c04e2f261c33bed6ca5245491cfca69195ccf",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "4.*|5.*"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"lib/random.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Paragon Initiative Enterprises",
|
||||
"email": "security@paragonie.com",
|
||||
"homepage": "https://paragonie.com"
|
||||
}
|
||||
],
|
||||
"description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
|
||||
"keywords": [
|
||||
"csprng",
|
||||
"pseudorandom",
|
||||
"random"
|
||||
],
|
||||
"time": "2016-04-03 06:00:07"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "doctrine/instantiator",
|
||||
|
@ -49,8 +49,6 @@
|
||||
|
||||
namespace phpseclib\Crypt;
|
||||
|
||||
use phpseclib\Crypt\Rijndael;
|
||||
|
||||
/**
|
||||
* Pure-PHP implementation of AES.
|
||||
*
|
||||
@ -68,30 +66,32 @@ class AES extends Rijndael
|
||||
* @see \phpseclib\Crypt\Rijndael::setBlockLength()
|
||||
* @access public
|
||||
* @param int $length
|
||||
* @throws \BadMethodCallException anytime it's called
|
||||
*/
|
||||
function setBlockLength($length)
|
||||
{
|
||||
return;
|
||||
throw new \BadMethodCallException('The block length cannot be set for AES.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key length
|
||||
*
|
||||
* Valid key lengths are 128, 192, and 256. If the length is less than 128, it will be rounded up to
|
||||
* 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
|
||||
* Valid key lengths are 128, 192, and 256. Set the link to bool(false) to disable a fixed key length
|
||||
*
|
||||
* @see \phpseclib\Crypt\Rijndael:setKeyLength()
|
||||
* @access public
|
||||
* @param int $length
|
||||
* @throws \LengthException if the key length isn't supported
|
||||
*/
|
||||
function setKeyLength($length)
|
||||
{
|
||||
switch ($length) {
|
||||
case 160:
|
||||
$length = 192;
|
||||
case 128:
|
||||
case 192:
|
||||
case 256:
|
||||
break;
|
||||
case 224:
|
||||
$length = 256;
|
||||
default:
|
||||
throw new \LengthException('Key of size ' . $length . ' not supported by this algorithm. Only keys of sizes 128, 192 or 256 supported');
|
||||
}
|
||||
parent::setKeyLength($length);
|
||||
}
|
||||
@ -105,24 +105,19 @@ class AES extends Rijndael
|
||||
* @see setKeyLength()
|
||||
* @access public
|
||||
* @param string $key
|
||||
* @throws \LengthException if the key length isn't supported
|
||||
*/
|
||||
function setKey($key)
|
||||
{
|
||||
parent::setKey($key);
|
||||
|
||||
if (!$this->explicit_key_length) {
|
||||
$length = strlen($key);
|
||||
switch (true) {
|
||||
case $length <= 16:
|
||||
$this->key_length = 16;
|
||||
break;
|
||||
case $length <= 24:
|
||||
$this->key_length = 24;
|
||||
break;
|
||||
default:
|
||||
$this->key_length = 32;
|
||||
}
|
||||
$this->_setEngine();
|
||||
switch (strlen($key)) {
|
||||
case 16:
|
||||
case 24:
|
||||
case 32:
|
||||
break;
|
||||
default:
|
||||
throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of sizes 16, 24 or 32 supported');
|
||||
}
|
||||
|
||||
parent::setKey($key);
|
||||
}
|
||||
}
|
||||
|
@ -36,8 +36,6 @@
|
||||
|
||||
namespace phpseclib\Crypt;
|
||||
|
||||
use phpseclib\Crypt\Hash;
|
||||
|
||||
/**
|
||||
* Base Class for all \phpseclib\Crypt\* cipher classes
|
||||
*
|
||||
@ -141,7 +139,7 @@ abstract class Base
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
var $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
|
||||
var $key = false;
|
||||
|
||||
/**
|
||||
* The Initialization Vector
|
||||
@ -150,7 +148,7 @@ abstract class Base
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
var $iv;
|
||||
var $iv = false;
|
||||
|
||||
/**
|
||||
* A "sliding" Initialization Vector
|
||||
@ -431,15 +429,6 @@ abstract class Base
|
||||
*/
|
||||
var $openssl_options;
|
||||
|
||||
/**
|
||||
* Has the key length explicitly been set or should it be derived from the key, itself?
|
||||
*
|
||||
* @see self::setKeyLength()
|
||||
* @var bool
|
||||
* @access private
|
||||
*/
|
||||
var $explicit_key_length = false;
|
||||
|
||||
/**
|
||||
* Don't truncate / null pad key
|
||||
*
|
||||
@ -450,9 +439,16 @@ abstract class Base
|
||||
var $skip_key_adjustment = false;
|
||||
|
||||
/**
|
||||
* Default Constructor.
|
||||
* Has the key length explicitly been set or should it be derived from the key, itself?
|
||||
*
|
||||
* Determines whether or not the mcrypt extension should be used.
|
||||
* @see self::setKeyLength()
|
||||
* @var bool
|
||||
* @access private
|
||||
*/
|
||||
var $explicit_key_length = false;
|
||||
|
||||
/**
|
||||
* Default Constructor.
|
||||
*
|
||||
* $mode could be:
|
||||
*
|
||||
@ -466,32 +462,29 @@ abstract class Base
|
||||
*
|
||||
* - self::MODE_OFB
|
||||
*
|
||||
* If not explicitly set, self::MODE_CBC will be used.
|
||||
*
|
||||
* @param int $mode
|
||||
* @access public
|
||||
* @throws \InvalidArgumentException if an invalid / unsupported mode is provided
|
||||
*/
|
||||
function __construct($mode = self::MODE_CBC)
|
||||
function __construct($mode)
|
||||
{
|
||||
// $mode dependent settings
|
||||
switch ($mode) {
|
||||
case self::MODE_ECB:
|
||||
case self::MODE_CBC:
|
||||
$this->paddable = true;
|
||||
$this->mode = self::MODE_ECB;
|
||||
break;
|
||||
case self::MODE_CTR:
|
||||
case self::MODE_CFB:
|
||||
case self::MODE_OFB:
|
||||
case self::MODE_STREAM:
|
||||
$this->mode = $mode;
|
||||
$this->paddable = false;
|
||||
break;
|
||||
case self::MODE_CBC:
|
||||
default:
|
||||
$this->paddable = true;
|
||||
$this->mode = self::MODE_CBC;
|
||||
throw new \InvalidArgumentException('No valid mode has been specified');
|
||||
}
|
||||
|
||||
$this->_setEngine();
|
||||
$this->mode = $mode;
|
||||
|
||||
// Determining whether inline crypting can be used by the cipher
|
||||
if ($this->use_inline_crypt !== false && function_exists('create_function')) {
|
||||
@ -500,19 +493,28 @@ abstract class Base
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the initialization vector. (optional)
|
||||
* Sets the initialization vector.
|
||||
*
|
||||
* SetIV is not required when self::MODE_ECB (or ie for AES: \phpseclib\Crypt\AES::MODE_ECB) is being used. If not explicitly set, it'll be assumed
|
||||
* to be all zero's.
|
||||
* setIV() is not required when self::MODE_ECB (or ie for AES: \phpseclib\Crypt\AES::MODE_ECB) is being used.
|
||||
*
|
||||
* @access public
|
||||
* @param string $iv
|
||||
* @throws \LengthException if the IV length isn't equal to the block size
|
||||
* @throws \InvalidArgumentException if an IV is provided when one shouldn't be
|
||||
* @internal Can be overwritten by a sub class, but does not have to be
|
||||
*/
|
||||
function setIV($iv)
|
||||
{
|
||||
if ($this->mode == self::MODE_ECB) {
|
||||
return;
|
||||
throw new \InvalidArgumentException('This mode does not require an IV.');
|
||||
}
|
||||
|
||||
if ($this->mode == self::MODE_STREAM && $this->usesIV()) {
|
||||
throw new \InvalidArgumentException('This algorithm does not use an IV.');
|
||||
}
|
||||
|
||||
if (strlen($iv) != $this->block_size) {
|
||||
throw new \LengthException('Received initialization vector of size ' . strlen($iv) . ', but size ' . $this->block_size . ' is required');
|
||||
}
|
||||
|
||||
$this->iv = $iv;
|
||||
@ -520,18 +522,14 @@ abstract class Base
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key length.
|
||||
*
|
||||
* Keys with explicitly set lengths need to be treated accordingly
|
||||
* Returns whether or not the algorithm uses an IV
|
||||
*
|
||||
* @access public
|
||||
* @param int $length
|
||||
* @return bool
|
||||
*/
|
||||
function setKeyLength($length)
|
||||
function usesIV()
|
||||
{
|
||||
$this->explicit_key_length = true;
|
||||
$this->changed = true;
|
||||
$this->_setEngine();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -556,6 +554,24 @@ abstract class Base
|
||||
return $this->block_size << 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key length.
|
||||
*
|
||||
* Keys with explicitly set lengths need to be treated accordingly
|
||||
*
|
||||
* @access public
|
||||
* @param int $length
|
||||
*/
|
||||
function setKeyLength($length)
|
||||
{
|
||||
$this->explicit_key_length = $length >> 3;
|
||||
|
||||
if (is_string($this->key) && strlen($this->key) != $this->explicit_key_length) {
|
||||
$this->key = false;
|
||||
throw new \LengthException('Key has already been set and is not ' .$this->explicit_key_length . ' bytes long');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key.
|
||||
*
|
||||
@ -572,12 +588,12 @@ abstract class Base
|
||||
*/
|
||||
function setKey($key)
|
||||
{
|
||||
if (!$this->explicit_key_length) {
|
||||
$this->setKeyLength(strlen($key) << 3);
|
||||
$this->explicit_key_length = false;
|
||||
if ($this->explicit_key_length !== false && strlen($key) != $this->explicit_key_length) {
|
||||
throw new \LengthException('Key length has already been set to ' . $this->explicit_key_length . ' bytes and this key is ' . strlen($key) . ' bytes');
|
||||
}
|
||||
|
||||
$this->key = $key;
|
||||
$this->key_length = strlen($key);
|
||||
$this->changed = true;
|
||||
$this->_setEngine();
|
||||
}
|
||||
@ -594,6 +610,7 @@ abstract class Base
|
||||
* @see Crypt/Hash.php
|
||||
* @param string $password
|
||||
* @param string $method
|
||||
* @throws \LengthException if pbkdf1 is being used and the derived key length exceeds the hash length
|
||||
* @return bool
|
||||
* @access public
|
||||
* @internal Could, but not must, extend by the child Crypt_* class
|
||||
@ -620,7 +637,8 @@ abstract class Base
|
||||
if (isset($func_args[5])) {
|
||||
$dkLen = $func_args[5];
|
||||
} else {
|
||||
$dkLen = $method == 'pbkdf1' ? 2 * $this->key_length : $this->key_length;
|
||||
$key_length = $this->explicit_key_length !== false ? $this->explicit_key_length : $this->key_length;
|
||||
$dkLen = $method == 'pbkdf1' ? 2 * $key_length : $key_length;
|
||||
}
|
||||
|
||||
switch (true) {
|
||||
@ -628,8 +646,7 @@ abstract class Base
|
||||
$hashObj = new Hash();
|
||||
$hashObj->setHash($hash);
|
||||
if ($dkLen > $hashObj->getLength()) {
|
||||
user_error('Derived key too long');
|
||||
return false;
|
||||
throw new \LengthException('Derived key length cannot be longer than the hash length');
|
||||
}
|
||||
$t = $password . $salt;
|
||||
for ($i = 0; $i < $count; ++$i) {
|
||||
@ -776,7 +793,7 @@ abstract class Base
|
||||
$this->changed = false;
|
||||
}
|
||||
if ($this->enchanged) {
|
||||
mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
|
||||
mcrypt_generic_init($this->enmcrypt, $this->key, $this->_getIV($this->encryptIV));
|
||||
$this->enchanged = false;
|
||||
}
|
||||
|
||||
@ -839,7 +856,7 @@ abstract class Base
|
||||
$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->_getIV($this->encryptIV));
|
||||
}
|
||||
|
||||
return $ciphertext;
|
||||
@ -988,14 +1005,13 @@ abstract class Base
|
||||
* @access public
|
||||
* @param string $ciphertext
|
||||
* @return string $plaintext
|
||||
* @throws \LengthException if we're inside a block cipher and the ciphertext length is not a multiple of the block size
|
||||
* @internal Could, but not must, extend by the child Crypt_* class
|
||||
*/
|
||||
function decrypt($ciphertext)
|
||||
{
|
||||
if ($this->paddable) {
|
||||
// we pad with chr(0) since that's what mcrypt_generic does. to quote from {@link http://www.php.net/function.mcrypt-generic}:
|
||||
// "The data is padded with "\0" to make sure the length of the data is n * blocksize."
|
||||
$ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($this->block_size - strlen($ciphertext) % $this->block_size) % $this->block_size, chr(0));
|
||||
if ($this->paddable && strlen($ciphertext) % $this->block_size) {
|
||||
throw new \LengthException('The ciphertext length (' . strlen($ciphertext) . ') needs to be a multiple of the block size (' . $this->block_size . ')');
|
||||
}
|
||||
|
||||
if ($this->engine === self::ENGINE_OPENSSL) {
|
||||
@ -1088,7 +1104,7 @@ abstract class Base
|
||||
$this->changed = false;
|
||||
}
|
||||
if ($this->dechanged) {
|
||||
mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
|
||||
mcrypt_generic_init($this->demcrypt, $this->key, $this->_getIV($this->decryptIV));
|
||||
$this->dechanged = false;
|
||||
}
|
||||
|
||||
@ -1133,7 +1149,7 @@ abstract class Base
|
||||
$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->_getIV($this->decryptIV));
|
||||
}
|
||||
|
||||
return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
|
||||
@ -1270,6 +1286,22 @@ abstract class Base
|
||||
return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the IV
|
||||
*
|
||||
* mcrypt requires an IV even if ECB is used
|
||||
*
|
||||
* @see self::encrypt()
|
||||
* @see self::decrypt()
|
||||
* @param string $iv
|
||||
* @return string
|
||||
* @access private
|
||||
*/
|
||||
function _getIV($iv)
|
||||
{
|
||||
return $this->mode == self::MODE_ECB ? str_repeat("\0", $this->block_size) : $iv;
|
||||
}
|
||||
|
||||
/**
|
||||
* OpenSSL CTR Processor
|
||||
*
|
||||
@ -1822,6 +1854,7 @@ abstract class Base
|
||||
*
|
||||
* @see self::_unpad()
|
||||
* @param string $text
|
||||
* @throws \LengthException if padding is disabled and the plaintext's length is not a multiple of the block size
|
||||
* @access private
|
||||
* @return string
|
||||
*/
|
||||
@ -1833,8 +1866,7 @@ abstract class Base
|
||||
if ($length % $this->block_size == 0) {
|
||||
return $text;
|
||||
} else {
|
||||
user_error("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size})");
|
||||
$this->padding = true;
|
||||
throw new \LengthException("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size}). Try enabling padding.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1851,6 +1883,7 @@ abstract class Base
|
||||
*
|
||||
* @see self::_pad()
|
||||
* @param string $text
|
||||
* @throws \LengthException if the ciphertext's length is not a multiple of the block size
|
||||
* @access private
|
||||
* @return string
|
||||
*/
|
||||
@ -1863,7 +1896,7 @@ abstract class Base
|
||||
$length = ord($text[strlen($text) - 1]);
|
||||
|
||||
if (!$length || $length > $this->block_size) {
|
||||
return false;
|
||||
throw new \LengthException("The ciphertext has an invalid padding length ($length) compared to the block size ({$this->block_size})");
|
||||
}
|
||||
|
||||
return substr($text, 0, -$length);
|
||||
@ -1876,20 +1909,19 @@ abstract class Base
|
||||
* after disableContinuousBuffer() or on cipher $engine (re)init
|
||||
* ie after setKey() or setIV()
|
||||
*
|
||||
* @access public
|
||||
* @access private
|
||||
* @internal Could, but not must, extend by the child Crypt_* class
|
||||
* @throws \UnexpectedValueException when an IV is required but not defined
|
||||
*/
|
||||
function _clearBuffers()
|
||||
{
|
||||
$this->enbuffer = $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true);
|
||||
|
||||
// mcrypt's handling of invalid's $iv:
|
||||
// $this->encryptIV = $this->decryptIV = strlen($this->iv) == $this->block_size ? $this->iv : str_repeat("\0", $this->block_size);
|
||||
$this->encryptIV = $this->decryptIV = str_pad(substr($this->iv, 0, $this->block_size), $this->block_size, "\0");
|
||||
|
||||
if (!$this->skip_key_adjustment) {
|
||||
$this->key = str_pad(substr($this->key, 0, $this->key_length), $this->key_length, "\0");
|
||||
if ($this->iv === false && !in_array($this->mode, array(self::MODE_STREAM, self::MODE_ECB))) {
|
||||
throw new \UnexpectedValueException('No IV has been defined');
|
||||
}
|
||||
|
||||
$this->encryptIV = $this->decryptIV = $this->iv;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -37,8 +37,6 @@
|
||||
|
||||
namespace phpseclib\Crypt;
|
||||
|
||||
use phpseclib\Crypt\Base;
|
||||
|
||||
/**
|
||||
* Pure-PHP implementation of Blowfish.
|
||||
*
|
||||
@ -285,6 +283,22 @@ class Blowfish extends Base
|
||||
*/
|
||||
var $key_length = 16;
|
||||
|
||||
/**
|
||||
* Default Constructor.
|
||||
*
|
||||
* @param int $mode
|
||||
* @access public
|
||||
* @throws \InvalidArgumentException if an invalid / unsupported mode is provided
|
||||
*/
|
||||
function __construct($mode)
|
||||
{
|
||||
if ($mode == self::MODE_STREAM) {
|
||||
throw new \InvalidArgumentException('Block ciphers cannot be ran in stream mode');
|
||||
}
|
||||
|
||||
parent::__construct($mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key length.
|
||||
*
|
||||
@ -295,14 +309,12 @@ class Blowfish extends Base
|
||||
*/
|
||||
function setKeyLength($length)
|
||||
{
|
||||
if ($length < 32) {
|
||||
$this->key_length = 7;
|
||||
} elseif ($length > 448) {
|
||||
$this->key_length = 56;
|
||||
} else {
|
||||
$this->key_length = $length >> 3;
|
||||
if ($length < 32 || $length > 448) {
|
||||
throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys of sizes between 32 and 448 bits are supported');
|
||||
}
|
||||
|
||||
$this->key_length = $length >> 3;
|
||||
|
||||
parent::setKeyLength($length);
|
||||
}
|
||||
|
||||
|
@ -42,8 +42,6 @@
|
||||
|
||||
namespace phpseclib\Crypt;
|
||||
|
||||
use phpseclib\Crypt\Base;
|
||||
|
||||
/**
|
||||
* Pure-PHP implementation of DES.
|
||||
*
|
||||
@ -580,6 +578,22 @@ class DES extends Base
|
||||
0x00000820, 0x00020020, 0x08000000, 0x08020800
|
||||
);
|
||||
|
||||
/**
|
||||
* Default Constructor.
|
||||
*
|
||||
* @param int $mode
|
||||
* @access public
|
||||
* @throws \InvalidArgumentException if an invalid / unsupported mode is provided
|
||||
*/
|
||||
function __construct($mode)
|
||||
{
|
||||
if ($mode == self::MODE_STREAM) {
|
||||
throw new \InvalidArgumentException('Block ciphers cannot be ran in stream mode');
|
||||
}
|
||||
|
||||
parent::__construct($mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for engine validity
|
||||
*
|
||||
@ -605,24 +619,18 @@ class DES extends Base
|
||||
/**
|
||||
* Sets the key.
|
||||
*
|
||||
* Keys can be of any length. DES, itself, uses 64-bit keys (eg. strlen($key) == 8), however, we
|
||||
* only use the first eight, if $key has more then eight characters in it, and pad $key with the
|
||||
* null byte if it is less then eight characters long.
|
||||
* Keys must be 64-bits long or 8 bytes long.
|
||||
*
|
||||
* DES also requires that every eighth bit be a parity bit, however, we'll ignore that.
|
||||
*
|
||||
* If the key is not explicitly set, it'll be assumed to be all zero's.
|
||||
*
|
||||
* @see \phpseclib\Crypt\Base::setKey()
|
||||
* @access public
|
||||
* @param string $key
|
||||
*/
|
||||
function setKey($key)
|
||||
{
|
||||
// We check/cut here only up to max length of the key.
|
||||
// Key padding to the proper length will be done in _setupKey()
|
||||
if (strlen($key) > $this->key_length_max) {
|
||||
$key = substr($key, 0, $this->key_length_max);
|
||||
if (!($this instanceof TripleDES) && strlen($key) != 8) {
|
||||
throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of size 8 are supported');
|
||||
}
|
||||
|
||||
// Sets the key
|
||||
|
@ -1,26 +1,19 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions.
|
||||
* Wrapper around hash() and hash_hmac() functions supporting truncated hashes
|
||||
* such as sha256-96. Any hash algorithm returned by hash_algos() (and
|
||||
* truncated versions thereof) are supported.
|
||||
*
|
||||
* Uses hash() or mhash() if available and an internal implementation, otherwise. Currently supports the following:
|
||||
*
|
||||
* md2, md5, md5-96, sha1, sha1-96, sha256, sha256-96, sha384, and sha512, sha512-96
|
||||
*
|
||||
* If {@link self::setKey() setKey()} is called, {@link self::hash() hash()} will return the HMAC as opposed to
|
||||
* the hash. If no valid algorithm is provided, sha1 will be used.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* {@internal The variable names are the same as those in
|
||||
* {@link http://tools.ietf.org/html/rfc2104#section-2 RFC2104}.}}
|
||||
* If {@link self::setKey() setKey()} is called, {@link self::hash() hash()} will
|
||||
* return the HMAC as opposed to the hash.
|
||||
*
|
||||
* Here's a short example of how to use this library:
|
||||
* <code>
|
||||
* <?php
|
||||
* include 'vendor/autoload.php';
|
||||
*
|
||||
* $hash = new \phpseclib\Crypt\Hash('sha1');
|
||||
* $hash = new \phpseclib\Crypt\Hash('sha512');
|
||||
*
|
||||
* $hash->setKey('abcdefg');
|
||||
*
|
||||
@ -31,7 +24,9 @@
|
||||
* @category Crypt
|
||||
* @package Hash
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2007 Jim Wigginton
|
||||
* @copyright 2015 Jim Wigginton
|
||||
* @author Andreas Fischer <bantu@phpbb.com>
|
||||
* @copyright 2015 Andreas Fischer
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
*/
|
||||
@ -39,34 +34,16 @@
|
||||
namespace phpseclib\Crypt;
|
||||
|
||||
use phpseclib\Math\BigInteger;
|
||||
use phpseclib\Exception\UnsupportedAlgorithmException;
|
||||
|
||||
/**
|
||||
* Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions.
|
||||
*
|
||||
* @package Hash
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @author Andreas Fischer <bantu@phpbb.com>
|
||||
* @access public
|
||||
*/
|
||||
class Hash
|
||||
{
|
||||
/**#@+
|
||||
* @access private
|
||||
* @see \phpseclib\Crypt\Hash::__construct()
|
||||
*/
|
||||
/**
|
||||
* Toggles the internal implementation
|
||||
*/
|
||||
const MODE_INTERNAL = 1;
|
||||
/**
|
||||
* Toggles the mhash() implementation, which has been deprecated on PHP 5.3.0+.
|
||||
*/
|
||||
const MODE_MHASH = 2;
|
||||
/**
|
||||
* Toggles the hash() implementation, which works on PHP 5.1.2+.
|
||||
*/
|
||||
const MODE_HASH = 3;
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
* Hash Parameter
|
||||
*
|
||||
@ -76,15 +53,6 @@ class Hash
|
||||
*/
|
||||
var $hashParam;
|
||||
|
||||
/**
|
||||
* Byte-length of compression blocks / key (Internal HMAC)
|
||||
*
|
||||
* @see self::setAlgorithm()
|
||||
* @var int
|
||||
* @access private
|
||||
*/
|
||||
var $b;
|
||||
|
||||
/**
|
||||
* Byte-length of hash output (Internal HMAC)
|
||||
*
|
||||
@ -92,7 +60,7 @@ class Hash
|
||||
* @var int
|
||||
* @access private
|
||||
*/
|
||||
var $l = false;
|
||||
var $length;
|
||||
|
||||
/**
|
||||
* Hash Algorithm
|
||||
@ -112,10 +80,23 @@ class Hash
|
||||
*/
|
||||
var $key = false;
|
||||
|
||||
/**
|
||||
* Initial Hash
|
||||
*
|
||||
* Used only for sha512/*
|
||||
*
|
||||
* @see self::_sha512()
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $initial = false;
|
||||
|
||||
/**
|
||||
* Outer XOR (Internal HMAC)
|
||||
*
|
||||
* @see self::setKey()
|
||||
* Used only for sha512/*
|
||||
*
|
||||
* @see self::hash()
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
@ -124,7 +105,9 @@ class Hash
|
||||
/**
|
||||
* Inner XOR (Internal HMAC)
|
||||
*
|
||||
* @see self::setKey()
|
||||
* Used only for sha512/*
|
||||
*
|
||||
* @see self::hash()
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
@ -134,25 +117,14 @@ class Hash
|
||||
* Default Constructor.
|
||||
*
|
||||
* @param string $hash
|
||||
* @return \phpseclib\Crypt\Hash
|
||||
* @access public
|
||||
*/
|
||||
function __construct($hash = 'sha1')
|
||||
function __construct($hash = 'sha256')
|
||||
{
|
||||
if (!defined('CRYPT_HASH_MODE')) {
|
||||
switch (true) {
|
||||
case extension_loaded('hash'):
|
||||
define('CRYPT_HASH_MODE', self::MODE_HASH);
|
||||
break;
|
||||
case extension_loaded('mhash'):
|
||||
define('CRYPT_HASH_MODE', self::MODE_MHASH);
|
||||
break;
|
||||
default:
|
||||
define('CRYPT_HASH_MODE', self::MODE_INTERNAL);
|
||||
}
|
||||
}
|
||||
|
||||
$this->setHash($hash);
|
||||
|
||||
$this->ipad = str_repeat(chr(0x36), 128);
|
||||
$this->opad = str_repeat(chr(0x5C), 128);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -191,101 +163,76 @@ class Hash
|
||||
{
|
||||
$this->hashParam = $hash = strtolower($hash);
|
||||
switch ($hash) {
|
||||
case 'md2-96':
|
||||
case 'md5-96':
|
||||
case 'sha1-96':
|
||||
case 'sha256-96':
|
||||
case 'sha512-96':
|
||||
case 'sha512/224-96':
|
||||
case 'sha512/256-96':
|
||||
$hash = substr($hash, 0, -3);
|
||||
$this->l = 12; // 96 / 8 = 12
|
||||
$this->length = 12; // 96 / 8 = 12
|
||||
break;
|
||||
case 'md2':
|
||||
case 'md5':
|
||||
$this->l = 16;
|
||||
$this->length = 16;
|
||||
break;
|
||||
case 'sha1':
|
||||
$this->l = 20;
|
||||
$this->length = 20;
|
||||
break;
|
||||
case 'sha512/224':
|
||||
$this->length = 28;
|
||||
break;
|
||||
case 'sha256':
|
||||
$this->l = 32;
|
||||
case 'sha512/256':
|
||||
$this->length = 32;
|
||||
break;
|
||||
case 'sha384':
|
||||
$this->l = 48;
|
||||
$this->length = 48;
|
||||
break;
|
||||
case 'sha512':
|
||||
$this->l = 64;
|
||||
}
|
||||
|
||||
switch ($hash) {
|
||||
case 'md2':
|
||||
$mode = 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->length = 64;
|
||||
break;
|
||||
default:
|
||||
$mode = CRYPT_HASH_MODE;
|
||||
}
|
||||
|
||||
switch ($mode) {
|
||||
case self::MODE_MHASH:
|
||||
switch ($hash) {
|
||||
case 'md5':
|
||||
$this->hash = MHASH_MD5;
|
||||
break;
|
||||
case 'sha256':
|
||||
$this->hash = MHASH_SHA256;
|
||||
break;
|
||||
case 'sha1':
|
||||
default:
|
||||
$this->hash = MHASH_SHA1;
|
||||
// see if the hash isn't "officially" supported see if it can
|
||||
// be "unofficially" supported and calculate the length
|
||||
// accordingly.
|
||||
if (in_array($hash, hash_algos())) {
|
||||
$this->length = strlen(hash($hash, '', true));
|
||||
break;
|
||||
}
|
||||
return;
|
||||
case self::MODE_HASH:
|
||||
switch ($hash) {
|
||||
case 'md5':
|
||||
$this->hash = 'md5';
|
||||
return;
|
||||
case 'md2':
|
||||
case 'sha256':
|
||||
case 'sha384':
|
||||
case 'sha512':
|
||||
$this->hash = $hash;
|
||||
return;
|
||||
case 'sha1':
|
||||
default:
|
||||
$this->hash = 'sha1';
|
||||
// if the hash algorithm doens't exist maybe it's a truncated
|
||||
// hash, e.g. whirlpool-12 or some such.
|
||||
if (preg_match('#(-\d+)$#', $hash, $matches)) {
|
||||
$hash = substr($hash, 0, -strlen($matches[1]));
|
||||
if (in_array($hash, hash_algos())) {
|
||||
$this->length = abs($matches[1]) >> 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
throw new UnsupportedAlgorithmException(
|
||||
"$hash is not a supported algorithm"
|
||||
);
|
||||
}
|
||||
|
||||
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');
|
||||
if ($hash == 'sha512/224' || $hash == 'sha512/256') {
|
||||
// from http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf#page=24
|
||||
$this->initial = $hash == 'sha512/256' ?
|
||||
array(
|
||||
'22312194FC2BF72C', '9F555FA3C84C64C2', '2393B86B6F53B151', '963877195940EABD',
|
||||
'96283EE2A88EFFE3', 'BE5E1E2553863992', '2B0199FC2C85B8AA', '0EB72DDC81C52CA2'
|
||||
) :
|
||||
array(
|
||||
'8C3D37C819544DA2', '73E1996689DCD4D6', '1DFAB7AE32FF9C82', '679DD514582F9FCF',
|
||||
'0F6D2B697BD44DA8', '77E36F7304C48942', '3F9D85A86A1D36C8', '1112E6AD91D692A1'
|
||||
);
|
||||
for ($i = 0; $i < 8; $i++) {
|
||||
$this->initial[$i] = new BigInteger($this->initial[$i], 16);
|
||||
$this->initial[$i]->setPrecision(64);
|
||||
}
|
||||
}
|
||||
|
||||
$this->ipad = str_repeat(chr(0x36), $this->b);
|
||||
$this->opad = str_repeat(chr(0x5C), $this->b);
|
||||
$this->hash = $hash;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -297,45 +244,35 @@ class Hash
|
||||
*/
|
||||
function hash($text)
|
||||
{
|
||||
$mode = is_array($this->hash) ? self::MODE_INTERNAL : CRYPT_HASH_MODE;
|
||||
switch ($this->hash) {
|
||||
case 'sha512/224':
|
||||
case 'sha512/256':
|
||||
if (empty($this->key) || !is_string($this->key)) {
|
||||
return substr(self::_sha512($text, $this->initial), 0, $this->length);
|
||||
}
|
||||
/* "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."
|
||||
|
||||
if (!empty($this->key) || is_string($this->key)) {
|
||||
switch ($mode) {
|
||||
case self::MODE_MHASH:
|
||||
$output = mhash($this->hash, $text, $this->key);
|
||||
break;
|
||||
case self::MODE_HASH:
|
||||
$output = hash_hmac($this->hash, $text, $this->key, 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 ? self::_sha512($this->key, $this->initial) : $this->key;
|
||||
|
||||
-- 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($this->key, 128, chr(0)); // step 1
|
||||
$temp = $this->ipad ^ $this->key; // step 2
|
||||
$temp .= $text; // step 3
|
||||
$temp = self::_sha512($temp, $this->initial); // step 4
|
||||
$output = $this->opad ^ $this->key; // step 5
|
||||
$output.= $temp; // step 6
|
||||
$output = self::_sha512($output, $this->initial); // step 7
|
||||
|
||||
$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
|
||||
}
|
||||
} else {
|
||||
switch ($mode) {
|
||||
case self::MODE_MHASH:
|
||||
$output = mhash($this->hash, $text);
|
||||
break;
|
||||
case self::MODE_HASH:
|
||||
$output = hash($this->hash, $text, true);
|
||||
break;
|
||||
case self::MODE_INTERNAL:
|
||||
$output = call_user_func($this->hash, $text);
|
||||
}
|
||||
return substr($output, 0, $this->length);
|
||||
}
|
||||
$output = !empty($this->key) || is_string($this->key) ?
|
||||
hash_hmac($this->hash, $text, $this->key, true) :
|
||||
hash($this->hash, $text, true);
|
||||
|
||||
return substr($output, 0, $this->l);
|
||||
return strlen($output) > $this->length
|
||||
? substr($output, 0, $this->length)
|
||||
: $output;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -346,243 +283,20 @@ class Hash
|
||||
*/
|
||||
function getLength()
|
||||
{
|
||||
return $this->l;
|
||||
return $this->length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for MD5
|
||||
* Pure-PHP implementation of SHA512
|
||||
*
|
||||
* @access private
|
||||
* @param string $m
|
||||
*/
|
||||
function _md5($m)
|
||||
static function _sha512($m, $hash)
|
||||
{
|
||||
return pack('H*', md5($m));
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for SHA1
|
||||
*
|
||||
* @access private
|
||||
* @param string $m
|
||||
*/
|
||||
function _sha1($m)
|
||||
{
|
||||
return pack('H*', sha1($m));
|
||||
}
|
||||
|
||||
/**
|
||||
* Pure-PHP implementation of MD2
|
||||
*
|
||||
* See {@link http://tools.ietf.org/html/rfc1319 RFC1319}.
|
||||
*
|
||||
* @access private
|
||||
* @param string $m
|
||||
*/
|
||||
function _md2($m)
|
||||
{
|
||||
static $s = array(
|
||||
41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
|
||||
19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
|
||||
76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
|
||||
138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
|
||||
245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
|
||||
148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
|
||||
39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
|
||||
181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
|
||||
150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
|
||||
112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
|
||||
96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
|
||||
85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
|
||||
234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
|
||||
129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
|
||||
8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
|
||||
203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
|
||||
166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
|
||||
31, 26, 219, 153, 141, 51, 159, 17, 131, 20
|
||||
);
|
||||
|
||||
// Step 1. Append Padding Bytes
|
||||
$pad = 16 - (strlen($m) & 0xF);
|
||||
$m.= str_repeat(chr($pad), $pad);
|
||||
|
||||
$length = strlen($m);
|
||||
|
||||
// Step 2. Append Checksum
|
||||
$c = str_repeat(chr(0), 16);
|
||||
$l = chr(0);
|
||||
for ($i = 0; $i < $length; $i+= 16) {
|
||||
for ($j = 0; $j < 16; $j++) {
|
||||
// RFC1319 incorrectly states that C[j] should be set to S[c xor L]
|
||||
//$c[$j] = chr($s[ord($m[$i + $j] ^ $l)]);
|
||||
// per <http://www.rfc-editor.org/errata_search.php?rfc=1319>, however, C[j] should be set to S[c xor L] xor C[j]
|
||||
$c[$j] = chr($s[ord($m[$i + $j] ^ $l)] ^ ord($c[$j]));
|
||||
$l = $c[$j];
|
||||
}
|
||||
}
|
||||
$m.= $c;
|
||||
|
||||
$length+= 16;
|
||||
|
||||
// Step 3. Initialize MD Buffer
|
||||
$x = str_repeat(chr(0), 48);
|
||||
|
||||
// Step 4. Process Message in 16-Byte Blocks
|
||||
for ($i = 0; $i < $length; $i+= 16) {
|
||||
for ($j = 0; $j < 16; $j++) {
|
||||
$x[$j + 16] = $m[$i + $j];
|
||||
$x[$j + 32] = $x[$j + 16] ^ $x[$j];
|
||||
}
|
||||
$t = chr(0);
|
||||
for ($j = 0; $j < 18; $j++) {
|
||||
for ($k = 0; $k < 48; $k++) {
|
||||
$x[$k] = $t = $x[$k] ^ chr($s[ord($t)]);
|
||||
//$t = $x[$k] = $x[$k] ^ chr($s[ord($t)]);
|
||||
}
|
||||
$t = chr(ord($t) + $j);
|
||||
}
|
||||
}
|
||||
|
||||
// Step 5. Output
|
||||
return substr($x, 0, 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pure-PHP implementation of SHA256
|
||||
*
|
||||
* See {@link http://en.wikipedia.org/wiki/SHA_hash_functions#SHA-256_.28a_SHA-2_variant.29_pseudocode SHA-256 (a SHA-2 variant) pseudocode - Wikipedia}.
|
||||
*
|
||||
* @access private
|
||||
* @param string $m
|
||||
*/
|
||||
function _sha256($m)
|
||||
{
|
||||
if (extension_loaded('suhosin')) {
|
||||
return pack('H*', sha256($m));
|
||||
}
|
||||
|
||||
// Initialize variables
|
||||
$hash = array(
|
||||
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
|
||||
);
|
||||
// Initialize table of round constants
|
||||
// (first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311)
|
||||
static $k = array(
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
);
|
||||
|
||||
// Pre-processing
|
||||
$length = strlen($m);
|
||||
// to round to nearest 56 mod 64, we'll add 64 - (length + (64 - 56)) % 64
|
||||
$m.= str_repeat(chr(0), 64 - (($length + 8) & 0x3F));
|
||||
$m[$length] = chr(0x80);
|
||||
// we don't support hashing strings 512MB long
|
||||
$m.= pack('N2', 0, $length << 3);
|
||||
|
||||
// Process the message in successive 512-bit chunks
|
||||
$chunks = str_split($m, 64);
|
||||
foreach ($chunks as $chunk) {
|
||||
$w = array();
|
||||
for ($i = 0; $i < 16; $i++) {
|
||||
extract(unpack('Ntemp', $this->_string_shift($chunk, 4)));
|
||||
$w[] = $temp;
|
||||
}
|
||||
|
||||
// Extend the sixteen 32-bit words into sixty-four 32-bit words
|
||||
for ($i = 16; $i < 64; $i++) {
|
||||
// @codingStandardsIgnoreStart
|
||||
$s0 = $this->_rightRotate($w[$i - 15], 7) ^
|
||||
$this->_rightRotate($w[$i - 15], 18) ^
|
||||
$this->_rightShift( $w[$i - 15], 3);
|
||||
$s1 = $this->_rightRotate($w[$i - 2], 17) ^
|
||||
$this->_rightRotate($w[$i - 2], 19) ^
|
||||
$this->_rightShift( $w[$i - 2], 10);
|
||||
// @codingStandardsIgnoreEnd
|
||||
$w[$i] = $this->_add($w[$i - 16], $s0, $w[$i - 7], $s1);
|
||||
}
|
||||
|
||||
// Initialize hash value for this chunk
|
||||
list($a, $b, $c, $d, $e, $f, $g, $h) = $hash;
|
||||
|
||||
// Main loop
|
||||
for ($i = 0; $i < 64; $i++) {
|
||||
$s0 = $this->_rightRotate($a, 2) ^
|
||||
$this->_rightRotate($a, 13) ^
|
||||
$this->_rightRotate($a, 22);
|
||||
$maj = ($a & $b) ^
|
||||
($a & $c) ^
|
||||
($b & $c);
|
||||
$t2 = $this->_add($s0, $maj);
|
||||
|
||||
$s1 = $this->_rightRotate($e, 6) ^
|
||||
$this->_rightRotate($e, 11) ^
|
||||
$this->_rightRotate($e, 25);
|
||||
$ch = ($e & $f) ^
|
||||
($this->_not($e) & $g);
|
||||
$t1 = $this->_add($h, $s1, $ch, $k[$i], $w[$i]);
|
||||
|
||||
$h = $g;
|
||||
$g = $f;
|
||||
$f = $e;
|
||||
$e = $this->_add($d, $t1);
|
||||
$d = $c;
|
||||
$c = $b;
|
||||
$b = $a;
|
||||
$a = $this->_add($t1, $t2);
|
||||
}
|
||||
|
||||
// Add this chunk's hash to result so far
|
||||
$hash = array(
|
||||
$this->_add($hash[0], $a),
|
||||
$this->_add($hash[1], $b),
|
||||
$this->_add($hash[2], $c),
|
||||
$this->_add($hash[3], $d),
|
||||
$this->_add($hash[4], $e),
|
||||
$this->_add($hash[5], $f),
|
||||
$this->_add($hash[6], $g),
|
||||
$this->_add($hash[7], $h)
|
||||
);
|
||||
}
|
||||
|
||||
// Produce the final hash value (big-endian)
|
||||
return pack('N8', $hash[0], $hash[1], $hash[2], $hash[3], $hash[4], $hash[5], $hash[6], $hash[7]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pure-PHP implementation of SHA384 and SHA512
|
||||
*
|
||||
* @access private
|
||||
* @param string $m
|
||||
*/
|
||||
function _sha512($m)
|
||||
{
|
||||
static $init384, $init512, $k;
|
||||
static $k;
|
||||
|
||||
if (!isset($k)) {
|
||||
// Initialize variables
|
||||
$init384 = array( // initial values for SHA384
|
||||
'cbbb9d5dc1059ed8', '629a292a367cd507', '9159015a3070dd17', '152fecd8f70e5939',
|
||||
'67332667ffc00b31', '8eb44a8768581511', 'db0c2e0d64f98fa7', '47b5481dbefa4fa4'
|
||||
);
|
||||
$init512 = array( // initial values for SHA512
|
||||
'6a09e667f3bcc908', 'bb67ae8584caa73b', '3c6ef372fe94f82b', 'a54ff53a5f1d36f1',
|
||||
'510e527fade682d1', '9b05688c2b3e6c1f', '1f83d9abfb41bd6b', '5be0cd19137e2179'
|
||||
);
|
||||
|
||||
for ($i = 0; $i < 8; $i++) {
|
||||
$init384[$i] = new BigInteger($init384[$i], 16);
|
||||
$init384[$i]->setPrecision(64);
|
||||
$init512[$i] = new BigInteger($init512[$i], 16);
|
||||
$init512[$i]->setPrecision(64);
|
||||
}
|
||||
|
||||
// Initialize table of round constants
|
||||
// (first 64 bits of the fractional parts of the cube roots of the first 80 primes 2..409)
|
||||
$k = array(
|
||||
@ -613,8 +327,6 @@ class Hash
|
||||
}
|
||||
}
|
||||
|
||||
$hash = $this->l == 48 ? $init384 : $init512;
|
||||
|
||||
// Pre-processing
|
||||
$length = strlen($m);
|
||||
// to round to nearest 112 mod 128, we'll add 128 - (length + (128 - 112)) % 128
|
||||
@ -628,7 +340,7 @@ class Hash
|
||||
foreach ($chunks as $chunk) {
|
||||
$w = array();
|
||||
for ($i = 0; $i < 16; $i++) {
|
||||
$temp = new BigInteger($this->_string_shift($chunk, 8), 256);
|
||||
$temp = new BigInteger(self::_string_shift($chunk, 8), 256);
|
||||
$temp->setPrecision(64);
|
||||
$w[] = $temp;
|
||||
}
|
||||
@ -649,21 +361,21 @@ class Hash
|
||||
);
|
||||
$s1 = $temp[0]->bitwise_xor($temp[1]);
|
||||
$s1 = $s1->bitwise_xor($temp[2]);
|
||||
$w[$i] = $w[$i - 16]->copy();
|
||||
$w[$i] = clone $w[$i - 16];
|
||||
$w[$i] = $w[$i]->add($s0);
|
||||
$w[$i] = $w[$i]->add($w[$i - 7]);
|
||||
$w[$i] = $w[$i]->add($s1);
|
||||
}
|
||||
|
||||
// Initialize hash value for this chunk
|
||||
$a = $hash[0]->copy();
|
||||
$b = $hash[1]->copy();
|
||||
$c = $hash[2]->copy();
|
||||
$d = $hash[3]->copy();
|
||||
$e = $hash[4]->copy();
|
||||
$f = $hash[5]->copy();
|
||||
$g = $hash[6]->copy();
|
||||
$h = $hash[7]->copy();
|
||||
$a = clone $hash[0];
|
||||
$b = clone $hash[1];
|
||||
$c = clone $hash[2];
|
||||
$d = clone $hash[3];
|
||||
$e = clone $hash[4];
|
||||
$f = clone $hash[5];
|
||||
$g = clone $hash[6];
|
||||
$h = clone $hash[7];
|
||||
|
||||
// Main loop
|
||||
for ($i = 0; $i < 80; $i++) {
|
||||
@ -700,13 +412,13 @@ class Hash
|
||||
$t1 = $t1->add($k[$i]);
|
||||
$t1 = $t1->add($w[$i]);
|
||||
|
||||
$h = $g->copy();
|
||||
$g = $f->copy();
|
||||
$f = $e->copy();
|
||||
$h = clone $g;
|
||||
$g = clone $f;
|
||||
$f = clone $e;
|
||||
$e = $d->add($t1);
|
||||
$d = $c->copy();
|
||||
$c = $b->copy();
|
||||
$b = $a->copy();
|
||||
$d = clone $c;
|
||||
$c = clone $b;
|
||||
$b = clone $a;
|
||||
$a = $t1->add($t2);
|
||||
}
|
||||
|
||||
@ -726,85 +438,11 @@ class Hash
|
||||
// Produce the final hash value (big-endian)
|
||||
// (\phpseclib\Crypt\Hash::hash() trims the output for hashes but not for HMACs. as such, we trim the output here)
|
||||
$temp = $hash[0]->toBytes() . $hash[1]->toBytes() . $hash[2]->toBytes() . $hash[3]->toBytes() .
|
||||
$hash[4]->toBytes() . $hash[5]->toBytes();
|
||||
if ($this->l != 48) {
|
||||
$temp.= $hash[6]->toBytes() . $hash[7]->toBytes();
|
||||
}
|
||||
$hash[4]->toBytes() . $hash[5]->toBytes() . $hash[6]->toBytes() . $hash[7]->toBytes();
|
||||
|
||||
return $temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Right Rotate
|
||||
*
|
||||
* @access private
|
||||
* @param int $int
|
||||
* @param int $amt
|
||||
* @see self::_sha256()
|
||||
* @return int
|
||||
*/
|
||||
function _rightRotate($int, $amt)
|
||||
{
|
||||
$invamt = 32 - $amt;
|
||||
$mask = (1 << $invamt) - 1;
|
||||
return (($int << $invamt) & 0xFFFFFFFF) | (($int >> $amt) & $mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Right Shift
|
||||
*
|
||||
* @access private
|
||||
* @param int $int
|
||||
* @param int $amt
|
||||
* @see self::_sha256()
|
||||
* @return int
|
||||
*/
|
||||
function _rightShift($int, $amt)
|
||||
{
|
||||
$mask = (1 << (32 - $amt)) - 1;
|
||||
return ($int >> $amt) & $mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Not
|
||||
*
|
||||
* @access private
|
||||
* @param int $int
|
||||
* @see self::_sha256()
|
||||
* @return int
|
||||
*/
|
||||
function _not($int)
|
||||
{
|
||||
return ~$int & 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add
|
||||
*
|
||||
* _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
|
||||
*/
|
||||
function _add()
|
||||
{
|
||||
static $mod;
|
||||
if (!isset($mod)) {
|
||||
$mod = pow(2, 32);
|
||||
}
|
||||
|
||||
$result = 0;
|
||||
$arguments = func_get_args();
|
||||
foreach ($arguments as $argument) {
|
||||
$result+= $argument < 0 ? ($argument & 0x7FFFFFFF) + 0x80000000 : $argument;
|
||||
}
|
||||
|
||||
return fmod($result, $mod);
|
||||
}
|
||||
|
||||
/**
|
||||
* String Shift
|
||||
*
|
||||
@ -815,7 +453,7 @@ class Hash
|
||||
* @return string
|
||||
* @access private
|
||||
*/
|
||||
function _string_shift(&$string, $index = 1)
|
||||
static function _string_shift(&$string, $index = 1)
|
||||
{
|
||||
$substr = substr($string, 0, $index);
|
||||
$string = substr($string, $index);
|
||||
|
@ -35,8 +35,6 @@
|
||||
|
||||
namespace phpseclib\Crypt;
|
||||
|
||||
use phpseclib\Crypt\Base;
|
||||
|
||||
/**
|
||||
* Pure-PHP implementation of RC2.
|
||||
*
|
||||
@ -261,6 +259,22 @@ class RC2 extends Base
|
||||
0x70, 0x02, 0xC2, 0x1E, 0xB8, 0x0A, 0xFC, 0xE6
|
||||
);
|
||||
|
||||
/**
|
||||
* Default Constructor.
|
||||
*
|
||||
* @param int $mode
|
||||
* @access public
|
||||
* @throws \InvalidArgumentException if an invalid / unsupported mode is provided
|
||||
*/
|
||||
function __construct($mode)
|
||||
{
|
||||
if ($mode == self::MODE_STREAM) {
|
||||
throw new \InvalidArgumentException('Block ciphers cannot be ran in stream mode');
|
||||
}
|
||||
|
||||
parent::__construct($mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for engine validity
|
||||
*
|
||||
@ -294,19 +308,15 @@ class RC2 extends Base
|
||||
*
|
||||
* @access public
|
||||
* @param int $length in bits
|
||||
* @throws \LengthException if the key length isn't supported
|
||||
*/
|
||||
function setKeyLength($length)
|
||||
{
|
||||
if ($length < 8) {
|
||||
$this->default_key_length = 8;
|
||||
} elseif ($length > 1024) {
|
||||
$this->default_key_length = 128;
|
||||
} else {
|
||||
$this->default_key_length = $length;
|
||||
if ($length < 8 || $length > 1024) {
|
||||
throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys between 1 and 1024 bits, inclusive, are supported');
|
||||
}
|
||||
$this->current_key_length = $this->default_key_length;
|
||||
|
||||
parent::setKeyLength($length);
|
||||
$this->default_key_length = $this->current_key_length = $length;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -335,16 +345,20 @@ class RC2 extends Base
|
||||
* @access public
|
||||
* @param string $key
|
||||
* @param int $t1 optional Effective key length in bits.
|
||||
* @throws \LengthException if the key length isn't supported
|
||||
*/
|
||||
function setKey($key, $t1 = 0)
|
||||
function setKey($key, $t1 = false)
|
||||
{
|
||||
$this->orig_key = $key;
|
||||
|
||||
if ($t1 <= 0) {
|
||||
if ($t1 === false) {
|
||||
$t1 = $this->default_key_length;
|
||||
} elseif ($t1 > 1024) {
|
||||
$t1 = 1024;
|
||||
}
|
||||
|
||||
if ($t1 < 1 || $t1 > 1024) {
|
||||
throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys between 1 and 1024 bits, inclusive, are supported');
|
||||
}
|
||||
|
||||
$this->current_key_length = $t1;
|
||||
// Key byte count should be 1..128.
|
||||
$key = strlen($key) ? substr($key, 0, 128) : "\x00";
|
||||
|
@ -44,8 +44,6 @@
|
||||
|
||||
namespace phpseclib\Crypt;
|
||||
|
||||
use phpseclib\Crypt\Base;
|
||||
|
||||
/**
|
||||
* Pure-PHP implementation of RC4.
|
||||
*
|
||||
@ -123,8 +121,6 @@ class RC4 extends Base
|
||||
/**
|
||||
* Default Constructor.
|
||||
*
|
||||
* Determines whether or not the mcrypt extension should be used.
|
||||
*
|
||||
* @see \phpseclib\Crypt\Base::__construct()
|
||||
* @return \phpseclib\Crypt\RC4
|
||||
* @access public
|
||||
@ -167,26 +163,14 @@ class RC4 extends Base
|
||||
}
|
||||
|
||||
/**
|
||||
* Dummy function.
|
||||
* RC4 does not use an IV
|
||||
*
|
||||
* Some protocols, such as WEP, prepend an "initialization vector" to the key, effectively creating a new key [1].
|
||||
* If you need to use an initialization vector in this manner, feel free to prepend it to the key, yourself, before
|
||||
* calling setKey().
|
||||
*
|
||||
* [1] WEP's initialization vectors (IV's) are used in a somewhat insecure way. Since, in that protocol,
|
||||
* the IV's are relatively easy to predict, an attack described by
|
||||
* {@link http://www.drizzle.com/~aboba/IEEE/rc4_ksaproc.pdf Scott Fluhrer, Itsik Mantin, and Adi Shamir}
|
||||
* can be used to quickly guess at the rest of the key. The following links elaborate:
|
||||
*
|
||||
* {@link http://www.rsa.com/rsalabs/node.asp?id=2009 http://www.rsa.com/rsalabs/node.asp?id=2009}
|
||||
* {@link http://en.wikipedia.org/wiki/Related_key_attack http://en.wikipedia.org/wiki/Related_key_attack}
|
||||
*
|
||||
* @param string $iv
|
||||
* @see self::setKey()
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
function setIV($iv)
|
||||
function usesIV()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -196,20 +180,38 @@ class RC4 extends Base
|
||||
*
|
||||
* @access public
|
||||
* @param int $length
|
||||
* @throws \LengthException if the key length is invalid
|
||||
*/
|
||||
function setKeyLength($length)
|
||||
{
|
||||
if ($length < 8) {
|
||||
$this->key_length = 1;
|
||||
} elseif ($length > 2048) {
|
||||
$this->key_length = 256;
|
||||
} else {
|
||||
$this->key_length = $length >> 3;
|
||||
if ($length < 8 || $length > 2048) {
|
||||
throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys between 1 and 256 bytes are supported');
|
||||
}
|
||||
|
||||
$this->key_length = $length >> 3;
|
||||
|
||||
parent::setKeyLength($length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key length
|
||||
*
|
||||
* Keys can be between 1 and 256 bytes long.
|
||||
*
|
||||
* @access public
|
||||
* @param int $length
|
||||
* @throws \LengthException if the key length is invalid
|
||||
*/
|
||||
function setKey($key)
|
||||
{
|
||||
$length = strlen($key);
|
||||
if ($length < 1 || $length > 256) {
|
||||
throw new \LengthException('Key size of ' . $length . ' bytes is not supported by RC4. Keys must be between 1 and 256 bytes long');
|
||||
}
|
||||
|
||||
parent::setKey($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts a message.
|
||||
*
|
||||
|
File diff suppressed because it is too large
Load Diff
223
phpseclib/Crypt/RSA/MSBLOB.php
Normal file
223
phpseclib/Crypt/RSA/MSBLOB.php
Normal file
@ -0,0 +1,223 @@
|
||||
<?php
|
||||
/**
|
||||
* Miccrosoft BLOB Formatted RSA Key Handler
|
||||
*
|
||||
* More info:
|
||||
*
|
||||
* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375601(v=vs.85).aspx
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category Crypt
|
||||
* @package RSA
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2015 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
*/
|
||||
|
||||
namespace phpseclib\Crypt\RSA;
|
||||
|
||||
use phpseclib\Math\BigInteger;
|
||||
|
||||
/**
|
||||
* Microsoft BLOB Formatted RSA Key Handler
|
||||
*
|
||||
* @package RSA
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
class MSBLOB
|
||||
{
|
||||
/**#@+
|
||||
* @access private
|
||||
*/
|
||||
/**
|
||||
* Public/Private Key Pair
|
||||
*/
|
||||
const PRIVATEKEYBLOB = 0x7;
|
||||
/**
|
||||
* Public Key
|
||||
*/
|
||||
const PUBLICKEYBLOB = 0x6;
|
||||
/**
|
||||
* Public Key
|
||||
*/
|
||||
const PUBLICKEYBLOBEX = 0xA;
|
||||
/**
|
||||
* RSA public key exchange algorithm
|
||||
*/
|
||||
const CALG_RSA_KEYX = 0x0000A400;
|
||||
/**
|
||||
* RSA public key exchange algorithm
|
||||
*/
|
||||
const CALG_RSA_SIGN = 0x00002400;
|
||||
/**
|
||||
* Public Key
|
||||
*/
|
||||
const RSA1 = 0x31415352;
|
||||
/**
|
||||
* Private Key
|
||||
*/
|
||||
const RSA2 = 0x32415352;
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
* Break a public or private key down into its constituent components
|
||||
*
|
||||
* @access public
|
||||
* @param string $key
|
||||
* @param string $password optional
|
||||
* @return array
|
||||
*/
|
||||
static function load($key, $password = '')
|
||||
{
|
||||
if (!is_string($key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$key = base64_decode($key);
|
||||
|
||||
if (!is_string($key) || strlen($key) < 20) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// PUBLICKEYSTRUC publickeystruc
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa387453(v=vs.85).aspx
|
||||
extract(unpack('atype/aversion/vreserved/Valgo', self::_string_shift($key, 8)));
|
||||
switch (ord($type)) {
|
||||
case self::PUBLICKEYBLOB:
|
||||
case self::PUBLICKEYBLOBEX:
|
||||
$publickey = true;
|
||||
break;
|
||||
case self::PRIVATEKEYBLOB:
|
||||
$publickey = false;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
$components = array('isPublicKey' => $publickey);
|
||||
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa375549(v=vs.85).aspx
|
||||
switch ($algo) {
|
||||
case self::CALG_RSA_KEYX:
|
||||
case self::CALG_RSA_SIGN:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
// RSAPUBKEY rsapubkey
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa387685(v=vs.85).aspx
|
||||
// could do V for pubexp but that's unsigned 32-bit whereas some PHP installs only do signed 32-bit
|
||||
extract(unpack('Vmagic/Vbitlen/a4pubexp', self::_string_shift($key, 12)));
|
||||
switch ($magic) {
|
||||
case self::RSA2:
|
||||
$components['isPublicKey'] = false;
|
||||
case self::RSA1:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
$baseLength = $bitlen / 16;
|
||||
if (strlen($key) != 2 * $baseLength && strlen($key) != 9 * $baseLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$components[$components['isPublicKey'] ? 'publicExponent' : 'privateExponent'] = new BigInteger(strrev($pubexp), 256);
|
||||
// BYTE modulus[rsapubkey.bitlen/8]
|
||||
$components['modulus'] = new BigInteger(strrev(self::_string_shift($key, $bitlen / 8)), 256);
|
||||
|
||||
if ($publickey) {
|
||||
return $components;
|
||||
}
|
||||
|
||||
$components['isPublicKey'] = false;
|
||||
|
||||
// BYTE prime1[rsapubkey.bitlen/16]
|
||||
$components['primes'] = array(1 => new BigInteger(strrev(self::_string_shift($key, $bitlen / 16)), 256));
|
||||
// BYTE prime2[rsapubkey.bitlen/16]
|
||||
$components['primes'][] = new BigInteger(strrev(self::_string_shift($key, $bitlen / 16)), 256);
|
||||
// BYTE exponent1[rsapubkey.bitlen/16]
|
||||
$components['exponents'] = array(1 => new BigInteger(strrev(self::_string_shift($key, $bitlen / 16)), 256));
|
||||
// BYTE exponent2[rsapubkey.bitlen/16]
|
||||
$components['exponents'][] = new BigInteger(strrev(self::_string_shift($key, $bitlen / 16)), 256);
|
||||
// BYTE coefficient[rsapubkey.bitlen/16]
|
||||
$components['coefficients'] = array(2 => new BigInteger(strrev(self::_string_shift($key, $bitlen / 16)), 256));
|
||||
if (isset($components['privateExponent'])) {
|
||||
$components['publicExponent'] = $components['privateExponent'];
|
||||
}
|
||||
// BYTE privateExponent[rsapubkey.bitlen/8]
|
||||
$components['privateExponent'] = new BigInteger(strrev(self::_string_shift($key, $bitlen / 8)), 256);
|
||||
|
||||
return $components;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a private key to the appropriate format.
|
||||
*
|
||||
* @access public
|
||||
* @param \phpseclib\Math\BigInteger $n
|
||||
* @param \phpseclib\Math\BigInteger $e
|
||||
* @param \phpseclib\Math\BigInteger $d
|
||||
* @param array $primes
|
||||
* @param array $exponents
|
||||
* @param array $coefficients
|
||||
* @param string $password optional
|
||||
* @return string
|
||||
*/
|
||||
static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, $primes, $exponents, $coefficients, $password = '')
|
||||
{
|
||||
$n = strrev($n->toBytes());
|
||||
$e = str_pad(strrev($e->toBytes()), 4, "\0");
|
||||
$key = pack('aavV', chr(self::PRIVATEKEYBLOB), chr(2), 0, self::CALG_RSA_KEYX);
|
||||
$key.= pack('VVa*', self::RSA2, 8 * strlen($n), $e);
|
||||
$key.= $n;
|
||||
$key.= strrev($primes[1]->toBytes());
|
||||
$key.= strrev($primes[2]->toBytes());
|
||||
$key.= strrev($exponents[1]->toBytes());
|
||||
$key.= strrev($exponents[2]->toBytes());
|
||||
$key.= strrev($coefficients[1]->toBytes());
|
||||
$key.= strrev($d->toBytes());
|
||||
|
||||
return base64_encode($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a public key to the appropriate format
|
||||
*
|
||||
* @access public
|
||||
* @param \phpseclib\Math\BigInteger $n
|
||||
* @param \phpseclib\Math\BigInteger $e
|
||||
* @return string
|
||||
*/
|
||||
static function savePublicKey(BigInteger $n, BigInteger $e)
|
||||
{
|
||||
$n = strrev($n->toBytes());
|
||||
$e = str_pad(strrev($e->toBytes()), 4, "\0");
|
||||
$key = pack('aavV', chr(self::PUBLICKEYBLOB), chr(2), 0, self::CALG_RSA_KEYX);
|
||||
$key.= pack('VVa*', self::RSA1, 8 * strlen($n), $e);
|
||||
$key.= $n;
|
||||
|
||||
return base64_encode($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* String Shift
|
||||
*
|
||||
* Inspired by array_shift
|
||||
*
|
||||
* @param string $string
|
||||
* @param int $index
|
||||
* @return string
|
||||
* @access private
|
||||
*/
|
||||
static function _string_shift(&$string, $index = 1)
|
||||
{
|
||||
$substr = substr($string, 0, $index);
|
||||
$string = substr($string, $index);
|
||||
return $substr;
|
||||
}
|
||||
}
|
140
phpseclib/Crypt/RSA/OpenSSH.php
Normal file
140
phpseclib/Crypt/RSA/OpenSSH.php
Normal file
@ -0,0 +1,140 @@
|
||||
<?php
|
||||
/**
|
||||
* OpenSSH Formatted RSA Key Handler
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* Place in $HOME/.ssh/authorized_keys
|
||||
*
|
||||
* @category Crypt
|
||||
* @package RSA
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2015 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
*/
|
||||
|
||||
namespace phpseclib\Crypt\RSA;
|
||||
|
||||
use phpseclib\Math\BigInteger;
|
||||
|
||||
/**
|
||||
* OpenSSH Formatted RSA Key Handler
|
||||
*
|
||||
* @package RSA
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
class OpenSSH
|
||||
{
|
||||
/**
|
||||
* Default comment
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
static $comment = 'phpseclib-generated-key';
|
||||
|
||||
/**
|
||||
* Sets the default comment
|
||||
*
|
||||
* @access public
|
||||
* @param string $comment
|
||||
*/
|
||||
static function setComment($comment)
|
||||
{
|
||||
self::$comment = str_replace(array("\r", "\n"), '', $comment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Break a public or private key down into its constituent components
|
||||
*
|
||||
* @access public
|
||||
* @param string $key
|
||||
* @param string $password optional
|
||||
* @return array
|
||||
*/
|
||||
static function load($key, $password = '')
|
||||
{
|
||||
if (!is_string($key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$parts = explode(' ', $key, 3);
|
||||
|
||||
$key = isset($parts[1]) ? base64_decode($parts[1]) : base64_decode($parts[0]);
|
||||
if ($key === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$comment = isset($parts[2]) ? $parts[2] : false;
|
||||
|
||||
if (substr($key, 0, 11) != "\0\0\0\7ssh-rsa") {
|
||||
return false;
|
||||
}
|
||||
self::_string_shift($key, 11);
|
||||
if (strlen($key) <= 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nlength', self::_string_shift($key, 4)));
|
||||
if (strlen($key) <= $length) {
|
||||
return false;
|
||||
}
|
||||
$publicExponent = new BigInteger(self::_string_shift($key, $length), -256);
|
||||
if (strlen($key) <= 4) {
|
||||
return false;
|
||||
}
|
||||
extract(unpack('Nlength', self::_string_shift($key, 4)));
|
||||
if (strlen($key) != $length) {
|
||||
return false;
|
||||
}
|
||||
$modulus = new BigInteger(self::_string_shift($key, $length), -256);
|
||||
|
||||
return array(
|
||||
'isPublicKey' => true,
|
||||
'modulus' => $modulus,
|
||||
'publicExponent' => $publicExponent,
|
||||
'comment' => $comment
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a public key to the appropriate format
|
||||
*
|
||||
* @access public
|
||||
* @param \phpseclib\Math\BigInteger $n
|
||||
* @param \phpseclib\Math\BigInteger $e
|
||||
* @return string
|
||||
*/
|
||||
static function savePublicKey(BigInteger $n, BigInteger $e)
|
||||
{
|
||||
$publicExponent = $e->toBytes(true);
|
||||
$modulus = $n->toBytes(true);
|
||||
|
||||
// from <http://tools.ietf.org/html/rfc4253#page-15>:
|
||||
// string "ssh-rsa"
|
||||
// mpint e
|
||||
// mpint n
|
||||
$RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus);
|
||||
$RSAPublicKey = 'ssh-rsa ' . base64_encode($RSAPublicKey) . ' ' . self::$comment;
|
||||
|
||||
return $RSAPublicKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* String Shift
|
||||
*
|
||||
* Inspired by array_shift
|
||||
*
|
||||
* @param string $string
|
||||
* @param int $index
|
||||
* @return string
|
||||
* @access private
|
||||
*/
|
||||
static function _string_shift(&$string, $index = 1)
|
||||
{
|
||||
$substr = substr($string, 0, $index);
|
||||
$string = substr($string, $index);
|
||||
return $substr;
|
||||
}
|
||||
}
|
485
phpseclib/Crypt/RSA/PKCS.php
Normal file
485
phpseclib/Crypt/RSA/PKCS.php
Normal file
@ -0,0 +1,485 @@
|
||||
<?php
|
||||
/**
|
||||
* PKCS Formatted RSA Key Handler
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category Crypt
|
||||
* @package RSA
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2015 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
*/
|
||||
|
||||
namespace phpseclib\Crypt\RSA;
|
||||
|
||||
use phpseclib\Crypt\AES;
|
||||
use phpseclib\Crypt\Base;
|
||||
use phpseclib\Crypt\DES;
|
||||
use phpseclib\Crypt\TripleDES;
|
||||
use phpseclib\Math\BigInteger;
|
||||
|
||||
/**
|
||||
* PKCS Formatted RSA Key Handler
|
||||
*
|
||||
* @package RSA
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
abstract class PKCS
|
||||
{
|
||||
/**#@+
|
||||
* @access private
|
||||
* @see \phpseclib\Crypt\RSA::createKey()
|
||||
*/
|
||||
/**
|
||||
* ASN1 Integer
|
||||
*/
|
||||
const ASN1_INTEGER = 2;
|
||||
/**
|
||||
* ASN1 Bit String
|
||||
*/
|
||||
const ASN1_BITSTRING = 3;
|
||||
/**
|
||||
* ASN1 Octet String
|
||||
*/
|
||||
const ASN1_OCTETSTRING = 4;
|
||||
/**
|
||||
* ASN1 Object Identifier
|
||||
*/
|
||||
const ASN1_OBJECT = 6;
|
||||
/**
|
||||
* ASN1 Sequence (with the constucted bit set)
|
||||
*/
|
||||
const ASN1_SEQUENCE = 48;
|
||||
/**#@-*/
|
||||
|
||||
/**#@+
|
||||
* @access private
|
||||
*/
|
||||
/**
|
||||
* Auto-detect the format
|
||||
*/
|
||||
const MODE_ANY = 0;
|
||||
/**
|
||||
* Require base64-encoded PEM's be supplied
|
||||
*/
|
||||
const MODE_PEM = 1;
|
||||
/**
|
||||
* Require raw DER's be supplied
|
||||
*/
|
||||
const MODE_DER = 2;
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
* Is the key a base-64 encoded PEM, DER or should it be auto-detected?
|
||||
*
|
||||
* @access private
|
||||
* @param int
|
||||
*/
|
||||
static $format = self::MODE_ANY;
|
||||
|
||||
/**
|
||||
* Returns the mode constant corresponding to the mode string
|
||||
*
|
||||
* @access public
|
||||
* @param string $mode
|
||||
* @return int
|
||||
* @throws \UnexpectedValueException if the block cipher mode is unsupported
|
||||
*/
|
||||
static function getEncryptionMode($mode)
|
||||
{
|
||||
switch ($mode) {
|
||||
case 'CBC':
|
||||
return Base::MODE_CBC;
|
||||
case 'ECB':
|
||||
return Base::MODE_ECB;
|
||||
case 'CFB':
|
||||
return Base::MODE_CFB;
|
||||
case 'OFB':
|
||||
return Base::MODE_OFB;
|
||||
case 'CTR':
|
||||
return Base::MODE_CTR;
|
||||
}
|
||||
throw new \UnexpectedValueException('Unsupported block cipher mode of operation');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a cipher object corresponding to a string
|
||||
*
|
||||
* @access public
|
||||
* @param string $algo
|
||||
* @return string
|
||||
* @throws \UnexpectedValueException if the encryption algorithm is unsupported
|
||||
*/
|
||||
static function getEncryptionObject($algo)
|
||||
{
|
||||
$modes = '(CBC|ECB|CFB|OFB|CTR)';
|
||||
switch (true) {
|
||||
case preg_match("#^AES-(128|192|256)-$modes$#", $algo, $matches):
|
||||
$cipher = new AES(self::getEncryptionMode($matches[2]));
|
||||
$cipher->setKeyLength($matches[1]);
|
||||
return $cipher;
|
||||
case preg_match("#^DES-EDE3-$modes$#", $algo, $matches):
|
||||
return new TripleDES(self::getEncryptionMode($matches[1]));
|
||||
case preg_match("#^DES-$modes$#", $algo, $matches):
|
||||
return new DES(self::getEncryptionMode($matches[1]));
|
||||
default:
|
||||
throw new \UnexpectedValueException('Unsupported encryption algorithmn');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a symmetric key for PKCS#1 keys
|
||||
*
|
||||
* @access public
|
||||
* @param string $password
|
||||
* @param string $iv
|
||||
* @param int $length
|
||||
* @return string
|
||||
*/
|
||||
static function generateSymmetricKey($password, $iv, $length)
|
||||
{
|
||||
$symkey = '';
|
||||
$iv = substr($iv, 0, 8);
|
||||
while (strlen($symkey) < $length) {
|
||||
$symkey.= pack('H*', md5($symkey . $password . $iv));
|
||||
}
|
||||
return substr($symkey, 0, $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Break a public or private key down into its constituent components
|
||||
*
|
||||
* @access public
|
||||
* @param string $key
|
||||
* @param string $password optional
|
||||
* @return array
|
||||
*/
|
||||
static function load($key, $password = '')
|
||||
{
|
||||
if (!is_string($key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$components = array('isPublicKey' => strpos($key, 'PUBLIC') !== false);
|
||||
|
||||
/* Although PKCS#1 proposes a format that public and private keys can use, encrypting them is
|
||||
"outside the scope" of PKCS#1. PKCS#1 then refers you to PKCS#12 and PKCS#15 if you're wanting to
|
||||
protect private keys, however, that's not what OpenSSL* does. OpenSSL protects private keys by adding
|
||||
two new "fields" to the key - DEK-Info and Proc-Type. These fields are discussed here:
|
||||
|
||||
http://tools.ietf.org/html/rfc1421#section-4.6.1.1
|
||||
http://tools.ietf.org/html/rfc1421#section-4.6.1.3
|
||||
|
||||
DES-EDE3-CBC as an algorithm, however, is not discussed anywhere, near as I can tell.
|
||||
DES-CBC and DES-EDE are discussed in RFC1423, however, DES-EDE3-CBC isn't, nor is its key derivation
|
||||
function. As is, the definitive authority on this encoding scheme isn't the IETF but rather OpenSSL's
|
||||
own implementation. ie. the implementation *is* the standard and any bugs that may exist in that
|
||||
implementation are part of the standard, as well.
|
||||
|
||||
* OpenSSL is the de facto standard. It's utilized by OpenSSH and other projects */
|
||||
if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) {
|
||||
$iv = pack('H*', trim($matches[2]));
|
||||
// remove the Proc-Type / DEK-Info sections as they're no longer needed
|
||||
$key = preg_replace('#^(?:Proc-Type|DEK-Info): .*#m', '', $key);
|
||||
$ciphertext = self::_extractBER($key);
|
||||
if ($ciphertext === false) {
|
||||
$ciphertext = $key;
|
||||
}
|
||||
$crypto = self::getEncryptionObject($matches[1]);
|
||||
$crypto->setKey(self::generateSymmetricKey($password, $iv, $crypto->getKeyLength() >> 3));
|
||||
$crypto->setIV($iv);
|
||||
$key = $crypto->decrypt($ciphertext);
|
||||
if ($key === false) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (self::$format != self::MODE_DER) {
|
||||
$decoded = self::_extractBER($key);
|
||||
if ($decoded !== false) {
|
||||
$key = $decoded;
|
||||
} elseif (self::$format == self::MODE_PEM) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ord(self::_string_shift($key)) != self::ASN1_SEQUENCE) {
|
||||
return false;
|
||||
}
|
||||
if (self::_decodeLength($key) != strlen($key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$tag = ord(self::_string_shift($key));
|
||||
/* intended for keys for which OpenSSL's asn1parse returns the following:
|
||||
|
||||
0:d=0 hl=4 l= 631 cons: SEQUENCE
|
||||
4:d=1 hl=2 l= 1 prim: INTEGER :00
|
||||
7:d=1 hl=2 l= 13 cons: SEQUENCE
|
||||
9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
|
||||
20:d=2 hl=2 l= 0 prim: NULL
|
||||
22:d=1 hl=4 l= 609 prim: OCTET STRING
|
||||
|
||||
ie. PKCS8 keys */
|
||||
|
||||
if ($tag == self::ASN1_INTEGER && substr($key, 0, 3) == "\x01\x00\x30") {
|
||||
self::_string_shift($key, 3);
|
||||
$tag = self::ASN1_SEQUENCE;
|
||||
}
|
||||
|
||||
if ($tag == self::ASN1_SEQUENCE) {
|
||||
$temp = self::_string_shift($key, self::_decodeLength($key));
|
||||
if (ord(self::_string_shift($temp)) != self::ASN1_OBJECT) {
|
||||
return false;
|
||||
}
|
||||
$length = self::_decodeLength($temp);
|
||||
switch (self::_string_shift($temp, $length)) {
|
||||
case "\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01": // rsaEncryption
|
||||
break;
|
||||
case "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03": // pbeWithMD5AndDES-CBC
|
||||
/*
|
||||
PBEParameter ::= SEQUENCE {
|
||||
salt OCTET STRING (SIZE(8)),
|
||||
iterationCount INTEGER }
|
||||
*/
|
||||
if (ord(self::_string_shift($temp)) != self::ASN1_SEQUENCE) {
|
||||
return false;
|
||||
}
|
||||
if (self::_decodeLength($temp) != strlen($temp)) {
|
||||
return false;
|
||||
}
|
||||
self::_string_shift($temp); // assume it's an octet string
|
||||
$salt = self::_string_shift($temp, self::_decodeLength($temp));
|
||||
if (ord(self::_string_shift($temp)) != self::ASN1_INTEGER) {
|
||||
return false;
|
||||
}
|
||||
self::_decodeLength($temp);
|
||||
list(, $iterationCount) = unpack('N', str_pad($temp, 4, chr(0), STR_PAD_LEFT));
|
||||
self::_string_shift($key); // assume it's an octet string
|
||||
$length = self::_decodeLength($key);
|
||||
if (strlen($key) != $length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$crypto = new DES(DES::MODE_CBC);
|
||||
$crypto->setPassword($password, 'pbkdf1', 'md5', $salt, $iterationCount);
|
||||
$key = $crypto->decrypt($key);
|
||||
if ($key === false) {
|
||||
return false;
|
||||
}
|
||||
return self::load($key);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
/* intended for keys for which OpenSSL's asn1parse returns the following:
|
||||
|
||||
0:d=0 hl=4 l= 290 cons: SEQUENCE
|
||||
4:d=1 hl=2 l= 13 cons: SEQUENCE
|
||||
6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
|
||||
17:d=2 hl=2 l= 0 prim: NULL
|
||||
19:d=1 hl=4 l= 271 prim: BIT STRING */
|
||||
$tag = ord(self::_string_shift($key)); // skip over the BIT STRING / OCTET STRING tag
|
||||
self::_decodeLength($key); // skip over the BIT STRING / OCTET STRING length
|
||||
// "The initial octet shall encode, as an unsigned binary integer wtih bit 1 as the least significant bit, the number of
|
||||
// unused bits in the final subsequent octet. The number shall be in the range zero to seven."
|
||||
// -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf (section 8.6.2.2)
|
||||
if ($tag == self::ASN1_BITSTRING) {
|
||||
self::_string_shift($key);
|
||||
}
|
||||
if (ord(self::_string_shift($key)) != self::ASN1_SEQUENCE) {
|
||||
return false;
|
||||
}
|
||||
if (self::_decodeLength($key) != strlen($key)) {
|
||||
return false;
|
||||
}
|
||||
$tag = ord(self::_string_shift($key));
|
||||
}
|
||||
if ($tag != self::ASN1_INTEGER) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$length = self::_decodeLength($key);
|
||||
$temp = self::_string_shift($key, $length);
|
||||
if (strlen($temp) != 1 || ord($temp) > 2) {
|
||||
$components['modulus'] = new BigInteger($temp, 256);
|
||||
self::_string_shift($key); // skip over self::ASN1_INTEGER
|
||||
$length = self::_decodeLength($key);
|
||||
$components[$components['isPublicKey'] ? 'publicExponent' : 'privateExponent'] = new BigInteger(self::_string_shift($key, $length), 256);
|
||||
|
||||
return $components;
|
||||
}
|
||||
if (ord(self::_string_shift($key)) != self::ASN1_INTEGER) {
|
||||
return false;
|
||||
}
|
||||
$length = self::_decodeLength($key);
|
||||
$components['modulus'] = new BigInteger(self::_string_shift($key, $length), 256);
|
||||
self::_string_shift($key);
|
||||
$length = self::_decodeLength($key);
|
||||
$components['publicExponent'] = new BigInteger(self::_string_shift($key, $length), 256);
|
||||
self::_string_shift($key);
|
||||
$length = self::_decodeLength($key);
|
||||
$components['privateExponent'] = new BigInteger(self::_string_shift($key, $length), 256);
|
||||
self::_string_shift($key);
|
||||
$length = self::_decodeLength($key);
|
||||
$components['primes'] = array(1 => new BigInteger(self::_string_shift($key, $length), 256));
|
||||
self::_string_shift($key);
|
||||
$length = self::_decodeLength($key);
|
||||
$components['primes'][] = new BigInteger(self::_string_shift($key, $length), 256);
|
||||
self::_string_shift($key);
|
||||
$length = self::_decodeLength($key);
|
||||
$components['exponents'] = array(1 => new BigInteger(self::_string_shift($key, $length), 256));
|
||||
self::_string_shift($key);
|
||||
$length = self::_decodeLength($key);
|
||||
$components['exponents'][] = new BigInteger(self::_string_shift($key, $length), 256);
|
||||
self::_string_shift($key);
|
||||
$length = self::_decodeLength($key);
|
||||
$components['coefficients'] = array(2 => new BigInteger(self::_string_shift($key, $length), 256));
|
||||
|
||||
if (!empty($key)) {
|
||||
if (ord(self::_string_shift($key)) != self::ASN1_SEQUENCE) {
|
||||
return false;
|
||||
}
|
||||
self::_decodeLength($key);
|
||||
while (!empty($key)) {
|
||||
if (ord(self::_string_shift($key)) != self::ASN1_SEQUENCE) {
|
||||
return false;
|
||||
}
|
||||
self::_decodeLength($key);
|
||||
$key = substr($key, 1);
|
||||
$length = self::_decodeLength($key);
|
||||
$components['primes'][] = new BigInteger(self::_string_shift($key, $length), 256);
|
||||
self::_string_shift($key);
|
||||
$length = self::_decodeLength($key);
|
||||
$components['exponents'][] = new BigInteger(self::_string_shift($key, $length), 256);
|
||||
self::_string_shift($key);
|
||||
$length = self::_decodeLength($key);
|
||||
$components['coefficients'][] = new BigInteger(self::_string_shift($key, $length), 256);
|
||||
}
|
||||
}
|
||||
|
||||
return $components;
|
||||
}
|
||||
|
||||
/**
|
||||
* Require base64-encoded PEM's be supplied
|
||||
*
|
||||
* @see self::load()
|
||||
* @access public
|
||||
*/
|
||||
static function requirePEM()
|
||||
{
|
||||
self::$format = self::MODE_PEM;
|
||||
}
|
||||
|
||||
/**
|
||||
* Require raw DER's be supplied
|
||||
*
|
||||
* @see self::load()
|
||||
* @access public
|
||||
*/
|
||||
static function requireDER()
|
||||
{
|
||||
self::$format = self::MODE_DER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept any format and auto detect the format
|
||||
*
|
||||
* This is the default setting
|
||||
*
|
||||
* @see self::load()
|
||||
* @access public
|
||||
*/
|
||||
static function requireAny()
|
||||
{
|
||||
self::$format = self::MODE_ANY;
|
||||
}
|
||||
|
||||
/**
|
||||
* DER-decode the length
|
||||
*
|
||||
* DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
|
||||
* {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
|
||||
*
|
||||
* @access private
|
||||
* @param string $string
|
||||
* @return int
|
||||
*/
|
||||
static function _decodeLength(&$string)
|
||||
{
|
||||
$length = ord(self::_string_shift($string));
|
||||
if ($length & 0x80) { // definite length, long form
|
||||
$length&= 0x7F;
|
||||
$temp = self::_string_shift($string, $length);
|
||||
list(, $length) = unpack('N', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4));
|
||||
}
|
||||
return $length;
|
||||
}
|
||||
|
||||
/**
|
||||
* DER-encode the length
|
||||
*
|
||||
* DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
|
||||
* {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
|
||||
*
|
||||
* @access private
|
||||
* @param int $length
|
||||
* @return string
|
||||
*/
|
||||
static function _encodeLength($length)
|
||||
{
|
||||
if ($length <= 0x7F) {
|
||||
return chr($length);
|
||||
}
|
||||
|
||||
$temp = ltrim(pack('N', $length), chr(0));
|
||||
return pack('Ca*', 0x80 | strlen($temp), $temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* String Shift
|
||||
*
|
||||
* Inspired by array_shift
|
||||
*
|
||||
* @param string $string
|
||||
* @param int $index
|
||||
* @return string
|
||||
* @access private
|
||||
*/
|
||||
static function _string_shift(&$string, $index = 1)
|
||||
{
|
||||
$substr = substr($string, 0, $index);
|
||||
$string = substr($string, $index);
|
||||
return $substr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract raw BER from Base64 encoding
|
||||
*
|
||||
* @access private
|
||||
* @param string $str
|
||||
* @return string
|
||||
*/
|
||||
static function _extractBER($str)
|
||||
{
|
||||
/* X.509 certs are assumed to be base64 encoded but sometimes they'll have additional things in them
|
||||
* above and beyond the ceritificate.
|
||||
* ie. some may have the following preceding the -----BEGIN CERTIFICATE----- line:
|
||||
*
|
||||
* Bag Attributes
|
||||
* localKeyID: 01 00 00 00
|
||||
* 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);
|
||||
// remove new lines
|
||||
$temp = str_replace(array("\r", "\n", ' '), '', $temp);
|
||||
$temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false;
|
||||
return $temp != false ? $temp : $str;
|
||||
}
|
||||
}
|
172
phpseclib/Crypt/RSA/PKCS1.php
Normal file
172
phpseclib/Crypt/RSA/PKCS1.php
Normal file
@ -0,0 +1,172 @@
|
||||
<?php
|
||||
/**
|
||||
* PKCS#1 Formatted RSA Key Handler
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* Used by File/X509.php
|
||||
*
|
||||
* Has the following header:
|
||||
*
|
||||
* -----BEGIN RSA PUBLIC KEY-----
|
||||
*
|
||||
* Analogous to ssh-keygen's pem format (as specified by -m)
|
||||
*
|
||||
* @category Crypt
|
||||
* @package RSA
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2015 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
*/
|
||||
|
||||
namespace phpseclib\Crypt\RSA;
|
||||
|
||||
use phpseclib\Crypt\AES;
|
||||
use phpseclib\Crypt\DES;
|
||||
use phpseclib\Crypt\Random;
|
||||
use phpseclib\Crypt\TripleDES;
|
||||
use phpseclib\Math\BigInteger;
|
||||
|
||||
/**
|
||||
* PKCS#1 Formatted RSA Key Handler
|
||||
*
|
||||
* @package RSA
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
class PKCS1 extends PKCS
|
||||
{
|
||||
/**
|
||||
* Default encryption algorithm
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
static $defaultEncryptionAlgorithm = 'DES-EDE3-CBC';
|
||||
|
||||
/**
|
||||
* Sets the default encryption algorithm
|
||||
*
|
||||
* @access public
|
||||
* @param string $algo
|
||||
*/
|
||||
static function setEncryptionAlgorithm($algo)
|
||||
{
|
||||
self::$defaultEncryptionAlgorithm = $algo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a private key to the appropriate format.
|
||||
*
|
||||
* @access public
|
||||
* @param \phpseclib\Math\BigInteger $n
|
||||
* @param \phpseclib\Math\BigInteger $e
|
||||
* @param \phpseclib\Math\BigInteger $d
|
||||
* @param array $primes
|
||||
* @param array $exponents
|
||||
* @param array $coefficients
|
||||
* @param string $password optional
|
||||
* @return string
|
||||
*/
|
||||
static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, $primes, $exponents, $coefficients, $password = '')
|
||||
{
|
||||
$num_primes = count($primes);
|
||||
$raw = array(
|
||||
'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi
|
||||
'modulus' => $n->toBytes(true),
|
||||
'publicExponent' => $e->toBytes(true),
|
||||
'privateExponent' => $d->toBytes(true),
|
||||
'prime1' => $primes[1]->toBytes(true),
|
||||
'prime2' => $primes[2]->toBytes(true),
|
||||
'exponent1' => $exponents[1]->toBytes(true),
|
||||
'exponent2' => $exponents[2]->toBytes(true),
|
||||
'coefficient' => $coefficients[2]->toBytes(true)
|
||||
);
|
||||
|
||||
$components = array();
|
||||
foreach ($raw as $name => $value) {
|
||||
$components[$name] = pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($value)), $value);
|
||||
}
|
||||
|
||||
$RSAPrivateKey = implode('', $components);
|
||||
|
||||
if ($num_primes > 2) {
|
||||
$OtherPrimeInfos = '';
|
||||
for ($i = 3; $i <= $num_primes; $i++) {
|
||||
// OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
|
||||
//
|
||||
// OtherPrimeInfo ::= SEQUENCE {
|
||||
// prime INTEGER, -- ri
|
||||
// exponent INTEGER, -- di
|
||||
// coefficient INTEGER -- ti
|
||||
// }
|
||||
$OtherPrimeInfo = pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($primes[$i]->toBytes(true))), $primes[$i]->toBytes(true));
|
||||
$OtherPrimeInfo.= pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($exponents[$i]->toBytes(true))), $exponents[$i]->toBytes(true));
|
||||
$OtherPrimeInfo.= pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($coefficients[$i]->toBytes(true))), $coefficients[$i]->toBytes(true));
|
||||
$OtherPrimeInfos.= pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($OtherPrimeInfo)), $OtherPrimeInfo);
|
||||
}
|
||||
$RSAPrivateKey.= pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($OtherPrimeInfos)), $OtherPrimeInfos);
|
||||
}
|
||||
|
||||
$RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
|
||||
|
||||
if (!empty($password) || is_string($password)) {
|
||||
$cipher = self::getEncryptionObject(self::$defaultEncryptionAlgorithm);
|
||||
$iv = Random::string($cipher->getBlockLength() >> 3);
|
||||
$cipher->setKey(self::generateSymmetricKey($password, $iv, $cipher->getKeyLength() >> 3));
|
||||
$cipher->setIV($iv);
|
||||
$iv = strtoupper(bin2hex($iv));
|
||||
$RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
|
||||
"Proc-Type: 4,ENCRYPTED\r\n" .
|
||||
"DEK-Info: " . self::$defaultEncryptionAlgorithm . ",$iv\r\n" .
|
||||
"\r\n" .
|
||||
chunk_split(base64_encode($cipher->encrypt($RSAPrivateKey)), 64) .
|
||||
'-----END RSA PRIVATE KEY-----';
|
||||
} else {
|
||||
$RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
|
||||
chunk_split(base64_encode($RSAPrivateKey), 64) .
|
||||
'-----END RSA PRIVATE KEY-----';
|
||||
}
|
||||
|
||||
return $RSAPrivateKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a public key to the appropriate format
|
||||
*
|
||||
* @access public
|
||||
* @param \phpseclib\Math\BigInteger $n
|
||||
* @param \phpseclib\Math\BigInteger $e
|
||||
* @return string
|
||||
*/
|
||||
static function savePublicKey(BigInteger $n, BigInteger $e)
|
||||
{
|
||||
$modulus = $n->toBytes(true);
|
||||
$publicExponent = $e->toBytes(true);
|
||||
|
||||
// from <http://tools.ietf.org/html/rfc3447#appendix-A.1.1>:
|
||||
// RSAPublicKey ::= SEQUENCE {
|
||||
// modulus INTEGER, -- n
|
||||
// publicExponent INTEGER -- e
|
||||
// }
|
||||
$components = array(
|
||||
'modulus' => pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($modulus)), $modulus),
|
||||
'publicExponent' => pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($publicExponent)), $publicExponent)
|
||||
);
|
||||
|
||||
$RSAPublicKey = pack(
|
||||
'Ca*a*a*',
|
||||
self::ASN1_SEQUENCE,
|
||||
self::_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])),
|
||||
$components['modulus'],
|
||||
$components['publicExponent']
|
||||
);
|
||||
|
||||
$RSAPublicKey = "-----BEGIN RSA PUBLIC KEY-----\r\n" .
|
||||
chunk_split(base64_encode($RSAPublicKey), 64) .
|
||||
'-----END RSA PUBLIC KEY-----';
|
||||
|
||||
return $RSAPublicKey;
|
||||
}
|
||||
}
|
208
phpseclib/Crypt/RSA/PKCS8.php
Normal file
208
phpseclib/Crypt/RSA/PKCS8.php
Normal file
@ -0,0 +1,208 @@
|
||||
<?php
|
||||
/**
|
||||
* PKCS#8 Formatted RSA Key Handler
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* Used by PHP's openssl_public_encrypt() and openssl's rsautl (when -pubin is set)
|
||||
*
|
||||
* Has the following header:
|
||||
*
|
||||
* -----BEGIN PUBLIC KEY-----
|
||||
*
|
||||
* Analogous to ssh-keygen's pkcs8 format (as specified by -m). Although PKCS8
|
||||
* is specific to private keys it's basically creating a DER-encoded wrapper
|
||||
* for keys. This just extends that same concept to public keys (much like ssh-keygen)
|
||||
*
|
||||
* @category Crypt
|
||||
* @package RSA
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2015 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
*/
|
||||
|
||||
namespace phpseclib\Crypt\RSA;
|
||||
|
||||
use phpseclib\Crypt\DES;
|
||||
use phpseclib\Crypt\Random;
|
||||
use phpseclib\Math\BigInteger;
|
||||
|
||||
/**
|
||||
* PKCS#8 Formatted RSA Key Handler
|
||||
*
|
||||
* @package RSA
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
class PKCS8 extends PKCS
|
||||
{
|
||||
/**
|
||||
* Convert a private key to the appropriate format.
|
||||
*
|
||||
* @access public
|
||||
* @param \phpseclib\Math\BigInteger $n
|
||||
* @param \phpseclib\Math\BigInteger $e
|
||||
* @param \phpseclib\Math\BigInteger $d
|
||||
* @param array $primes
|
||||
* @param array $exponents
|
||||
* @param array $coefficients
|
||||
* @param string $password optional
|
||||
* @return string
|
||||
*/
|
||||
static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, $primes, $exponents, $coefficients, $password = '')
|
||||
{
|
||||
$num_primes = count($primes);
|
||||
$raw = array(
|
||||
'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi
|
||||
'modulus' => $n->toBytes(true),
|
||||
'publicExponent' => $e->toBytes(true),
|
||||
'privateExponent' => $d->toBytes(true),
|
||||
'prime1' => $primes[1]->toBytes(true),
|
||||
'prime2' => $primes[2]->toBytes(true),
|
||||
'exponent1' => $exponents[1]->toBytes(true),
|
||||
'exponent2' => $exponents[2]->toBytes(true),
|
||||
'coefficient' => $coefficients[2]->toBytes(true)
|
||||
);
|
||||
|
||||
$components = array();
|
||||
foreach ($raw as $name => $value) {
|
||||
$components[$name] = pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($value)), $value);
|
||||
}
|
||||
|
||||
$RSAPrivateKey = implode('', $components);
|
||||
|
||||
if ($num_primes > 2) {
|
||||
$OtherPrimeInfos = '';
|
||||
for ($i = 3; $i <= $num_primes; $i++) {
|
||||
// OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
|
||||
//
|
||||
// OtherPrimeInfo ::= SEQUENCE {
|
||||
// prime INTEGER, -- ri
|
||||
// exponent INTEGER, -- di
|
||||
// coefficient INTEGER -- ti
|
||||
// }
|
||||
$OtherPrimeInfo = pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($primes[$i]->toBytes(true))), $primes[$i]->toBytes(true));
|
||||
$OtherPrimeInfo.= pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($exponents[$i]->toBytes(true))), $exponents[$i]->toBytes(true));
|
||||
$OtherPrimeInfo.= pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($coefficients[$i]->toBytes(true))), $coefficients[$i]->toBytes(true));
|
||||
$OtherPrimeInfos.= pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($OtherPrimeInfo)), $OtherPrimeInfo);
|
||||
}
|
||||
$RSAPrivateKey.= pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($OtherPrimeInfos)), $OtherPrimeInfos);
|
||||
}
|
||||
|
||||
$RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
|
||||
|
||||
$rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
|
||||
$RSAPrivateKey = pack(
|
||||
'Ca*a*Ca*a*',
|
||||
self::ASN1_INTEGER,
|
||||
"\01\00",
|
||||
$rsaOID,
|
||||
4,
|
||||
self::_encodeLength(strlen($RSAPrivateKey)),
|
||||
$RSAPrivateKey
|
||||
);
|
||||
$RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
|
||||
if (!empty($password) || is_string($password)) {
|
||||
$salt = Random::string(8);
|
||||
$iterationCount = 2048;
|
||||
|
||||
$crypto = new DES(DES::MODE_CBC);
|
||||
$crypto->setPassword($password, 'pbkdf1', 'md5', $salt, $iterationCount);
|
||||
$RSAPrivateKey = $crypto->encrypt($RSAPrivateKey);
|
||||
|
||||
$parameters = pack(
|
||||
'Ca*a*Ca*N',
|
||||
self::ASN1_OCTETSTRING,
|
||||
self::_encodeLength(strlen($salt)),
|
||||
$salt,
|
||||
self::ASN1_INTEGER,
|
||||
self::_encodeLength(4),
|
||||
$iterationCount
|
||||
);
|
||||
$pbeWithMD5AndDES_CBC = "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03";
|
||||
|
||||
$encryptionAlgorithm = pack(
|
||||
'Ca*a*Ca*a*',
|
||||
self::ASN1_OBJECT,
|
||||
self::_encodeLength(strlen($pbeWithMD5AndDES_CBC)),
|
||||
$pbeWithMD5AndDES_CBC,
|
||||
self::ASN1_SEQUENCE,
|
||||
self::_encodeLength(strlen($parameters)),
|
||||
$parameters
|
||||
);
|
||||
|
||||
$RSAPrivateKey = pack(
|
||||
'Ca*a*Ca*a*',
|
||||
self::ASN1_SEQUENCE,
|
||||
self::_encodeLength(strlen($encryptionAlgorithm)),
|
||||
$encryptionAlgorithm,
|
||||
self::ASN1_OCTETSTRING,
|
||||
self::_encodeLength(strlen($RSAPrivateKey)),
|
||||
$RSAPrivateKey
|
||||
);
|
||||
|
||||
$RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
|
||||
|
||||
$RSAPrivateKey = "-----BEGIN ENCRYPTED PRIVATE KEY-----\r\n" .
|
||||
chunk_split(base64_encode($RSAPrivateKey), 64) .
|
||||
'-----END ENCRYPTED PRIVATE KEY-----';
|
||||
} else {
|
||||
$RSAPrivateKey = "-----BEGIN PRIVATE KEY-----\r\n" .
|
||||
chunk_split(base64_encode($RSAPrivateKey), 64) .
|
||||
'-----END PRIVATE KEY-----';
|
||||
}
|
||||
|
||||
return $RSAPrivateKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a public key to the appropriate format
|
||||
*
|
||||
* @access public
|
||||
* @param \phpseclib\Math\BigInteger $n
|
||||
* @param \phpseclib\Math\BigInteger $e
|
||||
* @return string
|
||||
*/
|
||||
static function savePublicKey(BigInteger $n, BigInteger $e)
|
||||
{
|
||||
$modulus = $n->toBytes(true);
|
||||
$publicExponent = $e->toBytes(true);
|
||||
|
||||
// from <http://tools.ietf.org/html/rfc3447#appendix-A.1.1>:
|
||||
// RSAPublicKey ::= SEQUENCE {
|
||||
// modulus INTEGER, -- n
|
||||
// publicExponent INTEGER -- e
|
||||
// }
|
||||
$components = array(
|
||||
'modulus' => pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($modulus)), $modulus),
|
||||
'publicExponent' => pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($publicExponent)), $publicExponent)
|
||||
);
|
||||
|
||||
$RSAPublicKey = pack(
|
||||
'Ca*a*a*',
|
||||
self::ASN1_SEQUENCE,
|
||||
self::_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])),
|
||||
$components['modulus'],
|
||||
$components['publicExponent']
|
||||
);
|
||||
|
||||
// sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption.
|
||||
$rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
|
||||
$RSAPublicKey = chr(0) . $RSAPublicKey;
|
||||
$RSAPublicKey = chr(3) . self::_encodeLength(strlen($RSAPublicKey)) . $RSAPublicKey;
|
||||
|
||||
$RSAPublicKey = pack(
|
||||
'Ca*a*',
|
||||
self::ASN1_SEQUENCE,
|
||||
self::_encodeLength(strlen($rsaOID . $RSAPublicKey)),
|
||||
$rsaOID . $RSAPublicKey
|
||||
);
|
||||
|
||||
$RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
|
||||
chunk_split(base64_encode($RSAPublicKey), 64) .
|
||||
'-----END PUBLIC KEY-----';
|
||||
|
||||
return $RSAPublicKey;
|
||||
}
|
||||
}
|
311
phpseclib/Crypt/RSA/PuTTY.php
Normal file
311
phpseclib/Crypt/RSA/PuTTY.php
Normal file
@ -0,0 +1,311 @@
|
||||
<?php
|
||||
/**
|
||||
* PuTTY Formatted RSA Key Handler
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category Crypt
|
||||
* @package RSA
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2015 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
*/
|
||||
|
||||
namespace phpseclib\Crypt\RSA;
|
||||
|
||||
use phpseclib\Crypt\AES;
|
||||
use phpseclib\Crypt\Hash;
|
||||
use phpseclib\Math\BigInteger;
|
||||
|
||||
/**
|
||||
* PuTTY Formatted RSA Key Handler
|
||||
*
|
||||
* @package RSA
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
class PuTTY
|
||||
{
|
||||
/**
|
||||
* Default comment
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
static $comment = 'phpseclib-generated-key';
|
||||
|
||||
/**
|
||||
* Sets the default comment
|
||||
*
|
||||
* @access public
|
||||
* @param string $comment
|
||||
*/
|
||||
static function setComment($comment)
|
||||
{
|
||||
self::$comment = str_replace(array("\r", "\n"), '', $comment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a symmetric key for PuTTY keys
|
||||
*
|
||||
* @access public
|
||||
* @param string $password
|
||||
* @param string $iv
|
||||
* @param int $length
|
||||
* @return string
|
||||
*/
|
||||
static function generateSymmetricKey($password, $length)
|
||||
{
|
||||
$symkey = '';
|
||||
$sequence = 0;
|
||||
while (strlen($symkey) < $length) {
|
||||
$temp = pack('Na*', $sequence++, $password);
|
||||
$symkey.= pack('H*', sha1($temp));
|
||||
}
|
||||
return substr($symkey, 0, $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Break a public or private key down into its constituent components
|
||||
*
|
||||
* @access public
|
||||
* @param string $key
|
||||
* @param string $password optional
|
||||
* @return array
|
||||
*/
|
||||
static function load($key, $password = '')
|
||||
{
|
||||
if (!is_string($key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static $one;
|
||||
if (!isset($one)) {
|
||||
$one = new BigInteger(1);
|
||||
}
|
||||
|
||||
if (strpos($key, 'BEGIN SSH2 PUBLIC KEY')) {
|
||||
$data = preg_split('#[\r\n]+#', $key);
|
||||
$data = array_splice($data, 2, -1);
|
||||
$data = implode('', $data);
|
||||
|
||||
$components = OpenSSH::load($data);
|
||||
if ($components === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!preg_match('#Comment: "(.+)"#', $key, $matches)) {
|
||||
return false;
|
||||
}
|
||||
$components['comment'] = str_replace(array('\\\\', '\"'), array('\\', '"'), $matches[1]);
|
||||
|
||||
return $components;
|
||||
}
|
||||
|
||||
$components = array('isPublicKey' => false);
|
||||
$key = preg_split('#\r\n|\r|\n#', $key);
|
||||
$type = trim(preg_replace('#PuTTY-User-Key-File-2: (.+)#', '$1', $key[0]));
|
||||
if ($type != 'ssh-rsa') {
|
||||
return false;
|
||||
}
|
||||
$encryption = trim(preg_replace('#Encryption: (.+)#', '$1', $key[1]));
|
||||
$components['comment'] = trim(preg_replace('#Comment: (.+)#', '$1', $key[2]));
|
||||
|
||||
$publicLength = trim(preg_replace('#Public-Lines: (\d+)#', '$1', $key[3]));
|
||||
$public = base64_decode(implode('', array_map('trim', array_slice($key, 4, $publicLength))));
|
||||
$public = substr($public, 11);
|
||||
extract(unpack('Nlength', self::_string_shift($public, 4)));
|
||||
$components['publicExponent'] = new BigInteger(self::_string_shift($public, $length), -256);
|
||||
extract(unpack('Nlength', self::_string_shift($public, 4)));
|
||||
$components['modulus'] = new BigInteger(self::_string_shift($public, $length), -256);
|
||||
|
||||
$privateLength = trim(preg_replace('#Private-Lines: (\d+)#', '$1', $key[$publicLength + 4]));
|
||||
$private = base64_decode(implode('', array_map('trim', array_slice($key, $publicLength + 5, $privateLength))));
|
||||
|
||||
switch ($encryption) {
|
||||
case 'aes256-cbc':
|
||||
$symkey = static::generateSymmetricKey($password, 32);
|
||||
$crypto = new AES(AES::MODE_CBC);
|
||||
}
|
||||
|
||||
if ($encryption != 'none') {
|
||||
$crypto->setKey($symkey);
|
||||
$crypto->setIV(str_repeat("\0", $crypto->getBlockLength() >> 3));
|
||||
$crypto->disablePadding();
|
||||
$private = $crypto->decrypt($private);
|
||||
if ($private === false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
extract(unpack('Nlength', self::_string_shift($private, 4)));
|
||||
if (strlen($private) < $length) {
|
||||
return false;
|
||||
}
|
||||
$components['privateExponent'] = new BigInteger(self::_string_shift($private, $length), -256);
|
||||
extract(unpack('Nlength', self::_string_shift($private, 4)));
|
||||
if (strlen($private) < $length) {
|
||||
return false;
|
||||
}
|
||||
$components['primes'] = array(1 => new BigInteger(self::_string_shift($private, $length), -256));
|
||||
extract(unpack('Nlength', self::_string_shift($private, 4)));
|
||||
if (strlen($private) < $length) {
|
||||
return false;
|
||||
}
|
||||
$components['primes'][] = new BigInteger(self::_string_shift($private, $length), -256);
|
||||
|
||||
$temp = $components['primes'][1]->subtract($one);
|
||||
$components['exponents'] = array(1 => $components['publicExponent']->modInverse($temp));
|
||||
$temp = $components['primes'][2]->subtract($one);
|
||||
$components['exponents'][] = $components['publicExponent']->modInverse($temp);
|
||||
|
||||
extract(unpack('Nlength', self::_string_shift($private, 4)));
|
||||
if (strlen($private) < $length) {
|
||||
return false;
|
||||
}
|
||||
$components['coefficients'] = array(2 => new BigInteger(self::_string_shift($private, $length), -256));
|
||||
|
||||
return $components;
|
||||
}
|
||||
|
||||
/**
|
||||
* String Shift
|
||||
*
|
||||
* Inspired by array_shift
|
||||
*
|
||||
* @param string $string
|
||||
* @param int $index
|
||||
* @return string
|
||||
* @access private
|
||||
*/
|
||||
static function _string_shift(&$string, $index = 1)
|
||||
{
|
||||
$substr = substr($string, 0, $index);
|
||||
$string = substr($string, $index);
|
||||
return $substr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a private key to the appropriate format.
|
||||
*
|
||||
* @access public
|
||||
* @param \phpseclib\Math\BigInteger $n
|
||||
* @param \phpseclib\Math\BigInteger $e
|
||||
* @param \phpseclib\Math\BigInteger $d
|
||||
* @param array $primes
|
||||
* @param array $exponents
|
||||
* @param array $coefficients
|
||||
* @param string $password optional
|
||||
* @return string
|
||||
*/
|
||||
static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, $primes, $exponents, $coefficients, $password = '')
|
||||
{
|
||||
if (count($primes) != 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$raw = array(
|
||||
'modulus' => $n->toBytes(true),
|
||||
'publicExponent' => $e->toBytes(true),
|
||||
'privateExponent' => $d->toBytes(true),
|
||||
'prime1' => $primes[1]->toBytes(true),
|
||||
'prime2' => $primes[2]->toBytes(true),
|
||||
'exponent1' => $exponents[1]->toBytes(true),
|
||||
'exponent2' => $exponents[2]->toBytes(true),
|
||||
'coefficient' => $coefficients[2]->toBytes(true)
|
||||
);
|
||||
|
||||
$key = "PuTTY-User-Key-File-2: ssh-rsa\r\nEncryption: ";
|
||||
$encryption = (!empty($password) || is_string($password)) ? 'aes256-cbc' : 'none';
|
||||
$key.= $encryption;
|
||||
$key.= "\r\nComment: " . self::$comment . "\r\n";
|
||||
$public = pack(
|
||||
'Na*Na*Na*',
|
||||
strlen('ssh-rsa'),
|
||||
'ssh-rsa',
|
||||
strlen($raw['publicExponent']),
|
||||
$raw['publicExponent'],
|
||||
strlen($raw['modulus']),
|
||||
$raw['modulus']
|
||||
);
|
||||
$source = pack(
|
||||
'Na*Na*Na*Na*',
|
||||
strlen('ssh-rsa'),
|
||||
'ssh-rsa',
|
||||
strlen($encryption),
|
||||
$encryption,
|
||||
strlen(self::$comment),
|
||||
self::$comment,
|
||||
strlen($public),
|
||||
$public
|
||||
);
|
||||
$public = base64_encode($public);
|
||||
$key.= "Public-Lines: " . ((strlen($public) + 63) >> 6) . "\r\n";
|
||||
$key.= chunk_split($public, 64);
|
||||
$private = pack(
|
||||
'Na*Na*Na*Na*',
|
||||
strlen($raw['privateExponent']),
|
||||
$raw['privateExponent'],
|
||||
strlen($raw['prime1']),
|
||||
$raw['prime1'],
|
||||
strlen($raw['prime2']),
|
||||
$raw['prime2'],
|
||||
strlen($raw['coefficient']),
|
||||
$raw['coefficient']
|
||||
);
|
||||
if (empty($password) && !is_string($password)) {
|
||||
$source.= pack('Na*', strlen($private), $private);
|
||||
$hashkey = 'putty-private-key-file-mac-key';
|
||||
} else {
|
||||
$private.= Random::string(16 - (strlen($private) & 15));
|
||||
$source.= pack('Na*', strlen($private), $private);
|
||||
$crypto = new AES();
|
||||
|
||||
$crypto->setKey(static::generateSymmetricKey($password, 32));
|
||||
$crypto->setIV(str_repeat("\0", $crypto->getBlockLength() >> 3));
|
||||
$crypto->disablePadding();
|
||||
$private = $crypto->encrypt($private);
|
||||
$hashkey = 'putty-private-key-file-mac-key' . $password;
|
||||
}
|
||||
|
||||
$private = base64_encode($private);
|
||||
$key.= 'Private-Lines: ' . ((strlen($private) + 63) >> 6) . "\r\n";
|
||||
$key.= chunk_split($private, 64);
|
||||
$hash = new Hash('sha1');
|
||||
$hash->setKey(pack('H*', sha1($hashkey)));
|
||||
$key.= 'Private-MAC: ' . bin2hex($hash->hash($source)) . "\r\n";
|
||||
|
||||
return $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a public key to the appropriate format
|
||||
*
|
||||
* @access public
|
||||
* @param \phpseclib\Math\BigInteger $n
|
||||
* @param \phpseclib\Math\BigInteger $e
|
||||
* @return string
|
||||
*/
|
||||
static function savePublicKey(BigInteger $n, BigInteger $e)
|
||||
{
|
||||
$n = $n->toBytes(true);
|
||||
$e = $e->toBytes(true);
|
||||
|
||||
$key = pack(
|
||||
'Na*Na*Na*',
|
||||
strlen('ssh-rsa'),
|
||||
'ssh-rsa',
|
||||
strlen($e),
|
||||
$e,
|
||||
strlen($n),
|
||||
$n
|
||||
);
|
||||
$key = "---- BEGIN SSH2 PUBLIC KEY ----\r\n" .
|
||||
'Comment: "' . str_replace(array('\\', '"'), array('\\\\', '\"'), self::$comment) . "\"\r\n";
|
||||
chunk_split(base64_encode($key), 64) .
|
||||
'---- END SSH2 PUBLIC KEY ----';
|
||||
|
||||
return $key;
|
||||
}
|
||||
}
|
103
phpseclib/Crypt/RSA/Raw.php
Normal file
103
phpseclib/Crypt/RSA/Raw.php
Normal file
@ -0,0 +1,103 @@
|
||||
<?php
|
||||
/**
|
||||
* Raw RSA Key Handler
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* An array containing two \phpseclib\Math\BigInteger objects.
|
||||
*
|
||||
* The exponent can be indexed with any of the following:
|
||||
*
|
||||
* 0, e, exponent, publicExponent
|
||||
*
|
||||
* The modulus can be indexed with any of the following:
|
||||
*
|
||||
* 1, n, modulo, modulus
|
||||
*
|
||||
* @category Crypt
|
||||
* @package RSA
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2015 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
*/
|
||||
|
||||
namespace phpseclib\Crypt\RSA;
|
||||
|
||||
use phpseclib\Math\BigInteger;
|
||||
|
||||
/**
|
||||
* Raw RSA Key Handler
|
||||
*
|
||||
* @package RSA
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
class Raw
|
||||
{
|
||||
/**
|
||||
* Break a public or private key down into its constituent components
|
||||
*
|
||||
* @access public
|
||||
* @param string $key
|
||||
* @param string $password optional
|
||||
* @return array
|
||||
*/
|
||||
static function load($key, $password = '')
|
||||
{
|
||||
if (!is_array($key)) {
|
||||
return false;
|
||||
}
|
||||
if (isset($key['isPublicKey']) && isset($key['modulus'])) {
|
||||
if (isset($key['privateExponent']) || isset($key['publicExponent'])) {
|
||||
if (!isset($key['primes'])) {
|
||||
return $key;
|
||||
}
|
||||
if (isset($key['exponents']) && isset($key['coefficients']) && isset($key['publicExponent']) && isset($key['privateExponent'])) {
|
||||
return $key;
|
||||
}
|
||||
}
|
||||
}
|
||||
$components = array('isPublicKey' => true);
|
||||
switch (true) {
|
||||
case isset($key['e']):
|
||||
$components['publicExponent'] = $key['e'];
|
||||
break;
|
||||
case isset($key['exponent']):
|
||||
$components['publicExponent'] = $key['exponent'];
|
||||
break;
|
||||
case isset($key['publicExponent']):
|
||||
$components['publicExponent'] = $key['publicExponent'];
|
||||
break;
|
||||
case isset($key[0]):
|
||||
$components['publicExponent'] = $key[0];
|
||||
}
|
||||
switch (true) {
|
||||
case isset($key['n']):
|
||||
$components['modulus'] = $key['n'];
|
||||
break;
|
||||
case isset($key['modulo']):
|
||||
$components['modulus'] = $key['modulo'];
|
||||
break;
|
||||
case isset($key['modulus']):
|
||||
$components['modulus'] = $key['modulus'];
|
||||
break;
|
||||
case isset($key[1]):
|
||||
$components['modulus'] = $key[1];
|
||||
}
|
||||
return isset($components['modulus']) && isset($components['publicExponent']) ? $components : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a public key to the appropriate format
|
||||
*
|
||||
* @access public
|
||||
* @param \phpseclib\Math\BigInteger $n
|
||||
* @param \phpseclib\Math\BigInteger $e
|
||||
* @return string
|
||||
*/
|
||||
static function savePublicKey(BigInteger $n, BigInteger $e)
|
||||
{
|
||||
return array('e' => clone $e, 'n' => clone $n);
|
||||
}
|
||||
}
|
146
phpseclib/Crypt/RSA/XML.php
Normal file
146
phpseclib/Crypt/RSA/XML.php
Normal file
@ -0,0 +1,146 @@
|
||||
<?php
|
||||
/**
|
||||
* XML Formatted RSA Key Handler
|
||||
*
|
||||
* More info:
|
||||
*
|
||||
* http://www.w3.org/TR/xmldsig-core/#sec-RSAKeyValue
|
||||
* http://en.wikipedia.org/wiki/XML_Signature
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category Crypt
|
||||
* @package RSA
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2015 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
*/
|
||||
|
||||
namespace phpseclib\Crypt\RSA;
|
||||
|
||||
use phpseclib\Math\BigInteger;
|
||||
|
||||
/**
|
||||
* XML Formatted RSA Key Handler
|
||||
*
|
||||
* @package RSA
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
class XML
|
||||
{
|
||||
/**
|
||||
* Break a public or private key down into its constituent components
|
||||
*
|
||||
* @access public
|
||||
* @param string $key
|
||||
* @param string $password optional
|
||||
* @return array
|
||||
*/
|
||||
static function load($key, $password = '')
|
||||
{
|
||||
if (!is_string($key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$components = array(
|
||||
'isPublicKey' => false,
|
||||
'primes' => array(),
|
||||
'exponents' => array(),
|
||||
'coefficients' => array()
|
||||
);
|
||||
|
||||
$use_errors = libxml_use_internal_errors(true);
|
||||
|
||||
$dom = new \DOMDocument();
|
||||
if (!$dom->loadXML('<xml>' . $key . '</xml>')) {
|
||||
return false;
|
||||
}
|
||||
$xpath = new \DOMXPath($dom);
|
||||
$keys = array('modulus', 'exponent', 'p', 'q', 'dp', 'dq', 'inverseq', 'd');
|
||||
foreach ($keys as $key) {
|
||||
// $dom->getElementsByTagName($key) is case-sensitive
|
||||
$temp = $xpath->query("//*[translate(local-name(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='$key']");
|
||||
if (!$temp->length) {
|
||||
continue;
|
||||
}
|
||||
$value = new BigInteger(base64_decode($temp->item(0)->nodeValue), 256);
|
||||
switch ($key) {
|
||||
case 'modulus':
|
||||
$components['modulus'] = $value;
|
||||
break;
|
||||
case 'exponent':
|
||||
$components['publicExponent'] = $value;
|
||||
break;
|
||||
case 'p':
|
||||
$components['primes'][1] = $value;
|
||||
break;
|
||||
case 'q':
|
||||
$components['primes'][2] = $value;
|
||||
break;
|
||||
case 'dp':
|
||||
$components['exponents'][1] = $value;
|
||||
break;
|
||||
case 'dq':
|
||||
$components['exponents'][2] = $value;
|
||||
break;
|
||||
case 'inverseq':
|
||||
$components['coefficients'][2] = $value;
|
||||
break;
|
||||
case 'd':
|
||||
$components['privateExponent'] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
libxml_use_internal_errors($use_errors);
|
||||
|
||||
return isset($components['modulus']) && isset($components['publicExponent']) ? $components : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a private key to the appropriate format.
|
||||
*
|
||||
* @access public
|
||||
* @param \phpseclib\Math\BigInteger $n
|
||||
* @param \phpseclib\Math\BigInteger $e
|
||||
* @param \phpseclib\Math\BigInteger $d
|
||||
* @param array $primes
|
||||
* @param array $exponents
|
||||
* @param array $coefficients
|
||||
* @param string $password optional
|
||||
* @return string
|
||||
*/
|
||||
static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, $primes, $exponents, $coefficients, $password = '')
|
||||
{
|
||||
if (count($primes) != 2) {
|
||||
return false;
|
||||
}
|
||||
return "<RSAKeyValue>\r\n" .
|
||||
' <Modulus>' . base64_encode($n->toBytes()) . "</Modulus>\r\n" .
|
||||
' <Exponent>' . base64_encode($e->toBytes()) . "</Exponent>\r\n" .
|
||||
' <P>' . base64_encode($primes[1]->toBytes()) . "</P>\r\n" .
|
||||
' <Q>' . base64_encode($primes[2]->toBytes()) . "</Q>\r\n" .
|
||||
' <DP>' . base64_encode($exponents[1]->toBytes()) . "</DP>\r\n" .
|
||||
' <DQ>' . base64_encode($exponents[2]->toBytes()) . "</DQ>\r\n" .
|
||||
' <InverseQ>' . base64_encode($coefficients[2]->toBytes()) . "</InverseQ>\r\n" .
|
||||
' <D>' . base64_encode($d->toBytes()) . "</D>\r\n" .
|
||||
'</RSAKeyValue>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a public key to the appropriate format
|
||||
*
|
||||
* @access public
|
||||
* @param \phpseclib\Math\BigInteger $n
|
||||
* @param \phpseclib\Math\BigInteger $e
|
||||
* @return string
|
||||
*/
|
||||
static function savePublicKey(BigInteger $n, BigInteger $e)
|
||||
{
|
||||
return "<RSAKeyValue>\r\n" .
|
||||
' <Modulus>' . base64_encode($n->toBytes()) . "</Modulus>\r\n" .
|
||||
' <Exponent>' . base64_encode($e->toBytes()) . "</Exponent>\r\n" .
|
||||
'</RSAKeyValue>';
|
||||
}
|
||||
}
|
@ -24,14 +24,6 @@
|
||||
|
||||
namespace phpseclib\Crypt;
|
||||
|
||||
use phpseclib\Crypt\AES;
|
||||
use phpseclib\Crypt\Base;
|
||||
use phpseclib\Crypt\Blowfish;
|
||||
use phpseclib\Crypt\DES;
|
||||
use phpseclib\Crypt\RC4;
|
||||
use phpseclib\Crypt\TripleDES;
|
||||
use phpseclib\Crypt\Twofish;
|
||||
|
||||
/**
|
||||
* Pure-PHP Random Number Generator
|
||||
*
|
||||
@ -49,68 +41,22 @@ class Random
|
||||
* eg. for RSA key generation.
|
||||
*
|
||||
* @param int $length
|
||||
* @throws \RuntimeException if a symmetric cipher is needed but not loaded
|
||||
* @return string
|
||||
*/
|
||||
static function string($length)
|
||||
{
|
||||
if (version_compare(PHP_VERSION, '7.0.0', '>=')) {
|
||||
try {
|
||||
return \random_bytes($length);
|
||||
} catch (\Throwable $e) {
|
||||
// If a sufficient source of randomness is unavailable, random_bytes() will throw an
|
||||
// object that implements the Throwable interface (Exception, TypeError, Error).
|
||||
// We don't actually need to do anything here. The string() method should just continue
|
||||
// as normal. Note, however, that if we don't have a sufficient source of randomness for
|
||||
// random_bytes(), most of the other calls here will fail too, so we'll end up using
|
||||
// the PHP implementation.
|
||||
}
|
||||
}
|
||||
|
||||
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
|
||||
// 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);
|
||||
}
|
||||
// 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
|
||||
// openssl_random_pseudo_bytes and mcrypt_create_iv do the exact same thing on Windows. ie. they both
|
||||
// call php_win32_get_random_bytes():
|
||||
//
|
||||
// https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/openssl/openssl.c#L5008
|
||||
// https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1392
|
||||
//
|
||||
// php_win32_get_random_bytes() is defined thusly:
|
||||
//
|
||||
// https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/win32/winutil.c#L80
|
||||
//
|
||||
// we're calling it, all the same, in the off chance that the mcrypt extension is not available
|
||||
if (extension_loaded('openssl') && version_compare(PHP_VERSION, '5.3.4', '>=')) {
|
||||
return openssl_random_pseudo_bytes($length);
|
||||
}
|
||||
} else {
|
||||
// method 1. the fastest
|
||||
if (extension_loaded('openssl')) {
|
||||
return openssl_random_pseudo_bytes($length);
|
||||
}
|
||||
// method 2
|
||||
static $fp = true;
|
||||
if ($fp === true) {
|
||||
// warning's will be output unles the error suppression operator is used. errors such as
|
||||
// "open_basedir restriction in effect", "Permission denied", "No such file or directory", etc.
|
||||
$fp = @fopen('/dev/urandom', 'rb');
|
||||
}
|
||||
if ($fp !== true && $fp !== false) { // surprisingly faster than !is_bool() or is_resource()
|
||||
return fread($fp, $length);
|
||||
}
|
||||
// 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
|
||||
// surprisingly slower than method 2. maybe that's because mcrypt_create_iv does a bunch of error checking that we're
|
||||
// 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);
|
||||
}
|
||||
try {
|
||||
return \random_bytes($length);
|
||||
} catch (\Exception $e) {
|
||||
// random_compat will throw an Exception, which in PHP 5 does not implement Throwable
|
||||
} catch (\Throwable $e) {
|
||||
// If a sufficient source of randomness is unavailable, random_bytes() will throw an
|
||||
// object that implements the Throwable interface (Exception, TypeError, Error).
|
||||
// We don't actually need to do anything here. The string() method should just continue
|
||||
// as normal. Note, however, that if we don't have a sufficient source of randomness for
|
||||
// random_bytes(), most of the other calls here will fail too, so we'll end up using
|
||||
// the PHP implementation.
|
||||
}
|
||||
// at this point we have no choice but to use a pure-PHP CSPRNG
|
||||
|
||||
@ -148,13 +94,13 @@ class Random
|
||||
session_start();
|
||||
|
||||
$v = $seed = $_SESSION['seed'] = pack('H*', sha1(
|
||||
(isset($_SERVER) ? phpseclib_safe_serialize($_SERVER) : '') .
|
||||
(isset($_POST) ? phpseclib_safe_serialize($_POST) : '') .
|
||||
(isset($_GET) ? phpseclib_safe_serialize($_GET) : '') .
|
||||
(isset($_COOKIE) ? phpseclib_safe_serialize($_COOKIE) : '') .
|
||||
phpseclib_safe_serialize($GLOBALS) .
|
||||
phpseclib_safe_serialize($_SESSION) .
|
||||
phpseclib_safe_serialize($_OLD_SESSION)
|
||||
(isset($_SERVER) ? self::safe_serialize($_SERVER) : '') .
|
||||
(isset($_POST) ? self::safe_serialize($_POST) : '') .
|
||||
(isset($_GET) ? self::safe_serialize($_GET) : '') .
|
||||
(isset($_COOKIE) ? self::safe_serialize($_COOKIE) : '') .
|
||||
self::safe_serialize($GLOBALS) .
|
||||
self::safe_serialize($_SESSION) .
|
||||
self::safe_serialize($_OLD_SESSION)
|
||||
));
|
||||
if (!isset($_SESSION['count'])) {
|
||||
$_SESSION['count'] = 0;
|
||||
@ -212,8 +158,7 @@ class Random
|
||||
$crypto = new RC4();
|
||||
break;
|
||||
default:
|
||||
user_error(__CLASS__ . ' requires at least one symmetric cipher be loaded');
|
||||
return false;
|
||||
throw new \RuntimeException(__CLASS__ . ' requires at least one symmetric cipher be loaded');
|
||||
}
|
||||
|
||||
$crypto->setKey($key);
|
||||
@ -240,19 +185,16 @@ class Random
|
||||
}
|
||||
return substr($result, 0, $length);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('phpseclib_safe_serialize')) {
|
||||
/**
|
||||
* Safely serialize variables
|
||||
*
|
||||
* If a class has a private __sleep() method it'll give a fatal error on PHP 5.2 and earlier.
|
||||
* PHP 5.3 will emit a warning.
|
||||
* If a class has a private __sleep() it'll emit a warning
|
||||
*
|
||||
* @param mixed $arr
|
||||
* @access public
|
||||
*/
|
||||
function phpseclib_safe_serialize(&$arr)
|
||||
function safe_serialize(&$arr)
|
||||
{
|
||||
if (is_object($arr)) {
|
||||
return '';
|
||||
@ -269,7 +211,7 @@ if (!function_exists('phpseclib_safe_serialize')) {
|
||||
foreach (array_keys($arr) as $key) {
|
||||
// do not recurse on the '__phpseclib_marker' key itself, for smaller memory usage
|
||||
if ($key !== '__phpseclib_marker') {
|
||||
$safearr[$key] = phpseclib_safe_serialize($arr[$key]);
|
||||
$safearr[$key] = self::safe_serialize($arr[$key]);
|
||||
}
|
||||
}
|
||||
unset($arr['__phpseclib_marker']);
|
||||
|
@ -54,8 +54,6 @@
|
||||
|
||||
namespace phpseclib\Crypt;
|
||||
|
||||
use phpseclib\Crypt\Base;
|
||||
|
||||
/**
|
||||
* Pure-PHP implementation of Rijndael.
|
||||
*
|
||||
@ -170,11 +168,26 @@ class Rijndael extends Base
|
||||
*/
|
||||
var $kl;
|
||||
|
||||
/**
|
||||
* Default Constructor.
|
||||
*
|
||||
* @param int $mode
|
||||
* @access public
|
||||
* @throws \InvalidArgumentException if an invalid / unsupported mode is provided
|
||||
*/
|
||||
function __construct($mode)
|
||||
{
|
||||
if ($mode == self::MODE_STREAM) {
|
||||
throw new \InvalidArgumentException('Block ciphers cannot be ran in stream mode');
|
||||
}
|
||||
|
||||
parent::__construct($mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key length.
|
||||
*
|
||||
* Valid key lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to
|
||||
* 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
|
||||
* Valid key lengths are 128, 160, 192, 224, and 256.
|
||||
*
|
||||
* Note: phpseclib extends Rijndael (and AES) for using 160- and 224-bit keys but they are officially not defined
|
||||
* and the most (if not all) implementations are not able using 160/224-bit keys but round/pad them up to
|
||||
@ -188,49 +201,75 @@ class Rijndael extends Base
|
||||
* This results then in slower encryption.
|
||||
*
|
||||
* @access public
|
||||
* @throws \LengthException if the key length is invalid
|
||||
* @param int $length
|
||||
*/
|
||||
function setKeyLength($length)
|
||||
{
|
||||
switch (true) {
|
||||
case $length <= 128:
|
||||
$this->key_length = 16;
|
||||
break;
|
||||
case $length <= 160:
|
||||
$this->key_length = 20;
|
||||
break;
|
||||
case $length <= 192:
|
||||
$this->key_length = 24;
|
||||
break;
|
||||
case $length <= 224:
|
||||
$this->key_length = 28;
|
||||
switch ($length) {
|
||||
case 128:
|
||||
case 160:
|
||||
case 192:
|
||||
case 224:
|
||||
case 256:
|
||||
$this->key_length = $length >> 3;
|
||||
break;
|
||||
default:
|
||||
$this->key_length = 32;
|
||||
throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys of sizes 128, 160, 192, 224 or 256 bits are supported');
|
||||
}
|
||||
|
||||
parent::setKeyLength($length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key.
|
||||
*
|
||||
* Rijndael supports five different key lengths
|
||||
*
|
||||
* @see setKeyLength()
|
||||
* @access public
|
||||
* @param string $key
|
||||
* @throws \LengthException if the key length isn't supported
|
||||
*/
|
||||
function setKey($key)
|
||||
{
|
||||
switch (strlen($key)) {
|
||||
case 16:
|
||||
case 20:
|
||||
case 24:
|
||||
case 28:
|
||||
case 32:
|
||||
break;
|
||||
default:
|
||||
throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of sizes 16, 20, 24, 28 or 32 are supported');
|
||||
}
|
||||
|
||||
parent::setKey($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the block length
|
||||
*
|
||||
* Valid block lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to
|
||||
* 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
|
||||
* Valid block lengths are 128, 160, 192, 224, and 256.
|
||||
*
|
||||
* @access public
|
||||
* @param int $length
|
||||
*/
|
||||
function setBlockLength($length)
|
||||
{
|
||||
$length >>= 5;
|
||||
if ($length > 8) {
|
||||
$length = 8;
|
||||
} elseif ($length < 4) {
|
||||
$length = 4;
|
||||
switch ($length) {
|
||||
case 128:
|
||||
case 160:
|
||||
case 192:
|
||||
case 224:
|
||||
case 256:
|
||||
break;
|
||||
default:
|
||||
throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys of sizes 128, 160, 192, 224 or 256 bits are supported');
|
||||
}
|
||||
$this->Nb = $length;
|
||||
$this->block_size = $length << 2;
|
||||
|
||||
$this->Nb = $length >> 5;
|
||||
$this->block_size = $length >> 3;
|
||||
$this->changed = true;
|
||||
$this->_setEngine();
|
||||
}
|
||||
|
@ -36,9 +36,6 @@
|
||||
|
||||
namespace phpseclib\Crypt;
|
||||
|
||||
use phpseclib\Crypt\Base;
|
||||
use phpseclib\Crypt\DES;
|
||||
|
||||
/**
|
||||
* Pure-PHP implementation of Triple DES.
|
||||
*
|
||||
@ -131,7 +128,7 @@ class TripleDES extends DES
|
||||
/**
|
||||
* Default Constructor.
|
||||
*
|
||||
* Determines whether or not the mcrypt extension should be used.
|
||||
* Determines whether or not the mcrypt or OpenSSL extensions should be used.
|
||||
*
|
||||
* $mode could be:
|
||||
*
|
||||
@ -145,16 +142,14 @@ class TripleDES extends DES
|
||||
*
|
||||
* - \phpseclib\Crypt\Base::MODE_OFB
|
||||
*
|
||||
* - \phpseclib\Crypt\TripleDES::MODE_3CBC
|
||||
*
|
||||
* If not explicitly set, \phpseclib\Crypt\Base::MODE_CBC will be used.
|
||||
* - \phpseclib\Crypt\TripleDES::MODE_3CB
|
||||
*
|
||||
* @see \phpseclib\Crypt\DES::__construct()
|
||||
* @see \phpseclib\Crypt\Base::__construct()
|
||||
* @param int $mode
|
||||
* @access public
|
||||
*/
|
||||
function __construct($mode = Base::MODE_CBC)
|
||||
function __construct($mode)
|
||||
{
|
||||
switch ($mode) {
|
||||
// In case of self::MODE_3CBC, we init as CRYPT_DES_MODE_CBC
|
||||
@ -203,10 +198,9 @@ class TripleDES extends DES
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the initialization vector. (optional)
|
||||
* Sets the initialization vector.
|
||||
*
|
||||
* SetIV is not required when \phpseclib\Crypt\Base::MODE_ECB is being used. If not explicitly set, it'll be assumed
|
||||
* to be all zero's.
|
||||
* SetIV is not required when \phpseclib\Crypt\Base::MODE_ECB is being used.
|
||||
*
|
||||
* @see \phpseclib\Crypt\Base::setIV()
|
||||
* @access public
|
||||
@ -225,24 +219,23 @@ class TripleDES extends DES
|
||||
/**
|
||||
* Sets the key length.
|
||||
*
|
||||
* Valid key lengths are 64, 128 and 192
|
||||
* Valid key lengths are 128 and 192 bits.
|
||||
*
|
||||
* If you want to use a 64-bit key use DES.php
|
||||
*
|
||||
* @see \phpseclib\Crypt\Base:setKeyLength()
|
||||
* @access public
|
||||
* @throws \LengthException if the key length is invalid
|
||||
* @param int $length
|
||||
*/
|
||||
function setKeyLength($length)
|
||||
{
|
||||
$length >>= 3;
|
||||
switch (true) {
|
||||
case $length <= 8:
|
||||
$this->key_length = 8;
|
||||
break;
|
||||
case $length <= 16:
|
||||
$this->key_length = 16;
|
||||
switch ($length) {
|
||||
case 128:
|
||||
case 192:
|
||||
break;
|
||||
default:
|
||||
$this->key_length = 24;
|
||||
throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys of sizes 128 or 192 bits are supported');
|
||||
}
|
||||
|
||||
parent::setKeyLength($length);
|
||||
@ -251,36 +244,38 @@ class TripleDES extends DES
|
||||
/**
|
||||
* Sets the key.
|
||||
*
|
||||
* Keys can be of any length. Triple DES, itself, can use 128-bit (eg. strlen($key) == 16) or
|
||||
* 192-bit (eg. strlen($key) == 24) keys. This function pads and truncates $key as appropriate.
|
||||
* Triple DES can use 128-bit (eg. strlen($key) == 16) or 192-bit (eg. strlen($key) == 24) keys.
|
||||
*
|
||||
* DES also requires that every eighth bit be a parity bit, however, we'll ignore that.
|
||||
*
|
||||
* If the key is not explicitly set, it'll be assumed to be all null bytes.
|
||||
*
|
||||
* @access public
|
||||
* @see \phpseclib\Crypt\DES::setKey()
|
||||
* @see \phpseclib\Crypt\Base::setKey()
|
||||
* @throws \LengthException if the key length is invalid
|
||||
* @param string $key
|
||||
*/
|
||||
function setKey($key)
|
||||
{
|
||||
$length = $this->explicit_key_length ? $this->key_length : strlen($key);
|
||||
if ($length > 8) {
|
||||
$key = str_pad(substr($key, 0, 24), 24, chr(0));
|
||||
// if $key is between 64 and 128-bits, use the first 64-bits as the last, per this:
|
||||
// http://php.net/function.mcrypt-encrypt#47973
|
||||
$key = $length <= 16 ? substr_replace($key, substr($key, 0, 8), 16) : substr($key, 0, 24);
|
||||
} else {
|
||||
$key = str_pad($key, 8, chr(0));
|
||||
if ($this->explicit_key_length !== false && strlen($key) != $this->explicit_key_length) {
|
||||
throw new \LengthException('Key length has already been set to ' . $this->explicit_key_length . ' bytes and this key is ' . strlen($key) . ' bytes');
|
||||
}
|
||||
parent::setKey($key);
|
||||
|
||||
// And in case of self::MODE_3CBC:
|
||||
// if key <= 64bits we not need the 3 $des to work,
|
||||
// because we will then act as regular DES-CBC with just a <= 64bit key.
|
||||
// So only if the key > 64bits (> 8 bytes) we will call setKey() for the 3 $des.
|
||||
if ($this->mode_3cbc && $length > 8) {
|
||||
switch (strlen($key)) {
|
||||
case 16:
|
||||
$key.= substr($key, 0, 8);
|
||||
case 24:
|
||||
break;
|
||||
default:
|
||||
throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of sizes 16 or 24 are supported');
|
||||
}
|
||||
|
||||
// copied from Base::setKey()
|
||||
$this->key = $key;
|
||||
$this->key_length = strlen($key);
|
||||
$this->changed = true;
|
||||
$this->_setEngine();
|
||||
|
||||
if ($this->mode_3cbc) {
|
||||
$this->des[0]->setKey(substr($key, 0, 8));
|
||||
$this->des[1]->setKey(substr($key, 8, 8));
|
||||
$this->des[2]->setKey(substr($key, 16, 8));
|
||||
|
@ -37,8 +37,6 @@
|
||||
|
||||
namespace phpseclib\Crypt;
|
||||
|
||||
use phpseclib\Crypt\Base;
|
||||
|
||||
/**
|
||||
* Pure-PHP implementation of Twofish.
|
||||
*
|
||||
@ -370,6 +368,22 @@ class Twofish extends Base
|
||||
*/
|
||||
var $key_length = 16;
|
||||
|
||||
/**
|
||||
* Default Constructor.
|
||||
*
|
||||
* @param int $mode
|
||||
* @access public
|
||||
* @throws \InvalidArgumentException if an invalid / unsupported mode is provided
|
||||
*/
|
||||
function __construct($mode)
|
||||
{
|
||||
if ($mode == self::MODE_STREAM) {
|
||||
throw new \InvalidArgumentException('Block ciphers cannot be ran in stream mode');
|
||||
}
|
||||
|
||||
parent::__construct($mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key length.
|
||||
*
|
||||
@ -380,20 +394,42 @@ class Twofish extends Base
|
||||
*/
|
||||
function setKeyLength($length)
|
||||
{
|
||||
switch (true) {
|
||||
case $length <= 128:
|
||||
$this->key_length = 16;
|
||||
break;
|
||||
case $length <= 192:
|
||||
$this->key_length = 24;
|
||||
switch ($length) {
|
||||
case 128:
|
||||
case 192:
|
||||
case 256:
|
||||
break;
|
||||
default:
|
||||
$this->key_length = 32;
|
||||
throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of sizes 16, 24 or 32 supported');
|
||||
}
|
||||
|
||||
parent::setKeyLength($length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key.
|
||||
*
|
||||
* Rijndael supports five different key lengths
|
||||
*
|
||||
* @see setKeyLength()
|
||||
* @access public
|
||||
* @param string $key
|
||||
* @throws \LengthException if the key length isn't supported
|
||||
*/
|
||||
function setKey($key)
|
||||
{
|
||||
switch (strlen($key)) {
|
||||
case 16:
|
||||
case 24:
|
||||
case 32:
|
||||
break;
|
||||
default:
|
||||
throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of sizes 16, 24 or 32 supported');
|
||||
}
|
||||
|
||||
parent::setKey($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the key (expansion)
|
||||
*
|
||||
|
26
phpseclib/Exception/BadConfigurationException.php
Normal file
26
phpseclib/Exception/BadConfigurationException.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* BadConfigurationException
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category Exception
|
||||
* @package BadConfigurationException
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2015 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
*/
|
||||
|
||||
namespace phpseclib\Exception;
|
||||
|
||||
/**
|
||||
* BadConfigurationException
|
||||
*
|
||||
* @package BadConfigurationException
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
*/
|
||||
class BadConfigurationException extends \RuntimeException
|
||||
{
|
||||
}
|
26
phpseclib/Exception/FileNotFoundException.php
Normal file
26
phpseclib/Exception/FileNotFoundException.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* FileNotFoundException
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category Exception
|
||||
* @package FileNotFoundException
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2015 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
*/
|
||||
|
||||
namespace phpseclib\Exception;
|
||||
|
||||
/**
|
||||
* FileNotFoundException
|
||||
*
|
||||
* @package FileNotFoundException
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
*/
|
||||
class FileNotFoundException extends \RuntimeException
|
||||
{
|
||||
}
|
26
phpseclib/Exception/NoSupportedAlgorithmsException.php
Normal file
26
phpseclib/Exception/NoSupportedAlgorithmsException.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* NoSupportedAlgorithmsException
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category Exception
|
||||
* @package NoSupportedAlgorithmsException
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2015 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
*/
|
||||
|
||||
namespace phpseclib\Exception;
|
||||
|
||||
/**
|
||||
* NoSupportedAlgorithmsException
|
||||
*
|
||||
* @package NoSupportedAlgorithmsException
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
*/
|
||||
class NoSupportedAlgorithmsException extends \RuntimeException
|
||||
{
|
||||
}
|
26
phpseclib/Exception/UnsupportedAlgorithmException.php
Normal file
26
phpseclib/Exception/UnsupportedAlgorithmException.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* UnsupportedAlgorithmException
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category Exception
|
||||
* @package UnsupportedAlgorithmException
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2015 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
*/
|
||||
|
||||
namespace phpseclib\Exception;
|
||||
|
||||
/**
|
||||
* UnsupportedAlgorithmException
|
||||
*
|
||||
* @package UnsupportedAlgorithmException
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
*/
|
||||
class UnsupportedAlgorithmException extends \RuntimeException
|
||||
{
|
||||
}
|
@ -793,6 +793,7 @@ class ASN1
|
||||
* @param string $mapping
|
||||
* @param int $idx
|
||||
* @return string
|
||||
* @throws \RuntimeException if the input has an error in it
|
||||
* @access private
|
||||
*/
|
||||
function _encode_der($source, $mapping, $idx = null, $special = array())
|
||||
@ -985,7 +986,7 @@ class ASN1
|
||||
case self::TYPE_OBJECT_IDENTIFIER:
|
||||
$oid = preg_match('#(?:\d+\.)+#', $source) ? $source : array_search($source, $this->oids);
|
||||
if ($oid === false) {
|
||||
user_error('Invalid OID');
|
||||
throw new \RuntimeException('Invalid OID');
|
||||
return false;
|
||||
}
|
||||
$value = '';
|
||||
@ -1038,7 +1039,7 @@ class ASN1
|
||||
$filters = $filters[$part];
|
||||
}
|
||||
if ($filters === false) {
|
||||
user_error('No filters defined for ' . implode('/', $loc));
|
||||
throw new \RuntimeException('No filters defined for ' . implode('/', $loc));
|
||||
return false;
|
||||
}
|
||||
return $this->_encode_der($source, $filters + $mapping, null, $special);
|
||||
@ -1062,7 +1063,7 @@ class ASN1
|
||||
$value = $source ? "\xFF" : "\x00";
|
||||
break;
|
||||
default:
|
||||
user_error('Mapping provides no type definition for ' . implode('/', $this->location));
|
||||
throw new \RuntimeException('Mapping provides no type definition for ' . implode('/', $this->location));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -27,9 +27,9 @@
|
||||
namespace phpseclib\File;
|
||||
|
||||
use phpseclib\Crypt\Hash;
|
||||
use phpseclib\Crypt\RSA;
|
||||
use phpseclib\Crypt\Random;
|
||||
use phpseclib\File\ASN1;
|
||||
use phpseclib\Crypt\RSA;
|
||||
use phpseclib\Exception\UnsupportedAlgorithmException;
|
||||
use phpseclib\File\ASN1\Element;
|
||||
use phpseclib\Math\BigInteger;
|
||||
|
||||
@ -1654,7 +1654,7 @@ class X509
|
||||
$map = $this->_getMapping($id);
|
||||
if (is_bool($map)) {
|
||||
if (!$map) {
|
||||
user_error($id . ' is not a currently supported extension');
|
||||
//user_error($id . ' is not a currently supported extension');
|
||||
unset($extensions[$i]);
|
||||
}
|
||||
} else {
|
||||
@ -1727,7 +1727,7 @@ class X509
|
||||
$id = $attributes[$i]['type'];
|
||||
$map = $this->_getMapping($id);
|
||||
if ($map === false) {
|
||||
user_error($id . ' is not a currently supported attribute', E_USER_NOTICE);
|
||||
//user_error($id . ' is not a currently supported attribute', E_USER_NOTICE);
|
||||
unset($attributes[$i]);
|
||||
} elseif (is_array($attributes[$i]['value'])) {
|
||||
$values = &$attributes[$i]['value'];
|
||||
@ -2120,7 +2120,8 @@ class X509
|
||||
/**
|
||||
* Validates a signature
|
||||
*
|
||||
* Returns true if the signature is verified, false if it is not correct or null on error
|
||||
* Returns true if the signature is verified and false if it is not correct.
|
||||
* If the algorithms are unsupposed an exception is thrown.
|
||||
*
|
||||
* @param string $publicKeyAlgorithm
|
||||
* @param string $publicKey
|
||||
@ -2128,14 +2129,15 @@ class X509
|
||||
* @param string $signature
|
||||
* @param string $signatureSubject
|
||||
* @access private
|
||||
* @return int
|
||||
* @throws \phpseclib\Exception\UnsupportedAlgorithmException if the algorithm is unsupported
|
||||
* @return bool
|
||||
*/
|
||||
function _validateSignature($publicKeyAlgorithm, $publicKey, $signatureAlgorithm, $signature, $signatureSubject)
|
||||
{
|
||||
switch ($publicKeyAlgorithm) {
|
||||
case 'rsaEncryption':
|
||||
$rsa = new RSA();
|
||||
$rsa->loadKey($publicKey);
|
||||
$rsa->load($publicKey);
|
||||
|
||||
switch ($signatureAlgorithm) {
|
||||
case 'md2WithRSAEncryption':
|
||||
@ -2146,17 +2148,16 @@ class X509
|
||||
case 'sha384WithRSAEncryption':
|
||||
case 'sha512WithRSAEncryption':
|
||||
$rsa->setHash(preg_replace('#WithRSAEncryption$#', '', $signatureAlgorithm));
|
||||
$rsa->setSignatureMode(RSA::SIGNATURE_PKCS1);
|
||||
if (!@$rsa->verify($signatureSubject, $signature)) {
|
||||
if (!@$rsa->verify($signatureSubject, $signature, RSA::PADDING_PKCS1)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
throw new UnsupportedAlgorithmException('Signature algorithm unsupported');
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
throw new UnsupportedAlgorithmException('Public key algorithm unsupported');
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -2811,7 +2812,7 @@ class X509
|
||||
switch ($keyinfo['algorithm']['algorithm']) {
|
||||
case 'rsaEncryption':
|
||||
$publicKey = new RSA();
|
||||
$publicKey->loadKey($key);
|
||||
$publicKey->load($key);
|
||||
$publicKey->setPublicKey();
|
||||
break;
|
||||
default:
|
||||
@ -2887,7 +2888,7 @@ class X509
|
||||
switch ($algorithm) {
|
||||
case 'rsaEncryption':
|
||||
$this->publicKey = new RSA();
|
||||
$this->publicKey->loadKey($key);
|
||||
$this->publicKey->load($key);
|
||||
$this->publicKey->setPublicKey();
|
||||
break;
|
||||
default:
|
||||
@ -3010,7 +3011,7 @@ class X509
|
||||
switch ($algorithm) {
|
||||
case 'rsaEncryption':
|
||||
$this->publicKey = new RSA();
|
||||
$this->publicKey->loadKey($key);
|
||||
$this->publicKey->load($key);
|
||||
$this->publicKey->setPublicKey();
|
||||
break;
|
||||
default:
|
||||
@ -3405,7 +3406,7 @@ class X509
|
||||
$origPublicKey = $this->publicKey;
|
||||
$class = get_class($this->privateKey);
|
||||
$this->publicKey = new $class();
|
||||
$this->publicKey->loadKey($this->privateKey->getPublicKey());
|
||||
$this->publicKey->load($this->privateKey->getPublicKey());
|
||||
$this->publicKey->setPublicKey();
|
||||
if (!($publicKey = $this->_formatSubjectPublicKey())) {
|
||||
return false;
|
||||
@ -3463,7 +3464,7 @@ class X509
|
||||
$origPublicKey = $this->publicKey;
|
||||
$class = get_class($this->privateKey);
|
||||
$this->publicKey = new $class();
|
||||
$this->publicKey->loadKey($this->privateKey->getPublicKey());
|
||||
$this->publicKey->load($this->privateKey->getPublicKey());
|
||||
$this->publicKey->setPublicKey();
|
||||
$publicKey = $this->_formatSubjectPublicKey();
|
||||
if (!$publicKey) {
|
||||
@ -3651,6 +3652,7 @@ class X509
|
||||
* @param \phpseclib\File\X509 $subject
|
||||
* @param string $signatureAlgorithm
|
||||
* @access public
|
||||
* @throws \phpseclib\Exception\UnsupportedAlgorithmException if the algorithm is unsupported
|
||||
* @return mixed
|
||||
*/
|
||||
function _sign($key, $signatureAlgorithm)
|
||||
@ -3665,14 +3667,15 @@ class X509
|
||||
case 'sha384WithRSAEncryption':
|
||||
case 'sha512WithRSAEncryption':
|
||||
$key->setHash(preg_replace('#WithRSAEncryption$#', '', $signatureAlgorithm));
|
||||
$key->setSignatureMode(RSA::SIGNATURE_PKCS1);
|
||||
|
||||
$this->currentCert['signature'] = base64_encode("\0" . $key->sign($this->signatureSubject));
|
||||
$this->currentCert['signature'] = base64_encode("\0" . $key->sign($this->signatureSubject, RSA::PADDING_PKCS1));
|
||||
return $this->currentCert;
|
||||
default:
|
||||
throw new UnsupportedAlgorithmException('Signature algorithm unsupported');
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
throw new UnsupportedAlgorithmException('Unsupported public key algorithm');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4229,7 +4232,7 @@ class X509
|
||||
$raw = base64_decode($raw);
|
||||
// If the key is private, compute identifier from its corresponding public key.
|
||||
$key = new RSA();
|
||||
if (!$key->loadKey($raw)) {
|
||||
if (!$key->load($raw)) {
|
||||
return false; // Not an unencrypted RSA key.
|
||||
}
|
||||
if ($key->getPrivateKey() !== false) { // If private.
|
||||
@ -4249,7 +4252,7 @@ class X509
|
||||
}
|
||||
return false;
|
||||
default: // Should be a key object (i.e.: \phpseclib\Crypt\RSA).
|
||||
$key = $key->getPublicKey(RSA::PUBLIC_FORMAT_PKCS1);
|
||||
$key = $key->getPublicKey('PKCS1');
|
||||
break;
|
||||
}
|
||||
|
||||
@ -4282,7 +4285,7 @@ class X509
|
||||
//return new Element(base64_decode(preg_replace('#-.+-|[\r\n]#', '', $this->publicKey->getPublicKey())));
|
||||
return array(
|
||||
'algorithm' => array('algorithm' => 'rsaEncryption'),
|
||||
'subjectPublicKey' => $this->publicKey->getPublicKey(RSA::PUBLIC_FORMAT_PKCS1)
|
||||
'subjectPublicKey' => $this->publicKey->getPublicKey('PKCS1')
|
||||
);
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -32,8 +32,7 @@
|
||||
|
||||
namespace phpseclib\Net;
|
||||
|
||||
use phpseclib\Net\SSH1;
|
||||
use phpseclib\Net\SSH2;
|
||||
use phpseclib\Exception\FileNotFoundException;
|
||||
|
||||
/**
|
||||
* Pure-PHP implementations of SCP.
|
||||
@ -140,6 +139,7 @@ class SCP
|
||||
* @param string $data
|
||||
* @param int $mode
|
||||
* @param callable $callback
|
||||
* @throws \phpseclib\Exception\FileNotFoundException if you're uploading via a file and the file doesn't exist
|
||||
* @return bool
|
||||
* @access public
|
||||
*/
|
||||
@ -168,8 +168,7 @@ class SCP
|
||||
$size = strlen($data);
|
||||
} else {
|
||||
if (!is_file($data)) {
|
||||
user_error("$data is not a valid file", E_USER_NOTICE);
|
||||
return false;
|
||||
throw new FileNotFoundException("$data is not a valid file");
|
||||
}
|
||||
|
||||
$fp = @fopen($data, 'rb');
|
||||
@ -289,6 +288,7 @@ class SCP
|
||||
* Receives a packet from an SSH server
|
||||
*
|
||||
* @return string
|
||||
* @throws \UnexpectedValueException on receipt of an unexpected packet
|
||||
* @access private
|
||||
*/
|
||||
function _receive()
|
||||
@ -314,8 +314,7 @@ class SCP
|
||||
$this->ssh->bitmap = 0;
|
||||
return false;
|
||||
default:
|
||||
user_error('Unknown packet received', E_USER_NOTICE);
|
||||
return false;
|
||||
throw new \UnexpectedValueException('Unknown packet received');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,7 @@
|
||||
|
||||
namespace phpseclib\Net;
|
||||
|
||||
use phpseclib\Net\SSH2;
|
||||
use phpseclib\Exception\FileNotFoundException;
|
||||
|
||||
/**
|
||||
* Pure-PHP implementations of SFTP.
|
||||
@ -383,6 +383,7 @@ class SFTP extends SSH2
|
||||
*
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @throws \UnexpectedValueException on receipt of unexpected packets
|
||||
* @return bool
|
||||
* @access public
|
||||
*/
|
||||
@ -470,8 +471,7 @@ class SFTP extends SSH2
|
||||
|
||||
$response = $this->_get_sftp_packet();
|
||||
if ($this->packet_type != NET_SFTP_VERSION) {
|
||||
user_error('Expected SSH_FXP_VERSION');
|
||||
return false;
|
||||
throw new \UnexpectedValueException('Expected SSH_FXP_VERSION');
|
||||
}
|
||||
|
||||
extract(unpack('Nversion', $this->_string_shift($response, 4)));
|
||||
@ -610,6 +610,7 @@ class SFTP extends SSH2
|
||||
*
|
||||
* @see self::chdir()
|
||||
* @param string $path
|
||||
* @throws \UnexpectedValueException on receipt of unexpected packets
|
||||
* @return mixed
|
||||
* @access private
|
||||
*/
|
||||
@ -634,8 +635,7 @@ class SFTP extends SSH2
|
||||
$this->_logError($response);
|
||||
return false;
|
||||
default:
|
||||
user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
|
||||
return false;
|
||||
throw new \UnexpectedValueException('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
|
||||
}
|
||||
}
|
||||
|
||||
@ -666,6 +666,7 @@ class SFTP extends SSH2
|
||||
* Changes the current directory
|
||||
*
|
||||
* @param string $dir
|
||||
* @throws \UnexpectedValueException on receipt of unexpected packets
|
||||
* @return bool
|
||||
* @access public
|
||||
*/
|
||||
@ -710,8 +711,7 @@ class SFTP extends SSH2
|
||||
$this->_logError($response);
|
||||
return false;
|
||||
default:
|
||||
user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
|
||||
return false;
|
||||
throw new \UnexpectedValueException('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
|
||||
}
|
||||
|
||||
if (!$this->_close_handle($handle)) {
|
||||
@ -813,6 +813,7 @@ class SFTP extends SSH2
|
||||
* @param string $dir
|
||||
* @param bool $raw
|
||||
* @return mixed
|
||||
* @throws \UnexpectedValueException on receipt of unexpected packets
|
||||
* @access private
|
||||
*/
|
||||
function _list($dir, $raw = true)
|
||||
@ -844,8 +845,7 @@ class SFTP extends SSH2
|
||||
$this->_logError($response);
|
||||
return false;
|
||||
default:
|
||||
user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
|
||||
return false;
|
||||
throw new \UnexpectedValueException('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
|
||||
}
|
||||
|
||||
$this->_update_stat_cache($dir, array());
|
||||
@ -899,8 +899,7 @@ class SFTP extends SSH2
|
||||
}
|
||||
break 2;
|
||||
default:
|
||||
user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
|
||||
return false;
|
||||
throw new \UnexpectedValueException('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
|
||||
}
|
||||
}
|
||||
|
||||
@ -1259,6 +1258,7 @@ class SFTP extends SSH2
|
||||
*
|
||||
* @param string $filename
|
||||
* @param int $type
|
||||
* @throws \UnexpectedValueException on receipt of unexpected packets
|
||||
* @return mixed
|
||||
* @access private
|
||||
*/
|
||||
@ -1279,8 +1279,7 @@ class SFTP extends SSH2
|
||||
return false;
|
||||
}
|
||||
|
||||
user_error('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS');
|
||||
return false;
|
||||
throw new \UnexpectedValueException('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1306,6 +1305,7 @@ class SFTP extends SSH2
|
||||
* @param string $filename
|
||||
* @param int $time
|
||||
* @param int $atime
|
||||
* @throws \UnexpectedValueException on receipt of unexpected packets
|
||||
* @return bool
|
||||
* @access public
|
||||
*/
|
||||
@ -1342,8 +1342,7 @@ class SFTP extends SSH2
|
||||
$this->_logError($response);
|
||||
break;
|
||||
default:
|
||||
user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
|
||||
return false;
|
||||
throw new \UnexpectedValueException('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
|
||||
}
|
||||
|
||||
return $this->_setstat($filename, $attr, false);
|
||||
@ -1396,6 +1395,7 @@ class SFTP extends SSH2
|
||||
* @param int $mode
|
||||
* @param string $filename
|
||||
* @param bool $recursive
|
||||
* @throws \UnexpectedValueException on receipt of unexpected packets
|
||||
* @return mixed
|
||||
* @access public
|
||||
*/
|
||||
@ -1434,8 +1434,7 @@ class SFTP extends SSH2
|
||||
return false;
|
||||
}
|
||||
|
||||
user_error('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS');
|
||||
return false;
|
||||
throw new \UnexpectedValueException('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1444,6 +1443,7 @@ class SFTP extends SSH2
|
||||
* @param string $filename
|
||||
* @param string $attr
|
||||
* @param bool $recursive
|
||||
* @throws \UnexpectedValueException on receipt of unexpected packets
|
||||
* @return bool
|
||||
* @access private
|
||||
*/
|
||||
@ -1482,8 +1482,7 @@ class SFTP extends SSH2
|
||||
*/
|
||||
$response = $this->_get_sftp_packet();
|
||||
if ($this->packet_type != NET_SFTP_STATUS) {
|
||||
user_error('Expected SSH_FXP_STATUS');
|
||||
return false;
|
||||
throw new \UnexpectedValueException('Expected SSH_FXP_STATUS');
|
||||
}
|
||||
|
||||
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
|
||||
@ -1571,6 +1570,7 @@ class SFTP extends SSH2
|
||||
* Return the target of a symbolic link
|
||||
*
|
||||
* @param string $link
|
||||
* @throws \UnexpectedValueException on receipt of unexpected packets
|
||||
* @return mixed
|
||||
* @access public
|
||||
*/
|
||||
@ -1594,8 +1594,7 @@ class SFTP extends SSH2
|
||||
$this->_logError($response);
|
||||
return false;
|
||||
default:
|
||||
user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
|
||||
return false;
|
||||
throw new \UnexpectedValueException('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
|
||||
}
|
||||
|
||||
extract(unpack('Ncount', $this->_string_shift($response, 4)));
|
||||
@ -1615,6 +1614,7 @@ class SFTP extends SSH2
|
||||
*
|
||||
* @param string $target
|
||||
* @param string $link
|
||||
* @throws \UnexpectedValueException on receipt of unexpected packets
|
||||
* @return bool
|
||||
* @access public
|
||||
*/
|
||||
@ -1634,8 +1634,7 @@ class SFTP extends SSH2
|
||||
|
||||
$response = $this->_get_sftp_packet();
|
||||
if ($this->packet_type != NET_SFTP_STATUS) {
|
||||
user_error('Expected SSH_FXP_STATUS');
|
||||
return false;
|
||||
throw new \UnexpectedValueException('Expected SSH_FXP_STATUS');
|
||||
}
|
||||
|
||||
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
|
||||
@ -1687,6 +1686,7 @@ class SFTP extends SSH2
|
||||
*
|
||||
* @param string $dir
|
||||
* @return bool
|
||||
* @throws \UnexpectedValueException on receipt of unexpected packets
|
||||
* @access private
|
||||
*/
|
||||
function _mkdir_helper($dir, $attr)
|
||||
@ -1697,8 +1697,7 @@ class SFTP extends SSH2
|
||||
|
||||
$response = $this->_get_sftp_packet();
|
||||
if ($this->packet_type != NET_SFTP_STATUS) {
|
||||
user_error('Expected SSH_FXP_STATUS');
|
||||
return false;
|
||||
throw new \UnexpectedValueException('Expected SSH_FXP_STATUS');
|
||||
}
|
||||
|
||||
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
|
||||
@ -1714,6 +1713,7 @@ class SFTP extends SSH2
|
||||
* Removes a directory.
|
||||
*
|
||||
* @param string $dir
|
||||
* @throws \UnexpectedValueException on receipt of unexpected packets
|
||||
* @return bool
|
||||
* @access public
|
||||
*/
|
||||
@ -1734,8 +1734,7 @@ class SFTP extends SSH2
|
||||
|
||||
$response = $this->_get_sftp_packet();
|
||||
if ($this->packet_type != NET_SFTP_STATUS) {
|
||||
user_error('Expected SSH_FXP_STATUS');
|
||||
return false;
|
||||
throw new \UnexpectedValueException('Expected SSH_FXP_STATUS');
|
||||
}
|
||||
|
||||
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
|
||||
@ -1795,6 +1794,9 @@ class SFTP extends SSH2
|
||||
* @param int $start
|
||||
* @param int $local_start
|
||||
* @param callable|null $progressCallback
|
||||
* @throws \UnexpectedValueException on receipt of unexpected packets
|
||||
* @throws \BadFunctionCallException if you're uploading via a callback and the callback function is invalid
|
||||
* @throws \phpseclib\Exception\FileNotFoundException if you're uploading via a file and the file doesn't exist
|
||||
* @return bool
|
||||
* @access public
|
||||
* @internal ASCII mode for SFTPv4/5/6 can be supported by adding a new function - \phpseclib\Net\SFTP::setMode().
|
||||
@ -1842,8 +1844,7 @@ class SFTP extends SSH2
|
||||
$this->_logError($response);
|
||||
return false;
|
||||
default:
|
||||
user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
|
||||
return false;
|
||||
throw new \UnexpectedValueException('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
|
||||
}
|
||||
|
||||
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.3
|
||||
@ -1851,7 +1852,7 @@ class SFTP extends SSH2
|
||||
switch (true) {
|
||||
case $mode & self::SOURCE_CALLBACK:
|
||||
if (!is_callable($data)) {
|
||||
user_error("\$data should be is_callable() if you specify SOURCE_CALLBACK flag");
|
||||
throw new \BadFunctionCallException("\$data should be is_callable() if you specify SOURCE_CALLBACK flag");
|
||||
}
|
||||
$dataCallback = $data;
|
||||
// do nothing
|
||||
@ -1862,8 +1863,7 @@ class SFTP extends SSH2
|
||||
break;
|
||||
case $mode & self::SOURCE_LOCAL_FILE:
|
||||
if (!is_file($data)) {
|
||||
user_error("$data is not a valid file");
|
||||
return false;
|
||||
throw new FileNotFoundException("$data is not a valid file");
|
||||
}
|
||||
$fp = @fopen($data, 'rb');
|
||||
if (!$fp) {
|
||||
@ -1948,6 +1948,7 @@ class SFTP extends SSH2
|
||||
*
|
||||
* @param int $i
|
||||
* @return bool
|
||||
* @throws \UnexpectedValueException on receipt of unexpected packets
|
||||
* @access private
|
||||
*/
|
||||
function _read_put_responses($i)
|
||||
@ -1955,8 +1956,7 @@ class SFTP extends SSH2
|
||||
while ($i--) {
|
||||
$response = $this->_get_sftp_packet();
|
||||
if ($this->packet_type != NET_SFTP_STATUS) {
|
||||
user_error('Expected SSH_FXP_STATUS');
|
||||
return false;
|
||||
throw new \UnexpectedValueException('Expected SSH_FXP_STATUS');
|
||||
}
|
||||
|
||||
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
|
||||
@ -1974,6 +1974,7 @@ class SFTP extends SSH2
|
||||
*
|
||||
* @param string $handle
|
||||
* @return bool
|
||||
* @throws \UnexpectedValueException on receipt of unexpected packets
|
||||
* @access private
|
||||
*/
|
||||
function _close_handle($handle)
|
||||
@ -1986,8 +1987,7 @@ class SFTP extends SSH2
|
||||
// -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.3
|
||||
$response = $this->_get_sftp_packet();
|
||||
if ($this->packet_type != NET_SFTP_STATUS) {
|
||||
user_error('Expected SSH_FXP_STATUS');
|
||||
return false;
|
||||
throw new \UnexpectedValueException('Expected SSH_FXP_STATUS');
|
||||
}
|
||||
|
||||
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
|
||||
@ -2012,6 +2012,7 @@ class SFTP extends SSH2
|
||||
* @param string $local_file
|
||||
* @param int $offset
|
||||
* @param int $length
|
||||
* @throws \UnexpectedValueException on receipt of unexpected packets
|
||||
* @return mixed
|
||||
* @access public
|
||||
*/
|
||||
@ -2040,8 +2041,7 @@ class SFTP extends SSH2
|
||||
$this->_logError($response);
|
||||
return false;
|
||||
default:
|
||||
user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
|
||||
return false;
|
||||
throw new \UnexpectedValueException('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
|
||||
}
|
||||
|
||||
if (is_resource($local_file)) {
|
||||
@ -2063,40 +2063,68 @@ class SFTP extends SSH2
|
||||
$fclose_check = $local_file !== false && !is_resource($local_file);
|
||||
|
||||
$start = $offset;
|
||||
$size = $this->max_sftp_packet < $length || $length < 0 ? $this->max_sftp_packet : $length;
|
||||
$read = 0;
|
||||
while (true) {
|
||||
$packet = pack('Na*N3', strlen($handle), $handle, $offset / 4294967296, $offset, $size);
|
||||
if (!$this->_send_sftp_packet(NET_SFTP_READ, $packet)) {
|
||||
if ($fclose_check) {
|
||||
fclose($fp);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
$i = 0;
|
||||
|
||||
$response = $this->_get_sftp_packet();
|
||||
switch ($this->packet_type) {
|
||||
case NET_SFTP_DATA:
|
||||
$temp = substr($response, 4);
|
||||
$offset+= strlen($temp);
|
||||
if ($local_file === false) {
|
||||
$content.= $temp;
|
||||
} else {
|
||||
fputs($fp, $temp);
|
||||
}
|
||||
break;
|
||||
case NET_SFTP_STATUS:
|
||||
// could, in theory, return false if !strlen($content) but we'll hold off for the time being
|
||||
$this->_logError($response);
|
||||
break 2;
|
||||
default:
|
||||
user_error('Expected SSH_FXP_DATA or SSH_FXP_STATUS');
|
||||
while ($i < NET_SFTP_QUEUE_SIZE && ($length < 0 || $read < $length)) {
|
||||
$tempoffset = $start + $read;
|
||||
|
||||
$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 ($fclose_check) {
|
||||
fclose($fp);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
$packet = null;
|
||||
$read+= $packet_size;
|
||||
$i++;
|
||||
}
|
||||
|
||||
if ($length > 0 && $length <= $offset - $start) {
|
||||
if (!$i) {
|
||||
break;
|
||||
}
|
||||
|
||||
$clear_responses = false;
|
||||
while ($i > 0) {
|
||||
$i--;
|
||||
|
||||
if ($clear_responses) {
|
||||
$this->_get_sftp_packet();
|
||||
continue;
|
||||
} else {
|
||||
$response = $this->_get_sftp_packet();
|
||||
}
|
||||
|
||||
switch ($this->packet_type) {
|
||||
case NET_SFTP_DATA:
|
||||
$temp = substr($response, 4);
|
||||
$offset+= strlen($temp);
|
||||
if ($local_file === false) {
|
||||
$content.= $temp;
|
||||
} else {
|
||||
fputs($fp, $temp);
|
||||
}
|
||||
$temp = null;
|
||||
break;
|
||||
case NET_SFTP_STATUS:
|
||||
// could, in theory, return false if !strlen($content) but we'll hold off for the time being
|
||||
$this->_logError($response);
|
||||
$clear_responses = true; // don't break out of the loop yet, so we can read the remaining responses
|
||||
break;
|
||||
default:
|
||||
if ($fclose_check) {
|
||||
fclose($fp);
|
||||
}
|
||||
throw new \UnexpectedValueException('Expected SSH_FXP_DATA or SSH_FXP_STATUS');
|
||||
}
|
||||
$response = null;
|
||||
}
|
||||
|
||||
if ($clear_responses) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -2127,6 +2155,7 @@ class SFTP extends SSH2
|
||||
* @param string $path
|
||||
* @param bool $recursive
|
||||
* @return bool
|
||||
* @throws \UnexpectedValueException on receipt of unexpected packets
|
||||
* @access public
|
||||
*/
|
||||
function delete($path, $recursive = true)
|
||||
@ -2147,8 +2176,7 @@ class SFTP extends SSH2
|
||||
|
||||
$response = $this->_get_sftp_packet();
|
||||
if ($this->packet_type != NET_SFTP_STATUS) {
|
||||
user_error('Expected SSH_FXP_STATUS');
|
||||
return false;
|
||||
throw new \UnexpectedValueException('Expected SSH_FXP_STATUS');
|
||||
}
|
||||
|
||||
// if $status isn't SSH_FX_OK it's probably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
|
||||
@ -2480,6 +2508,7 @@ class SFTP extends SSH2
|
||||
* @param string $oldname
|
||||
* @param string $newname
|
||||
* @return bool
|
||||
* @throws \UnexpectedValueException on receipt of unexpected packets
|
||||
* @access public
|
||||
*/
|
||||
function rename($oldname, $newname)
|
||||
@ -2502,8 +2531,7 @@ class SFTP extends SSH2
|
||||
|
||||
$response = $this->_get_sftp_packet();
|
||||
if ($this->packet_type != NET_SFTP_STATUS) {
|
||||
user_error('Expected SSH_FXP_STATUS');
|
||||
return false;
|
||||
throw new \UnexpectedValueException('Expected SSH_FXP_STATUS');
|
||||
}
|
||||
|
||||
// if $status isn't SSH_FX_OK it's probably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
|
||||
@ -2677,13 +2705,13 @@ 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) {
|
||||
if (NET_SFTP_LOGGING == self::LOG_REALTIME) {
|
||||
echo "<pre>\r\n" . $this->_format_log(array($data), array($packet_type)) . "\r\n</pre>\r\n";
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -2753,13 +2781,13 @@ 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) {
|
||||
if (NET_SFTP_LOGGING == self::LOG_REALTIME) {
|
||||
echo "<pre>\r\n" . $this->_format_log(array($packet), array($packet_type)) . "\r\n</pre>\r\n";
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -2771,7 +2799,7 @@ class SFTP extends SSH2
|
||||
/**
|
||||
* Returns a log of the packets that have been sent and received.
|
||||
*
|
||||
* Returns a string if NET_SFTP_LOGGING == NET_SFTP_LOG_COMPLEX, an array if NET_SFTP_LOGGING == NET_SFTP_LOG_SIMPLE and false if !defined('NET_SFTP_LOGGING')
|
||||
* Returns a string if NET_SFTP_LOGGING == self::LOG_COMPLEX, an array if NET_SFTP_LOGGING == self::LOG_SIMPLE and false if !defined('NET_SFTP_LOGGING')
|
||||
*
|
||||
* @access public
|
||||
* @return string or Array
|
||||
@ -2783,10 +2811,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;
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ namespace phpseclib\Net\SFTP;
|
||||
|
||||
use phpseclib\Crypt\RSA;
|
||||
use phpseclib\Net\SFTP;
|
||||
use phpseclib\Net\SSH2;
|
||||
|
||||
/**
|
||||
* SFTP Stream Wrapper
|
||||
@ -177,13 +178,12 @@ class Stream
|
||||
}
|
||||
}
|
||||
|
||||
if ($host[0] == '$') {
|
||||
$host = substr($host, 1);
|
||||
global $$host;
|
||||
if (($$host instanceof SFTP) === false) {
|
||||
if (preg_match('/^{[a-z0-9]+}$/i', $host)) {
|
||||
$host = SSH2::getConnectionByResourceId($host);
|
||||
if ($host === false) {
|
||||
return false;
|
||||
}
|
||||
$this->sftp = $$host;
|
||||
$this->sftp = $host;
|
||||
} else {
|
||||
if (isset($this->context)) {
|
||||
$context = stream_context_get_options($this->context);
|
||||
|
@ -537,14 +537,15 @@ class SSH1
|
||||
* Connect to an SSHv1 server
|
||||
*
|
||||
* @return bool
|
||||
* @throws \UnexpectedValueException on receipt of unexpected packets
|
||||
* @throws \RuntimeException on other errors
|
||||
* @access private
|
||||
*/
|
||||
function _connect()
|
||||
{
|
||||
$this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $this->connectionTimeout);
|
||||
if (!$this->fsock) {
|
||||
user_error(rtrim("Cannot connect to {$this->host}:{$this->port}. Error $errno. $errstr"));
|
||||
return false;
|
||||
throw new \RuntimeException(rtrim("Cannot connect to $host. Error $errno. $errstr"));
|
||||
}
|
||||
|
||||
$this->server_identification = $init_line = fgets($this->fsock, 255);
|
||||
@ -555,20 +556,17 @@ class SSH1
|
||||
}
|
||||
|
||||
if (!preg_match('#SSH-([0-9\.]+)-(.+)#', $init_line, $parts)) {
|
||||
user_error('Can only connect to SSH servers');
|
||||
return false;
|
||||
throw new \RuntimeException('Can only connect to SSH servers');
|
||||
}
|
||||
if ($parts[1][0] != 1) {
|
||||
user_error("Cannot connect to SSH $parts[1] servers");
|
||||
return false;
|
||||
throw new \RuntimeException("Cannot connect to $parts[1] servers");
|
||||
}
|
||||
|
||||
fputs($this->fsock, $this->identifier."\r\n");
|
||||
|
||||
$response = $this->_get_binary_packet();
|
||||
if ($response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_PUBLIC_KEY) {
|
||||
user_error('Expected SSH_SMSG_PUBLIC_KEY');
|
||||
return false;
|
||||
throw new \UnexpectedValueException('Expected SSH_SMSG_PUBLIC_KEY');
|
||||
}
|
||||
|
||||
$anti_spoofing_cookie = $this->_string_shift($response[self::RESPONSE_DATA], 8);
|
||||
@ -652,8 +650,7 @@ class SSH1
|
||||
$data = pack('C2a*na*N', NET_SSH1_CMSG_SESSION_KEY, $cipher, $anti_spoofing_cookie, 8 * strlen($double_encrypted_session_key), $double_encrypted_session_key, 0);
|
||||
|
||||
if (!$this->_send_binary_packet($data)) {
|
||||
user_error('Error sending SSH_CMSG_SESSION_KEY');
|
||||
return false;
|
||||
throw new \RuntimeException('Error sending SSH_CMSG_SESSION_KEY');
|
||||
}
|
||||
|
||||
switch ($cipher) {
|
||||
@ -661,16 +658,20 @@ class SSH1
|
||||
// $this->crypto = new \phpseclib\Crypt\Null();
|
||||
// break;
|
||||
case self::CIPHER_DES:
|
||||
$this->crypto = new DES();
|
||||
$this->crypto = new DES(DES::MODE_CBC);
|
||||
$this->crypto->disablePadding();
|
||||
$this->crypto->enableContinuousBuffer();
|
||||
$this->crypto->setKey(substr($session_key, 0, 8));
|
||||
// "The iv (initialization vector) is initialized to all zeroes."
|
||||
$this->crypto->setIV(str_repeat("\0", 8));
|
||||
break;
|
||||
case self::CIPHER_3DES:
|
||||
$this->crypto = new TripleDES(TripleDES::MODE_3CBC);
|
||||
$this->crypto->disablePadding();
|
||||
$this->crypto->enableContinuousBuffer();
|
||||
$this->crypto->setKey(substr($session_key, 0, 24));
|
||||
// "All three initialization vectors are initialized to zero."
|
||||
$this->crypto->setIV(str_repeat("\0", 8));
|
||||
break;
|
||||
//case self::CIPHER_RC4:
|
||||
// $this->crypto = new RC4();
|
||||
@ -682,8 +683,7 @@ class SSH1
|
||||
$response = $this->_get_binary_packet();
|
||||
|
||||
if ($response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) {
|
||||
user_error('Expected SSH_SMSG_SUCCESS');
|
||||
return false;
|
||||
throw new \UnexpectedValueException('Expected SSH_SMSG_SUCCESS');
|
||||
}
|
||||
|
||||
$this->bitmap = self::MASK_CONNECTED;
|
||||
@ -697,6 +697,8 @@ class SSH1
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @return bool
|
||||
* @throws \UnexpectedValueException on receipt of unexpected packets
|
||||
* @throws \RuntimeException on other errors
|
||||
* @access public
|
||||
*/
|
||||
function login($username, $password = '')
|
||||
@ -715,8 +717,7 @@ class SSH1
|
||||
$data = pack('CNa*', NET_SSH1_CMSG_USER, strlen($username), $username);
|
||||
|
||||
if (!$this->_send_binary_packet($data)) {
|
||||
user_error('Error sending SSH_CMSG_USER');
|
||||
return false;
|
||||
throw new \RuntimeException('Error sending SSH_CMSG_USER');
|
||||
}
|
||||
|
||||
$response = $this->_get_binary_packet();
|
||||
@ -728,15 +729,13 @@ class SSH1
|
||||
$this->bitmap |= self::MASK_LOGIN;
|
||||
return true;
|
||||
} elseif ($response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_FAILURE) {
|
||||
user_error('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE');
|
||||
return false;
|
||||
throw new \UnexpectedValueException('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE');
|
||||
}
|
||||
|
||||
$data = pack('CNa*', NET_SSH1_CMSG_AUTH_PASSWORD, strlen($password), $password);
|
||||
|
||||
if (!$this->_send_binary_packet($data)) {
|
||||
user_error('Error sending SSH_CMSG_AUTH_PASSWORD');
|
||||
return false;
|
||||
throw new \RuntimeException('Error sending SSH_CMSG_AUTH_PASSWORD');
|
||||
}
|
||||
|
||||
// remove the username and password from the last logged packet
|
||||
@ -756,8 +755,7 @@ class SSH1
|
||||
} elseif ($response[self::RESPONSE_TYPE] == NET_SSH1_SMSG_FAILURE) {
|
||||
return false;
|
||||
} else {
|
||||
user_error('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE');
|
||||
return false;
|
||||
throw new \UnexpectedValueException('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE');
|
||||
}
|
||||
}
|
||||
|
||||
@ -792,20 +790,19 @@ class SSH1
|
||||
* @see self::interactiveWrite()
|
||||
* @param string $cmd
|
||||
* @return mixed
|
||||
* @throws \RuntimeException on error sending command
|
||||
* @access public
|
||||
*/
|
||||
function exec($cmd, $block = true)
|
||||
{
|
||||
if (!($this->bitmap & self::MASK_LOGIN)) {
|
||||
user_error('Operation disallowed prior to login()');
|
||||
return false;
|
||||
throw new \RuntimeException('Operation disallowed prior to login()');
|
||||
}
|
||||
|
||||
$data = pack('CNa*', NET_SSH1_CMSG_EXEC_CMD, strlen($cmd), $cmd);
|
||||
|
||||
if (!$this->_send_binary_packet($data)) {
|
||||
user_error('Error sending SSH_CMSG_EXEC_CMD');
|
||||
return false;
|
||||
throw new \RuntimeException('Error sending SSH_CMSG_EXEC_CMD');
|
||||
}
|
||||
|
||||
if (!$block) {
|
||||
@ -841,6 +838,8 @@ class SSH1
|
||||
* @see self::interactiveRead()
|
||||
* @see self::interactiveWrite()
|
||||
* @return bool
|
||||
* @throws \UnexpectedValueException on receipt of unexpected packets
|
||||
* @throws \RuntimeException on other errors
|
||||
* @access private
|
||||
*/
|
||||
function _initShell()
|
||||
@ -851,8 +850,7 @@ class SSH1
|
||||
$data = pack('CNa*N4C', NET_SSH1_CMSG_REQUEST_PTY, strlen('vt100'), 'vt100', 24, 80, 0, 0, self::TTY_OP_END);
|
||||
|
||||
if (!$this->_send_binary_packet($data)) {
|
||||
user_error('Error sending SSH_CMSG_REQUEST_PTY');
|
||||
return false;
|
||||
throw new \RuntimeException('Error sending SSH_CMSG_REQUEST_PTY');
|
||||
}
|
||||
|
||||
$response = $this->_get_binary_packet();
|
||||
@ -861,15 +859,13 @@ class SSH1
|
||||
return false;
|
||||
}
|
||||
if ($response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) {
|
||||
user_error('Expected SSH_SMSG_SUCCESS');
|
||||
return false;
|
||||
throw new \UnexpectedValueException('Expected SSH_SMSG_SUCCESS');
|
||||
}
|
||||
|
||||
$data = pack('C', NET_SSH1_CMSG_EXEC_SHELL);
|
||||
|
||||
if (!$this->_send_binary_packet($data)) {
|
||||
user_error('Error sending SSH_CMSG_EXEC_SHELL');
|
||||
return false;
|
||||
throw new \RuntimeException('Error sending SSH_CMSG_EXEC_SHELL');
|
||||
}
|
||||
|
||||
$this->bitmap |= self::MASK_SHELL;
|
||||
@ -902,18 +898,17 @@ class SSH1
|
||||
* @param string $expect
|
||||
* @param int $mode
|
||||
* @return bool
|
||||
* @throws \RuntimeException on connection error
|
||||
* @access public
|
||||
*/
|
||||
function read($expect, $mode = self::READ__SIMPLE)
|
||||
{
|
||||
if (!($this->bitmap & self::MASK_LOGIN)) {
|
||||
user_error('Operation disallowed prior to login()');
|
||||
return false;
|
||||
throw new \RuntimeException('Operation disallowed prior to login()');
|
||||
}
|
||||
|
||||
if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
|
||||
user_error('Unable to initiate an interactive shell session');
|
||||
return false;
|
||||
throw new \RuntimeException('Unable to initiate an interactive shell session');
|
||||
}
|
||||
|
||||
$match = $expect;
|
||||
@ -941,25 +936,23 @@ class SSH1
|
||||
* @see self::interactiveRead()
|
||||
* @param string $cmd
|
||||
* @return bool
|
||||
* @throws \RuntimeException on connection error
|
||||
* @access public
|
||||
*/
|
||||
function interactiveWrite($cmd)
|
||||
{
|
||||
if (!($this->bitmap & self::MASK_LOGIN)) {
|
||||
user_error('Operation disallowed prior to login()');
|
||||
return false;
|
||||
throw new \RuntimeException('Operation disallowed prior to login()');
|
||||
}
|
||||
|
||||
if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
|
||||
user_error('Unable to initiate an interactive shell session');
|
||||
return false;
|
||||
throw new \RuntimeException('Unable to initiate an interactive shell session');
|
||||
}
|
||||
|
||||
$data = pack('CNa*', NET_SSH1_CMSG_STDIN_DATA, strlen($cmd), $cmd);
|
||||
|
||||
if (!$this->_send_binary_packet($data)) {
|
||||
user_error('Error sending SSH_CMSG_STDIN');
|
||||
return false;
|
||||
throw new \RuntimeException('Error sending SSH_CMSG_STDIN');
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -976,18 +969,17 @@ class SSH1
|
||||
*
|
||||
* @see self::interactiveRead()
|
||||
* @return string
|
||||
* @throws \RuntimeException on connection error
|
||||
* @access public
|
||||
*/
|
||||
function interactiveRead()
|
||||
{
|
||||
if (!($this->bitmap & self::MASK_LOGIN)) {
|
||||
user_error('Operation disallowed prior to login()');
|
||||
return false;
|
||||
throw new \RuntimeException('Operation disallowed prior to login()');
|
||||
}
|
||||
|
||||
if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
|
||||
user_error('Unable to initiate an interactive shell session');
|
||||
return false;
|
||||
throw new \RuntimeException('Unable to initiate an interactive shell session');
|
||||
}
|
||||
|
||||
$read = array($this->fsock);
|
||||
@ -1313,9 +1305,9 @@ class SSH1
|
||||
{
|
||||
/*
|
||||
$rsa = new RSA();
|
||||
$rsa->loadKey($key, RSA::PUBLIC_FORMAT_RAW);
|
||||
$rsa->setEncryptionMode(RSA::ENCRYPTION_PKCS1);
|
||||
return $rsa->encrypt($m);
|
||||
$rsa->load($key, 'raw');
|
||||
$rsa->setHash('sha1');
|
||||
return $rsa->encrypt($m, RSA::PADDING_PKCS1);
|
||||
*/
|
||||
|
||||
// To quote from protocol-1.5.txt:
|
||||
|
@ -26,7 +26,7 @@
|
||||
*
|
||||
* $key = new \phpseclib\Crypt\RSA();
|
||||
* //$key->setPassword('whatever');
|
||||
* $key->loadKey(file_get_contents('privatekey'));
|
||||
* $key->load(file_get_contents('privatekey'));
|
||||
*
|
||||
* $ssh = new \phpseclib\Net\SSH2('www.domain.tld');
|
||||
* if (!$ssh->login('username', $key)) {
|
||||
@ -60,6 +60,7 @@ use phpseclib\Crypt\TripleDES;
|
||||
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;
|
||||
use phpseclib\Exception\NoSupportedAlgorithmsException;
|
||||
|
||||
/**
|
||||
* Pure-PHP implementation of SSHv2.
|
||||
@ -866,6 +867,14 @@ class SSH2
|
||||
*/
|
||||
var $agent;
|
||||
|
||||
/**
|
||||
* Connection storage to replicates ssh2 extension functionality:
|
||||
* {@link http://php.net/manual/en/wrappers.ssh2.php#refsect1-wrappers.ssh2-examples}
|
||||
*
|
||||
* @var SSH2[]
|
||||
*/
|
||||
static $connections;
|
||||
|
||||
/**
|
||||
* Default Constructor.
|
||||
*
|
||||
@ -959,6 +968,8 @@ class SSH2
|
||||
31 => 'NET_SSH2_MSG_KEX_ECDH_REPLY')
|
||||
);
|
||||
|
||||
self::$connections[$this->getResourceId()] = $this;
|
||||
|
||||
if (is_resource($host)) {
|
||||
$this->fsock = $host;
|
||||
return;
|
||||
@ -989,6 +1000,8 @@ class SSH2
|
||||
* Connect to an SSHv2 server
|
||||
*
|
||||
* @return bool
|
||||
* @throws \UnexpectedValueException on receipt of unexpected packets
|
||||
* @throws \RuntimeException on other errors
|
||||
* @access private
|
||||
*/
|
||||
function _connect()
|
||||
@ -1008,8 +1021,7 @@ class SSH2
|
||||
$this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $this->curTimeout);
|
||||
if (!$this->fsock) {
|
||||
$host = $this->host . ':' . $this->port;
|
||||
user_error(rtrim("Cannot connect to $host. Error $errno. $errstr"));
|
||||
return false;
|
||||
throw new \RuntimeException(rtrim("Cannot connect to $host. Error $errno. $errstr"));
|
||||
}
|
||||
$elapsed = microtime(true) - $start;
|
||||
|
||||
@ -1060,8 +1072,7 @@ class SSH2
|
||||
}
|
||||
|
||||
if (feof($this->fsock)) {
|
||||
user_error('Connection closed by server');
|
||||
return false;
|
||||
throw new \RuntimeException('Connection closed by server');
|
||||
}
|
||||
|
||||
$this->identifier = $this->_generate_identifier();
|
||||
@ -1077,21 +1088,18 @@ class SSH2
|
||||
}
|
||||
|
||||
if ($matches[1] != '1.99' && $matches[1] != '2.0') {
|
||||
user_error("Cannot connect to SSH $matches[1] servers");
|
||||
return false;
|
||||
throw new \RuntimeException("Cannot connect to SSH $matches[1] servers");
|
||||
}
|
||||
|
||||
fputs($this->fsock, $this->identifier . "\r\n");
|
||||
|
||||
$response = $this->_get_binary_packet();
|
||||
if ($response === false) {
|
||||
user_error('Connection closed by server');
|
||||
return false;
|
||||
throw new \RuntimeException('Connection closed by server');
|
||||
}
|
||||
|
||||
if (ord($response[0]) != NET_SSH2_MSG_KEXINIT) {
|
||||
user_error('Expected SSH_MSG_KEXINIT');
|
||||
return false;
|
||||
throw new \UnexpectedValueException('Expected SSH_MSG_KEXINIT');
|
||||
}
|
||||
|
||||
if (!$this->_key_exchange($response)) {
|
||||
@ -1143,6 +1151,9 @@ class SSH2
|
||||
* Key Exchange
|
||||
*
|
||||
* @param string $kexinit_payload_server
|
||||
* @throws \UnexpectedValueException on receipt of unexpected packets
|
||||
* @throws \RuntimeException on other errors
|
||||
* @throws \phpseclib\Exception\NoSupportedAlgorithmsException when none of the algorithms phpseclib has loaded are compatible
|
||||
* @access private
|
||||
*/
|
||||
function _key_exchange($kexinit_payload_server)
|
||||
@ -1354,27 +1365,28 @@ class SSH2
|
||||
// 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);
|
||||
$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);
|
||||
$this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
||||
throw new NoSupportedAlgorithmsException('No compatible server to client encryption algorithms found');
|
||||
}
|
||||
|
||||
$encrypt = $this->_array_intersect_first($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');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
||||
$this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
||||
throw new NoSupportedAlgorithmsException('No compatible client to server encryption algorithms found');
|
||||
}
|
||||
|
||||
// through diffie-hellman key exchange a symmetric key is obtained
|
||||
$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);
|
||||
$this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
||||
throw new NoSupportedAlgorithmsException('No compatible key exchange algorithms found');
|
||||
}
|
||||
|
||||
// Only relevant in diffie-hellman-group-exchange-sha{1,256}, otherwise empty.
|
||||
@ -1483,7 +1495,7 @@ class SSH2
|
||||
$max = $one->bitwise_leftShift(16 * $keyLength); // 2 * 8 * $keyLength
|
||||
$max = $max->subtract($one);
|
||||
|
||||
$x = $one->random($one, $max);
|
||||
$x = BigInteger::random($one, $max);
|
||||
$e = $g->modPow($x, $prime);
|
||||
|
||||
$eBytes = $e->toBytes(true);
|
||||
@ -1491,20 +1503,17 @@ class SSH2
|
||||
$data = pack('CNa*', $clientKexInitMessage, strlen($eBytes), $eBytes);
|
||||
|
||||
if (!$this->_send_binary_packet($data)) {
|
||||
user_error('Connection closed by server');
|
||||
return false;
|
||||
throw new \RuntimeException('Connection closed by server');
|
||||
}
|
||||
|
||||
$response = $this->_get_binary_packet();
|
||||
if ($response === false) {
|
||||
user_error('Connection closed by server');
|
||||
return false;
|
||||
throw new \RuntimeException('Connection closed by server');
|
||||
}
|
||||
extract(unpack('Ctype', $this->_string_shift($response, 1)));
|
||||
|
||||
if ($type != $serverKexReplyMessage) {
|
||||
user_error('Expected SSH_MSG_KEXDH_REPLY');
|
||||
return false;
|
||||
throw new \UnexpectedValueException('Expected SSH_MSG_KEXDH_REPLY');
|
||||
}
|
||||
|
||||
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
||||
@ -1564,13 +1573,13 @@ class SSH2
|
||||
|
||||
$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);
|
||||
$this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
||||
throw new NoSupportedAlgorithmsException('No compatible server host key algorithms found');
|
||||
}
|
||||
|
||||
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);
|
||||
$this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
||||
throw new \RuntimeException('Server Host Key Algorithm Mismatch');
|
||||
}
|
||||
|
||||
$packet = pack(
|
||||
@ -1585,15 +1594,13 @@ class SSH2
|
||||
$response = $this->_get_binary_packet();
|
||||
|
||||
if ($response === false) {
|
||||
user_error('Connection closed by server');
|
||||
return false;
|
||||
throw new \RuntimeException('Connection closed by server');
|
||||
}
|
||||
|
||||
extract(unpack('Ctype', $this->_string_shift($response, 1)));
|
||||
|
||||
if ($type != NET_SSH2_MSG_NEWKEYS) {
|
||||
user_error('Expected SSH_MSG_NEWKEYS');
|
||||
return false;
|
||||
throw new \UnexpectedValueException('Expected SSH_MSG_NEWKEYS');
|
||||
}
|
||||
|
||||
$keyBytes = pack('Na*', strlen($keyBytes), $keyBytes);
|
||||
@ -1609,11 +1616,13 @@ class SSH2
|
||||
$this->encrypt->enableContinuousBuffer();
|
||||
$this->encrypt->disablePadding();
|
||||
|
||||
$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);
|
||||
if ($this->encrypt->usesIV()) {
|
||||
$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);
|
||||
}
|
||||
$this->encrypt->setIV(substr($iv, 0, $this->encrypt_block_size));
|
||||
}
|
||||
$this->encrypt->setIV(substr($iv, 0, $this->encrypt_block_size));
|
||||
|
||||
$key = $kexHash->hash($keyBytes . $this->exchange_hash . 'C' . $this->session_id);
|
||||
while ($encryptKeyLength > strlen($key)) {
|
||||
@ -1633,11 +1642,13 @@ class SSH2
|
||||
$this->decrypt->enableContinuousBuffer();
|
||||
$this->decrypt->disablePadding();
|
||||
|
||||
$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);
|
||||
if ($this->decrypt->usesIV()) {
|
||||
$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);
|
||||
}
|
||||
$this->decrypt->setIV(substr($iv, 0, $this->decrypt_block_size));
|
||||
}
|
||||
$this->decrypt->setIV(substr($iv, 0, $this->decrypt_block_size));
|
||||
|
||||
$key = $kexHash->hash($keyBytes . $this->exchange_hash . 'D' . $this->session_id);
|
||||
while ($decryptKeyLength > strlen($key)) {
|
||||
@ -1662,8 +1673,8 @@ class SSH2
|
||||
|
||||
$mac_algorithm = $this->_array_intersect_first($mac_algorithms, $this->mac_algorithms_client_to_server);
|
||||
if ($mac_algorithm === false) {
|
||||
user_error('No compatible client to server message authentication algorithms found');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
||||
$this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
||||
throw new NoSupportedAlgorithmsException('No compatible client to server message authentication algorithms found');
|
||||
}
|
||||
|
||||
$createKeyLength = 0; // ie. $mac_algorithm == 'none'
|
||||
@ -1691,8 +1702,8 @@ class SSH2
|
||||
|
||||
$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->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
||||
throw new NoSupportedAlgorithmsException('No compatible server to client message authentication algorithms found');
|
||||
}
|
||||
|
||||
$checkKeyLength = 0;
|
||||
@ -1738,15 +1749,15 @@ class SSH2
|
||||
|
||||
$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->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
||||
throw new NoSupportedAlgorithmsException('No compatible server to client compression algorithms found');
|
||||
}
|
||||
$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->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
||||
throw new NoSupportedAlgorithmsException('No compatible client to server compression algorithms found');
|
||||
}
|
||||
$this->compress = $compression_algorithm == 'zlib';
|
||||
|
||||
@ -1804,26 +1815,26 @@ class SSH2
|
||||
{
|
||||
switch ($algorithm) {
|
||||
case '3des-cbc':
|
||||
return new TripleDES();
|
||||
return new TripleDES(Base::MODE_CBC);
|
||||
case '3des-ctr':
|
||||
return new TripleDES(Base::MODE_CTR);
|
||||
case 'aes256-cbc':
|
||||
case 'aes192-cbc':
|
||||
case 'aes128-cbc':
|
||||
return new Rijndael();
|
||||
return new Rijndael(Base::MODE_CBC);
|
||||
case 'aes256-ctr':
|
||||
case 'aes192-ctr':
|
||||
case 'aes128-ctr':
|
||||
return new Rijndael(Base::MODE_CTR);
|
||||
case 'blowfish-cbc':
|
||||
return new Blowfish();
|
||||
return new Blowfish(Base::MODE_CBC);
|
||||
case 'blowfish-ctr':
|
||||
return new Blowfish(Base::MODE_CTR);
|
||||
case 'twofish128-cbc':
|
||||
case 'twofish192-cbc':
|
||||
case 'twofish256-cbc':
|
||||
case 'twofish-cbc':
|
||||
return new Twofish();
|
||||
return new Twofish(Base::MODE_CBC);
|
||||
case 'twofish128-ctr':
|
||||
case 'twofish192-ctr':
|
||||
case 'twofish256-ctr':
|
||||
@ -1891,6 +1902,8 @@ class SSH2
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @return bool
|
||||
* @throws \UnexpectedValueException on receipt of unexpected packets
|
||||
* @throws \RuntimeException on other errors
|
||||
* @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}
|
||||
* by sending dummy SSH_MSG_IGNORE messages.
|
||||
@ -1915,15 +1928,13 @@ class SSH2
|
||||
|
||||
$response = $this->_get_binary_packet();
|
||||
if ($response === false) {
|
||||
user_error('Connection closed by server');
|
||||
return false;
|
||||
throw new \RuntimeException('Connection closed by server');
|
||||
}
|
||||
|
||||
extract(unpack('Ctype', $this->_string_shift($response, 1)));
|
||||
|
||||
if ($type != NET_SSH2_MSG_SERVICE_ACCEPT) {
|
||||
user_error('Expected SSH_MSG_SERVICE_ACCEPT');
|
||||
return false;
|
||||
throw new \UnexpectedValueException('Expected SSH_MSG_SERVICE_ACCEPT');
|
||||
}
|
||||
$this->bitmap |= self::MASK_LOGIN_REQ;
|
||||
}
|
||||
@ -1964,8 +1975,7 @@ class SSH2
|
||||
|
||||
$response = $this->_get_binary_packet();
|
||||
if ($response === false) {
|
||||
user_error('Connection closed by server');
|
||||
return false;
|
||||
throw new \RuntimeException('Connection closed by server');
|
||||
}
|
||||
|
||||
extract(unpack('Ctype', $this->_string_shift($response, 1)));
|
||||
@ -2019,8 +2029,7 @@ class SSH2
|
||||
|
||||
$response = $this->_get_binary_packet();
|
||||
if ($response === false) {
|
||||
user_error('Connection closed by server');
|
||||
return false;
|
||||
throw new \RuntimeException('Connection closed by server');
|
||||
}
|
||||
|
||||
extract(unpack('Ctype', $this->_string_shift($response, 1)));
|
||||
@ -2096,6 +2105,7 @@ class SSH2
|
||||
*
|
||||
* @param string $responses...
|
||||
* @return bool
|
||||
* @throws \RuntimeException on connection error
|
||||
* @access private
|
||||
*/
|
||||
function _keyboard_interactive_process()
|
||||
@ -2107,8 +2117,7 @@ class SSH2
|
||||
} else {
|
||||
$orig = $response = $this->_get_binary_packet();
|
||||
if ($response === false) {
|
||||
user_error('Connection closed by server');
|
||||
return false;
|
||||
throw new \RuntimeException('Connection closed by server');
|
||||
}
|
||||
}
|
||||
|
||||
@ -2232,6 +2241,7 @@ class SSH2
|
||||
* @param string $username
|
||||
* @param \phpseclib\Crypt\RSA $password
|
||||
* @return bool
|
||||
* @throws \RuntimeException on connection error
|
||||
* @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}
|
||||
* by sending dummy SSH_MSG_IGNORE messages.
|
||||
@ -2239,7 +2249,7 @@ class SSH2
|
||||
function _privatekey_login($username, $privatekey)
|
||||
{
|
||||
// see http://tools.ietf.org/html/rfc4253#page-15
|
||||
$publickey = $privatekey->getPublicKey(RSA::PUBLIC_FORMAT_RAW);
|
||||
$publickey = $privatekey->getPublicKey('Raw');
|
||||
if ($publickey === false) {
|
||||
return false;
|
||||
}
|
||||
@ -2277,8 +2287,7 @@ class SSH2
|
||||
|
||||
$response = $this->_get_binary_packet();
|
||||
if ($response === false) {
|
||||
user_error('Connection closed by server');
|
||||
return false;
|
||||
throw new \RuntimeException('Connection closed by server');
|
||||
}
|
||||
|
||||
extract(unpack('Ctype', $this->_string_shift($response, 1)));
|
||||
@ -2301,8 +2310,8 @@ class SSH2
|
||||
}
|
||||
|
||||
$packet = $part1 . chr(1) . $part2;
|
||||
$privatekey->setSignatureMode(RSA::SIGNATURE_PKCS1);
|
||||
$signature = $privatekey->sign(pack('Na*a*', strlen($this->session_id), $this->session_id, $packet));
|
||||
$privatekey->setHash('sha1');
|
||||
$signature = $privatekey->sign(pack('Na*a*', strlen($this->session_id), $this->session_id, $packet), RSA::PADDING_PKCS1);
|
||||
$signature = pack('Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($signature), $signature);
|
||||
$packet.= pack('Na*', strlen($signature), $signature);
|
||||
|
||||
@ -2312,8 +2321,7 @@ class SSH2
|
||||
|
||||
$response = $this->_get_binary_packet();
|
||||
if ($response === false) {
|
||||
user_error('Connection closed by server');
|
||||
return false;
|
||||
throw new \RuntimeException('Connection closed by server');
|
||||
}
|
||||
|
||||
extract(unpack('Ctype', $this->_string_shift($response, 1)));
|
||||
@ -2363,6 +2371,7 @@ class SSH2
|
||||
* @param string $command
|
||||
* @param Callback $callback
|
||||
* @return string
|
||||
* @throws \RuntimeException on connection error
|
||||
* @access public
|
||||
*/
|
||||
function exec($command, $callback = null)
|
||||
@ -2430,8 +2439,7 @@ class SSH2
|
||||
|
||||
$response = $this->_get_binary_packet();
|
||||
if ($response === false) {
|
||||
user_error('Connection closed by server');
|
||||
return false;
|
||||
throw new \RuntimeException('Connection closed by server');
|
||||
}
|
||||
|
||||
list(, $type) = unpack('C', $this->_string_shift($response, 1));
|
||||
@ -2441,8 +2449,8 @@ class SSH2
|
||||
break;
|
||||
case NET_SSH2_MSG_CHANNEL_FAILURE:
|
||||
default:
|
||||
user_error('Unable to request pseudo-terminal');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
|
||||
$this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
|
||||
throw new \RuntimeException('Unable to request pseudo-terminal');
|
||||
}
|
||||
$this->in_request_pty_exec = true;
|
||||
}
|
||||
@ -2510,6 +2518,8 @@ class SSH2
|
||||
* @see self::read()
|
||||
* @see self::write()
|
||||
* @return bool
|
||||
* @throws \UnexpectedValueException on receipt of unexpected packets
|
||||
* @throws \RuntimeException on other errors
|
||||
* @access private
|
||||
*/
|
||||
function _initShell()
|
||||
@ -2566,8 +2576,7 @@ class SSH2
|
||||
|
||||
$response = $this->_get_binary_packet();
|
||||
if ($response === false) {
|
||||
user_error('Connection closed by server');
|
||||
return false;
|
||||
throw new \RuntimeException('Connection closed by server');
|
||||
}
|
||||
|
||||
list(, $type) = unpack('C', $this->_string_shift($response, 1));
|
||||
@ -2578,8 +2587,8 @@ class SSH2
|
||||
case NET_SSH2_MSG_CHANNEL_FAILURE:
|
||||
break;
|
||||
default:
|
||||
user_error('Unable to request pseudo-terminal');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
|
||||
$this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
|
||||
throw new \UnexpectedValueException('Unable to request pseudo-terminal');
|
||||
}
|
||||
|
||||
$packet = pack(
|
||||
@ -2656,6 +2665,7 @@ class SSH2
|
||||
* @param string $expect
|
||||
* @param int $mode
|
||||
* @return string
|
||||
* @throws \RuntimeException on connection error
|
||||
* @access public
|
||||
*/
|
||||
function read($expect = '', $mode = self::READ_SIMPLE)
|
||||
@ -2664,13 +2674,11 @@ class SSH2
|
||||
$this->is_timeout = false;
|
||||
|
||||
if (!($this->bitmap & self::MASK_LOGIN)) {
|
||||
user_error('Operation disallowed prior to login()');
|
||||
return false;
|
||||
throw new \RuntimeException('Operation disallowed prior to login()');
|
||||
}
|
||||
|
||||
if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
|
||||
user_error('Unable to initiate an interactive shell session');
|
||||
return false;
|
||||
throw new \RuntimeException('Unable to initiate an interactive shell session');
|
||||
}
|
||||
|
||||
$channel = $this->_get_interactive_channel();
|
||||
@ -2701,18 +2709,17 @@ class SSH2
|
||||
* @see self::read()
|
||||
* @param string $cmd
|
||||
* @return bool
|
||||
* @throws \RuntimeException on connection error
|
||||
* @access public
|
||||
*/
|
||||
function write($cmd)
|
||||
{
|
||||
if (!($this->bitmap & self::MASK_LOGIN)) {
|
||||
user_error('Operation disallowed prior to login()');
|
||||
return false;
|
||||
throw new \RuntimeException('Operation disallowed prior to login()');
|
||||
}
|
||||
|
||||
if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
|
||||
user_error('Unable to initiate an interactive shell session');
|
||||
return false;
|
||||
throw new \RuntimeException('Unable to initiate an interactive shell session');
|
||||
}
|
||||
|
||||
return $this->_send_channel_packet($this->_get_interactive_channel(), $cmd);
|
||||
@ -2836,6 +2843,7 @@ class SSH2
|
||||
if (isset($this->realtime_log_file) && is_resource($this->realtime_log_file)) {
|
||||
fclose($this->realtime_log_file);
|
||||
}
|
||||
unset(self::$connections[$this->getResourceId()]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2880,14 +2888,14 @@ class SSH2
|
||||
*
|
||||
* @see self::_send_binary_packet()
|
||||
* @return string
|
||||
* @throws \RuntimeException on connection errors
|
||||
* @access private
|
||||
*/
|
||||
function _get_binary_packet()
|
||||
{
|
||||
if (!is_resource($this->fsock) || feof($this->fsock)) {
|
||||
user_error('Connection closed prematurely');
|
||||
$this->bitmap = 0;
|
||||
return false;
|
||||
throw new \RuntimeException('Connection closed prematurely');
|
||||
}
|
||||
|
||||
$start = microtime(true);
|
||||
@ -2901,8 +2909,7 @@ class SSH2
|
||||
$raw = $this->decrypt->decrypt($raw);
|
||||
}
|
||||
if ($raw === false) {
|
||||
user_error('Unable to decrypt content');
|
||||
return false;
|
||||
throw new \RuntimeException('Unable to decrypt content');
|
||||
}
|
||||
|
||||
extract(unpack('Npacket_length/Cpadding_length', $this->_string_shift($raw, 5)));
|
||||
@ -2913,17 +2920,15 @@ 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) {
|
||||
user_error('Invalid size');
|
||||
return false;
|
||||
throw new \RuntimeException('Invalid size');
|
||||
}
|
||||
|
||||
$buffer = '';
|
||||
while ($remaining_length > 0) {
|
||||
$temp = fread($this->fsock, $remaining_length);
|
||||
if ($temp === false || feof($this->fsock)) {
|
||||
user_error('Error reading from socket');
|
||||
$this->bitmap = 0;
|
||||
return false;
|
||||
throw new \RuntimeException('Error reading from socket');
|
||||
}
|
||||
$buffer.= $temp;
|
||||
$remaining_length-= strlen($temp);
|
||||
@ -2939,12 +2944,10 @@ class SSH2
|
||||
if ($this->hmac_check !== false) {
|
||||
$hmac = fread($this->fsock, $this->hmac_size);
|
||||
if ($hmac === false || strlen($hmac) != $this->hmac_size) {
|
||||
user_error('Error reading socket');
|
||||
$this->bitmap = 0;
|
||||
return false;
|
||||
throw new \RuntimeException('Error reading socket');
|
||||
} elseif ($hmac != $this->hmac_check->hash(pack('NNCa*', $this->get_seq_no, $packet_length, $padding_length, $payload . $padding))) {
|
||||
user_error('Invalid HMAC');
|
||||
return false;
|
||||
throw new \RuntimeException('Invalid HMAC');
|
||||
}
|
||||
}
|
||||
|
||||
@ -3170,6 +3173,7 @@ class SSH2
|
||||
*
|
||||
* @param $client_channel
|
||||
* @return mixed
|
||||
* @throws \RuntimeException on connection error
|
||||
* @access private
|
||||
*/
|
||||
function _get_channel_packet($client_channel, $skip_extended = false)
|
||||
@ -3202,8 +3206,7 @@ class SSH2
|
||||
|
||||
$response = $this->_get_binary_packet();
|
||||
if ($response === false) {
|
||||
user_error('Connection closed by server');
|
||||
return false;
|
||||
throw new \RuntimeException('Connection closed by server');
|
||||
}
|
||||
if ($client_channel == -1 && $response === true) {
|
||||
return true;
|
||||
@ -3252,8 +3255,8 @@ class SSH2
|
||||
return $result;
|
||||
//case NET_SSH2_MSG_CHANNEL_OPEN_FAILURE:
|
||||
default:
|
||||
user_error('Unable to open channel');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
|
||||
$this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
|
||||
throw new \RuntimeException('Unable to open channel');
|
||||
}
|
||||
break;
|
||||
case NET_SSH2_MSG_CHANNEL_REQUEST:
|
||||
@ -3263,8 +3266,8 @@ class SSH2
|
||||
case NET_SSH2_MSG_CHANNEL_FAILURE:
|
||||
return false;
|
||||
default:
|
||||
user_error('Unable to fulfill channel request');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
|
||||
$this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
|
||||
throw new \RuntimeException('Unable to fulfill channel request');
|
||||
}
|
||||
case NET_SSH2_MSG_CHANNEL_CLOSE:
|
||||
return $type == NET_SSH2_MSG_CHANNEL_CLOSE ? true : $this->_get_channel_packet($client_channel, $skip_extended);
|
||||
@ -3373,8 +3376,8 @@ class SSH2
|
||||
case NET_SSH2_MSG_CHANNEL_EOF:
|
||||
break;
|
||||
default:
|
||||
user_error('Error reading channel data');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
|
||||
$this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
|
||||
throw new \RuntimeException('Error reading channel data');
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3393,9 +3396,8 @@ 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;
|
||||
return false;
|
||||
throw new \RuntimeException('Connection closed prematurely');
|
||||
}
|
||||
|
||||
//if ($this->compress) {
|
||||
@ -3486,14 +3488,14 @@ class SSH2
|
||||
@flush();
|
||||
@ob_flush();
|
||||
break;
|
||||
// basically the same thing as self::LOG_REALTIME with the caveat that self::LOG_REALTIME_FILE
|
||||
// basically the same thing as self::LOG_REALTIME with the caveat that NET_SFTP_LOG_REALTIME_FILENAME
|
||||
// needs to be defined and that the resultant log file will be capped out at self::LOG_MAX_SIZE.
|
||||
// the earliest part of the log file is denoted by the first <<< START >>> and is not going to necessarily
|
||||
// at the beginning of the file
|
||||
case self::LOG_REALTIME_FILE:
|
||||
if (!isset($this->realtime_log_file)) {
|
||||
// PHP doesn't seem to like using constants in fopen()
|
||||
$filename = self::LOG_REALTIME_FILENAME;
|
||||
$filename = NET_SSH2_LOG_REALTIME_FILENAME;
|
||||
$fp = fopen($filename, 'w');
|
||||
$this->realtime_log_file = $fp;
|
||||
}
|
||||
@ -3958,6 +3960,8 @@ class SSH2
|
||||
* is recommended. Returns false if the server signature is not signed correctly with the public host key.
|
||||
*
|
||||
* @return mixed
|
||||
* @throws \RuntimeException on badly formatted keys
|
||||
* @throws \phpseclib\Exception\NoSupportedAlgorithmsException when the key isn't in a supported format
|
||||
* @access public
|
||||
*/
|
||||
function getServerPublicHostKey()
|
||||
@ -4003,8 +4007,8 @@ class SSH2
|
||||
padding, unsigned, and in network byte order). */
|
||||
$temp = unpack('Nlength', $this->_string_shift($signature, 4));
|
||||
if ($temp['length'] != 40) {
|
||||
user_error('Invalid signature');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
||||
$this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
||||
throw new \RuntimeException('Invalid signature');
|
||||
}
|
||||
|
||||
$r = new BigInteger($this->_string_shift($signature, 20), 256);
|
||||
@ -4015,8 +4019,8 @@ class SSH2
|
||||
case $r->compare($q) >= 0:
|
||||
case $s->equals($zero):
|
||||
case $s->compare($q) >= 0:
|
||||
user_error('Invalid signature');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
||||
$this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
||||
throw new \RuntimeException('Invalid signature');
|
||||
}
|
||||
|
||||
$w = $s->modInverse($q);
|
||||
@ -4035,7 +4039,7 @@ class SSH2
|
||||
list(, $v) = $v->divide($q);
|
||||
|
||||
if (!$v->equals($r)) {
|
||||
user_error('Bad server signature');
|
||||
//user_error('Bad server signature');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
|
||||
}
|
||||
|
||||
@ -4054,10 +4058,10 @@ class SSH2
|
||||
$signature = $this->_string_shift($signature, $temp['length']);
|
||||
|
||||
$rsa = new RSA();
|
||||
$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');
|
||||
$rsa->load(array('e' => $e, 'n' => $n), 'raw');
|
||||
$rsa->setHash('sha1');
|
||||
if (!$rsa->verify($this->exchange_hash, $signature, RSA::PADDING_PKCS1)) {
|
||||
//user_error('Bad server signature');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
|
||||
}
|
||||
*/
|
||||
@ -4072,8 +4076,8 @@ class SSH2
|
||||
// also, see SSHRSA.c (rsa2_verifysig) in PuTTy's source.
|
||||
|
||||
if ($s->compare(new BigInteger()) < 0 || $s->compare($n->subtract(new BigInteger(1))) > 0) {
|
||||
user_error('Invalid signature');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
||||
$this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
||||
throw new \RuntimeException('Invalid signature');
|
||||
}
|
||||
|
||||
$s = $s->modPow($e, $n);
|
||||
@ -4083,13 +4087,13 @@ class SSH2
|
||||
$h = chr(0x01) . str_repeat(chr(0xFF), $nLength - 2 - strlen($h)) . $h;
|
||||
|
||||
if ($s != $h) {
|
||||
user_error('Bad server signature');
|
||||
//user_error('Bad server signature');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
user_error('Unsupported signature format');
|
||||
return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
|
||||
$this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
|
||||
throw new NoSupportedAlgorithmsException('Unsupported signature format');
|
||||
}
|
||||
|
||||
return $this->signature_format . ' ' . base64_encode($this->server_public_host_key);
|
||||
@ -4165,4 +4169,47 @@ class SSH2
|
||||
$this->windowColumns = $columns;
|
||||
$this->windowRows = $rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
function __toString()
|
||||
{
|
||||
return $this->getResourceId();
|
||||
}
|
||||
|
||||
/**
|
||||
* We use {} because that symbols should not be in URL according to
|
||||
* {@link http://tools.ietf.org/html/rfc3986#section-2 RFC}.
|
||||
* It will safe us from any conflicts, because otherwise regexp will
|
||||
* match all alphanumeric domains.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function getResourceId()
|
||||
{
|
||||
return '{' . spl_object_hash($this) . '}';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return existing connection
|
||||
*
|
||||
* @param string $id
|
||||
*
|
||||
* @return bool|SSH2 will return false if no such connection
|
||||
*/
|
||||
static function getConnectionByResourceId($id)
|
||||
{
|
||||
return isset(self::$connections[$id]) ? self::$connections[$id] : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all excising connections
|
||||
*
|
||||
* @return SSH2[]
|
||||
*/
|
||||
static function getConnections()
|
||||
{
|
||||
return self::$connections;
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,7 @@
|
||||
namespace phpseclib\System\SSH;
|
||||
|
||||
use phpseclib\Crypt\RSA;
|
||||
use phpseclib\Exception\BadConfigurationException;
|
||||
use phpseclib\System\SSH\Agent\Identity;
|
||||
|
||||
/**
|
||||
@ -115,6 +116,8 @@ class Agent
|
||||
* Default Constructor
|
||||
*
|
||||
* @return \phpseclib\System\SSH\Agent
|
||||
* @throws \phpseclib\Exception\BadConfigurationException if SSH_AUTH_SOCK cannot be found
|
||||
* @throws \RuntimeException on connection errors
|
||||
* @access public
|
||||
*/
|
||||
function __construct()
|
||||
@ -127,13 +130,12 @@ class Agent
|
||||
$address = $_ENV['SSH_AUTH_SOCK'];
|
||||
break;
|
||||
default:
|
||||
user_error('SSH_AUTH_SOCK not found');
|
||||
return false;
|
||||
throw new BadConfigurationException('SSH_AUTH_SOCK not found');
|
||||
}
|
||||
|
||||
$this->fsock = fsockopen('unix://' . $address, 0, $errno, $errstr);
|
||||
if (!$this->fsock) {
|
||||
user_error("Unable to connect to ssh-agent (Error $errno: $errstr)");
|
||||
throw new \RuntimeException("Unable to connect to ssh-agent (Error $errno: $errstr)");
|
||||
}
|
||||
}
|
||||
|
||||
@ -144,6 +146,7 @@ class Agent
|
||||
* Returns an array containing zero or more \phpseclib\System\SSH\Agent\Identity objects
|
||||
*
|
||||
* @return array
|
||||
* @throws \RuntimeException on receipt of unexpected packets
|
||||
* @access public
|
||||
*/
|
||||
function requestIdentities()
|
||||
@ -154,13 +157,13 @@ 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');
|
||||
throw new \RuntimeException('Connection closed while requesting identities');
|
||||
}
|
||||
|
||||
$length = current(unpack('N', fread($this->fsock, 4)));
|
||||
$type = ord(fread($this->fsock, 1));
|
||||
if ($type != self::SSH_AGENT_IDENTITIES_ANSWER) {
|
||||
user_error('Unable to request identities');
|
||||
throw new \RuntimeException('Unable to request identities');
|
||||
}
|
||||
|
||||
$identities = array();
|
||||
@ -178,7 +181,7 @@ class Agent
|
||||
switch ($key_type) {
|
||||
case 'ssh-rsa':
|
||||
$key = new RSA();
|
||||
$key->loadKey($key_str);
|
||||
$key->load($key_str);
|
||||
break;
|
||||
case 'ssh-dss':
|
||||
// not currently supported
|
||||
@ -274,6 +277,7 @@ class Agent
|
||||
*
|
||||
* @param string $data
|
||||
* @return data from SSH Agent
|
||||
* @throws \RuntimeException on connection errors
|
||||
* @access private
|
||||
*/
|
||||
function _forward_data($data)
|
||||
@ -292,7 +296,7 @@ class Agent
|
||||
}
|
||||
|
||||
if (strlen($this->socket_buffer) != fwrite($this->fsock, $this->socket_buffer)) {
|
||||
user_error('Connection closed attempting to forward data to SSH agent');
|
||||
throw new \RuntimeException('Connection closed attempting to forward data to SSH agent');
|
||||
}
|
||||
|
||||
$this->socket_buffer = '';
|
||||
|
@ -15,6 +15,8 @@
|
||||
|
||||
namespace phpseclib\System\SSH\Agent;
|
||||
|
||||
use phpseclib\Crypt\RSA;
|
||||
use phpseclib\Exception\UnsupportedAlgorithmException;
|
||||
use phpseclib\System\SSH\Agent;
|
||||
|
||||
/**
|
||||
@ -23,9 +25,8 @@ use phpseclib\System\SSH\Agent;
|
||||
* Instantiation should only be performed by \phpseclib\System\SSH\Agent class.
|
||||
* This could be thought of as implementing an interface that phpseclib\Crypt\RSA
|
||||
* implements. ie. maybe a Net_SSH_Auth_PublicKey interface or something.
|
||||
* The methods in this interface would be getPublicKey, setSignatureMode
|
||||
* and sign since those are the methods phpseclib looks for to perform
|
||||
* public key authentication.
|
||||
* The methods in this interface would be getPublicKey and sign since those are the
|
||||
* methods phpseclib looks for to perform public key authentication.
|
||||
*
|
||||
* @package SSH\Agent
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
@ -105,26 +106,29 @@ class Identity
|
||||
*
|
||||
* Wrapper for $this->key->getPublicKey()
|
||||
*
|
||||
* @param int $format optional
|
||||
* @param int $type optional
|
||||
* @return mixed
|
||||
* @access public
|
||||
*/
|
||||
function getPublicKey($format = null)
|
||||
function getPublicKey($type = 'PKCS8')
|
||||
{
|
||||
return !isset($format) ? $this->key->getPublicKey() : $this->key->getPublicKey($format);
|
||||
return $this->key->getPublicKey($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Signature Mode
|
||||
* Sets the hash
|
||||
*
|
||||
* Doesn't do anything as ssh-agent doesn't let you pick and choose the signature mode. ie.
|
||||
* ssh-agent's only supported mode is \phpseclib\Crypt\RSA::SIGNATURE_PKCS1
|
||||
* ssh-agent only supports signatures with sha1 hashes but to maintain BC with RSA.php this function exists
|
||||
*
|
||||
* @param int $mode
|
||||
* @param string $hash optional
|
||||
* @throws \phpseclib\Exception\UnsupportedAlgorithmException if the algorithm is unsupported
|
||||
* @access public
|
||||
*/
|
||||
function setSignatureMode($mode)
|
||||
function setHash($hash = 'sha1')
|
||||
{
|
||||
if ($hash != 'sha1') {
|
||||
throw new UnsupportedAlgorithmException('ssh-agent can only be used with the sha1 hash');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -133,22 +137,29 @@ class Identity
|
||||
* See "2.6.2 Protocol 2 private key signature request"
|
||||
*
|
||||
* @param string $message
|
||||
* @param int $padding optional
|
||||
* @return string
|
||||
* @throws \RuntimeException on connection errors
|
||||
* @throws \phpseclib\Exception\UnsupportedAlgorithmException if the algorithm is unsupported
|
||||
* @access public
|
||||
*/
|
||||
function sign($message)
|
||||
function sign($message, $padding = RSA::PADDING_PKCS1)
|
||||
{
|
||||
if ($padding != RSA::PADDING_PKCS1 && $padding != RSA::PADDING_RELAXED_PKCS1) {
|
||||
throw new UnsupportedAlgorithmException('ssh-agent can only create PKCS1 signatures');
|
||||
}
|
||||
|
||||
// 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('Na*', strlen($packet), $packet);
|
||||
if (strlen($packet) != fputs($this->fsock, $packet)) {
|
||||
user_error('Connection closed during signing');
|
||||
throw new \RuntimeException('Connection closed during signing');
|
||||
}
|
||||
|
||||
$length = current(unpack('N', fread($this->fsock, 4)));
|
||||
$type = ord(fread($this->fsock, 1));
|
||||
if ($type != Agent::SSH_AGENT_SIGN_RESPONSE) {
|
||||
user_error('Unable to retreive signature');
|
||||
throw new \RuntimeException('Unable to retreive signature');
|
||||
}
|
||||
|
||||
$signature_blob = fread($this->fsock, $length - 1);
|
||||
|
@ -1,14 +1,18 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Bootstrapping File for phpseclib
|
||||
*
|
||||
* composer isn't a requirement for phpseclib 2.0 but this file isn't really required
|
||||
* either. it's a bonus for those using composer but if you're not phpseclib will
|
||||
* still work
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
*/
|
||||
|
||||
if (extension_loaded('mbstring')) {
|
||||
// 2 - MB_OVERLOAD_STRING
|
||||
if (ini_get('mbstring.func_overload') & 2) {
|
||||
throw new \UnexpectedValueException(
|
||||
throw new UnexpectedValueException(
|
||||
'Overloading of string functions using mbstring.func_overload ' .
|
||||
'is not supported by phpseclib.'
|
||||
);
|
||||
|
@ -42,6 +42,19 @@ class Functional_Net_SFTPStreamTest extends Functional_Net_SFTPTestCase
|
||||
$this->assertTrue(in_array('te#st.txt', $this->sftp->nlist()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests connection reuse functionality same as ssh2 extension:
|
||||
* {@link http://php.net/manual/en/wrappers.ssh2.php#refsect1-wrappers.ssh2-examples}
|
||||
*/
|
||||
public function testConnectionReuse()
|
||||
{
|
||||
$originalConnectionsCount = count(\phpseclib\Net\SSH2::getConnections());
|
||||
$session = $this->sftp;
|
||||
$dirs = scandir("sftp://$session/");
|
||||
$this->assertCount($originalConnectionsCount, \phpseclib\Net\SSH2::getConnections());
|
||||
$this->assertEquals(array('.', '..'), array_slice($dirs, 0, 2));
|
||||
}
|
||||
|
||||
protected function buildUrl($suffix)
|
||||
{
|
||||
return sprintf(
|
||||
|
@ -13,6 +13,9 @@ use phpseclib\Net\SFTP;
|
||||
*/
|
||||
abstract class Functional_Net_SFTPTestCase extends PhpseclibFunctionalTestCase
|
||||
{
|
||||
/**
|
||||
* @var SFTP
|
||||
*/
|
||||
protected $sftp;
|
||||
protected $scratchDir;
|
||||
|
||||
|
@ -28,9 +28,7 @@ abstract class PhpseclibFunctionalTestCase extends PhpseclibTestCase
|
||||
'Should have gmp or bcmath extension for functional test.'
|
||||
);
|
||||
}
|
||||
self::ensureConstant('CRYPT_HASH_MODE', Hash::MODE_HASH);
|
||||
self::reRequireFile('Math/BigInteger.php');
|
||||
self::reRequireFile('Crypt/Hash.php');
|
||||
}
|
||||
parent::setUpBeforeClass();
|
||||
}
|
||||
|
@ -47,13 +47,13 @@ abstract class Unit_Crypt_AES_TestCase extends PhpseclibTestCase
|
||||
':-):-):-):-):-):-)', // https://github.com/phpseclib/phpseclib/pull/43
|
||||
);
|
||||
$ivs = array(
|
||||
'',
|
||||
'test123',
|
||||
str_repeat("\0", 16),
|
||||
str_pad('test123', 16, "\0"),
|
||||
);
|
||||
$keys = array(
|
||||
'',
|
||||
':-8', // https://github.com/phpseclib/phpseclib/pull/43
|
||||
'FOOBARZ',
|
||||
str_repeat("\0", 16),
|
||||
str_pad(':-8', 16, "\0"), // https://github.com/phpseclib/phpseclib/pull/43
|
||||
str_pad('FOOBARZ', 16, "\0"),
|
||||
);
|
||||
|
||||
$result = array();
|
||||
@ -100,10 +100,11 @@ abstract class Unit_Crypt_AES_TestCase extends PhpseclibTestCase
|
||||
// this test case is from the following URL:
|
||||
// https://web.archive.org/web/20070209120224/http://fp.gladman.plus.com/cryptography_technology/rijndael/aesdvec.zip
|
||||
|
||||
$aes = new Rijndael();
|
||||
$aes = new Rijndael(Base::MODE_CBC);
|
||||
$aes->setPreferredEngine($this->engine);
|
||||
$aes->disablePadding();
|
||||
$aes->setKey(pack('H*', '2b7e151628aed2a6abf7158809cf4f3c762e7160')); // 160-bit key. Valid in Rijndael.
|
||||
$aes->setIV(str_repeat("\0", 16));
|
||||
//$this->_checkEngine($aes); // should only work in internal mode
|
||||
$ciphertext = $aes->encrypt(pack('H*', '3243f6a8885a308d313198a2e0370734'));
|
||||
$this->assertEquals($ciphertext, pack('H*', '231d844639b31b412211cfe93712b880'));
|
||||
@ -111,15 +112,17 @@ abstract class Unit_Crypt_AES_TestCase extends PhpseclibTestCase
|
||||
|
||||
/**
|
||||
* @group github451
|
||||
* @expectedException \LengthException
|
||||
*/
|
||||
public function testKeyPaddingAES()
|
||||
{
|
||||
// same as the above - just with a different ciphertext
|
||||
|
||||
$aes = new AES();
|
||||
$aes = new AES(Base::MODE_CBC);
|
||||
$aes->setPreferredEngine($this->engine);
|
||||
$aes->disablePadding();
|
||||
$aes->setKey(pack('H*', '2b7e151628aed2a6abf7158809cf4f3c762e7160')); // 160-bit key. AES should null pad to 192-bits
|
||||
$aes->setKey(pack('H*', '2b7e151628aed2a6abf7158809cf4f3c762e7160')); // 160-bit key. supported by Rijndael - not AES
|
||||
$aes->setIV(str_repeat("\0", 16));
|
||||
$this->_checkEngine($aes);
|
||||
$ciphertext = $aes->encrypt(pack('H*', '3243f6a8885a308d313198a2e0370734'));
|
||||
$this->assertEquals($ciphertext, pack('H*', 'c109292b173f841b88e0ee49f13db8c0'));
|
||||
@ -264,7 +267,7 @@ abstract class Unit_Crypt_AES_TestCase extends PhpseclibTestCase
|
||||
// from http://csrc.nist.gov/groups/STM/cavp/documents/aes/AESAVS.pdf#page=16
|
||||
public function testGFSBox128()
|
||||
{
|
||||
$aes = new AES();
|
||||
$aes = new AES(Base::MODE_CBC);
|
||||
|
||||
$aes->setKey(pack('H*', '00000000000000000000000000000000'));
|
||||
$aes->setIV(pack('H*', '00000000000000000000000000000000'));
|
||||
@ -291,7 +294,7 @@ abstract class Unit_Crypt_AES_TestCase extends PhpseclibTestCase
|
||||
|
||||
public function testGFSBox192()
|
||||
{
|
||||
$aes = new AES();
|
||||
$aes = new AES(Base::MODE_CBC);
|
||||
|
||||
$aes->setKey(pack('H*', '000000000000000000000000000000000000000000000000'));
|
||||
$aes->setIV(pack('H*', '00000000000000000000000000000000'));
|
||||
@ -316,7 +319,7 @@ abstract class Unit_Crypt_AES_TestCase extends PhpseclibTestCase
|
||||
|
||||
public function testGFSBox256()
|
||||
{
|
||||
$aes = new AES();
|
||||
$aes = new AES(Base::MODE_CBC);
|
||||
|
||||
$aes->setKey(pack('H*', '00000000000000000000000000000000' . '00000000000000000000000000000000'));
|
||||
$aes->setIV(pack('H*', '00000000000000000000000000000000'));
|
||||
@ -339,33 +342,41 @@ abstract class Unit_Crypt_AES_TestCase extends PhpseclibTestCase
|
||||
|
||||
public function testGetKeyLengthDefault()
|
||||
{
|
||||
$aes = new AES();
|
||||
$aes = new AES(Base::MODE_CBC);
|
||||
$this->assertSame($aes->getKeyLength(), 128);
|
||||
}
|
||||
|
||||
public function testGetKeyLengthWith192BitKey()
|
||||
{
|
||||
$aes = new AES();
|
||||
$aes = new AES(Base::MODE_CBC);
|
||||
$aes->setKey(str_repeat('a', 24));
|
||||
$this->assertSame($aes->getKeyLength(), 192);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \LengthException
|
||||
*/
|
||||
public function testSetKeyLengthWithLargerKey()
|
||||
{
|
||||
$aes = new AES();
|
||||
$aes = new AES(Base::MODE_CBC);
|
||||
$aes->setKeyLength(128);
|
||||
$aes->setKey(str_repeat('a', 24));
|
||||
$aes->setIV(str_repeat("\0", 16));
|
||||
$this->assertSame($aes->getKeyLength(), 128);
|
||||
$ciphertext = bin2hex($aes->encrypt('a'));
|
||||
$this->assertSame($ciphertext, '82b7b068dfc60ed2a46893b69fecd6c2');
|
||||
$this->assertSame($aes->getKeyLength(), 128);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \LengthException
|
||||
*/
|
||||
public function testSetKeyLengthWithSmallerKey()
|
||||
{
|
||||
$aes = new AES();
|
||||
$aes = new AES(Base::MODE_CBC);
|
||||
$aes->setKeyLength(256);
|
||||
$aes->setKey(str_repeat('a', 16));
|
||||
$aes->setIV(str_repeat("\0", 16));
|
||||
$this->assertSame($aes->getKeyLength(), 256);
|
||||
$ciphertext = bin2hex($aes->encrypt('a'));
|
||||
$this->assertSame($ciphertext, 'fd4250c0d234aa7e1aa592820aa8406b');
|
||||
@ -377,7 +388,7 @@ abstract class Unit_Crypt_AES_TestCase extends PhpseclibTestCase
|
||||
*/
|
||||
public function testContinuousBuffer()
|
||||
{
|
||||
$aes = new AES();
|
||||
$aes = new AES(AES::MODE_CBC);
|
||||
$aes->disablePadding();
|
||||
$aes->enableContinuousBuffer();
|
||||
$aes->setIV(pack('H*', '0457bdb4a6712986688349a29eb82535'));
|
||||
|
@ -73,8 +73,9 @@ class Unit_Crypt_BlowfishTest extends PhpseclibTestCase
|
||||
*/
|
||||
public function testVectors($engine, $engineName, $key, $plaintext, $expected)
|
||||
{
|
||||
$bf = new Blowfish();
|
||||
$bf = new Blowfish(Blowfish::MODE_CBC);
|
||||
$bf->setKey($key);
|
||||
$bf->setIV(str_repeat("\0", $bf->getBlockLength() >> 3));
|
||||
if (!$bf->isValidEngine($engine)) {
|
||||
self::markTestSkipped('Unable to initialize ' . $engineName . ' engine');
|
||||
}
|
||||
|
@ -1,78 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Andreas Fischer <bantu@phpbb.com>
|
||||
* @copyright MMXIII Andreas Fischer
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
*/
|
||||
|
||||
use phpseclib\Crypt\Base;
|
||||
use phpseclib\Crypt\DES;
|
||||
|
||||
// the AES tests establish the correctness of the modes of operation. this test is inteded to establish the consistency of
|
||||
// key and iv padding between the multiple engines
|
||||
class Unit_Crypt_DESTest extends PhpseclibTestCase
|
||||
{
|
||||
public function testEncryptPadding()
|
||||
{
|
||||
$des = new DES(Base::MODE_CBC);
|
||||
$des->setKey('d');
|
||||
$des->setIV('d');
|
||||
|
||||
$des->setPreferredEngine(Base::ENGINE_INTERNAL);
|
||||
|
||||
$result = pack('H*', '3e7613642049af1e');
|
||||
|
||||
$internal = $des->encrypt('d');
|
||||
$this->assertEquals($result, $internal, 'Failed asserting that the internal engine produced the correct result');
|
||||
|
||||
$des->setPreferredEngine(Base::ENGINE_MCRYPT);
|
||||
if ($des->getEngine() == Base::ENGINE_MCRYPT) {
|
||||
$mcrypt = $des->encrypt('d');
|
||||
$this->assertEquals($result, $mcrypt, 'Failed asserting that the mcrypt engine produced the correct result');
|
||||
} else {
|
||||
self::markTestSkipped('Unable to initialize mcrypt engine');
|
||||
}
|
||||
|
||||
$des->setPreferredEngine(Base::ENGINE_OPENSSL);
|
||||
if ($des->getEngine() == Base::ENGINE_OPENSSL) {
|
||||
$openssl = $des->encrypt('d');
|
||||
$this->assertEquals($result, $openssl, 'Failed asserting that the OpenSSL engine produced the correct result');
|
||||
} else {
|
||||
self::markTestSkipped('Unable to initialize OpenSSL engine');
|
||||
}
|
||||
}
|
||||
|
||||
// phpseclib null pads ciphertext's if they're not long enough and you're in ecb / cbc mode. this silent failure mode is consistent
|
||||
// with mcrypt's behavior. maybe throwing an exception would be better but whatever. this test is more intended to establish consistent
|
||||
// behavior between the various engine's
|
||||
public function testDecryptPadding()
|
||||
{
|
||||
$des = new DES(Base::MODE_CBC);
|
||||
$des->disablePadding();
|
||||
// when the key and iv are not specified they should be null padded
|
||||
//$des->setKey();
|
||||
//$des->setIV();
|
||||
|
||||
$des->setPreferredEngine(Base::ENGINE_INTERNAL);
|
||||
$internal = $des->decrypt('d');
|
||||
|
||||
$result = pack('H*', '79b305d1ce555221');
|
||||
$this->assertEquals($result, $internal, 'Failed asserting that the internal engine produced the correct result');
|
||||
|
||||
$des->setPreferredEngine(Base::ENGINE_MCRYPT);
|
||||
if ($des->getEngine() == Base::ENGINE_MCRYPT) {
|
||||
$mcrypt = $des->decrypt('d');
|
||||
$this->assertEquals($result, $mcrypt, 'Failed asserting that the mcrypt engine produced the correct result');
|
||||
} else {
|
||||
self::markTestSkipped('Unable to initialize mcrypt engine');
|
||||
}
|
||||
|
||||
$des->setPreferredEngine(Base::ENGINE_OPENSSL);
|
||||
if ($des->getEngine() == Base::ENGINE_OPENSSL) {
|
||||
$openssl = $des->decrypt('d');
|
||||
$this->assertEquals($result, $openssl, 'Failed asserting that the OpenSSL engine produced the correct result');
|
||||
} else {
|
||||
self::markTestSkipped('Unable to initialize OpenSSL engine');
|
||||
}
|
||||
}
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Andreas Fischer <bantu@phpbb.com>
|
||||
* @copyright 2012 Andreas Fischer
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
*/
|
||||
|
||||
use phpseclib\Crypt\Hash;
|
||||
|
||||
class Unit_Crypt_Hash_MD5Test extends Unit_Crypt_Hash_TestCase
|
||||
{
|
||||
public function getInstance()
|
||||
{
|
||||
return new Hash('md5');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider hashData()
|
||||
*/
|
||||
public function testHash($message, $result)
|
||||
{
|
||||
$this->assertHashesTo($this->getInstance(), $message, $result);
|
||||
}
|
||||
|
||||
public static function hashData()
|
||||
{
|
||||
return array(
|
||||
array('', 'd41d8cd98f00b204e9800998ecf8427e'),
|
||||
array('The quick brown fox jumps over the lazy dog', '9e107d9d372bb6826bd81d3542a419d6'),
|
||||
array('The quick brown fox jumps over the lazy dog.', 'e4d909c290d0fb1ca068ffaddf22cbd0'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider hmacData()
|
||||
*/
|
||||
public function testHMAC($key, $message, $result)
|
||||
{
|
||||
$this->assertHMACsTo($this->getInstance(), $key, $message, $result);
|
||||
}
|
||||
|
||||
public static function hmacData()
|
||||
{
|
||||
return array(
|
||||
array('', '', '74e6f7298a9c2d168935f58c001bad88'),
|
||||
array('key', 'The quick brown fox jumps over the lazy dog', '80070713463e7749b90c2dc24911e275'),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Andreas Fischer <bantu@phpbb.com>
|
||||
* @copyright 2014 Andreas Fischer
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
*/
|
||||
|
||||
use phpseclib\Crypt\Hash;
|
||||
|
||||
class Unit_Crypt_Hash_SHA256Test extends Unit_Crypt_Hash_TestCase
|
||||
{
|
||||
public function getInstance()
|
||||
{
|
||||
return new Hash('sha256');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider hashData()
|
||||
*/
|
||||
public function testHash($message, $result)
|
||||
{
|
||||
$this->assertHashesTo($this->getInstance(), $message, $result);
|
||||
}
|
||||
|
||||
public static function hashData()
|
||||
{
|
||||
return array(
|
||||
array(
|
||||
'',
|
||||
'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
|
||||
),
|
||||
array(
|
||||
'The quick brown fox jumps over the lazy dog',
|
||||
'd7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592',
|
||||
),
|
||||
array(
|
||||
'The quick brown fox jumps over the lazy dog.',
|
||||
'ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider hmacData()
|
||||
*/
|
||||
public function testHMAC($key, $message, $result)
|
||||
{
|
||||
$this->assertHMACsTo($this->getInstance(), $key, $message, $result);
|
||||
}
|
||||
|
||||
public static function hmacData()
|
||||
{
|
||||
return array(
|
||||
// RFC 4231
|
||||
// Test Case 1
|
||||
array(
|
||||
pack('H*', '0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b'),
|
||||
pack('H*', '4869205468657265'),
|
||||
'b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7',
|
||||
),
|
||||
// Test Case 2
|
||||
array(
|
||||
pack('H*', '4a656665'),
|
||||
pack('H*', '7768617420646f2079612077616e7420666f72206e6f7468696e673f'),
|
||||
'5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843',
|
||||
),
|
||||
// Test Case 3
|
||||
array(
|
||||
pack('H*', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),
|
||||
pack('H*', 'dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd'),
|
||||
'773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe',
|
||||
),
|
||||
// Test Case 4
|
||||
array(
|
||||
pack('H*', '0102030405060708090a0b0c0d0e0f10111213141516171819'),
|
||||
pack('H*', 'cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd'),
|
||||
'82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Andreas Fischer <bantu@phpbb.com>
|
||||
* @copyright 2014 Andreas Fischer
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
*/
|
||||
|
||||
use phpseclib\Crypt\Hash;
|
||||
|
||||
class Unit_Crypt_Hash_SHA256_96Test extends Unit_Crypt_Hash_SHA256Test
|
||||
{
|
||||
public function getInstance()
|
||||
{
|
||||
return new Hash('sha256-96');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider hashData()
|
||||
*/
|
||||
public function testHash($message, $longResult)
|
||||
{
|
||||
parent::testHash($message, substr($longResult, 0, 24));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider hmacData()
|
||||
*/
|
||||
public function testHMAC($key, $message, $longResult)
|
||||
{
|
||||
parent::testHMAC($key, $message, substr($longResult, 0, 24));
|
||||
}
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Andreas Fischer <bantu@phpbb.com>
|
||||
* @copyright 2014 Andreas Fischer
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
*/
|
||||
|
||||
use phpseclib\Crypt\Hash;
|
||||
|
||||
class Unit_Crypt_Hash_SHA512Test extends Unit_Crypt_Hash_TestCase
|
||||
{
|
||||
public function getInstance()
|
||||
{
|
||||
return new Hash('sha512');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider hashData()
|
||||
*/
|
||||
public function testHash($message, $result)
|
||||
{
|
||||
$this->assertHashesTo($this->getInstance(), $message, $result);
|
||||
}
|
||||
|
||||
public static function hashData()
|
||||
{
|
||||
return array(
|
||||
array(
|
||||
'',
|
||||
'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e'
|
||||
),
|
||||
array(
|
||||
'The quick brown fox jumps over the lazy dog',
|
||||
'07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6',
|
||||
),
|
||||
array(
|
||||
'The quick brown fox jumps over the lazy dog.',
|
||||
'91ea1245f20d46ae9a037a989f54f1f790f0a47607eeb8a14d12890cea77a1bbc6c7ed9cf205e67b7f2b8fd4c7dfd3a7a8617e45f3c463d481c7e586c39ac1ed',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider hmacData()
|
||||
*/
|
||||
public function testHMAC($key, $message, $result)
|
||||
{
|
||||
$this->assertHMACsTo($this->getInstance(), $key, $message, $result);
|
||||
}
|
||||
|
||||
public static function hmacData()
|
||||
{
|
||||
return array(
|
||||
// RFC 4231
|
||||
// Test Case 1
|
||||
array(
|
||||
pack('H*', '0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b'),
|
||||
pack('H*', '4869205468657265'),
|
||||
'87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854',
|
||||
),
|
||||
// Test Case 2
|
||||
array(
|
||||
pack('H*', '4a656665'),
|
||||
pack('H*', '7768617420646f2079612077616e7420666f72206e6f7468696e673f'),
|
||||
'164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737',
|
||||
),
|
||||
// Test Case 3
|
||||
array(
|
||||
pack('H*', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),
|
||||
pack('H*', 'dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd'),
|
||||
'fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33b2279d39bf3e848279a722c806b485a47e67c807b946a337bee8942674278859e13292fb',
|
||||
),
|
||||
// Test Case 4
|
||||
array(
|
||||
pack('H*', '0102030405060708090a0b0c0d0e0f10111213141516171819'),
|
||||
pack('H*', 'cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd'),
|
||||
'b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050361ee3dba91ca5c11aa25eb4d679275cc5788063a5f19741120c4f2de2adebeb10a298dd',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Andreas Fischer <bantu@phpbb.com>
|
||||
* @copyright 2014 Andreas Fischer
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
*/
|
||||
|
||||
use phpseclib\Crypt\Hash;
|
||||
|
||||
class Unit_Crypt_Hash_SHA512_96Test extends Unit_Crypt_Hash_SHA512Test
|
||||
{
|
||||
public function getInstance()
|
||||
{
|
||||
return new Hash('sha512-96');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider hashData()
|
||||
*/
|
||||
public function testHash($message, $longResult)
|
||||
{
|
||||
parent::testHash($message, substr($longResult, 0, 24));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider hmacData()
|
||||
*/
|
||||
public function testHMAC($key, $message, $longResult)
|
||||
{
|
||||
parent::testHMAC($key, $message, substr($longResult, 0, 24));
|
||||
}
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Andreas Fischer <bantu@phpbb.com>
|
||||
* @copyright 2012 Andreas Fischer
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
*/
|
||||
|
||||
use phpseclib\Crypt\Hash;
|
||||
|
||||
abstract class Unit_Crypt_Hash_TestCase extends PhpseclibTestCase
|
||||
{
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
if (!defined('CRYPT_HASH_MODE')) {
|
||||
define('CRYPT_HASH_MODE', Hash::MODE_INTERNAL);
|
||||
}
|
||||
}
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
if (defined('CRYPT_HASH_MODE') && CRYPT_HASH_MODE !== Hash::MODE_INTERNAL) {
|
||||
$this->markTestSkipped(
|
||||
'Skipping test because CRYPT_HASH_MODE is not defined as \phpseclib\Crypt\Hash::MODE_INTERNAL.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected function assertHashesTo(Hash $hash, $message, $expected)
|
||||
{
|
||||
$this->assertEquals(
|
||||
strtolower($expected),
|
||||
bin2hex($hash->hash($message)),
|
||||
sprintf("Failed asserting that '%s' hashes to '%s'.", $message, $expected)
|
||||
);
|
||||
}
|
||||
|
||||
protected function assertHMACsTo(Hash $hash, $key, $message, $expected)
|
||||
{
|
||||
$hash->setKey($key);
|
||||
|
||||
$this->assertEquals(
|
||||
strtolower($expected),
|
||||
bin2hex($hash->hash($message)),
|
||||
sprintf(
|
||||
"Failed asserting that '%s' HMACs to '%s' with key '%s'.",
|
||||
$message,
|
||||
$expected,
|
||||
$key
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
423
tests/Unit/Crypt/HashTest.php
Normal file
423
tests/Unit/Crypt/HashTest.php
Normal file
@ -0,0 +1,423 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Andreas Fischer <bantu@phpbb.com>
|
||||
* @copyright 2012 Andreas Fischer
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
*/
|
||||
|
||||
use phpseclib\Crypt\Hash;
|
||||
|
||||
class Unit_Crypt_HashTest extends PhpseclibTestCase
|
||||
{
|
||||
protected function assertHashesTo($hash, $message, $expected)
|
||||
{
|
||||
$hash = new Hash($hash);
|
||||
|
||||
$this->assertSame(
|
||||
strtolower($expected),
|
||||
bin2hex($hash->hash($message)),
|
||||
sprintf("Failed asserting that '%s' hashes to '%s'.", $message, $expected)
|
||||
);
|
||||
}
|
||||
|
||||
protected function assertHMACsTo($hash, $key, $message, $expected)
|
||||
{
|
||||
$hash = new Hash($hash);
|
||||
$hash->setKey($key);
|
||||
|
||||
$this->assertSame(
|
||||
strtolower($expected),
|
||||
bin2hex($hash->hash($message)),
|
||||
sprintf(
|
||||
"Failed asserting that '%s' HMACs to '%s' with key '%s'.",
|
||||
$message,
|
||||
$expected,
|
||||
$key
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public static function hashData()
|
||||
{
|
||||
return array(
|
||||
array('md5', '', 'd41d8cd98f00b204e9800998ecf8427e'),
|
||||
array('md5', 'The quick brown fox jumps over the lazy dog', '9e107d9d372bb6826bd81d3542a419d6'),
|
||||
array('md5', 'The quick brown fox jumps over the lazy dog.', 'e4d909c290d0fb1ca068ffaddf22cbd0'),
|
||||
array('sha1', 'The quick brown fox jumps over the lazy dog', '2fd4e1c67a2d28fced849ee1bb76e7391b93eb12'),
|
||||
array('sha1', 'The quick brown fox jumps over the lazy dog.', '408d94384216f890ff7a0c3528e8bed1e0b01621'),
|
||||
array(
|
||||
'sha256',
|
||||
'',
|
||||
'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
|
||||
),
|
||||
array(
|
||||
'sha256',
|
||||
'The quick brown fox jumps over the lazy dog',
|
||||
'd7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592',
|
||||
),
|
||||
array(
|
||||
'sha256',
|
||||
'The quick brown fox jumps over the lazy dog.',
|
||||
'ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c',
|
||||
),
|
||||
array(
|
||||
'sha384',
|
||||
'',
|
||||
'38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b'
|
||||
),
|
||||
array(
|
||||
'sha384',
|
||||
'The quick brown fox jumps over the lazy dog',
|
||||
'ca737f1014a48f4c0b6dd43cb177b0afd9e5169367544c494011e3317dbf9a509cb1e5dc1e85a941bbee3d7f2afbc9b1',
|
||||
),
|
||||
array(
|
||||
'sha512',
|
||||
'',
|
||||
'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e'
|
||||
),
|
||||
array(
|
||||
'sha512',
|
||||
'The quick brown fox jumps over the lazy dog',
|
||||
'07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6',
|
||||
),
|
||||
array(
|
||||
'sha512',
|
||||
'The quick brown fox jumps over the lazy dog.',
|
||||
'91ea1245f20d46ae9a037a989f54f1f790f0a47607eeb8a14d12890cea77a1bbc6c7ed9cf205e67b7f2b8fd4c7dfd3a7a8617e45f3c463d481c7e586c39ac1ed',
|
||||
),
|
||||
array(
|
||||
'whirlpool',
|
||||
'The quick brown fox jumps over the lazy dog.',
|
||||
'87a7ff096082e3ffeb86db10feb91c5af36c2c71bc426fe310ce662e0338223e217def0eab0b02b80eecf875657802bc5965e48f5c0a05467756f0d3f396faba'
|
||||
),
|
||||
array(
|
||||
'whirlpool',
|
||||
'The quick brown fox jumps over the lazy dog.',
|
||||
'87a7ff096082e3ffeb86db10feb91c5af36c2c71bc426fe310ce662e0338223e217def0eab0b02b80eecf875657802bc5965e48f5c0a05467756f0d3f396faba'
|
||||
),
|
||||
array(
|
||||
'whirlpool',
|
||||
'The quick brown fox jumps over the lazy dog.',
|
||||
'87a7ff096082e3ffeb86db10feb91c5af36c2c71bc426fe310ce662e0338223e217def0eab0b02b80eecf875657802bc5965e48f5c0a05467756f0d3f396faba'
|
||||
),
|
||||
// from http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA512_224.pdf
|
||||
array(
|
||||
'sha512/224',
|
||||
'abc',
|
||||
'4634270f707b6a54daae7530460842e20e37ed265ceee9a43e8924aa'
|
||||
),
|
||||
array(
|
||||
'sha512/224',
|
||||
'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu',
|
||||
'23fec5bb94d60b23308192640b0c453335d664734fe40e7268674af9'
|
||||
),
|
||||
// from http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA512_256.pdf
|
||||
array(
|
||||
'sha512/256',
|
||||
'abc',
|
||||
'53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23'
|
||||
),
|
||||
array(
|
||||
'sha512/256',
|
||||
'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu',
|
||||
'3928e184fb8690f840da3988121d31be65cb9d3ef83ee6146feac861e19b563a'
|
||||
),
|
||||
// from http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA224.pdf
|
||||
array(
|
||||
'sha224',
|
||||
'abc',
|
||||
'23097D223405D8228642A477BDA255B32AADBCE4BDA0B3F7E36C9DA7'
|
||||
),
|
||||
array(
|
||||
'sha224',
|
||||
'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq',
|
||||
'75388B16512776CC5DBA5DA1FD890150B0C6455CB4F58B1952522525'
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider hmacData()
|
||||
*/
|
||||
public function testHMAC($hash, $key, $message, $result)
|
||||
{
|
||||
$this->assertHMACsTo($hash, $key, $message, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider hmacData()
|
||||
*/
|
||||
public function testHMAC96($hash, $key, $message, $result)
|
||||
{
|
||||
$this->assertHMACsTo($hash . '-96', $key, $message, substr($result, 0, 24));
|
||||
}
|
||||
|
||||
public static function hmacData()
|
||||
{
|
||||
return array(
|
||||
array('md5', '', '', '74e6f7298a9c2d168935f58c001bad88'),
|
||||
array('md5', 'key', 'The quick brown fox jumps over the lazy dog', '80070713463e7749b90c2dc24911e275'),
|
||||
|
||||
array(
|
||||
'whirlpool',
|
||||
'abcd',
|
||||
'The quick brown fox jumps over the lazy dog',
|
||||
'e71aabb2588d789292fa6fef00b35cc269ec3ea912b1c1cd7127daf95f004a5df5392ee563d322bac7e19d9eab161932fe9c257d63e0d09eca0d91ab4010125e',
|
||||
),
|
||||
|
||||
// from https://tools.ietf.org/rfc/rfc4231.txt
|
||||
// test case 1
|
||||
array(
|
||||
'sha224',
|
||||
str_repeat("\x0b", 20),
|
||||
'Hi There',
|
||||
'896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22',
|
||||
),
|
||||
// test case 2
|
||||
array(
|
||||
'sha224',
|
||||
'Jefe',
|
||||
'what do ya want for nothing?',
|
||||
'a30e01098bc6dbbf45690f3a7e9e6d0f8bbea2a39e6148008fd05e44',
|
||||
),
|
||||
// test case 3
|
||||
array(
|
||||
'sha224',
|
||||
pack('H*', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),
|
||||
pack('H*', 'dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd'),
|
||||
'7fb3cb3588c6c1f6ffa9694d7d6ad2649365b0c1f65d69d1ec8333ea',
|
||||
),
|
||||
// test case 4
|
||||
array(
|
||||
'sha224',
|
||||
pack('H*', '0102030405060708090a0b0c0d0e0f10111213141516171819'),
|
||||
pack('H*', 'cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd'),
|
||||
'6c11506874013cac6a2abc1bb382627cec6a90d86efc012de7afec5a',
|
||||
),
|
||||
// skip test case 5; truncation is only supported to 96 bits (eg. sha1-96) and that's already unit tested
|
||||
// test case 6
|
||||
array(
|
||||
'sha224',
|
||||
pack('H*', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),
|
||||
'Test Using Larger Than Block-Size Key - Hash Key First',
|
||||
'95e9a0db962095adaebe9b2d6f0dbce2d499f112f2d2b7273fa6870e',
|
||||
),
|
||||
// test case 7
|
||||
array(
|
||||
'sha224',
|
||||
pack('H*', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),
|
||||
'This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.',
|
||||
'3a854166ac5d9f023f54d517d0b39dbd946770db9c2b95c9f6f565d1'
|
||||
),
|
||||
|
||||
// test case 1
|
||||
array(
|
||||
'sha256',
|
||||
str_repeat("\x0b", 20),
|
||||
'Hi There',
|
||||
'b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7',
|
||||
),
|
||||
// test case 2
|
||||
array(
|
||||
'sha256',
|
||||
'Jefe',
|
||||
'what do ya want for nothing?',
|
||||
'5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843',
|
||||
),
|
||||
// test case 3
|
||||
array(
|
||||
'sha256',
|
||||
pack('H*', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),
|
||||
pack('H*', 'dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd'),
|
||||
'773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe',
|
||||
),
|
||||
// test case 4
|
||||
array(
|
||||
'sha256',
|
||||
pack('H*', '0102030405060708090a0b0c0d0e0f10111213141516171819'),
|
||||
pack('H*', 'cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd'),
|
||||
'82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b',
|
||||
),
|
||||
// skip test case 5; truncation is only supported to 96 bits (eg. sha1-96) and that's already unit tested
|
||||
// test case 6
|
||||
array(
|
||||
'sha256',
|
||||
pack('H*', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),
|
||||
'Test Using Larger Than Block-Size Key - Hash Key First',
|
||||
'60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54',
|
||||
),
|
||||
// test case 7
|
||||
array(
|
||||
'sha256',
|
||||
pack('H*', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),
|
||||
'This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.',
|
||||
'9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2'
|
||||
),
|
||||
|
||||
// test case 1
|
||||
array(
|
||||
'sha384',
|
||||
str_repeat("\x0b", 20),
|
||||
'Hi There',
|
||||
'afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c7cebc59cfaea9ea9076ede7f4af152e8b2fa9cb6',
|
||||
),
|
||||
// test case 2
|
||||
array(
|
||||
'sha384',
|
||||
'Jefe',
|
||||
'what do ya want for nothing?',
|
||||
'af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec3736322445e8e2240ca5e69e2c78b3239ecfab21649',
|
||||
),
|
||||
// test case 3
|
||||
array(
|
||||
'sha384',
|
||||
pack('H*', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),
|
||||
pack('H*', 'dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd'),
|
||||
'88062608d3e6ad8a0aa2ace014c8a86f0aa635d947ac9febe83ef4e55966144b2a5ab39dc13814b94e3ab6e101a34f27',
|
||||
),
|
||||
// test case 4
|
||||
array(
|
||||
'sha384',
|
||||
pack('H*', '0102030405060708090a0b0c0d0e0f10111213141516171819'),
|
||||
pack('H*', 'cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd'),
|
||||
'3e8a69b7783c25851933ab6290af6ca77a9981480850009cc5577c6e1f573b4e6801dd23c4a7d679ccf8a386c674cffb',
|
||||
),
|
||||
// skip test case 5; truncation is only supported to 96 bits (eg. sha1-96) and that's already unit tested
|
||||
// test case 6
|
||||
array(
|
||||
'sha384',
|
||||
pack('H*', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),
|
||||
'Test Using Larger Than Block-Size Key - Hash Key First',
|
||||
'4ece084485813e9088d2c63a041bc5b44f9ef1012a2b588f3cd11f05033ac4c60c2ef6ab4030fe8296248df163f44952',
|
||||
),
|
||||
// test case 7
|
||||
array(
|
||||
'sha384',
|
||||
pack('H*', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),
|
||||
'This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.',
|
||||
'6617178e941f020d351e2f254e8fd32c602420feb0b8fb9adccebb82461e99c5a678cc31e799176d3860e6110c46523e'
|
||||
),
|
||||
|
||||
// test case 1
|
||||
array(
|
||||
'sha512',
|
||||
str_repeat("\x0b", 20),
|
||||
'Hi There',
|
||||
'87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854',
|
||||
),
|
||||
// test case 2
|
||||
array(
|
||||
'sha512',
|
||||
'Jefe',
|
||||
'what do ya want for nothing?',
|
||||
'164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737',
|
||||
),
|
||||
// test case 3
|
||||
array(
|
||||
'sha512',
|
||||
pack('H*', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),
|
||||
pack('H*', 'dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd'),
|
||||
'fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33b2279d39bf3e848279a722c806b485a47e67c807b946a337bee8942674278859e13292fb',
|
||||
),
|
||||
// test case 4
|
||||
array(
|
||||
'sha512',
|
||||
pack('H*', '0102030405060708090a0b0c0d0e0f10111213141516171819'),
|
||||
pack('H*', 'cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd'),
|
||||
'b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050361ee3dba91ca5c11aa25eb4d679275cc5788063a5f19741120c4f2de2adebeb10a298dd',
|
||||
),
|
||||
// skip test case 5; truncation is only supported to 96 bits (eg. sha1-96) and that's already unit tested
|
||||
// test case 6
|
||||
array(
|
||||
'sha512',
|
||||
pack('H*', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),
|
||||
'Test Using Larger Than Block-Size Key - Hash Key First',
|
||||
'80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b013783f8f3526b56d037e05f2598bd0fd2215d6a1e5295e64f73f63f0aec8b915a985d786598',
|
||||
),
|
||||
// test case 7
|
||||
array(
|
||||
'sha512',
|
||||
pack('H*', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),
|
||||
'This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.',
|
||||
'e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58'
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider hashData()
|
||||
*/
|
||||
public function testHash($hash, $message, $result)
|
||||
{
|
||||
$this->assertHashesTo($hash, $message, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider hashData()
|
||||
*/
|
||||
public function testHash96($hash, $message, $result)
|
||||
{
|
||||
$this->assertHashesTo($hash . '-96', $message, substr($result, 0, 24));
|
||||
}
|
||||
|
||||
public function testConstructorDefault()
|
||||
{
|
||||
$hash = new Hash();
|
||||
$this->assertSame($hash->getHash(), 'sha256');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \phpseclib\Exception\UnsupportedAlgorithmException
|
||||
*/
|
||||
public function testConstructorArgumentInvalid()
|
||||
{
|
||||
new Hash('abcdefghijklmnopqrst');
|
||||
}
|
||||
|
||||
public function testConstructorArgumentValid()
|
||||
{
|
||||
$hash = new Hash('whirlpool');
|
||||
$this->assertSame($hash->getHash(), 'whirlpool');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \phpseclib\Exception\UnsupportedAlgorithmException
|
||||
*/
|
||||
public function testSetHashInvalid()
|
||||
{
|
||||
$hash = new Hash('md5');
|
||||
$hash->setHash('abcdefghijklmnopqrst-96');
|
||||
}
|
||||
|
||||
public function testSetHashValid()
|
||||
{
|
||||
$hash = new Hash('md5');
|
||||
$this->assertSame($hash->getHash(), 'md5');
|
||||
$hash->setHash('sha1');
|
||||
$this->assertSame($hash->getHash(), 'sha1');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider lengths
|
||||
*/
|
||||
public function testGetLengthKnown($algorithm, $length)
|
||||
{
|
||||
$hash = new Hash($algorithm);
|
||||
$this->assertSame($hash->getLength(), $length);
|
||||
}
|
||||
|
||||
public function lengths()
|
||||
{
|
||||
return array(
|
||||
// known
|
||||
array('md5-96', 12),
|
||||
array('md5', 16),
|
||||
array('sha1', 20),
|
||||
array('sha256', 32),
|
||||
array('sha384', 48),
|
||||
array('sha512', 64),
|
||||
// unknown
|
||||
array('whirlpool', 64),
|
||||
);
|
||||
}
|
||||
}
|
@ -110,10 +110,11 @@ class Unit_Crypt_RC2Test extends PhpseclibTestCase
|
||||
*/
|
||||
public function testVectors($engine, $engineName, $key, $keyLen, $plaintext, $ciphertext)
|
||||
{
|
||||
$rc2 = new RC2();
|
||||
$rc2 = new RC2(RC2::MODE_CBC);
|
||||
$rc2->disablePadding();
|
||||
$rc2->setKeyLength($keyLen);
|
||||
$rc2->setKey(pack('H*', $key)); // could also do $rc2->setKey(pack('H*', $key), $keyLen)
|
||||
$rc2->setIV(str_repeat("\0", $rc2->getBlockLength() >> 3));
|
||||
if (!$rc2->isValidEngine($engine)) {
|
||||
self::markTestSkipped('Unable to initialize ' . $engineName . ' engine');
|
||||
}
|
||||
|
34
tests/Unit/Crypt/RSA/CreateKeyTest.php
Normal file
34
tests/Unit/Crypt/RSA/CreateKeyTest.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2015 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
*/
|
||||
|
||||
use phpseclib\Crypt\RSA;
|
||||
|
||||
class Unit_Crypt_RSA_CreateKeyTest extends PhpseclibTestCase
|
||||
{
|
||||
public function testCreateKey()
|
||||
{
|
||||
extract(RSA::createKey(768));
|
||||
$this->assertInstanceOf('\phpseclib\Crypt\RSA', $privatekey);
|
||||
$this->assertInstanceOf('\phpseclib\Crypt\RSA', $publickey);
|
||||
$this->assertNotEmpty("$privatekey");
|
||||
$this->assertNotEmpty("$publickey");
|
||||
|
||||
return array($publickey, $privatekey);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateKey
|
||||
*/
|
||||
public function testEncryptDecrypt($args)
|
||||
{
|
||||
list($publickey, $privatekey) = $args;
|
||||
$ciphertext = $publickey->encrypt('zzz');
|
||||
$this->assertInternalType('string', $ciphertext);
|
||||
$plaintext = $privatekey->decrypt($ciphertext);
|
||||
$this->assertSame($plaintext, 'zzz');
|
||||
}
|
||||
}
|
@ -6,6 +6,9 @@
|
||||
*/
|
||||
|
||||
use phpseclib\Crypt\RSA;
|
||||
use phpseclib\Crypt\RSA\PKCS1;
|
||||
use phpseclib\Crypt\RSA\PuTTY;
|
||||
use phpseclib\Math\BigInteger;
|
||||
|
||||
class Unit_Crypt_RSA_LoadKeyTest extends PhpseclibTestCase
|
||||
{
|
||||
@ -15,7 +18,7 @@ class Unit_Crypt_RSA_LoadKeyTest extends PhpseclibTestCase
|
||||
|
||||
$key = 'zzzzzzzzzzzzzz';
|
||||
|
||||
$this->assertFalse($rsa->loadKey($key));
|
||||
$this->assertFalse($rsa->load($key));
|
||||
}
|
||||
|
||||
public function testPKCS1Key()
|
||||
@ -36,7 +39,7 @@ U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
|
||||
37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=
|
||||
-----END RSA PRIVATE KEY-----';
|
||||
|
||||
$this->assertTrue($rsa->loadKey($key));
|
||||
$this->assertTrue($rsa->load($key));
|
||||
$this->assertInternalType('string', $rsa->getPrivateKey());
|
||||
}
|
||||
|
||||
@ -59,7 +62,7 @@ U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
|
||||
-----END RSA PRIVATE KEY-----';
|
||||
$key = str_replace(array("\r", "\n", "\r\n"), ' ', $key);
|
||||
|
||||
$this->assertTrue($rsa->loadKey($key));
|
||||
$this->assertTrue($rsa->load($key));
|
||||
$this->assertInternalType('string', $rsa->getPrivateKey());
|
||||
}
|
||||
|
||||
@ -79,7 +82,7 @@ X6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl
|
||||
U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
|
||||
37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=';
|
||||
|
||||
$this->assertTrue($rsa->loadKey($key));
|
||||
$this->assertTrue($rsa->load($key));
|
||||
$this->assertInternalType('string', $rsa->getPrivateKey());
|
||||
}
|
||||
|
||||
@ -99,7 +102,7 @@ U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
|
||||
'U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ' .
|
||||
'37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=';
|
||||
|
||||
$this->assertTrue($rsa->loadKey($key));
|
||||
$this->assertTrue($rsa->load($key));
|
||||
$this->assertInternalType('string', $rsa->getPrivateKey());
|
||||
}
|
||||
|
||||
@ -120,7 +123,7 @@ U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
|
||||
'37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=';
|
||||
$key = base64_decode($key);
|
||||
|
||||
$this->assertTrue($rsa->loadKey($key));
|
||||
$this->assertTrue($rsa->load($key));
|
||||
$this->assertInternalType('string', $rsa->getPrivateKey());
|
||||
}
|
||||
|
||||
@ -159,7 +162,7 @@ GF/qoZyC1mbqdtyyeWgHtVbJVUORmpbNnXOII9duEqBUNDiO9VSZNn/8h/VsYeAB
|
||||
xryZaRDVmtMuf/OZBQ==
|
||||
-----END ENCRYPTED PRIVATE KEY-----';
|
||||
|
||||
$this->assertTrue($rsa->loadKey($key));
|
||||
$this->assertTrue($rsa->load($key));
|
||||
$this->assertInternalType('string', $rsa->getPrivateKey());
|
||||
}
|
||||
|
||||
@ -182,12 +185,12 @@ U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
|
||||
-----END RSA PRIVATE KEY-----';
|
||||
$rsa->setPassword('password');
|
||||
|
||||
$this->assertTrue($rsa->loadKey($key));
|
||||
$this->assertTrue($rsa->load($key));
|
||||
|
||||
$key = $rsa->getPrivateKey(RSA::PRIVATE_FORMAT_PKCS8);
|
||||
$key = $rsa->getPrivateKey('PKCS8');
|
||||
$this->assertInternalType('string', $key);
|
||||
|
||||
$this->assertTrue($rsa->loadKey($key));
|
||||
$this->assertTrue($rsa->load($key));
|
||||
}
|
||||
|
||||
public function testPubKey1()
|
||||
@ -203,7 +206,7 @@ gPiUWOPatVkt7+Bs3h5Ramxh7XjBOXeulmCpGSynXNcpZ/06+vofGi/2MlpQZNhH
|
||||
Ao8eayMp6FcvNucIpUndo1X8dKMv3Y26ZQIDAQAB
|
||||
-----END RSA PUBLIC KEY-----';
|
||||
|
||||
$this->assertTrue($rsa->loadKey($key));
|
||||
$this->assertTrue($rsa->load($key));
|
||||
$this->assertInternalType('string', $rsa->getPublicKey());
|
||||
$this->assertFalse($rsa->getPrivateKey());
|
||||
}
|
||||
@ -222,7 +225,7 @@ lmCpGSynXNcpZ/06+vofGi/2MlpQZNhHAo8eayMp6FcvNucIpUndo1X8dKMv3Y26
|
||||
ZQIDAQAB
|
||||
-----END PUBLIC KEY-----';
|
||||
|
||||
$this->assertTrue($rsa->loadKey($key));
|
||||
$this->assertTrue($rsa->load($key));
|
||||
$this->assertInternalType('string', $rsa->getPublicKey());
|
||||
$this->assertFalse($rsa->getPrivateKey());
|
||||
}
|
||||
@ -236,7 +239,7 @@ ZQIDAQAB
|
||||
'GkVb1/3j+skZ6UtW+5u09lHNsj6tQ51s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZw== ' .
|
||||
'phpseclib-generated-key';
|
||||
|
||||
$this->assertTrue($rsa->loadKey($key));
|
||||
$this->assertTrue($rsa->load($key));
|
||||
$this->assertInternalType('string', $rsa->getPublicKey());
|
||||
$this->assertFalse($rsa->getPrivateKey());
|
||||
}
|
||||
@ -252,7 +255,7 @@ ZQIDAQAB
|
||||
'b6wYtY/q/WtUFr3nK+x0lgOtokhnJfRR/6fnmC1CztPnIT4BWK81VGKWONAxuhMyQ5XChyu6S9'.
|
||||
'mWG5tUlUI/5';
|
||||
|
||||
$this->assertTrue($rsa->loadKey($key));
|
||||
$this->assertTrue($rsa->load($key));
|
||||
$this->assertSame($rsa->getPublicKeyFingerprint('md5'), 'bd:2c:2f:31:b9:ef:b8:f8:ad:fc:40:a6:94:4f:28:82');
|
||||
$this->assertSame($rsa->getPublicKeyFingerprint('sha256'), 'N9sV2uSNZEe8TITODku0pRI27l+Zk0IY0TrRTw3ozwM');
|
||||
}
|
||||
@ -270,7 +273,7 @@ gPiUWOPatVkt7+Bs3h5Ramxh7XjBOXeulmCpGSynXNcpZ/06+vofGi/2MlpQZNhH
|
||||
Ao8eayMp6FcvNucIpUndo1X8dKMv3Y26ZQIDAQAB
|
||||
-----END RSA PUBLIC KEY-----';
|
||||
|
||||
$this->assertTrue($rsa->loadKey($key));
|
||||
$this->assertTrue($rsa->load($key));
|
||||
$this->assertTrue($rsa->setPrivateKey());
|
||||
$this->assertGreaterThanOrEqual(1, strlen("$rsa"));
|
||||
$this->assertFalse($rsa->getPublicKey());
|
||||
@ -290,11 +293,11 @@ Ao8eayMp6FcvNucIpUndo1X8dKMv3Y26ZQIDAQAB
|
||||
<Exponent>AQAB</Exponent>
|
||||
</RSAKeyValue>';
|
||||
|
||||
$rsa->loadKey($key);
|
||||
$rsa->load($key);
|
||||
$rsa->setPublicKey();
|
||||
$newkey = $rsa->getPublicKey(RSA::PUBLIC_FORMAT_XML);
|
||||
$newkey = $rsa->getPublicKey('XML');
|
||||
|
||||
$this->assertSame(preg_replace('#\s#', '', $key), preg_replace('#\s#', '', $newkey));
|
||||
$this->assertSame(strtolower(preg_replace('#\s#', '', $key)), strtolower(preg_replace('#\s#', '', $newkey)));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -311,7 +314,7 @@ JWrQdxx/WNN+ABG426rgYYbeGcIlWLZCw6Bx/1HtN5ef6nVEoiGNChYKIRB4QFOi
|
||||
01smFxps1w8ZIQnD6wIDAQAB
|
||||
-----END PUBLIC KEY-----';
|
||||
|
||||
$rsa->loadKey($key);
|
||||
$rsa->load($key);
|
||||
$rsa->setPublicKey();
|
||||
$newkey = $rsa->getPublicKey();
|
||||
|
||||
@ -342,11 +345,162 @@ qMnD/pkHR/NFcYSYShUJS0cHyryVl7/eCclsQlZTRdnVTtKF9xPGTQC8fK0G7BDN
|
||||
Z2sKniRCcDT1ZP4=
|
||||
-----END PRIVATE KEY-----';
|
||||
|
||||
$result = $rsa->loadKey($key, RSA::PRIVATE_FORMAT_PKCS8);
|
||||
$result = $rsa->load($key, 'PKCS8');
|
||||
|
||||
$this->assertTrue($result);
|
||||
}
|
||||
|
||||
public function testPKCS1EncryptionChange()
|
||||
{
|
||||
$rsa = new RSA();
|
||||
|
||||
$key = 'PuTTY-User-Key-File-2: ssh-rsa
|
||||
Encryption: none
|
||||
Comment: phpseclib-generated-key
|
||||
Public-Lines: 4
|
||||
AAAAB3NzaC1yc2EAAAADAQABAAAAgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4
|
||||
eCZ0FPqri0cb2JZfXJ/DgYSF6vUpwmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RK
|
||||
NUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ51s1SPrCBkedbNf0Tp0GbMJDy
|
||||
R4e9T04ZZw==
|
||||
Private-Lines: 8
|
||||
AAAAgBYo5KOevqhsjfDNEVcmkQF8/vsU6hwS4d7ceFYDLa0PlhIAo4aE8KNtyjAQ
|
||||
LiRkmJ0ZqAWTN5TH0ynryJAInTxMb2AnZuXWKt106C5JC7+S9qSCFThTAxvihEpw
|
||||
BVe5dnPnJ80TFtPm+n/JkdQic2bsVSy+kNNn7y4uef5m0mMRAAAAQQDeAw6fiIQX
|
||||
GukBI4eMZZt4nscy2o12KyYner3VpoeE+Np2q+Z3pvAMd/aNzQ/W9WaI+NRfcxUJ
|
||||
rmfPwIGm63ilAAAAQQDEIvkdBvZtCvgHKitwxab+EQ/YxnNE5XvfIXjWE+xEL2br
|
||||
oquF470c9Mm6jf/2zmn6yobE6UUvQ0O3hKSiyOAbAAAAQBGoiuSoSjafUhV7i1cE
|
||||
Gpb88h5NBYZzWXGZ37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ
|
||||
4p0=
|
||||
Private-MAC: 03e2cb74e1d67652fbad063d2ed0478f31bdf256
|
||||
';
|
||||
$key = preg_replace('#(?<!\r)\n#', "\r\n", $key);
|
||||
$this->assertTrue($rsa->load($key));
|
||||
|
||||
PKCS1::setEncryptionAlgorithm('AES-256-CBC');
|
||||
$rsa->setPassword('demo');
|
||||
|
||||
$encryptedKey = (string) $rsa;
|
||||
|
||||
$this->assertRegExp('#AES-256-CBC#', $encryptedKey);
|
||||
|
||||
$rsa = new RSA();
|
||||
$rsa->setPassword('demo');
|
||||
$this->assertTrue($rsa->load($encryptedKey));
|
||||
$rsa->setPassword();
|
||||
$rsa->setPrivateKeyFormat('PuTTY');
|
||||
$key2 = (string) $rsa;
|
||||
|
||||
$this->assertSame($key, $key2);
|
||||
}
|
||||
|
||||
public function testRawKey()
|
||||
{
|
||||
$rsa = new RSA();
|
||||
|
||||
$key = array(
|
||||
'e' => new BigInteger('10001', 16),
|
||||
'n' => new BigInteger('aa18aba43b50deef38598faf87d2ab634e4571c130a9bca7b878267414faab8b471bd8965f5c9fc3' .
|
||||
'818485eaf529c26246f3055064a8de19c8c338be5496cbaeb059dc0b358143b44a35449eb2641131' .
|
||||
'21a455bd7fde3fac919e94b56fb9bb4f651cdb23ead439d6cd523eb08191e75b35fd13a7419b3090' .
|
||||
'f24787bd4f4e1967', 16)
|
||||
);
|
||||
$this->assertTrue($rsa->load($key));
|
||||
$rsa->setPublicKeyFormat('raw');
|
||||
$this->assertEmpty("$rsa");
|
||||
}
|
||||
|
||||
public function testRawComment()
|
||||
{
|
||||
$key = 'PuTTY-User-Key-File-2: ssh-rsa
|
||||
Encryption: aes256-cbc
|
||||
Comment: phpseclib-generated-key
|
||||
Public-Lines: 4
|
||||
AAAAB3NzaC1yc2EAAAADAQABAAAAgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4
|
||||
eCZ0FPqri0cb2JZfXJ/DgYSF6vUpwmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RK
|
||||
NUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ51s1SPrCBkedbNf0Tp0GbMJDy
|
||||
R4e9T04ZZw==
|
||||
Private-Lines: 8
|
||||
llx04QMegql0/nE5RvcJSrGrodxt6ytuv/JX2caeZBUyQwQc2WBNYagLHyHPM9jI
|
||||
9OUWz59FLhjFXZMDNMoUXxVmjwQpOAaVPYNxxFM9AF6/NXFji64K7huD9n4A+kLn
|
||||
sHwMLWPR5a/tZA0r05DZNz9ULA3mQu7Hz4EQ8ifu3uTPJuTmL51x6RmudYKysb20
|
||||
fM8VzC3ukvzzRh0pujUVTr/yQdmciASVFnZlt4xQy+ZEOVUAOfwjd//AFfXTvk6x
|
||||
7A45rNlU/uicHwLgoY1APvRHCFxw7F+uVW5L4mSX7NNzqBKkZ+1qpQTAfQvIfEIb
|
||||
444+CXsgIyOpqt6VxJH2u6elAtE1wau3YaFR8Alm8m97rFYzRi3oDP5NZYkTCWSV
|
||||
EOpSeghXSs7IilJu8I6/sB1w5dakdeBSFkIynrlFXkO0uUw+QJJWjxY8SypzgIuP
|
||||
DzduF6XsQrCyo6dnIpGQCQ==
|
||||
Private-MAC: 35134b7434bf828b21404099861d455e660e8740';
|
||||
$raw = PuTTY::load($key, 'password');
|
||||
$this->assertArrayHasKey('comment', $raw);
|
||||
$this->assertEquals($raw['comment'], 'phpseclib-generated-key');
|
||||
|
||||
$rsa = new RSA();
|
||||
$rsa->load($raw);
|
||||
$this->assertGreaterThanOrEqual(1, strlen("$rsa"));
|
||||
}
|
||||
|
||||
public function testPrivateMSBlob()
|
||||
{
|
||||
$key = 'BwIAAACkAABSU0EyAAQAAAEAAQAnh6FFs6kYe/gmb9dzqsQKmtjFE9mxNAe9mEU3OwOEEfyI' .
|
||||
'wkAx0/8dwh12fuP4wzNbdZAq4mmqCE6Lo8wTNNIJVNYEhKq5chHg1+hPDgfETFgtEO54JZSg' .
|
||||
'3cBZWEV/Tq3LHEX8CaLvHZxMEfFXbTfliFYMLoJ+YK1mpg9GYcmbrVmMAKSoOgETkkiJJzYm' .
|
||||
'XftO3KOveBtvkAzjHxxSS1yP/Ba10BzeIleH96SbTuQtQRLXwRykdX9uazK+YsiSud9/PyLb' .
|
||||
'gy5TI+o28OHq5P+0y5+a9IaAQ/92UwlrkHUYfhN/xTVlUIxKlTEdUQTIf+iHif8d4ABb3OdY' .
|
||||
'JXZOW6fGeUP10jMyvbnrEoPDsYy9qfNk++0/8UP2NeO1IATszuZYg1nEXOW/5jmUxMCdiFyd' .
|
||||
'p9ES211kpEZ4XcvjGaDlaQ+bLWj05i2m/9aHYcBrfcxxvlMa/9ZvrX4DfPWeydUDDDQ4+ntp' .
|
||||
'T50BunSvmyf7cUk76Bf2sPgLXUQFoufEQ5g1Qo/v1uyhWBJzh6OSUO/DDXN/s8ec/tN05RQQ' .
|
||||
'FZQ0na+v0hOCrV9IuRqtBuj4WAj1I/A1JjwyyP9Y/6yWFPM6EcS/6lyPy30lJPoULh7G29zk' .
|
||||
'n7NVdTEkDtthdDjtX7Qhgd9qWvm5ADlmnvsS9A5m7ToOgQyOxtJoSlLitLbf/09LRycl/cdI' .
|
||||
'zoMOCEdPe3DQcyEKqUPsghAq+DKw3uZpXwHzwTdfqlHSWAnHDggFKV1HZuWc1c4rV4k4b513TqE=';
|
||||
|
||||
$plaintext = 'zzz';
|
||||
|
||||
$privKey = new RSA();
|
||||
$privKey->load($key);
|
||||
|
||||
$this->assertSame($privKey->getLoadedFormat(), 'MSBLOB');
|
||||
|
||||
$this->assertGreaterThanOrEqual(1, strlen("$privKey"));
|
||||
|
||||
$pubKey = new RSA();
|
||||
$pubKey->load($privKey->getPublicKey('msblob'));
|
||||
|
||||
$this->assertGreaterThanOrEqual(1, strlen("$pubKey"));
|
||||
|
||||
$ciphertext = $pubKey->encrypt($plaintext);
|
||||
|
||||
$this->assertSame($privKey->decrypt($ciphertext), $plaintext);
|
||||
}
|
||||
|
||||
public function testNakedOpenSSHKey()
|
||||
{
|
||||
$key = 'AAAAB3NzaC1yc2EAAAABIwAAAIEA/NcGSQFZ0ZgN1EbDusV6LLwLnQjs05ljKcVVP7Z6aKIJUyhUDHE30uJa5XfwPPBsZ3L3Q7S0yycVcuuHjdauugmpn9xx+gyoYs7UiV5G5rvxNcA/Tc+MofGhAMiTmNicorNAs5mv6fRoVbkpIONRXPz6WK0kjx/X04EV42Vm9Qk=';
|
||||
|
||||
$rsa = new RSA();
|
||||
$rsa->load($key);
|
||||
|
||||
$this->assertSame($rsa->getLoadedFormat(), 'OpenSSH');
|
||||
|
||||
$this->assertGreaterThanOrEqual(1, strlen("$rsa"));
|
||||
}
|
||||
|
||||
public function testPuttyPublicKey()
|
||||
{
|
||||
$key = '---- BEGIN SSH2 PUBLIC KEY ----
|
||||
Comment: "rsa-key-20151023"
|
||||
AAAAB3NzaC1yc2EAAAABJQAAAIEAhC/CSqJ+8vgeQ4H7fJru29h/McqAC9zdGzw0
|
||||
9QsifLQ7s5MvXCavhjUPYIfV0KsdLQydNPLJcbKpXmpVD9azo61zLXwsYr8d1eHr
|
||||
C/EwUYl8b0fAwEsEF3myb+ryzgA9ihY08Zs9NZdmt1Maa+I7lQcLX9F/65YdcAch
|
||||
ILaEujU=
|
||||
---- END SSH2 PUBLIC KEY ----';
|
||||
|
||||
$rsa = new RSA();
|
||||
$rsa->load($key);
|
||||
|
||||
$this->assertSame($rsa->getLoadedFormat(), 'PuTTY');
|
||||
|
||||
$this->assertGreaterThanOrEqual(1, strlen("$rsa"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group github960
|
||||
*/
|
||||
@ -373,11 +527,11 @@ Private-MAC: 35134b7434bf828b21404099861d455e660e8740';
|
||||
|
||||
$rsa = new RSA();
|
||||
$rsa->setPrivateKey($key);
|
||||
$rsa->loadKey($key);
|
||||
$rsa->load($key);
|
||||
|
||||
$rsa = new RSA();
|
||||
$rsa->loadKey($key);
|
||||
$rsa->load($key);
|
||||
$rsa->setPrivateKey();
|
||||
$rsa->loadKey($rsa);
|
||||
$rsa->load($rsa);
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
use phpseclib\Crypt\RSA;
|
||||
use phpseclib\Math\BigInteger;
|
||||
|
||||
class Unit_Crypt_RSA_ModeTest extends PhpseclibTestCase
|
||||
{
|
||||
@ -28,20 +29,19 @@ X6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl
|
||||
U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
|
||||
37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=
|
||||
-----END RSA PRIVATE KEY-----';
|
||||
$rsa->loadKey($privatekey);
|
||||
$rsa->loadKey($rsa->getPublicKey());
|
||||
$rsa->load($privatekey);
|
||||
$rsa->load($rsa->getPublicKey());
|
||||
|
||||
$rsa->setEncryptionMode(RSA::ENCRYPTION_NONE);
|
||||
$expected = '105b92f59a87a8ad4da52c128b8c99491790ef5a54770119e0819060032fb9e772ed6772828329567f3d7e9472154c1530f8156ba7fd732f52ca1c06' .
|
||||
'5a3f5ed8a96c442e4662e0464c97f133aed31262170201993085a589565d67cc9e727e0d087e3b225c8965203b271e38a499c92fc0d6502297eca712' .
|
||||
'4d04bd467f6f1e7c';
|
||||
$expected = pack('H*', $expected);
|
||||
$result = $rsa->encrypt($plaintext);
|
||||
$result = $rsa->encrypt($plaintext, RSA::PADDING_NONE);
|
||||
|
||||
$this->assertEquals($result, $expected);
|
||||
|
||||
$rsa->loadKey($privatekey);
|
||||
$this->assertEquals(trim($rsa->decrypt($result), "\0"), $plaintext);
|
||||
$rsa->load($privatekey);
|
||||
$this->assertEquals(trim($rsa->decrypt($result, RSA::PADDING_NONE), "\0"), $plaintext);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -50,7 +50,9 @@ U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
|
||||
public function testPSSSigs()
|
||||
{
|
||||
$rsa = new RSA();
|
||||
$rsa->loadKey('-----BEGIN PUBLIC KEY-----
|
||||
$rsa->setHash('sha1');
|
||||
$rsa->setMGFHash('sha1');
|
||||
$rsa->load('-----BEGIN PUBLIC KEY-----
|
||||
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqGKukO1De7zhZj6+H0qtjTkVx
|
||||
wTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUpwmJG8wVQZKjeGcjDOL5UlsuusFnc
|
||||
CzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ51s1SPrCBkedbNf0T
|
||||
@ -63,4 +65,38 @@ p0GbMJDyR4e9T04ZZwIDAQAB
|
||||
|
||||
$this->assertTrue($rsa->verify('zzzz', $sig));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \OutOfBoundsException
|
||||
*/
|
||||
public function testSmallModulo()
|
||||
{
|
||||
$plaintext = 'x';
|
||||
$n = new BigInteger(base64_decode('272435F22706FA96DE26E980D22DFF67'), 256);
|
||||
$e = new BigInteger(base64_decode('158753FF2AF4D1E5BBAB574D5AE6B54D'), 256);
|
||||
|
||||
$rsa = new RSA();
|
||||
$rsa->load(array('n' => $n, 'e' => $e));
|
||||
$rsa->encrypt($plaintext);
|
||||
}
|
||||
|
||||
public function testPKCS1LooseVerify()
|
||||
{
|
||||
$rsa = new RSA();
|
||||
$rsa->load('-----BEGIN RSA PUBLIC KEY-----
|
||||
MIGJAoGBAMuqkz8ij+ESAaNvgocVGmapjlrIldmhRo4h2NX4e6IXiCLTSxASQtY4
|
||||
iqRnmyxqQSfaan2okTfQ6sP95bl8Qz8lgneW3ClC6RXG/wpJgsx7TXQ2kodlcKBF
|
||||
m4k72G75QXhZ+I40ZG7cjBf1/9egakR0a0X0MpeOrKCzMBLv9+mpAgMBAAE=
|
||||
-----END RSA PUBLIC KEY-----');
|
||||
|
||||
$message = base64_decode('MYIBLjAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0xNDA1MTUxNDM4MzRaMC8GCSqGSIb3DQEJBDEiBCBLzLIBGdOf0L2WRrIY' .
|
||||
'9KTwiHnReBW48S9C7LNRaPp5mDCBwgYLKoZIhvcNAQkQAi8xgbIwga8wgawwgakEIJDB9ZGwihf+TaiwrHQNkNHkqbN8Nuws0e77QNObkvFZMIGEMHCkbjBs' .
|
||||
'MQswCQYDVQQGEwJJVDEYMBYGA1UECgwPQXJ1YmFQRUMgUy5wLkEuMSEwHwYDVQQLDBhDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eUMxIDAeBgNVBAMMF0FydWJh' .
|
||||
'UEVDIFMucC5BLiBORyBDQSAzAhAv4L3QcFssQNLDYN/Vu40R');
|
||||
|
||||
$sig = base64_decode('XDSZWw6IcUj8ICxRJf04HzF8stzoiFAZSR2a0Rw3ziZxTOT0/NVUYJO5+9TaaREXEgxuCLpgmA+6W2SWrrGoxbbNfaI90ZoKeOAws4IX+9RfiWuooibjKcvt' .
|
||||
'GJYVVOCcjvQYxUUNbQ4EjCUonk3h7ECXfCCmWqbeq2LsyXeeYGE=');
|
||||
|
||||
$this->assertTrue($rsa->verify($message, $sig, RSA::PADDING_RELAXED_PKCS1));
|
||||
}
|
||||
}
|
||||
|
@ -104,12 +104,13 @@ class Unit_Crypt_TripleDESTest extends PhpseclibTestCase
|
||||
*/
|
||||
public function testVectors($engine, $engineName, $key, $plaintext, $expected)
|
||||
{
|
||||
$des = new TripleDES();
|
||||
$des = new TripleDES(TripleDES::MODE_CBC);
|
||||
if (!$des->isValidEngine($engine)) {
|
||||
self::markTestSkipped('Unable to initialize ' . $engineName . ' engine');
|
||||
}
|
||||
$des->setPreferredEngine($engine);
|
||||
$des->setKey($key);
|
||||
$des->setIV(str_repeat("\0", $des->getBlockLength() >> 3));
|
||||
$des->disablePadding();
|
||||
$result = $des->encrypt($plaintext);
|
||||
$plaintext = bin2hex($plaintext);
|
||||
@ -155,7 +156,7 @@ class Unit_Crypt_TripleDESTest extends PhpseclibTestCase
|
||||
*/
|
||||
public function testVectorsWithIV($engine, $engineName, $key, $iv, $plaintext, $expected)
|
||||
{
|
||||
$des = new TripleDES();
|
||||
$des = new TripleDES(TripleDES::MODE_CBC);
|
||||
if (!$des->isValidEngine($engine)) {
|
||||
self::markTestSkipped('Unable to initialize ' . $engineName . ' engine');
|
||||
}
|
||||
@ -176,6 +177,7 @@ class Unit_Crypt_TripleDESTest extends PhpseclibTestCase
|
||||
|
||||
$des = new TripleDES(TripleDES::MODE_3CBC);
|
||||
$des->setKey('abcdefghijklmnopqrstuvwx');
|
||||
$des->setIV(str_repeat("\0", $des->getBlockLength() >> 3));
|
||||
|
||||
foreach ($this->engines as $engine => $engineName) {
|
||||
$des->setPreferredEngine($engine);
|
||||
|
@ -19,7 +19,8 @@ class Unit_Crypt_TwofishTest extends PhpseclibTestCase
|
||||
);
|
||||
|
||||
foreach ($engines as $engine => $name) {
|
||||
$tf = new Twofish();
|
||||
$tf = new Twofish(Twofish::MODE_CBC);
|
||||
$tf->setIV(str_repeat("\0", $tf->getBlockLength() >> 3));
|
||||
$tf->disablePadding();
|
||||
|
||||
// tests from https://www.schneier.com/code/ecb_ival.txt
|
||||
|
@ -48,10 +48,9 @@ class Unit_File_X509_SPKACTest extends PhpseclibTestCase
|
||||
{
|
||||
$privKey = new RSA();
|
||||
extract($privKey->createKey());
|
||||
$privKey->loadKey($privatekey);
|
||||
|
||||
$x509 = new X509();
|
||||
$x509->setPrivateKey($privKey);
|
||||
$x509->setPrivateKey($privatekey);
|
||||
$x509->setChallenge('...');
|
||||
|
||||
$spkac = $x509->signSPKAC();
|
||||
|
@ -154,7 +154,7 @@ IOkKcGQRCMha8X2e7GmlpdWC1ycenlbN0nbVeSv3JUMcafC4+Q==
|
||||
public function testSaveNullRSAParam()
|
||||
{
|
||||
$privKey = new RSA();
|
||||
$privKey->loadKey('-----BEGIN RSA PRIVATE KEY-----
|
||||
$privKey->load('-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICXQIBAAKBgQDMswfEpAgnUDWA74zZw5XcPsWh1ly1Vk99tsqwoFDkLF7jvXy1
|
||||
dDLHYfuquvfxCgcp8k/4fQhx4ubR8bbGgEq9B05YRnViK0R0iBB5Ui4IaxWYYhKE
|
||||
8xqAEH2fL+/7nsqqNFKkEN9KeFwc7WbMY49U2adlMrpBdRjk1DqIEW3QTwIDAQAB
|
||||
@ -171,7 +171,7 @@ aBtsWpliLSex/HHhtRW9AkBGcq67zKmEpJ9kXcYLEjJii3flFS+Ct/rNm+Hhm1l7
|
||||
-----END RSA PRIVATE KEY-----');
|
||||
|
||||
$pubKey = new RSA();
|
||||
$pubKey->loadKey($privKey->getPublicKey());
|
||||
$pubKey->load($privKey->getPublicKey());
|
||||
$pubKey->setPublicKey();
|
||||
|
||||
$subject = new X509();
|
||||
|
@ -273,29 +273,13 @@ abstract class Unit_Math_BigInteger_TestCase extends PhpseclibTestCase
|
||||
$min = $this->getInstance(0);
|
||||
$max = $this->getInstance('18446744073709551616');
|
||||
|
||||
$rand1 = $min->random($min, $max);
|
||||
$rand1 = \phpseclib\Math\BigInteger::random($min, $max);
|
||||
// technically $rand1 can equal $min but with the $min and $max we've
|
||||
// chosen it's just not that likely
|
||||
$this->assertTrue($rand1->compare($min) > 0);
|
||||
$this->assertTrue($rand1->compare($max) < 0);
|
||||
}
|
||||
|
||||
public function testRandomOneArgument()
|
||||
{
|
||||
$min = $this->getInstance(0);
|
||||
$max = $this->getInstance('18446744073709551616');
|
||||
|
||||
$rand1 = $min->random($max);
|
||||
$this->assertTrue($rand1->compare($min) > 0);
|
||||
$this->assertTrue($rand1->compare($max) < 0);
|
||||
|
||||
$rand2 = $max->random($min);
|
||||
$this->assertTrue($rand2->compare($min) > 0);
|
||||
$this->assertTrue($rand2->compare($max) < 0);
|
||||
|
||||
$this->assertFalse($rand1->equals($rand2));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group github279
|
||||
*/
|
||||
@ -331,8 +315,8 @@ abstract class Unit_Math_BigInteger_TestCase extends PhpseclibTestCase
|
||||
Code for generation of $alicePrivate and $bobPrivate.
|
||||
$one = $this->getInstance(1);
|
||||
$max = $one->bitwise_leftShift(512)->subtract($one);
|
||||
$alicePrivate = $one->random($one, $max);
|
||||
$bobPrivate = $one->random($one, $max);
|
||||
$alicePrivate = \phpseclib\Math\BigInteger::random($one, $max);
|
||||
$bobPrivate = \phpseclib\Math\BigInteger::random($one, $max);
|
||||
var_dump($alicePrivate->toHex(), $bobPrivate->toHex());
|
||||
*/
|
||||
|
||||
@ -369,7 +353,21 @@ abstract class Unit_Math_BigInteger_TestCase extends PhpseclibTestCase
|
||||
$num = $this->getInstance(50);
|
||||
$str = print_r($num, true);
|
||||
$this->assertContains('[value] => 0x32', $str);
|
||||
return $str;
|
||||
}
|
||||
|
||||
public function testPrecision()
|
||||
{
|
||||
$a = $this->getInstance(51);
|
||||
$this->assertSame($a->getPrecision(), -1);
|
||||
$b = $a;
|
||||
$c = clone $a;
|
||||
$b->setPrecision(1);
|
||||
$this->assertSame($a->getPrecision(), 1);
|
||||
$this->assertSame("$a", '1');
|
||||
$this->assertSame($b->getPrecision(), 1);
|
||||
$this->assertSame("$b", '1');
|
||||
$this->assertSame($c->getPrecision(), -1);
|
||||
$this->assertSame("$c", '51');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -110,6 +110,18 @@ class Unit_Net_SSH2Test extends PhpseclibTestCase
|
||||
$this->assertFalse($ssh->isQuietModeEnabled());
|
||||
}
|
||||
|
||||
public function testGetConnectionByResourceId()
|
||||
{
|
||||
$ssh = new \phpseclib\Net\SSH2('localhost');
|
||||
$this->assertSame($ssh, \phpseclib\Net\SSH2::getConnectionByResourceId($ssh->getResourceId()));
|
||||
}
|
||||
|
||||
public function testGetResourceId()
|
||||
{
|
||||
$ssh = new \phpseclib\Net\SSH2('localhost');
|
||||
$this->assertSame('{' . spl_object_hash($ssh) . '}', $ssh->getResourceId());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \phpseclib\Net\SSH2
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user