diff --git a/README.md b/README.md
index 29580c66..b6f96fad 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# phpseclib - PHP Secure Communications Library
-[![Build Status](https://secure.travis-ci.org/phpseclib/phpseclib.png?branch=2.0)](http://travis-ci.org/phpseclib/phpseclib)
+[![Build Status](https://secure.travis-ci.org/phpseclib/phpseclib.png?branch=master)](http://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.0)](http://sourceforge.net/projects/phpseclib/files/phpseclib1.0.0.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/)
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
diff --git a/phpseclib/Crypt/Base.php b/phpseclib/Crypt/Base.php
index 6b64aa99..024327d8 100644
--- a/phpseclib/Crypt/Base.php
+++ b/phpseclib/Crypt/Base.php
@@ -605,6 +605,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
@@ -639,8 +640,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) {
@@ -1827,6 +1827,7 @@ abstract class Base
*
* @see \phpseclib\Crypt\Base::_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
*/
@@ -1838,8 +1839,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.");
}
}
@@ -1856,6 +1856,7 @@ abstract class Base
*
* @see \phpseclib\Crypt\Base::_pad()
* @param string $text
+ * @throws \LengthException if the ciphertext's length is not a multiple of the block size
* @access private
* @return string
*/
@@ -1868,7 +1869,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);
diff --git a/phpseclib/Crypt/Hash.php b/phpseclib/Crypt/Hash.php
index c8ca476a..41afd6d9 100644
--- a/phpseclib/Crypt/Hash.php
+++ b/phpseclib/Crypt/Hash.php
@@ -1,26 +1,20 @@
* setKey('abcdefg');
*
@@ -31,42 +25,25 @@
* @category Crypt
* @package Hash
* @author Jim Wigginton
- * @copyright 2007 Jim Wigginton
+ * @copyright 2015 Jim Wigginton
+ * @author Andreas Fischer
+ * @copyright 2015 Andreas Fischer
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
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
+ * @author Andreas Fischer
* @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 \phpseclib\Crypt\Hash::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,46 +80,14 @@ class Hash
*/
var $key = false;
- /**
- * Outer XOR (Internal HMAC)
- *
- * @see \phpseclib\Crypt\Hash::setKey()
- * @var string
- * @access private
- */
- var $opad;
-
- /**
- * Inner XOR (Internal HMAC)
- *
- * @see \phpseclib\Crypt\Hash::setKey()
- * @var string
- * @access private
- */
- var $ipad;
-
/**
* 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);
}
@@ -196,96 +132,47 @@ class Hash
case 'sha256-96':
case 'sha512-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 'sha256':
- $this->l = 32;
+ $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');
- }
-
- $this->ipad = str_repeat(chr(0x36), $this->b);
- $this->opad = str_repeat(chr(0x5C), $this->b);
+ $this->hash = $hash;
}
/**
@@ -297,45 +184,13 @@ class Hash
*/
function hash($text)
{
- $mode = is_array($this->hash) ? self::MODE_INTERNAL : CRYPT_HASH_MODE;
+ $output = !empty($this->key) || is_string($this->key) ?
+ hash_hmac($this->hash, $text, $this->key, true) :
+ hash($this->hash, $text, true);
- 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 ? call_user_func($this->hash, $this->key) : $this->key;
-
- $key = str_pad($key, $this->b, chr(0)); // step 1
- $temp = $this->ipad ^ $key; // step 2
- $temp .= $text; // step 3
- $temp = call_user_func($this->hash, $temp); // step 4
- $output = $this->opad ^ $key; // step 5
- $output.= $temp; // step 6
- $output = call_user_func($this->hash, $output); // step 7
- }
- } 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->l);
+ return strlen($output) > $this->length
+ ? substr($output, 0, $this->length)
+ : $output;
}
/**
@@ -346,480 +201,6 @@ class Hash
*/
function getLength()
{
- return $this->l;
- }
-
- /**
- * Wrapper for MD5
- *
- * @access private
- * @param string $m
- */
- function _md5($m)
- {
- 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 , 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;
-
- 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(
- '428a2f98d728ae22', '7137449123ef65cd', 'b5c0fbcfec4d3b2f', 'e9b5dba58189dbbc',
- '3956c25bf348b538', '59f111f1b605d019', '923f82a4af194f9b', 'ab1c5ed5da6d8118',
- 'd807aa98a3030242', '12835b0145706fbe', '243185be4ee4b28c', '550c7dc3d5ffb4e2',
- '72be5d74f27b896f', '80deb1fe3b1696b1', '9bdc06a725c71235', 'c19bf174cf692694',
- 'e49b69c19ef14ad2', 'efbe4786384f25e3', '0fc19dc68b8cd5b5', '240ca1cc77ac9c65',
- '2de92c6f592b0275', '4a7484aa6ea6e483', '5cb0a9dcbd41fbd4', '76f988da831153b5',
- '983e5152ee66dfab', 'a831c66d2db43210', 'b00327c898fb213f', 'bf597fc7beef0ee4',
- 'c6e00bf33da88fc2', 'd5a79147930aa725', '06ca6351e003826f', '142929670a0e6e70',
- '27b70a8546d22ffc', '2e1b21385c26c926', '4d2c6dfc5ac42aed', '53380d139d95b3df',
- '650a73548baf63de', '766a0abb3c77b2a8', '81c2c92e47edaee6', '92722c851482353b',
- 'a2bfe8a14cf10364', 'a81a664bbc423001', 'c24b8b70d0f89791', 'c76c51a30654be30',
- 'd192e819d6ef5218', 'd69906245565a910', 'f40e35855771202a', '106aa07032bbd1b8',
- '19a4c116b8d2d0c8', '1e376c085141ab53', '2748774cdf8eeb99', '34b0bcb5e19b48a8',
- '391c0cb3c5c95a63', '4ed8aa4ae3418acb', '5b9cca4f7763e373', '682e6ff3d6b2b8a3',
- '748f82ee5defb2fc', '78a5636f43172f60', '84c87814a1f0ab72', '8cc702081a6439ec',
- '90befffa23631e28', 'a4506cebde82bde9', 'bef9a3f7b2c67915', 'c67178f2e372532b',
- 'ca273eceea26619c', 'd186b8c721c0c207', 'eada7dd6cde0eb1e', 'f57d4f7fee6ed178',
- '06f067aa72176fba', '0a637dc5a2c898a6', '113f9804bef90dae', '1b710b35131c471b',
- '28db77f523047d84', '32caab7b40c72493', '3c9ebe0a15c9bebc', '431d67c49c100d4c',
- '4cc5d4becb3e42b6', '597f299cfc657e2a', '5fcb6fab3ad6faec', '6c44198c4a475817'
- );
-
- for ($i = 0; $i < 80; $i++) {
- $k[$i] = new BigInteger($k[$i], 16);
- }
- }
-
- $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
- $m.= str_repeat(chr(0), 128 - (($length + 16) & 0x7F));
- $m[$length] = chr(0x80);
- // we don't support hashing strings 512MB long
- $m.= pack('N4', 0, 0, 0, $length << 3);
-
- // Process the message in successive 1024-bit chunks
- $chunks = str_split($m, 128);
- foreach ($chunks as $chunk) {
- $w = array();
- for ($i = 0; $i < 16; $i++) {
- $temp = new BigInteger($this->_string_shift($chunk, 8), 256);
- $temp->setPrecision(64);
- $w[] = $temp;
- }
-
- // Extend the sixteen 32-bit words into eighty 32-bit words
- for ($i = 16; $i < 80; $i++) {
- $temp = array(
- $w[$i - 15]->bitwise_rightRotate(1),
- $w[$i - 15]->bitwise_rightRotate(8),
- $w[$i - 15]->bitwise_rightShift(7)
- );
- $s0 = $temp[0]->bitwise_xor($temp[1]);
- $s0 = $s0->bitwise_xor($temp[2]);
- $temp = array(
- $w[$i - 2]->bitwise_rightRotate(19),
- $w[$i - 2]->bitwise_rightRotate(61),
- $w[$i - 2]->bitwise_rightShift(6)
- );
- $s1 = $temp[0]->bitwise_xor($temp[1]);
- $s1 = $s1->bitwise_xor($temp[2]);
- $w[$i] = $w[$i - 16]->copy();
- $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();
-
- // Main loop
- for ($i = 0; $i < 80; $i++) {
- $temp = array(
- $a->bitwise_rightRotate(28),
- $a->bitwise_rightRotate(34),
- $a->bitwise_rightRotate(39)
- );
- $s0 = $temp[0]->bitwise_xor($temp[1]);
- $s0 = $s0->bitwise_xor($temp[2]);
- $temp = array(
- $a->bitwise_and($b),
- $a->bitwise_and($c),
- $b->bitwise_and($c)
- );
- $maj = $temp[0]->bitwise_xor($temp[1]);
- $maj = $maj->bitwise_xor($temp[2]);
- $t2 = $s0->add($maj);
-
- $temp = array(
- $e->bitwise_rightRotate(14),
- $e->bitwise_rightRotate(18),
- $e->bitwise_rightRotate(41)
- );
- $s1 = $temp[0]->bitwise_xor($temp[1]);
- $s1 = $s1->bitwise_xor($temp[2]);
- $temp = array(
- $e->bitwise_and($f),
- $g->bitwise_and($e->bitwise_not())
- );
- $ch = $temp[0]->bitwise_xor($temp[1]);
- $t1 = $h->add($s1);
- $t1 = $t1->add($ch);
- $t1 = $t1->add($k[$i]);
- $t1 = $t1->add($w[$i]);
-
- $h = $g->copy();
- $g = $f->copy();
- $f = $e->copy();
- $e = $d->add($t1);
- $d = $c->copy();
- $c = $b->copy();
- $b = $a->copy();
- $a = $t1->add($t2);
- }
-
- // Add this chunk's hash to result so far
- $hash = array(
- $hash[0]->add($a),
- $hash[1]->add($b),
- $hash[2]->add($c),
- $hash[3]->add($d),
- $hash[4]->add($e),
- $hash[5]->add($f),
- $hash[6]->add($g),
- $hash[7]->add($h)
- );
- }
-
- // 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();
- }
-
- return $temp;
- }
-
- /**
- * Right Rotate
- *
- * @access private
- * @param int $int
- * @param int $amt
- * @see _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 _sha256()
- * @return int
- */
- function _rightShift($int, $amt)
- {
- $mask = (1 << (32 - $amt)) - 1;
- return ($int >> $amt) & $mask;
- }
-
- /**
- * Not
- *
- * @access private
- * @param int $int
- * @see _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 _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
- *
- * Inspired by array_shift
- *
- * @param string $string
- * @param int $index
- * @return string
- * @access private
- */
- function _string_shift(&$string, $index = 1)
- {
- $substr = substr($string, 0, $index);
- $string = substr($string, $index);
- return $substr;
+ return $this->length;
}
}
diff --git a/phpseclib/Crypt/RSA.php b/phpseclib/Crypt/RSA.php
index 254b7351..558cd5fa 100644
--- a/phpseclib/Crypt/RSA.php
+++ b/phpseclib/Crypt/RSA.php
@@ -29,11 +29,9 @@
*
* $plaintext = 'terrafrost';
*
- * $rsa->loadKey($privatekey);
- * $signature = $rsa->sign($plaintext);
+ * $signature = $privatekey->sign($plaintext);
*
- * $rsa->loadKey($publickey);
- * echo $rsa->verify($plaintext, $signature) ? 'verified' : 'unverified';
+ * echo $publickey->verify($plaintext, $signature) ? 'verified' : 'unverified';
* ?>
*
*
@@ -351,6 +349,20 @@ class RSA
}
}
+ /**
+ * Initialize static variables
+ *
+ * @access private
+ */
+ static function _initialize_static_variables()
+ {
+ if (!isset(self::$zero)) {
+ self::$zero= new BigInteger(0);
+ self::$one = new BigInteger(1);
+ self::$configFile = __DIR__ . '/../openssl.cnf';
+ }
+ }
+
/**
* The constructor
*
@@ -664,7 +676,6 @@ class RSA
$this->encryptionMode = $key->encryptionMode;
$this->signatureMode = $key->signatureMode;
$this->password = $key->password;
- $this->configFile = $key->configFile;
$this->comment = $key->comment;
if (is_object($key->hash)) {
diff --git a/phpseclib/Crypt/Random.php b/phpseclib/Crypt/Random.php
index 0bee3c45..4ce919f7 100644
--- a/phpseclib/Crypt/Random.php
+++ b/phpseclib/Crypt/Random.php
@@ -49,6 +49,7 @@ 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)
@@ -211,8 +212,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);
diff --git a/phpseclib/Exception/BadConfigurationException.php b/phpseclib/Exception/BadConfigurationException.php
new file mode 100644
index 00000000..096148a0
--- /dev/null
+++ b/phpseclib/Exception/BadConfigurationException.php
@@ -0,0 +1,26 @@
+
+ * @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
+ */
+class BadConfigurationException extends \RuntimeException
+{
+}
diff --git a/phpseclib/Exception/FileNotFoundException.php b/phpseclib/Exception/FileNotFoundException.php
new file mode 100644
index 00000000..984edfcc
--- /dev/null
+++ b/phpseclib/Exception/FileNotFoundException.php
@@ -0,0 +1,26 @@
+
+ * @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
+ */
+class FileNotFoundException extends \RuntimeException
+{
+}
diff --git a/phpseclib/Exception/NoSupportedAlgorithmsException.php b/phpseclib/Exception/NoSupportedAlgorithmsException.php
new file mode 100644
index 00000000..bca9a753
--- /dev/null
+++ b/phpseclib/Exception/NoSupportedAlgorithmsException.php
@@ -0,0 +1,26 @@
+
+ * @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
+ */
+class NoSupportedAlgorithmsException extends \RuntimeException
+{
+}
diff --git a/phpseclib/Exception/UnsupportedAlgorithmException.php b/phpseclib/Exception/UnsupportedAlgorithmException.php
new file mode 100644
index 00000000..47cc41d4
--- /dev/null
+++ b/phpseclib/Exception/UnsupportedAlgorithmException.php
@@ -0,0 +1,26 @@
+
+ * @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
+ */
+class UnsupportedAlgorithmException extends \RuntimeException
+{
+}
diff --git a/phpseclib/File/ASN1.php b/phpseclib/File/ASN1.php
index b71469b4..cd17174b 100644
--- a/phpseclib/File/ASN1.php
+++ b/phpseclib/File/ASN1.php
@@ -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;
}
diff --git a/phpseclib/File/X509.php b/phpseclib/File/X509.php
index 55d25706..2ee9300d 100644
--- a/phpseclib/File/X509.php
+++ b/phpseclib/File/X509.php
@@ -32,6 +32,7 @@ use phpseclib\Crypt\Random;
use phpseclib\File\ASN1;
use phpseclib\File\ASN1\Element;
use phpseclib\Math\BigInteger;
+use phpseclib\Exception\UnsupportedAlgorithmException;
/**
* Pure-PHP X.509 Parser
@@ -1641,7 +1642,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 {
@@ -1714,7 +1715,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'];
@@ -2107,7 +2108,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
@@ -2115,7 +2117,8 @@ 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)
{
@@ -2139,11 +2142,11 @@ class X509
}
break;
default:
- return null;
+ throw new UnsupportedAlgorithmException('Signature algorithm unsupported');
}
break;
default:
- return null;
+ throw new UnsupportedAlgorithmException('Public key algorithm unsupported');
}
return true;
@@ -3628,6 +3631,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)
@@ -3646,10 +3650,12 @@ class X509
$this->currentCert['signature'] = base64_encode("\0" . $key->sign($this->signatureSubject));
return $this->currentCert;
+ default:
+ throw new UnsupportedAlgorithmException('Signature algorithm unsupported');
}
}
- return false;
+ throw new UnsupportedAlgorithmException('Unsupported public key algorithm');
}
/**
diff --git a/phpseclib/Net/SCP.php b/phpseclib/Net/SCP.php
index 4db28857..a2818970 100644
--- a/phpseclib/Net/SCP.php
+++ b/phpseclib/Net/SCP.php
@@ -34,6 +34,7 @@ namespace phpseclib\Net;
use phpseclib\Net\SSH1;
use phpseclib\Net\SSH2;
+use phpseclib\Exception\FileNotFoundException;
/**
* Pure-PHP implementations of SCP.
@@ -140,6 +141,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 +170,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 +290,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 +316,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');
}
}
}
diff --git a/phpseclib/Net/SFTP.php b/phpseclib/Net/SFTP.php
index e139be53..eba6fc03 100644
--- a/phpseclib/Net/SFTP.php
+++ b/phpseclib/Net/SFTP.php
@@ -38,6 +38,7 @@
namespace phpseclib\Net;
use phpseclib\Net\SSH2;
+use phpseclib\Exception\FileNotFoundException;
/**
* Pure-PHP implementations of SFTP.
@@ -383,6 +384,7 @@ class SFTP extends SSH2
*
* @param string $username
* @param string $password
+ * @throws \UnexpectedValueException on receipt of unexpected packets
* @return bool
* @access public
*/
@@ -470,8 +472,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 +611,7 @@ class SFTP extends SSH2
*
* @see \phpseclib\Net\SFTP::chdir()
* @param string $path
+ * @throws \UnexpectedValueException on receipt of unexpected packets
* @return mixed
* @access private
*/
@@ -634,8 +636,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 +667,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 +712,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 +814,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 +846,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 +900,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 +1259,7 @@ class SFTP extends SSH2
*
* @param string $filename
* @param int $type
+ * @throws \UnexpectedValueException on receipt of unexpected packets
* @return mixed
* @access private
*/
@@ -1279,8 +1280,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 +1306,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 +1343,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 +1396,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
*/
@@ -1433,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');
}
/**
@@ -1443,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
*/
@@ -1481,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)));
@@ -1570,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
*/
@@ -1593,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)));
@@ -1614,6 +1614,7 @@ class SFTP extends SSH2
*
* @param string $target
* @param string $link
+ * @throws \UnexpectedValueException on receipt of unexpected packets
* @return bool
* @access public
*/
@@ -1633,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)));
@@ -1686,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)
@@ -1696,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)));
@@ -1713,6 +1713,7 @@ class SFTP extends SSH2
* Removes a directory.
*
* @param string $dir
+ * @throws \UnexpectedValueException on receipt of unexpected packets
* @return bool
* @access public
*/
@@ -1733,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)));
@@ -1794,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().
@@ -1841,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
@@ -1850,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
@@ -1861,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) {
@@ -1876,10 +1877,7 @@ class SFTP extends SSH2
if ($local_start >= 0) {
fseek($fp, $local_start);
- } elseif ($mode & self::RESUME_START) {
- // do nothing
- } else {
- fseek($fp, $offset);
+ $size-= $local_start;
}
} elseif ($dataCallback) {
$size = 0;
@@ -1950,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)
@@ -1957,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)));
@@ -1976,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)
@@ -1988,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)));
@@ -2014,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
*/
@@ -2042,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)) {
@@ -2091,11 +2089,10 @@ class SFTP extends SSH2
$this->_logError($response);
break 2;
default:
- user_error('Expected SSH_FXP_DATA or SSH_FXP_STATUS');
if ($fclose_check) {
fclose($fp);
}
- return false;
+ throw new \UnexpectedValueException('Expected SSH_FXP_DATA or SSH_FXP_STATUS');
}
if ($length > 0 && $length <= $offset - $start) {
@@ -2129,6 +2126,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)
@@ -2149,8 +2147,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
@@ -2482,6 +2479,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)
@@ -2504,8 +2502,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
diff --git a/phpseclib/Net/SFTP/Stream.php b/phpseclib/Net/SFTP/Stream.php
index a62eb4ab..7af7280a 100644
--- a/phpseclib/Net/SFTP/Stream.php
+++ b/phpseclib/Net/SFTP/Stream.php
@@ -19,6 +19,7 @@ namespace phpseclib\Net\SFTP;
use phpseclib\Crypt\RSA;
use phpseclib\Net\SFTP;
+use phpseclib\Net\SSH2;
/**
* SFTP Stream Wrapper
@@ -166,13 +167,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);
diff --git a/phpseclib/Net/SSH1.php b/phpseclib/Net/SSH1.php
index 3ddb47b6..2e0a26d0 100644
--- a/phpseclib/Net/SSH1.php
+++ b/phpseclib/Net/SSH1.php
@@ -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) {
@@ -682,8 +679,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 +693,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 +713,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 +725,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 +751,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 +786,19 @@ class SSH1
* @see \phpseclib\Net\SSH1::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 +834,8 @@ class SSH1
* @see \phpseclib\Net\SSH1::interactiveRead()
* @see \phpseclib\Net\SSH1::interactiveWrite()
* @return bool
+ * @throws \UnexpectedValueException on receipt of unexpected packets
+ * @throws \RuntimeException on other errors
* @access private
*/
function _initShell()
@@ -851,8 +846,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 +855,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 +894,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 +932,23 @@ class SSH1
* @see \phpseclib\Net\SSH1::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 +965,17 @@ class SSH1
*
* @see \phpseclib\Net\SSH1::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,7 +1301,7 @@ class SSH1
{
/*
$rsa = new RSA();
- $rsa->loadKey($key, RSA::PUBLIC_FORMAT_RAW);
+ $rsa->load($key, RSA::PUBLIC_FORMAT_RAW);
$rsa->setEncryptionMode(RSA::ENCRYPTION_PKCS1);
return $rsa->encrypt($m);
*/
diff --git a/phpseclib/Net/SSH2.php b/phpseclib/Net/SSH2.php
index a779dc7c..c084c8a3 100644
--- a/phpseclib/Net/SSH2.php
+++ b/phpseclib/Net/SSH2.php
@@ -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.
@@ -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);
@@ -1662,8 +1669,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 +1698,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 +1745,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';
@@ -1891,6 +1898,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 +1924,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 +1971,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 +2025,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 +2101,7 @@ class SSH2
*
* @param string $responses...
* @return bool
+ * @throws \RuntimeException on connection error
* @access private
*/
function _keyboard_interactive_process()
@@ -2107,8 +2113,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 +2237,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.
@@ -2277,8 +2283,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)));
@@ -2312,8 +2317,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 +2367,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 +2435,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 +2445,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 +2514,8 @@ class SSH2
* @see \phpseclib\Net\SSH2::read()
* @see \phpseclib\Net\SSH2::write()
* @return bool
+ * @throws \UnexpectedValueException on receipt of unexpected packets
+ * @throws \RuntimeException on other errors
* @access private
*/
function _initShell()
@@ -2566,8 +2572,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 +2583,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 +2661,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 +2670,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 +2705,17 @@ class SSH2
* @see \phpseclib\Net\SSH2::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 +2839,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()]);
}
/**
@@ -2869,14 +2873,14 @@ class SSH2
*
* @see \phpseclib\Net\SSH2::_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);
@@ -2890,8 +2894,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)));
@@ -2902,17 +2905,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);
@@ -2928,12 +2929,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');
}
}
@@ -3161,6 +3160,7 @@ class SSH2
*
* @param $client_channel
* @return mixed
+ * @throws \RuntimeException on connection error
* @access private
*/
function _get_channel_packet($client_channel, $skip_extended = false)
@@ -3193,8 +3193,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;
@@ -3243,8 +3242,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:
@@ -3254,8 +3253,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);
@@ -3364,8 +3363,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');
}
}
}
@@ -3384,9 +3383,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) {
@@ -3945,6 +3943,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()
@@ -3990,8 +3990,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);
@@ -4002,8 +4002,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);
@@ -4022,7 +4022,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);
}
@@ -4042,9 +4042,9 @@ class SSH2
$rsa = new RSA();
$rsa->setSignatureMode(RSA::SIGNATURE_PKCS1);
- $rsa->loadKey(array('e' => $e, 'n' => $n), 'Raw');
+ $rsa->load(array('e' => $e, 'n' => $n), 'Raw');
if (!$rsa->verify($this->exchange_hash, $signature)) {
- user_error('Bad server signature');
+ //user_error('Bad server signature');
return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
}
*/
@@ -4059,8 +4059,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);
@@ -4070,13 +4070,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);
@@ -4152,4 +4152,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;
+ }
}
diff --git a/phpseclib/System/SSH/Agent.php b/phpseclib/System/SSH/Agent.php
index af055f52..17b52ad8 100644
--- a/phpseclib/System/SSH/Agent.php
+++ b/phpseclib/System/SSH/Agent.php
@@ -35,6 +35,7 @@ namespace phpseclib\System\SSH;
use phpseclib\Crypt\RSA;
use phpseclib\System\SSH\Agent\Identity;
+use phpseclib\Exception\BadConfigurationException;
/**
* Pure-PHP ssh-agent client identity factory
@@ -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();
@@ -271,6 +274,7 @@ class Agent
*
* @param string $data
* @return data from SSH Agent
+ * @throws \RuntimeException on connection errors
* @access private
*/
function _forward_data($data)
@@ -289,7 +293,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 = '';
diff --git a/phpseclib/System/SSH/Agent/Identity.php b/phpseclib/System/SSH/Agent/Identity.php
index f52bc31c..42a4dae2 100644
--- a/phpseclib/System/SSH/Agent/Identity.php
+++ b/phpseclib/System/SSH/Agent/Identity.php
@@ -134,6 +134,7 @@ class Identity
*
* @param string $message
* @return string
+ * @throws \RuntimeException on connection errors
* @access public
*/
function sign($message)
@@ -142,13 +143,13 @@ class Identity
$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);
diff --git a/tests/Functional/Net/SFTPStreamTest.php b/tests/Functional/Net/SFTPStreamTest.php
index b596c4f8..aab16ec9 100644
--- a/tests/Functional/Net/SFTPStreamTest.php
+++ b/tests/Functional/Net/SFTPStreamTest.php
@@ -27,6 +27,19 @@ class Functional_Net_SFTPStreamTest extends Functional_Net_SFTPTestCase
$this->assertSame(0, $this->sftp->size('fooo.txt'));
}
+ /**
+ * 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(
diff --git a/tests/Functional/Net/SFTPTestCase.php b/tests/Functional/Net/SFTPTestCase.php
index abd5999d..aec75e71 100644
--- a/tests/Functional/Net/SFTPTestCase.php
+++ b/tests/Functional/Net/SFTPTestCase.php
@@ -13,6 +13,9 @@ use phpseclib\Net\SFTP;
*/
abstract class Functional_Net_SFTPTestCase extends PhpseclibFunctionalTestCase
{
+ /**
+ * @var SFTP
+ */
protected $sftp;
protected $scratchDir;
diff --git a/tests/Functional/Net/SFTPUserStoryTest.php b/tests/Functional/Net/SFTPUserStoryTest.php
index 6539c675..fcc41eda 100644
--- a/tests/Functional/Net/SFTPUserStoryTest.php
+++ b/tests/Functional/Net/SFTPUserStoryTest.php
@@ -651,5 +651,28 @@ class Functional_Net_SFTPUserStoryTest extends PhpseclibFunctionalTestCase
$this->assertSame($stat['type'], NET_SFTP_TYPE_SYMLINK);
$sftp->enableStatCache();
+
+ return $sftp;
+ }
+
+ /**
+ * @depends testStatVsLstat
+ * @group github830
+ */
+ public function testUploadOffsets($sftp)
+ {
+ $sftp->put('offset.txt', 'res.txt', SFTP::SOURCE_LOCAL_FILE, 0, 10);
+ $this->assertSame(
+ substr(self::$exampleData, 10),
+ $sftp->get('offset.txt'),
+ 'Failed asserting that portions of a file could be uploaded.'
+ );
+
+ $sftp->put('offset.txt', 'res.txt', SFTP::SOURCE_LOCAL_FILE, self::$exampleDataLength - 100);
+ $this->assertSame(
+ substr(self::$exampleData, 10, -90) . self::$exampleData,
+ $sftp->get('offset.txt'),
+ 'Failed asserting that you could upload into the middle of a file.'
+ );
}
}
diff --git a/tests/PhpseclibFunctionalTestCase.php b/tests/PhpseclibFunctionalTestCase.php
index e0b3a7cf..ba646edb 100644
--- a/tests/PhpseclibFunctionalTestCase.php
+++ b/tests/PhpseclibFunctionalTestCase.php
@@ -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();
}
diff --git a/tests/Unit/Crypt/Hash/MD5Test.php b/tests/Unit/Crypt/Hash/MD5Test.php
deleted file mode 100644
index 431184ee..00000000
--- a/tests/Unit/Crypt/Hash/MD5Test.php
+++ /dev/null
@@ -1,49 +0,0 @@
-
- * @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'),
- );
- }
-}
diff --git a/tests/Unit/Crypt/Hash/SHA256Test.php b/tests/Unit/Crypt/Hash/SHA256Test.php
deleted file mode 100644
index bad46b36..00000000
--- a/tests/Unit/Crypt/Hash/SHA256Test.php
+++ /dev/null
@@ -1,81 +0,0 @@
-
- * @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',
- ),
- );
- }
-}
diff --git a/tests/Unit/Crypt/Hash/SHA256_96Test.php b/tests/Unit/Crypt/Hash/SHA256_96Test.php
deleted file mode 100644
index 85aaf295..00000000
--- a/tests/Unit/Crypt/Hash/SHA256_96Test.php
+++ /dev/null
@@ -1,32 +0,0 @@
-
- * @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));
- }
-}
diff --git a/tests/Unit/Crypt/Hash/SHA512Test.php b/tests/Unit/Crypt/Hash/SHA512Test.php
deleted file mode 100644
index ad2e63e3..00000000
--- a/tests/Unit/Crypt/Hash/SHA512Test.php
+++ /dev/null
@@ -1,81 +0,0 @@
-
- * @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',
- ),
- );
- }
-}
diff --git a/tests/Unit/Crypt/Hash/SHA512_96Test.php b/tests/Unit/Crypt/Hash/SHA512_96Test.php
deleted file mode 100644
index 760fa243..00000000
--- a/tests/Unit/Crypt/Hash/SHA512_96Test.php
+++ /dev/null
@@ -1,32 +0,0 @@
-
- * @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));
- }
-}
diff --git a/tests/Unit/Crypt/Hash/TestCase.php b/tests/Unit/Crypt/Hash/TestCase.php
deleted file mode 100644
index 2ef63c6b..00000000
--- a/tests/Unit/Crypt/Hash/TestCase.php
+++ /dev/null
@@ -1,52 +0,0 @@
-
- * @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
- )
- );
- }
-}
diff --git a/tests/Unit/Crypt/HashTest.php b/tests/Unit/Crypt/HashTest.php
new file mode 100644
index 00000000..72779ea1
--- /dev/null
+++ b/tests/Unit/Crypt/HashTest.php
@@ -0,0 +1,265 @@
+
+ * @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'
+ ),
+ );
+ }
+
+ /**
+ * @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'),
+ // RFC 4231
+ // Test Case 1
+ array(
+ 'sha256',
+ pack('H*', '0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b'),
+ pack('H*', '4869205468657265'),
+ 'b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7',
+ ),
+ // Test Case 2
+ array(
+ 'sha256',
+ pack('H*', '4a656665'),
+ pack('H*', '7768617420646f2079612077616e7420666f72206e6f7468696e673f'),
+ '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',
+ ),
+ // RFC 4231
+ // Test Case 1
+ array(
+ 'sha512',
+ pack('H*', '0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b'),
+ pack('H*', '4869205468657265'),
+ '87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854',
+ ),
+ // Test Case 2
+ array(
+ 'sha512',
+ pack('H*', '4a656665'),
+ pack('H*', '7768617420646f2079612077616e7420666f72206e6f7468696e673f'),
+ '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',
+ ),
+ array(
+ 'whirlpool',
+ 'abcd',
+ 'The quick brown fox jumps over the lazy dog',
+ 'e71aabb2588d789292fa6fef00b35cc269ec3ea912b1c1cd7127daf95f004a5df5392ee563d322bac7e19d9eab161932fe9c257d63e0d09eca0d91ab4010125e',
+ ),
+ );
+ }
+
+ /**
+ * @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),
+ );
+ }
+}
diff --git a/tests/Unit/Net/SSH2Test.php b/tests/Unit/Net/SSH2Test.php
index df9651af..1d3c6439 100644
--- a/tests/Unit/Net/SSH2Test.php
+++ b/tests/Unit/Net/SSH2Test.php
@@ -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
*/