update to phpseclib 2.0.6

This commit is contained in:
Roland Gruber 2017-09-16 15:09:25 +02:00
parent aa435cecfb
commit 0e251a3244
31 changed files with 33503 additions and 33988 deletions

View File

@ -1,197 +1,126 @@
<?php <?php
/** /**
* Pure-PHP implementation of AES. * Pure-PHP implementation of AES.
* *
* Uses mcrypt, if available/possible, and an internal implementation, otherwise. * Uses mcrypt, if available/possible, and an internal implementation, otherwise.
* *
* PHP versions 4 and 5 * PHP version 5
* *
* NOTE: Since AES.php is (for compatibility and phpseclib-historical reasons) virtually * NOTE: Since AES.php is (for compatibility and phpseclib-historical reasons) virtually
* just a wrapper to Rijndael.php you may consider using Rijndael.php instead of * just a wrapper to Rijndael.php you may consider using Rijndael.php instead of
* to save one include_once(). * to save one include_once().
* *
* If {@link self::setKeyLength() setKeyLength()} isn't called, it'll be calculated from * If {@link self::setKeyLength() setKeyLength()} isn't called, it'll be calculated from
* {@link self::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's 136-bits * {@link self::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's 136-bits
* it'll be null-padded to 192-bits and 192 bits will be the key length until {@link self::setKey() setKey()} * it'll be null-padded to 192-bits and 192 bits will be the key length until {@link self::setKey() setKey()}
* is called, again, at which point, it'll be recalculated. * is called, again, at which point, it'll be recalculated.
* *
* Since Crypt_AES extends Crypt_Rijndael, some functions are available to be called that, in the context of AES, don't * Since \phpseclib\Crypt\AES extends \phpseclib\Crypt\Rijndael, some functions are available to be called that, in the context of AES, don't
* make a whole lot of sense. {@link self::setBlockLength() setBlockLength()}, for instance. Calling that function, * make a whole lot of sense. {@link self::setBlockLength() setBlockLength()}, for instance. Calling that function,
* however possible, won't do anything (AES has a fixed block length whereas Rijndael has a variable one). * however possible, won't do anything (AES has a fixed block length whereas Rijndael has a variable one).
* *
* Here's a short example of how to use this library: * Here's a short example of how to use this library:
* <code> * <code>
* <?php * <?php
* include 'Crypt/AES.php'; * include 'vendor/autoload.php';
* *
* $aes = new Crypt_AES(); * $aes = new \phpseclib\Crypt\AES();
* *
* $aes->setKey('abcdefghijklmnop'); * $aes->setKey('abcdefghijklmnop');
* *
* $size = 10 * 1024; * $size = 10 * 1024;
* $plaintext = ''; * $plaintext = '';
* for ($i = 0; $i < $size; $i++) { * for ($i = 0; $i < $size; $i++) {
* $plaintext.= 'a'; * $plaintext.= 'a';
* } * }
* *
* echo $aes->decrypt($aes->encrypt($plaintext)); * echo $aes->decrypt($aes->encrypt($plaintext));
* ?> * ?>
* </code> * </code>
* *
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy * @category Crypt
* of this software and associated documentation files (the "Software"), to deal * @package AES
* in the Software without restriction, including without limitation the rights * @author Jim Wigginton <terrafrost@php.net>
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * @copyright 2008 Jim Wigginton
* copies of the Software, and to permit persons to whom the Software is * @license http://www.opensource.org/licenses/mit-license.html MIT License
* furnished to do so, subject to the following conditions: * @link http://phpseclib.sourceforge.net
* */
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software. namespace phpseclib\Crypt;
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR /**
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * Pure-PHP implementation of AES.
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * @package AES
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * @author Jim Wigginton <terrafrost@php.net>
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * @access public
* THE SOFTWARE. */
* class AES extends Rijndael
* @category Crypt {
* @package Crypt_AES /**
* @author Jim Wigginton <terrafrost@php.net> * Dummy function
* @copyright 2008 Jim Wigginton *
* @license http://www.opensource.org/licenses/mit-license.html MIT License * Since \phpseclib\Crypt\AES extends \phpseclib\Crypt\Rijndael, this function is, technically, available, but it doesn't do anything.
* @link http://phpseclib.sourceforge.net *
*/ * @see \phpseclib\Crypt\Rijndael::setBlockLength()
* @access public
/** * @param int $length
* Include Crypt_Rijndael */
*/ function setBlockLength($length)
if (!class_exists('Crypt_Rijndael')) { {
include_once 'Rijndael.php'; return;
} }
/**#@+ /**
* @access public * Sets the key length
* @see self::encrypt() *
* @see self::decrypt() * Valid key lengths are 128, 192, and 256. If the length is less than 128, it will be rounded up to
*/ * 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
/** *
* Encrypt / decrypt using the Counter mode. * @see \phpseclib\Crypt\Rijndael:setKeyLength()
* * @access public
* Set to -1 since that's what Crypt/Random.php uses to index the CTR mode. * @param int $length
* */
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 function setKeyLength($length)
*/ {
define('CRYPT_AES_MODE_CTR', CRYPT_MODE_CTR); switch ($length) {
/** case 160:
* Encrypt / decrypt using the Electronic Code Book mode. $length = 192;
* break;
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29 case 224:
*/ $length = 256;
define('CRYPT_AES_MODE_ECB', CRYPT_MODE_ECB); }
/** parent::setKeyLength($length);
* Encrypt / decrypt using the Code Book Chaining mode. }
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 /**
*/ * Sets the key.
define('CRYPT_AES_MODE_CBC', CRYPT_MODE_CBC); *
/** * Rijndael supports five different key lengths, AES only supports three.
* Encrypt / decrypt using the Cipher Feedback mode. *
* * @see \phpseclib\Crypt\Rijndael:setKey()
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 * @see setKeyLength()
*/ * @access public
define('CRYPT_AES_MODE_CFB', CRYPT_MODE_CFB); * @param string $key
/** */
* Encrypt / decrypt using the Cipher Feedback mode. function setKey($key)
* {
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 parent::setKey($key);
*/
define('CRYPT_AES_MODE_OFB', CRYPT_MODE_OFB); if (!$this->explicit_key_length) {
/**#@-*/ $length = strlen($key);
switch (true) {
/** case $length <= 16:
* Pure-PHP implementation of AES. $this->key_length = 16;
* break;
* @package Crypt_AES case $length <= 24:
* @author Jim Wigginton <terrafrost@php.net> $this->key_length = 24;
* @access public break;
*/ default:
class Crypt_AES extends Crypt_Rijndael $this->key_length = 32;
{ }
/** $this->_setEngine();
* The namespace used by the cipher for its constants. }
* }
* @see Crypt_Base::const_namespace }
* @var string
* @access private
*/
var $const_namespace = 'AES';
/**
* Dummy function
*
* Since Crypt_AES extends Crypt_Rijndael, this function is, technically, available, but it doesn't do anything.
*
* @see Crypt_Rijndael::setBlockLength()
* @access public
* @param int $length
*/
function setBlockLength($length)
{
return;
}
/**
* Sets the key length
*
* Valid key lengths are 128, 192, and 256. If the length is less than 128, it will be rounded up to
* 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
*
* @see Crypt_Rijndael:setKeyLength()
* @access public
* @param int $length
*/
function setKeyLength($length)
{
switch ($length) {
case 160:
$length = 192;
break;
case 224:
$length = 256;
}
parent::setKeyLength($length);
}
/**
* Sets the key.
*
* Rijndael supports five different key lengths, AES only supports three.
*
* @see Crypt_Rijndael:setKey()
* @see setKeyLength()
* @access public
* @param string $key
*/
function setKey($key)
{
parent::setKey($key);
if (!$this->explicit_key_length) {
$length = strlen($key);
switch (true) {
case $length <= 16:
$this->key_length = 16;
break;
case $length <= 24:
$this->key_length = 24;
break;
default:
$this->key_length = 32;
}
$this->_setEngine();
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,352 +1,342 @@
<?php <?php
/** /**
* Pure-PHP implementation of RC4. * Pure-PHP implementation of RC4.
* *
* Uses mcrypt, if available, and an internal implementation, otherwise. * Uses mcrypt, if available, and an internal implementation, otherwise.
* *
* PHP versions 4 and 5 * PHP version 5
* *
* Useful resources are as follows: * Useful resources are as follows:
* *
* - {@link http://www.mozilla.org/projects/security/pki/nss/draft-kaukonen-cipher-arcfour-03.txt ARCFOUR Algorithm} * - {@link http://www.mozilla.org/projects/security/pki/nss/draft-kaukonen-cipher-arcfour-03.txt ARCFOUR Algorithm}
* - {@link http://en.wikipedia.org/wiki/RC4 - Wikipedia: RC4} * - {@link http://en.wikipedia.org/wiki/RC4 - Wikipedia: RC4}
* *
* RC4 is also known as ARCFOUR or ARC4. The reason is elaborated upon at Wikipedia. This class is named RC4 and not * RC4 is also known as ARCFOUR or ARC4. The reason is elaborated upon at Wikipedia. This class is named RC4 and not
* ARCFOUR or ARC4 because RC4 is how it is referred to in the SSH1 specification. * ARCFOUR or ARC4 because RC4 is how it is referred to in the SSH1 specification.
* *
* Here's a short example of how to use this library: * Here's a short example of how to use this library:
* <code> * <code>
* <?php * <?php
* include 'Crypt/RC4.php'; * include 'vendor/autoload.php';
* *
* $rc4 = new Crypt_RC4(); * $rc4 = new \phpseclib\Crypt\RC4();
* *
* $rc4->setKey('abcdefgh'); * $rc4->setKey('abcdefgh');
* *
* $size = 10 * 1024; * $size = 10 * 1024;
* $plaintext = ''; * $plaintext = '';
* for ($i = 0; $i < $size; $i++) { * for ($i = 0; $i < $size; $i++) {
* $plaintext.= 'a'; * $plaintext.= 'a';
* } * }
* *
* echo $rc4->decrypt($rc4->encrypt($plaintext)); * echo $rc4->decrypt($rc4->encrypt($plaintext));
* ?> * ?>
* </code> * </code>
* *
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy * @category Crypt
* of this software and associated documentation files (the "Software"), to deal * @package RC4
* in the Software without restriction, including without limitation the rights * @author Jim Wigginton <terrafrost@php.net>
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * @copyright 2007 Jim Wigginton
* copies of the Software, and to permit persons to whom the Software is * @license http://www.opensource.org/licenses/mit-license.html MIT License
* furnished to do so, subject to the following conditions: * @link http://phpseclib.sourceforge.net
* */
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software. namespace phpseclib\Crypt;
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR /**
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * Pure-PHP implementation of RC4.
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * @package RC4
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * @author Jim Wigginton <terrafrost@php.net>
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * @access public
* THE SOFTWARE. */
* class RC4 extends Base
* @category Crypt {
* @package Crypt_RC4 /**#@+
* @author Jim Wigginton <terrafrost@php.net> * @access private
* @copyright 2007 Jim Wigginton * @see \phpseclib\Crypt\RC4::_crypt()
* @license http://www.opensource.org/licenses/mit-license.html MIT License */
* @link http://phpseclib.sourceforge.net const ENCRYPT = 0;
*/ const DECRYPT = 1;
/**#@-*/
/**
* Include Crypt_Base /**
* * Block Length of the cipher
* Base cipher class *
*/ * RC4 is a stream cipher
if (!class_exists('Crypt_Base')) { * so we the block_size to 0
include_once 'Base.php'; *
} * @see \phpseclib\Crypt\Base::block_size
* @var int
/**#@+ * @access private
* @access private */
* @see self::_crypt() var $block_size = 0;
*/
define('CRYPT_RC4_ENCRYPT', 0); /**
define('CRYPT_RC4_DECRYPT', 1); * Key Length (in bytes)
/**#@-*/ *
* @see \phpseclib\Crypt\RC4::setKeyLength()
/** * @var int
* Pure-PHP implementation of RC4. * @access private
* */
* @package Crypt_RC4 var $key_length = 128; // = 1024 bits
* @author Jim Wigginton <terrafrost@php.net>
* @access public /**
*/ * The mcrypt specific name of the cipher
class Crypt_RC4 extends Crypt_Base *
{ * @see \phpseclib\Crypt\Base::cipher_name_mcrypt
/** * @var string
* Block Length of the cipher * @access private
* */
* RC4 is a stream cipher var $cipher_name_mcrypt = 'arcfour';
* so we the block_size to 0
* /**
* @see Crypt_Base::block_size * Holds whether performance-optimized $inline_crypt() can/should be used.
* @var int *
* @access private * @see \phpseclib\Crypt\Base::inline_crypt
*/ * @var mixed
var $block_size = 0; * @access private
*/
/** var $use_inline_crypt = false; // currently not available
* Key Length (in bytes)
* /**
* @see Crypt_RC4::setKeyLength() * The Key
* @var int *
* @access private * @see self::setKey()
*/ * @var string
var $key_length = 128; // = 1024 bits * @access private
*/
/** var $key = "\0";
* The namespace used by the cipher for its constants.
* /**
* @see Crypt_Base::const_namespace * The Key Stream for decryption and encryption
* @var string *
* @access private * @see self::setKey()
*/ * @var array
var $const_namespace = 'RC4'; * @access private
*/
/** var $stream;
* The mcrypt specific name of the cipher
* /**
* @see Crypt_Base::cipher_name_mcrypt * Default Constructor.
* @var string *
* @access private * Determines whether or not the mcrypt extension should be used.
*/ *
var $cipher_name_mcrypt = 'arcfour'; * @see \phpseclib\Crypt\Base::__construct()
* @return \phpseclib\Crypt\RC4
/** * @access public
* Holds whether performance-optimized $inline_crypt() can/should be used. */
* function __construct()
* @see Crypt_Base::inline_crypt {
* @var mixed parent::__construct(Base::MODE_STREAM);
* @access private }
*/
var $use_inline_crypt = false; // currently not available /**
* Test for engine validity
/** *
* The Key * This is mainly just a wrapper to set things up for \phpseclib\Crypt\Base::isValidEngine()
* *
* @see self::setKey() * @see \phpseclib\Crypt\Base::__construct()
* @var string * @param int $engine
* @access private * @access public
*/ * @return bool
var $key = "\0"; */
function isValidEngine($engine)
/** {
* The Key Stream for decryption and encryption if ($engine == Base::ENGINE_OPENSSL) {
* if (version_compare(PHP_VERSION, '5.3.7') >= 0) {
* @see self::setKey() $this->cipher_name_openssl = 'rc4-40';
* @var array } else {
* @access private switch (strlen($this->key)) {
*/ case 5:
var $stream; $this->cipher_name_openssl = 'rc4-40';
break;
/** case 8:
* Default Constructor. $this->cipher_name_openssl = 'rc4-64';
* break;
* Determines whether or not the mcrypt extension should be used. case 16:
* $this->cipher_name_openssl = 'rc4';
* @see Crypt_Base::Crypt_Base() break;
* @return Crypt_RC4 default:
* @access public return false;
*/ }
function Crypt_RC4() }
{ }
parent::Crypt_Base(CRYPT_MODE_STREAM);
} return parent::isValidEngine($engine);
}
/**
* Test for engine validity /**
* * Dummy function.
* This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine() *
* * Some protocols, such as WEP, prepend an "initialization vector" to the key, effectively creating a new key [1].
* @see Crypt_Base::Crypt_Base() * If you need to use an initialization vector in this manner, feel free to prepend it to the key, yourself, before
* @param int $engine * calling setKey().
* @access public *
* @return bool * [1] WEP's initialization vectors (IV's) are used in a somewhat insecure way. Since, in that protocol,
*/ * the IV's are relatively easy to predict, an attack described by
function isValidEngine($engine) * {@link http://www.drizzle.com/~aboba/IEEE/rc4_ksaproc.pdf Scott Fluhrer, Itsik Mantin, and Adi Shamir}
{ * can be used to quickly guess at the rest of the key. The following links elaborate:
switch ($engine) { *
case CRYPT_ENGINE_OPENSSL: * {@link http://www.rsa.com/rsalabs/node.asp?id=2009 http://www.rsa.com/rsalabs/node.asp?id=2009}
switch (strlen($this->key)) { * {@link http://en.wikipedia.org/wiki/Related_key_attack http://en.wikipedia.org/wiki/Related_key_attack}
case 5: *
$this->cipher_name_openssl = 'rc4-40'; * @param string $iv
break; * @see self::setKey()
case 8: * @access public
$this->cipher_name_openssl = 'rc4-64'; */
break; function setIV($iv)
case 16: {
$this->cipher_name_openssl = 'rc4'; }
break;
default: /**
return false; * Sets the key length
} *
} * Keys can be between 1 and 256 bytes long.
*
return parent::isValidEngine($engine); * @access public
} * @param int $length
*/
/** function setKeyLength($length)
* Dummy function. {
* if ($length < 8) {
* Some protocols, such as WEP, prepend an "initialization vector" to the key, effectively creating a new key [1]. $this->key_length = 1;
* If you need to use an initialization vector in this manner, feel free to prepend it to the key, yourself, before } elseif ($length > 2048) {
* calling setKey(). $this->key_length = 256;
* } else {
* [1] WEP's initialization vectors (IV's) are used in a somewhat insecure way. Since, in that protocol, $this->key_length = $length >> 3;
* the IV's are relatively easy to predict, an attack described by }
* {@link http://www.drizzle.com/~aboba/IEEE/rc4_ksaproc.pdf Scott Fluhrer, Itsik Mantin, and Adi Shamir}
* can be used to quickly guess at the rest of the key. The following links elaborate: parent::setKeyLength($length);
* }
* {@link http://www.rsa.com/rsalabs/node.asp?id=2009 http://www.rsa.com/rsalabs/node.asp?id=2009}
* {@link http://en.wikipedia.org/wiki/Related_key_attack http://en.wikipedia.org/wiki/Related_key_attack} /**
* * Encrypts a message.
* @param string $iv *
* @see self::setKey() * @see \phpseclib\Crypt\Base::decrypt()
* @access public * @see self::_crypt()
*/ * @access public
function setIV($iv) * @param string $plaintext
{ * @return string $ciphertext
} */
function encrypt($plaintext)
/** {
* Sets the key length if ($this->engine != Base::ENGINE_INTERNAL) {
* return parent::encrypt($plaintext);
* Keys can be between 1 and 256 bytes long. }
* return $this->_crypt($plaintext, self::ENCRYPT);
* @access public }
* @param int $length
*/ /**
function setKeyLength($length) * Decrypts a message.
{ *
if ($length < 8) { * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)).
$this->key_length = 1; * At least if the continuous buffer is disabled.
} elseif ($length > 2048) { *
$this->key_length = 256; * @see \phpseclib\Crypt\Base::encrypt()
} else { * @see self::_crypt()
$this->key_length = $length >> 3; * @access public
} * @param string $ciphertext
* @return string $plaintext
parent::setKeyLength($length); */
} function decrypt($ciphertext)
{
/** if ($this->engine != Base::ENGINE_INTERNAL) {
* Encrypts a message. return parent::decrypt($ciphertext);
* }
* @see Crypt_Base::decrypt() return $this->_crypt($ciphertext, self::DECRYPT);
* @see self::_crypt() }
* @access public
* @param string $plaintext /**
* @return string $ciphertext * Encrypts a block
*/ *
function encrypt($plaintext) * @access private
{ * @param string $in
if ($this->engine != CRYPT_ENGINE_INTERNAL) { */
return parent::encrypt($plaintext); function _encryptBlock($in)
} {
return $this->_crypt($plaintext, CRYPT_RC4_ENCRYPT); // RC4 does not utilize this method
} }
/** /**
* Decrypts a message. * Decrypts a block
* *
* $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)). * @access private
* At least if the continuous buffer is disabled. * @param string $in
* */
* @see Crypt_Base::encrypt() function _decryptBlock($in)
* @see self::_crypt() {
* @access public // RC4 does not utilize this method
* @param string $ciphertext }
* @return string $plaintext
*/ /**
function decrypt($ciphertext) * Setup the key (expansion)
{ *
if ($this->engine != CRYPT_ENGINE_INTERNAL) { * @see \phpseclib\Crypt\Base::_setupKey()
return parent::decrypt($ciphertext); * @access private
} */
return $this->_crypt($ciphertext, CRYPT_RC4_DECRYPT); function _setupKey()
} {
$key = $this->key;
$keyLength = strlen($key);
/** $keyStream = range(0, 255);
* Setup the key (expansion) $j = 0;
* for ($i = 0; $i < 256; $i++) {
* @see Crypt_Base::_setupKey() $j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255;
* @access private $temp = $keyStream[$i];
*/ $keyStream[$i] = $keyStream[$j];
function _setupKey() $keyStream[$j] = $temp;
{ }
$key = $this->key;
$keyLength = strlen($key); $this->stream = array();
$keyStream = range(0, 255); $this->stream[self::DECRYPT] = $this->stream[self::ENCRYPT] = array(
$j = 0; 0, // index $i
for ($i = 0; $i < 256; $i++) { 0, // index $j
$j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255; $keyStream
$temp = $keyStream[$i]; );
$keyStream[$i] = $keyStream[$j]; }
$keyStream[$j] = $temp;
} /**
* Encrypts or decrypts a message.
$this->stream = array(); *
$this->stream[CRYPT_RC4_DECRYPT] = $this->stream[CRYPT_RC4_ENCRYPT] = array( * @see self::encrypt()
0, // index $i * @see self::decrypt()
0, // index $j * @access private
$keyStream * @param string $text
); * @param int $mode
} * @return string $text
*/
/** function _crypt($text, $mode)
* Encrypts or decrypts a message. {
* if ($this->changed) {
* @see self::encrypt() $this->_setup();
* @see self::decrypt() $this->changed = false;
* @access private }
* @param string $text
* @param int $mode $stream = &$this->stream[$mode];
* @return string $text if ($this->continuousBuffer) {
*/ $i = &$stream[0];
function _crypt($text, $mode) $j = &$stream[1];
{ $keyStream = &$stream[2];
if ($this->changed) { } else {
$this->_setup(); $i = $stream[0];
$this->changed = false; $j = $stream[1];
} $keyStream = $stream[2];
}
$stream = &$this->stream[$mode];
if ($this->continuousBuffer) { $len = strlen($text);
$i = &$stream[0]; for ($k = 0; $k < $len; ++$k) {
$j = &$stream[1]; $i = ($i + 1) & 255;
$keyStream = &$stream[2]; $ksi = $keyStream[$i];
} else { $j = ($j + $ksi) & 255;
$i = $stream[0]; $ksj = $keyStream[$j];
$j = $stream[1];
$keyStream = $stream[2]; $keyStream[$i] = $ksj;
} $keyStream[$j] = $ksi;
$text[$k] = $text[$k] ^ chr($keyStream[($ksj + $ksi) & 255]);
$len = strlen($text); }
for ($k = 0; $k < $len; ++$k) {
$i = ($i + 1) & 255; return $text;
$ksi = $keyStream[$i]; }
$j = ($j + $ksi) & 255; }
$ksj = $keyStream[$j];
$keyStream[$i] = $ksj;
$keyStream[$j] = $ksi;
$text[$k] = $text[$k] ^ chr($keyStream[($ksj + $ksi) & 255]);
}
return $text;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,334 +1,270 @@
<?php <?php
/** /**
* Random Number Generator * Random Number Generator
* *
* The idea behind this function is that it can be easily replaced with your own crypt_random_string() * PHP version 5
* function. eg. maybe you have a better source of entropy for creating the initial states or whatever. *
* * Here's a short example of how to use this library:
* PHP versions 4 and 5 * <code>
* * <?php
* Here's a short example of how to use this library: * include 'vendor/autoload.php';
* <code> *
* <?php * echo bin2hex(\phpseclib\Crypt\Random::string(8));
* include 'Crypt/Random.php'; * ?>
* * </code>
* echo bin2hex(crypt_random_string(8)); *
* ?> * @category Crypt
* </code> * @package Random
* * @author Jim Wigginton <terrafrost@php.net>
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy * @copyright 2007 Jim Wigginton
* of this software and associated documentation files (the "Software"), to deal * @license http://www.opensource.org/licenses/mit-license.html MIT License
* in the Software without restriction, including without limitation the rights * @link http://phpseclib.sourceforge.net
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions: namespace phpseclib\Crypt;
*
* The above copyright notice and this permission notice shall be included in /**
* all copies or substantial portions of the Software. * Pure-PHP Random Number Generator
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * @package Random
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * @author Jim Wigginton <terrafrost@php.net>
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * @access public
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, class Random
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN {
* THE SOFTWARE. /**
* * Generate a random string.
* @category Crypt *
* @package Crypt_Random * Although microoptimizations are generally discouraged as they impair readability this function is ripe with
* @author Jim Wigginton <terrafrost@php.net> * microoptimizations because this function has the potential of being called a huge number of times.
* @copyright 2007 Jim Wigginton * eg. for RSA key generation.
* @license http://www.opensource.org/licenses/mit-license.html MIT License *
* @link http://phpseclib.sourceforge.net * @param int $length
*/ * @return string
*/
// laravel is a PHP framework that utilizes phpseclib. laravel workbenches may, independently, static function string($length)
// have phpseclib as a requirement as well. if you're developing such a program you may encounter {
// a "Cannot redeclare crypt_random_string()" error. if (version_compare(PHP_VERSION, '7.0.0', '>=')) {
if (!function_exists('crypt_random_string')) { try {
/** return \random_bytes($length);
* "Is Windows" test } catch (\Throwable $e) {
* // If a sufficient source of randomness is unavailable, random_bytes() will throw an
* @access private // object that implements the Throwable interface (Exception, TypeError, Error).
*/ // We don't actually need to do anything here. The string() method should just continue
define('CRYPT_RANDOM_IS_WINDOWS', strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'); // as normal. Note, however, that if we don't have a sufficient source of randomness for
// random_bytes(), most of the other calls here will fail too, so we'll end up using
/** // the PHP implementation.
* Generate a random string. }
* }
* Although microoptimizations are generally discouraged as they impair readability this function is ripe with
* microoptimizations because this function has the potential of being called a huge number of times. if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
* eg. for RSA key generation. // method 1. prior to PHP 5.3 this would call rand() on windows hence the function_exists('class_alias') call.
* // ie. class_alias is a function that was introduced in PHP 5.3
* @param int $length if (extension_loaded('mcrypt') && function_exists('class_alias')) {
* @return string return @mcrypt_create_iv($length);
* @access public }
*/ // method 2. openssl_random_pseudo_bytes was introduced in PHP 5.3.0 but prior to PHP 5.3.4 there was,
function crypt_random_string($length) // to quote <http://php.net/ChangeLog-5.php#5.3.4>, "possible blocking behavior". as of 5.3.4
{ // openssl_random_pseudo_bytes and mcrypt_create_iv do the exact same thing on Windows. ie. they both
if (CRYPT_RANDOM_IS_WINDOWS) { // call php_win32_get_random_bytes():
// method 1. prior to PHP 5.3, mcrypt_create_iv() would call rand() on windows //
if (extension_loaded('mcrypt') && version_compare(PHP_VERSION, '5.3.0', '>=')) { // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/openssl/openssl.c#L5008
return mcrypt_create_iv($length); // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1392
} //
// method 2. openssl_random_pseudo_bytes was introduced in PHP 5.3.0 but prior to PHP 5.3.4 there was, // php_win32_get_random_bytes() is defined thusly:
// to quote <http://php.net/ChangeLog-5.php#5.3.4>, "possible blocking behavior". as of 5.3.4 //
// openssl_random_pseudo_bytes and mcrypt_create_iv do the exact same thing on Windows. ie. they both // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/win32/winutil.c#L80
// call php_win32_get_random_bytes(): //
// // we're calling it, all the same, in the off chance that the mcrypt extension is not available
// https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/openssl/openssl.c#L5008 if (extension_loaded('openssl') && version_compare(PHP_VERSION, '5.3.4', '>=')) {
// https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1392 return openssl_random_pseudo_bytes($length);
// }
// php_win32_get_random_bytes() is defined thusly: } else {
// // method 1. the fastest
// https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/win32/winutil.c#L80 if (extension_loaded('openssl')) {
// return openssl_random_pseudo_bytes($length);
// we're calling it, all the same, in the off chance that the mcrypt extension is not available }
if (extension_loaded('openssl') && version_compare(PHP_VERSION, '5.3.4', '>=')) { // method 2
return openssl_random_pseudo_bytes($length); static $fp = true;
} if ($fp === true) {
} else { // warning's will be output unles the error suppression operator is used. errors such as
// method 1. the fastest // "open_basedir restriction in effect", "Permission denied", "No such file or directory", etc.
if (extension_loaded('openssl') && version_compare(PHP_VERSION, '5.3.0', '>=')) { $fp = @fopen('/dev/urandom', 'rb');
return openssl_random_pseudo_bytes($length); }
} if ($fp !== true && $fp !== false) { // surprisingly faster than !is_bool() or is_resource()
// method 2 return fread($fp, $length);
static $fp = true; }
if ($fp === true) { // method 3. pretty much does the same thing as method 2 per the following url:
// warning's will be output unles the error suppression operator is used. errors such as // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1391
// "open_basedir restriction in effect", "Permission denied", "No such file or directory", etc. // surprisingly slower than method 2. maybe that's because mcrypt_create_iv does a bunch of error checking that we're
$fp = @fopen('/dev/urandom', 'rb'); // not doing. regardless, this'll only be called if this PHP script couldn't open /dev/urandom due to open_basedir
} // restrictions or some such
if ($fp !== true && $fp !== false) { // surprisingly faster than !is_bool() or is_resource() if (extension_loaded('mcrypt')) {
return fread($fp, $length); return @mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
} }
// method 3. pretty much does the same thing as method 2 per the following url: }
// https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1391 // at this point we have no choice but to use a pure-PHP CSPRNG
// surprisingly slower than method 2. maybe that's because mcrypt_create_iv does a bunch of error checking that we're
// not doing. regardless, this'll only be called if this PHP script couldn't open /dev/urandom due to open_basedir // cascade entropy across multiple PHP instances by fixing the session and collecting all
// restrictions or some such // environmental variables, including the previous session data and the current session
if (extension_loaded('mcrypt')) { // data.
return mcrypt_create_iv($length, MCRYPT_DEV_URANDOM); //
} // mt_rand seeds itself by looking at the PID and the time, both of which are (relatively)
} // easy to guess at. linux uses mouse clicks, keyboard timings, etc, as entropy sources, but
// at this point we have no choice but to use a pure-PHP CSPRNG // PHP isn't low level to be able to use those as sources and on a web server there's not likely
// going to be a ton of keyboard or mouse action. web servers do have one thing that we can use
// cascade entropy across multiple PHP instances by fixing the session and collecting all // however, a ton of people visiting the website. obviously you don't want to base your seeding
// environmental variables, including the previous session data and the current session // soley on parameters a potential attacker sends but (1) not everything in $_SERVER is controlled
// data. // by the user and (2) this isn't just looking at the data sent by the current user - it's based
// // on the data sent by all users. one user requests the page and a hash of their info is saved.
// mt_rand seeds itself by looking at the PID and the time, both of which are (relatively) // another user visits the page and the serialization of their data is utilized along with the
// easy to guess at. linux uses mouse clicks, keyboard timings, etc, as entropy sources, but // server envirnment stuff and a hash of the previous http request data (which itself utilizes
// PHP isn't low level to be able to use those as sources and on a web server there's not likely // a hash of the session data before that). certainly an attacker should be assumed to have
// going to be a ton of keyboard or mouse action. web servers do have one thing that we can use // full control over his own http requests. he, however, is not going to have control over
// however, a ton of people visiting the website. obviously you don't want to base your seeding // everyone's http requests.
// soley on parameters a potential attacker sends but (1) not everything in $_SERVER is controlled static $crypto = false, $v;
// by the user and (2) this isn't just looking at the data sent by the current user - it's based if ($crypto === false) {
// on the data sent by all users. one user requests the page and a hash of their info is saved. // save old session data
// another user visits the page and the serialization of their data is utilized along with the $old_session_id = session_id();
// server envirnment stuff and a hash of the previous http request data (which itself utilizes $old_use_cookies = ini_get('session.use_cookies');
// a hash of the session data before that). certainly an attacker should be assumed to have $old_session_cache_limiter = session_cache_limiter();
// full control over his own http requests. he, however, is not going to have control over $_OLD_SESSION = isset($_SESSION) ? $_SESSION : false;
// everyone's http requests. if ($old_session_id != '') {
static $crypto = false, $v; session_write_close();
if ($crypto === false) { }
// save old session data
$old_session_id = session_id(); session_id(1);
$old_use_cookies = ini_get('session.use_cookies'); ini_set('session.use_cookies', 0);
$old_session_cache_limiter = session_cache_limiter(); session_cache_limiter('');
$_OLD_SESSION = isset($_SESSION) ? $_SESSION : false; session_start();
if ($old_session_id != '') {
session_write_close(); $v = $seed = $_SESSION['seed'] = pack('H*', sha1(
} (isset($_SERVER) ? phpseclib_safe_serialize($_SERVER) : '') .
(isset($_POST) ? phpseclib_safe_serialize($_POST) : '') .
session_id(1); (isset($_GET) ? phpseclib_safe_serialize($_GET) : '') .
ini_set('session.use_cookies', 0); (isset($_COOKIE) ? phpseclib_safe_serialize($_COOKIE) : '') .
session_cache_limiter(''); phpseclib_safe_serialize($GLOBALS) .
session_start(); phpseclib_safe_serialize($_SESSION) .
phpseclib_safe_serialize($_OLD_SESSION)
$v = $seed = $_SESSION['seed'] = pack('H*', sha1( ));
(isset($_SERVER) ? phpseclib_safe_serialize($_SERVER) : '') . if (!isset($_SESSION['count'])) {
(isset($_POST) ? phpseclib_safe_serialize($_POST) : '') . $_SESSION['count'] = 0;
(isset($_GET) ? phpseclib_safe_serialize($_GET) : '') . }
(isset($_COOKIE) ? phpseclib_safe_serialize($_COOKIE) : '') . $_SESSION['count']++;
phpseclib_safe_serialize($GLOBALS) .
phpseclib_safe_serialize($_SESSION) . session_write_close();
phpseclib_safe_serialize($_OLD_SESSION)
)); // restore old session data
if (!isset($_SESSION['count'])) { if ($old_session_id != '') {
$_SESSION['count'] = 0; session_id($old_session_id);
} session_start();
$_SESSION['count']++; ini_set('session.use_cookies', $old_use_cookies);
session_cache_limiter($old_session_cache_limiter);
session_write_close(); } else {
if ($_OLD_SESSION !== false) {
// restore old session data $_SESSION = $_OLD_SESSION;
if ($old_session_id != '') { unset($_OLD_SESSION);
session_id($old_session_id); } else {
session_start(); unset($_SESSION);
ini_set('session.use_cookies', $old_use_cookies); }
session_cache_limiter($old_session_cache_limiter); }
} else {
if ($_OLD_SESSION !== false) { // in SSH2 a shared secret and an exchange hash are generated through the key exchange process.
$_SESSION = $_OLD_SESSION; // the IV client to server is the hash of that "nonce" with the letter A and for the encryption key it's the letter C.
unset($_OLD_SESSION); // if the hash doesn't produce enough a key or an IV that's long enough concat successive hashes of the
} else { // original hash and the current hash. we'll be emulating that. for more info see the following URL:
unset($_SESSION); //
} // http://tools.ietf.org/html/rfc4253#section-7.2
} //
// see the is_string($crypto) part for an example of how to expand the keys
// in SSH2 a shared secret and an exchange hash are generated through the key exchange process. $key = pack('H*', sha1($seed . 'A'));
// the IV client to server is the hash of that "nonce" with the letter A and for the encryption key it's the letter C. $iv = pack('H*', sha1($seed . 'C'));
// if the hash doesn't produce enough a key or an IV that's long enough concat successive hashes of the
// original hash and the current hash. we'll be emulating that. for more info see the following URL: // ciphers are used as per the nist.gov link below. also, see this link:
// //
// http://tools.ietf.org/html/rfc4253#section-7.2 // http://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator#Designs_based_on_cryptographic_primitives
// switch (true) {
// see the is_string($crypto) part for an example of how to expand the keys case class_exists('\phpseclib\Crypt\AES'):
$key = pack('H*', sha1($seed . 'A')); $crypto = new AES(Base::MODE_CTR);
$iv = pack('H*', sha1($seed . 'C')); break;
case class_exists('\phpseclib\Crypt\Twofish'):
// ciphers are used as per the nist.gov link below. also, see this link: $crypto = new Twofish(Base::MODE_CTR);
// break;
// http://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator#Designs_based_on_cryptographic_primitives case class_exists('\phpseclib\Crypt\Blowfish'):
switch (true) { $crypto = new Blowfish(Base::MODE_CTR);
case phpseclib_resolve_include_path('Crypt/AES.php'): break;
if (!class_exists('Crypt_AES')) { case class_exists('\phpseclib\Crypt\TripleDES'):
include_once 'AES.php'; $crypto = new TripleDES(Base::MODE_CTR);
} break;
$crypto = new Crypt_AES(CRYPT_AES_MODE_CTR); case class_exists('\phpseclib\Crypt\DES'):
break; $crypto = new DES(Base::MODE_CTR);
case phpseclib_resolve_include_path('Crypt/Twofish.php'): break;
if (!class_exists('Crypt_Twofish')) { case class_exists('\phpseclib\Crypt\RC4'):
include_once 'Twofish.php'; $crypto = new RC4();
} break;
$crypto = new Crypt_Twofish(CRYPT_TWOFISH_MODE_CTR); default:
break; user_error(__CLASS__ . ' requires at least one symmetric cipher be loaded');
case phpseclib_resolve_include_path('Crypt/Blowfish.php'): return false;
if (!class_exists('Crypt_Blowfish')) { }
include_once 'Blowfish.php';
} $crypto->setKey($key);
$crypto = new Crypt_Blowfish(CRYPT_BLOWFISH_MODE_CTR); $crypto->setIV($iv);
break; $crypto->enableContinuousBuffer();
case phpseclib_resolve_include_path('Crypt/TripleDES.php'): }
if (!class_exists('Crypt_TripleDES')) {
include_once 'TripleDES.php'; //return $crypto->encrypt(str_repeat("\0", $length));
}
$crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CTR); // the following is based off of ANSI X9.31:
break; //
case phpseclib_resolve_include_path('Crypt/DES.php'): // http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf
if (!class_exists('Crypt_DES')) { //
include_once 'DES.php'; // OpenSSL uses that same standard for it's random numbers:
} //
$crypto = new Crypt_DES(CRYPT_DES_MODE_CTR); // http://www.opensource.apple.com/source/OpenSSL/OpenSSL-38/openssl/fips-1.0/rand/fips_rand.c
break; // (do a search for "ANS X9.31 A.2.4")
case phpseclib_resolve_include_path('Crypt/RC4.php'): $result = '';
if (!class_exists('Crypt_RC4')) { while (strlen($result) < $length) {
include_once 'RC4.php'; $i = $crypto->encrypt(microtime()); // strlen(microtime()) == 21
} $r = $crypto->encrypt($i ^ $v); // strlen($v) == 20
$crypto = new Crypt_RC4(); $v = $crypto->encrypt($r ^ $i); // strlen($r) == 20
break; $result.= $r;
default: }
user_error('crypt_random_string requires at least one symmetric cipher be loaded'); return substr($result, 0, $length);
return false; }
} }
$crypto->setKey($key); if (!function_exists('phpseclib_safe_serialize')) {
$crypto->setIV($iv); /**
$crypto->enableContinuousBuffer(); * Safely serialize variables
} *
* If a class has a private __sleep() method it'll give a fatal error on PHP 5.2 and earlier.
//return $crypto->encrypt(str_repeat("\0", $length)); * PHP 5.3 will emit a warning.
*
// the following is based off of ANSI X9.31: * @param mixed $arr
// * @access public
// http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf */
// function phpseclib_safe_serialize(&$arr)
// OpenSSL uses that same standard for it's random numbers: {
// if (is_object($arr)) {
// http://www.opensource.apple.com/source/OpenSSL/OpenSSL-38/openssl/fips-1.0/rand/fips_rand.c return '';
// (do a search for "ANS X9.31 A.2.4") }
$result = ''; if (!is_array($arr)) {
while (strlen($result) < $length) { return serialize($arr);
$i = $crypto->encrypt(microtime()); // strlen(microtime()) == 21 }
$r = $crypto->encrypt($i ^ $v); // strlen($v) == 20 // prevent circular array recursion
$v = $crypto->encrypt($r ^ $i); // strlen($r) == 20 if (isset($arr['__phpseclib_marker'])) {
$result.= $r; return '';
} }
return substr($result, 0, $length); $safearr = array();
} $arr['__phpseclib_marker'] = true;
} foreach (array_keys($arr) as $key) {
// do not recurse on the '__phpseclib_marker' key itself, for smaller memory usage
if (!function_exists('phpseclib_safe_serialize')) { if ($key !== '__phpseclib_marker') {
/** $safearr[$key] = phpseclib_safe_serialize($arr[$key]);
* Safely serialize variables }
* }
* If a class has a private __sleep() method it'll give a fatal error on PHP 5.2 and earlier. unset($arr['__phpseclib_marker']);
* PHP 5.3 will emit a warning. return serialize($safearr);
* }
* @param mixed $arr }
* @access public
*/
function phpseclib_safe_serialize(&$arr)
{
if (is_object($arr)) {
return '';
}
if (!is_array($arr)) {
return serialize($arr);
}
// prevent circular array recursion
if (isset($arr['__phpseclib_marker'])) {
return '';
}
$safearr = array();
$arr['__phpseclib_marker'] = true;
foreach (array_keys($arr) as $key) {
// do not recurse on the '__phpseclib_marker' key itself, for smaller memory usage
if ($key !== '__phpseclib_marker') {
$safearr[$key] = phpseclib_safe_serialize($arr[$key]);
}
}
unset($arr['__phpseclib_marker']);
return serialize($safearr);
}
}
if (!function_exists('phpseclib_resolve_include_path')) {
/**
* Resolve filename against the include path.
*
* Wrapper around stream_resolve_include_path() (which was introduced in
* PHP 5.3.2) with fallback implementation for earlier PHP versions.
*
* @param string $filename
* @return string|false
* @access public
*/
function phpseclib_resolve_include_path($filename)
{
if (function_exists('stream_resolve_include_path')) {
return stream_resolve_include_path($filename);
}
// handle non-relative paths
if (file_exists($filename)) {
return realpath($filename);
}
$paths = PATH_SEPARATOR == ':' ?
preg_split('#(?<!phar):#', get_include_path()) :
explode(PATH_SEPARATOR, get_include_path());
foreach ($paths as $prefix) {
// path's specified in include_path don't always end in /
$ds = substr($prefix, -1) == DIRECTORY_SEPARATOR ? '' : DIRECTORY_SEPARATOR;
$file = $prefix . $ds . $filename;
if (file_exists($file)) {
return realpath($file);
}
}
return false;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,505 +1,460 @@
<?php <?php
/** /**
* Pure-PHP implementation of Triple DES. * Pure-PHP implementation of Triple DES.
* *
* Uses mcrypt, if available, and an internal implementation, otherwise. Operates in the EDE3 mode (encrypt-decrypt-encrypt). * Uses mcrypt, if available, and an internal implementation, otherwise. Operates in the EDE3 mode (encrypt-decrypt-encrypt).
* *
* PHP versions 4 and 5 * PHP version 5
* *
* Here's a short example of how to use this library: * Here's a short example of how to use this library:
* <code> * <code>
* <?php * <?php
* include 'Crypt/TripleDES.php'; * include 'vendor/autoload.php';
* *
* $des = new Crypt_TripleDES(); * $des = new \phpseclib\Crypt\TripleDES();
* *
* $des->setKey('abcdefghijklmnopqrstuvwx'); * $des->setKey('abcdefghijklmnopqrstuvwx');
* *
* $size = 10 * 1024; * $size = 10 * 1024;
* $plaintext = ''; * $plaintext = '';
* for ($i = 0; $i < $size; $i++) { * for ($i = 0; $i < $size; $i++) {
* $plaintext.= 'a'; * $plaintext.= 'a';
* } * }
* *
* echo $des->decrypt($des->encrypt($plaintext)); * echo $des->decrypt($des->encrypt($plaintext));
* ?> * ?>
* </code> * </code>
* *
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy * @category Crypt
* of this software and associated documentation files (the "Software"), to deal * @package TripleDES
* in the Software without restriction, including without limitation the rights * @author Jim Wigginton <terrafrost@php.net>
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * @copyright 2007 Jim Wigginton
* copies of the Software, and to permit persons to whom the Software is * @license http://www.opensource.org/licenses/mit-license.html MIT License
* furnished to do so, subject to the following conditions: * @link http://phpseclib.sourceforge.net
* */
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software. namespace phpseclib\Crypt;
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR /**
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * Pure-PHP implementation of Triple DES.
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * @package TripleDES
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * @author Jim Wigginton <terrafrost@php.net>
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * @access public
* THE SOFTWARE. */
* class TripleDES extends DES
* @category Crypt {
* @package Crypt_TripleDES /**
* @author Jim Wigginton <terrafrost@php.net> * Encrypt / decrypt using inner chaining
* @copyright 2007 Jim Wigginton *
* @license http://www.opensource.org/licenses/mit-license.html MIT License * Inner chaining is used by SSH-1 and is generally considered to be less secure then outer chaining (self::MODE_CBC3).
* @link http://phpseclib.sourceforge.net */
*/ const MODE_3CBC = -2;
/** /**
* Include Crypt_DES * Encrypt / decrypt using outer chaining
*/ *
if (!class_exists('Crypt_DES')) { * Outer chaining is used by SSH-2 and when the mode is set to \phpseclib\Crypt\Base::MODE_CBC.
include_once 'DES.php'; */
} const MODE_CBC3 = Base::MODE_CBC;
/**#@+ /**
* @access public * Key Length (in bytes)
* @see self::Crypt_TripleDES() *
*/ * @see \phpseclib\Crypt\TripleDES::setKeyLength()
/** * @var int
* Encrypt / decrypt using inner chaining * @access private
* */
* Inner chaining is used by SSH-1 and is generally considered to be less secure then outer chaining (CRYPT_DES_MODE_CBC3). var $key_length = 24;
*/
define('CRYPT_MODE_3CBC', -2); /**
/** * The default salt used by setPassword()
* BC version of the above. *
*/ * @see \phpseclib\Crypt\Base::password_default_salt
define('CRYPT_DES_MODE_3CBC', -2); * @see \phpseclib\Crypt\Base::setPassword()
/** * @var string
* Encrypt / decrypt using outer chaining * @access private
* */
* Outer chaining is used by SSH-2 and when the mode is set to CRYPT_DES_MODE_CBC. var $password_default_salt = 'phpseclib';
*/
define('CRYPT_MODE_CBC3', CRYPT_MODE_CBC); /**
/** * The mcrypt specific name of the cipher
* BC version of the above. *
*/ * @see \phpseclib\Crypt\DES::cipher_name_mcrypt
define('CRYPT_DES_MODE_CBC3', CRYPT_MODE_CBC3); * @see \phpseclib\Crypt\Base::cipher_name_mcrypt
/**#@-*/ * @var string
* @access private
/** */
* Pure-PHP implementation of Triple DES. var $cipher_name_mcrypt = 'tripledes';
*
* @package Crypt_TripleDES /**
* @author Jim Wigginton <terrafrost@php.net> * Optimizing value while CFB-encrypting
* @access public *
*/ * @see \phpseclib\Crypt\Base::cfb_init_len
class Crypt_TripleDES extends Crypt_DES * @var int
{ * @access private
/** */
* Key Length (in bytes) var $cfb_init_len = 750;
*
* @see Crypt_TripleDES::setKeyLength() /**
* @var int * max possible size of $key
* @access private *
*/ * @see self::setKey()
var $key_length = 24; * @see \phpseclib\Crypt\DES::setKey()
* @var string
/** * @access private
* The default salt used by setPassword() */
* var $key_length_max = 24;
* @see Crypt_Base::password_default_salt
* @see Crypt_Base::setPassword() /**
* @var string * Internal flag whether using self::MODE_3CBC or not
* @access private *
*/ * @var bool
var $password_default_salt = 'phpseclib'; * @access private
*/
/** var $mode_3cbc;
* The namespace used by the cipher for its constants.
* /**
* @see Crypt_DES::const_namespace * The \phpseclib\Crypt\DES objects
* @see Crypt_Base::const_namespace *
* @var string * Used only if $mode_3cbc === true
* @access private *
*/ * @var array
var $const_namespace = 'DES'; * @access private
*/
/** var $des;
* The mcrypt specific name of the cipher
* /**
* @see Crypt_DES::cipher_name_mcrypt * Default Constructor.
* @see Crypt_Base::cipher_name_mcrypt *
* @var string * Determines whether or not the mcrypt extension should be used.
* @access private *
*/ * $mode could be:
var $cipher_name_mcrypt = 'tripledes'; *
* - \phpseclib\Crypt\Base::MODE_ECB
/** *
* Optimizing value while CFB-encrypting * - \phpseclib\Crypt\Base::MODE_CBC
* *
* @see Crypt_Base::cfb_init_len * - \phpseclib\Crypt\Base::MODE_CTR
* @var int *
* @access private * - \phpseclib\Crypt\Base::MODE_CFB
*/ *
var $cfb_init_len = 750; * - \phpseclib\Crypt\Base::MODE_OFB
*
/** * - \phpseclib\Crypt\TripleDES::MODE_3CBC
* max possible size of $key *
* * If not explicitly set, \phpseclib\Crypt\Base::MODE_CBC will be used.
* @see self::setKey() *
* @see Crypt_DES::setKey() * @see \phpseclib\Crypt\DES::__construct()
* @var string * @see \phpseclib\Crypt\Base::__construct()
* @access private * @param int $mode
*/ * @access public
var $key_length_max = 24; */
function __construct($mode = Base::MODE_CBC)
/** {
* Internal flag whether using CRYPT_DES_MODE_3CBC or not switch ($mode) {
* // In case of self::MODE_3CBC, we init as CRYPT_DES_MODE_CBC
* @var bool // and additional flag us internally as 3CBC
* @access private case self::MODE_3CBC:
*/ parent::__construct(Base::MODE_CBC);
var $mode_3cbc; $this->mode_3cbc = true;
/** // This three $des'es will do the 3CBC work (if $key > 64bits)
* The Crypt_DES objects $this->des = array(
* new DES(Base::MODE_CBC),
* Used only if $mode_3cbc === true new DES(Base::MODE_CBC),
* new DES(Base::MODE_CBC),
* @var array );
* @access private
*/ // we're going to be doing the padding, ourselves, so disable it in the \phpseclib\Crypt\DES objects
var $des; $this->des[0]->disablePadding();
$this->des[1]->disablePadding();
/** $this->des[2]->disablePadding();
* Default Constructor. break;
* // If not 3CBC, we init as usual
* Determines whether or not the mcrypt extension should be used. default:
* parent::__construct($mode);
* $mode could be: }
* }
* - CRYPT_DES_MODE_ECB
* /**
* - CRYPT_DES_MODE_CBC * Test for engine validity
* *
* - CRYPT_DES_MODE_CTR * This is mainly just a wrapper to set things up for \phpseclib\Crypt\Base::isValidEngine()
* *
* - CRYPT_DES_MODE_CFB * @see \phpseclib\Crypt\Base::__construct()
* * @param int $engine
* - CRYPT_DES_MODE_OFB * @access public
* * @return bool
* - CRYPT_DES_MODE_3CBC */
* function isValidEngine($engine)
* If not explicitly set, CRYPT_DES_MODE_CBC will be used. {
* if ($engine == self::ENGINE_OPENSSL) {
* @see Crypt_DES::Crypt_DES() $this->cipher_name_openssl_ecb = 'des-ede3';
* @see Crypt_Base::Crypt_Base() $mode = $this->_openssl_translate_mode();
* @param int $mode $this->cipher_name_openssl = $mode == 'ecb' ? 'des-ede3' : 'des-ede3-' . $mode;
* @access public }
*/
function Crypt_TripleDES($mode = CRYPT_MODE_CBC) return parent::isValidEngine($engine);
{ }
switch ($mode) {
// In case of CRYPT_DES_MODE_3CBC, we init as CRYPT_DES_MODE_CBC /**
// and additional flag us internally as 3CBC * Sets the initialization vector. (optional)
case CRYPT_DES_MODE_3CBC: *
parent::Crypt_Base(CRYPT_MODE_CBC); * SetIV is not required when \phpseclib\Crypt\Base::MODE_ECB is being used. If not explicitly set, it'll be assumed
$this->mode_3cbc = true; * to be all zero's.
*
// This three $des'es will do the 3CBC work (if $key > 64bits) * @see \phpseclib\Crypt\Base::setIV()
$this->des = array( * @access public
new Crypt_DES(CRYPT_MODE_CBC), * @param string $iv
new Crypt_DES(CRYPT_MODE_CBC), */
new Crypt_DES(CRYPT_MODE_CBC), function setIV($iv)
); {
parent::setIV($iv);
// we're going to be doing the padding, ourselves, so disable it in the Crypt_DES objects if ($this->mode_3cbc) {
$this->des[0]->disablePadding(); $this->des[0]->setIV($iv);
$this->des[1]->disablePadding(); $this->des[1]->setIV($iv);
$this->des[2]->disablePadding(); $this->des[2]->setIV($iv);
break; }
// If not 3CBC, we init as usual }
default:
parent::Crypt_Base($mode); /**
} * Sets the key length.
} *
* Valid key lengths are 64, 128 and 192
/** *
* Test for engine validity * @see \phpseclib\Crypt\Base:setKeyLength()
* * @access public
* This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine() * @param int $length
* */
* @see Crypt_Base::Crypt_Base() function setKeyLength($length)
* @param int $engine {
* @access public $length >>= 3;
* @return bool switch (true) {
*/ case $length <= 8:
function isValidEngine($engine) $this->key_length = 8;
{ break;
if ($engine == CRYPT_ENGINE_OPENSSL) { case $length <= 16:
$this->cipher_name_openssl_ecb = 'des-ede3'; $this->key_length = 16;
$mode = $this->_openssl_translate_mode(); break;
$this->cipher_name_openssl = $mode == 'ecb' ? 'des-ede3' : 'des-ede3-' . $mode; default:
} $this->key_length = 24;
}
return parent::isValidEngine($engine);
} parent::setKeyLength($length);
}
/**
* Sets the initialization vector. (optional) /**
* * Sets the key.
* SetIV is not required when CRYPT_DES_MODE_ECB is being used. If not explicitly set, it'll be assumed *
* to be all zero's. * Keys can be of any length. Triple DES, itself, can use 128-bit (eg. strlen($key) == 16) or
* * 192-bit (eg. strlen($key) == 24) keys. This function pads and truncates $key as appropriate.
* @see Crypt_Base::setIV() *
* @access public * DES also requires that every eighth bit be a parity bit, however, we'll ignore that.
* @param string $iv *
*/ * If the key is not explicitly set, it'll be assumed to be all null bytes.
function setIV($iv) *
{ * @access public
parent::setIV($iv); * @see \phpseclib\Crypt\DES::setKey()
if ($this->mode_3cbc) { * @see \phpseclib\Crypt\Base::setKey()
$this->des[0]->setIV($iv); * @param string $key
$this->des[1]->setIV($iv); */
$this->des[2]->setIV($iv); function setKey($key)
} {
} $length = $this->explicit_key_length ? $this->key_length : strlen($key);
if ($length > 8) {
/** $key = str_pad(substr($key, 0, 24), 24, chr(0));
* Sets the key length. // if $key is between 64 and 128-bits, use the first 64-bits as the last, per this:
* // http://php.net/function.mcrypt-encrypt#47973
* Valid key lengths are 64, 128 and 192 $key = $length <= 16 ? substr_replace($key, substr($key, 0, 8), 16) : substr($key, 0, 24);
* } else {
* @see Crypt_Base:setKeyLength() $key = str_pad($key, 8, chr(0));
* @access public }
* @param int $length parent::setKey($key);
*/
function setKeyLength($length) // And in case of self::MODE_3CBC:
{ // if key <= 64bits we not need the 3 $des to work,
$length >>= 3; // because we will then act as regular DES-CBC with just a <= 64bit key.
switch (true) { // So only if the key > 64bits (> 8 bytes) we will call setKey() for the 3 $des.
case $length <= 8: if ($this->mode_3cbc && $length > 8) {
$this->key_length = 8; $this->des[0]->setKey(substr($key, 0, 8));
break; $this->des[1]->setKey(substr($key, 8, 8));
case $length <= 16: $this->des[2]->setKey(substr($key, 16, 8));
$this->key_length = 16; }
break; }
default:
$this->key_length = 24; /**
} * Encrypts a message.
*
parent::setKeyLength($length); * @see \phpseclib\Crypt\Base::encrypt()
} * @access public
* @param string $plaintext
/** * @return string $cipertext
* Sets the key. */
* function encrypt($plaintext)
* Keys can be of any length. Triple DES, itself, can use 128-bit (eg. strlen($key) == 16) or {
* 192-bit (eg. strlen($key) == 24) keys. This function pads and truncates $key as appropriate. // parent::en/decrypt() is able to do all the work for all modes and keylengths,
* // except for: self::MODE_3CBC (inner chaining CBC) with a key > 64bits
* DES also requires that every eighth bit be a parity bit, however, we'll ignore that.
* // if the key is smaller then 8, do what we'd normally do
* If the key is not explicitly set, it'll be assumed to be all null bytes. if ($this->mode_3cbc && strlen($this->key) > 8) {
* return $this->des[2]->encrypt(
* @access public $this->des[1]->decrypt(
* @see Crypt_DES::setKey() $this->des[0]->encrypt(
* @see Crypt_Base::setKey() $this->_pad($plaintext)
* @param string $key )
*/ )
function setKey($key) );
{ }
$length = $this->explicit_key_length ? $this->key_length : strlen($key);
if ($length > 8) { return parent::encrypt($plaintext);
$key = str_pad(substr($key, 0, 24), 24, chr(0)); }
// if $key is between 64 and 128-bits, use the first 64-bits as the last, per this:
// http://php.net/function.mcrypt-encrypt#47973 /**
$key = $length <= 16 ? substr_replace($key, substr($key, 0, 8), 16) : substr($key, 0, 24); * Decrypts a message.
} else { *
$key = str_pad($key, 8, chr(0)); * @see \phpseclib\Crypt\Base::decrypt()
} * @access public
parent::setKey($key); * @param string $ciphertext
* @return string $plaintext
// And in case of CRYPT_DES_MODE_3CBC: */
// if key <= 64bits we not need the 3 $des to work, function decrypt($ciphertext)
// because we will then act as regular DES-CBC with just a <= 64bit key. {
// So only if the key > 64bits (> 8 bytes) we will call setKey() for the 3 $des. if ($this->mode_3cbc && strlen($this->key) > 8) {
if ($this->mode_3cbc && $length > 8) { return $this->_unpad(
$this->des[0]->setKey(substr($key, 0, 8)); $this->des[0]->decrypt(
$this->des[1]->setKey(substr($key, 8, 8)); $this->des[1]->encrypt(
$this->des[2]->setKey(substr($key, 16, 8)); $this->des[2]->decrypt(
} str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, "\0")
} )
)
/** )
* Encrypts a message. );
* }
* @see Crypt_Base::encrypt()
* @access public return parent::decrypt($ciphertext);
* @param string $plaintext }
* @return string $cipertext
*/ /**
function encrypt($plaintext) * Treat consecutive "packets" as if they are a continuous buffer.
{ *
// parent::en/decrypt() is able to do all the work for all modes and keylengths, * Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets
// except for: CRYPT_MODE_3CBC (inner chaining CBC) with a key > 64bits * will yield different outputs:
*
// if the key is smaller then 8, do what we'd normally do * <code>
if ($this->mode_3cbc && strlen($this->key) > 8) { * echo $des->encrypt(substr($plaintext, 0, 8));
return $this->des[2]->encrypt( * echo $des->encrypt(substr($plaintext, 8, 8));
$this->des[1]->decrypt( * </code>
$this->des[0]->encrypt( * <code>
$this->_pad($plaintext) * echo $des->encrypt($plaintext);
) * </code>
) *
); * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
} * another, as demonstrated with the following:
*
return parent::encrypt($plaintext); * <code>
} * $des->encrypt(substr($plaintext, 0, 8));
* echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
/** * </code>
* Decrypts a message. * <code>
* * echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
* @see Crypt_Base::decrypt() * </code>
* @access public *
* @param string $ciphertext * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
* @return string $plaintext * outputs. The reason is due to the fact that the initialization vector's change after every encryption /
*/ * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
function decrypt($ciphertext) *
{ * Put another way, when the continuous buffer is enabled, the state of the \phpseclib\Crypt\DES() object changes after each
if ($this->mode_3cbc && strlen($this->key) > 8) { * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
return $this->_unpad( * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
$this->des[0]->decrypt( * however, they are also less intuitive and more likely to cause you problems.
$this->des[1]->encrypt( *
$this->des[2]->decrypt( * @see \phpseclib\Crypt\Base::enableContinuousBuffer()
str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, "\0") * @see self::disableContinuousBuffer()
) * @access public
) */
) function enableContinuousBuffer()
); {
} parent::enableContinuousBuffer();
if ($this->mode_3cbc) {
return parent::decrypt($ciphertext); $this->des[0]->enableContinuousBuffer();
} $this->des[1]->enableContinuousBuffer();
$this->des[2]->enableContinuousBuffer();
/** }
* Treat consecutive "packets" as if they are a continuous buffer. }
*
* Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets /**
* will yield different outputs: * Treat consecutive packets as if they are a discontinuous buffer.
* *
* <code> * The default behavior.
* echo $des->encrypt(substr($plaintext, 0, 8)); *
* echo $des->encrypt(substr($plaintext, 8, 8)); * @see \phpseclib\Crypt\Base::disableContinuousBuffer()
* </code> * @see self::enableContinuousBuffer()
* <code> * @access public
* echo $des->encrypt($plaintext); */
* </code> function disableContinuousBuffer()
* {
* The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates parent::disableContinuousBuffer();
* another, as demonstrated with the following: if ($this->mode_3cbc) {
* $this->des[0]->disableContinuousBuffer();
* <code> $this->des[1]->disableContinuousBuffer();
* $des->encrypt(substr($plaintext, 0, 8)); $this->des[2]->disableContinuousBuffer();
* echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8))); }
* </code> }
* <code>
* echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8))); /**
* </code> * Creates the key schedule
* *
* With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different * @see \phpseclib\Crypt\DES::_setupKey()
* outputs. The reason is due to the fact that the initialization vector's change after every encryption / * @see \phpseclib\Crypt\Base::_setupKey()
* decryption round when the continuous buffer is enabled. When it's disabled, they remain constant. * @access private
* */
* Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each function _setupKey()
* encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that {
* continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them), switch (true) {
* however, they are also less intuitive and more likely to cause you problems. // if $key <= 64bits we configure our internal pure-php cipher engine
* // to act as regular [1]DES, not as 3DES. mcrypt.so::tripledes does the same.
* @see Crypt_Base::enableContinuousBuffer() case strlen($this->key) <= 8:
* @see self::disableContinuousBuffer() $this->des_rounds = 1;
* @access public break;
*/
function enableContinuousBuffer() // otherwise, if $key > 64bits, we configure our engine to work as 3DES.
{ default:
parent::enableContinuousBuffer(); $this->des_rounds = 3;
if ($this->mode_3cbc) {
$this->des[0]->enableContinuousBuffer(); // (only) if 3CBC is used we have, of course, to setup the $des[0-2] keys also separately.
$this->des[1]->enableContinuousBuffer(); if ($this->mode_3cbc) {
$this->des[2]->enableContinuousBuffer(); $this->des[0]->_setupKey();
} $this->des[1]->_setupKey();
} $this->des[2]->_setupKey();
/** // because $des[0-2] will, now, do all the work we can return here
* Treat consecutive packets as if they are a discontinuous buffer. // not need unnecessary stress parent::_setupKey() with our, now unused, $key.
* return;
* The default behavior. }
* }
* @see Crypt_Base::disableContinuousBuffer() // setup our key
* @see self::enableContinuousBuffer() parent::_setupKey();
* @access public }
*/
function disableContinuousBuffer() /**
{ * Sets the internal crypt engine
parent::disableContinuousBuffer(); *
if ($this->mode_3cbc) { * @see \phpseclib\Crypt\Base::__construct()
$this->des[0]->disableContinuousBuffer(); * @see \phpseclib\Crypt\Base::setPreferredEngine()
$this->des[1]->disableContinuousBuffer(); * @param int $engine
$this->des[2]->disableContinuousBuffer(); * @access public
} * @return int
} */
function setPreferredEngine($engine)
/** {
* Creates the key schedule if ($this->mode_3cbc) {
* $this->des[0]->setPreferredEngine($engine);
* @see Crypt_DES::_setupKey() $this->des[1]->setPreferredEngine($engine);
* @see Crypt_Base::_setupKey() $this->des[2]->setPreferredEngine($engine);
* @access private }
*/
function _setupKey() return parent::setPreferredEngine($engine);
{ }
switch (true) { }
// if $key <= 64bits we configure our internal pure-php cipher engine
// to act as regular [1]DES, not as 3DES. mcrypt.so::tripledes does the same.
case strlen($this->key) <= 8:
$this->des_rounds = 1;
break;
// otherwise, if $key > 64bits, we configure our engine to work as 3DES.
default:
$this->des_rounds = 3;
// (only) if 3CBC is used we have, of course, to setup the $des[0-2] keys also separately.
if ($this->mode_3cbc) {
$this->des[0]->_setupKey();
$this->des[1]->_setupKey();
$this->des[2]->_setupKey();
// because $des[0-2] will, now, do all the work we can return here
// not need unnecessary stress parent::_setupKey() with our, now unused, $key.
return;
}
}
// setup our key
parent::_setupKey();
}
/**
* Sets the internal crypt engine
*
* @see Crypt_Base::Crypt_Base()
* @see Crypt_Base::setPreferredEngine()
* @param int $engine
* @access public
* @return int
*/
function setPreferredEngine($engine)
{
if ($this->mode_3cbc) {
$this->des[0]->setPreferredEngine($engine);
$this->des[1]->setPreferredEngine($engine);
$this->des[2]->setPreferredEngine($engine);
}
return parent::setPreferredEngine($engine);
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,47 @@
<?php
/**
* Pure-PHP ASN.1 Parser
*
* PHP version 5
*
* @category File
* @package ASN1
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2012 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace phpseclib\File\ASN1;
/**
* ASN.1 Element
*
* Bypass normal encoding rules in phpseclib\File\ASN1::encodeDER()
*
* @package ASN1
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
class Element
{
/**
* Raw element value
*
* @var string
* @access private
*/
var $element;
/**
* Constructor
*
* @param string $encoded
* @return \phpseclib\File\ASN1\Element
* @access public
*/
function __construct($encoded)
{
$this->element = $encoded;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,360 +1,337 @@
<?php <?php
/** /**
* Pure-PHP implementation of SCP. * Pure-PHP implementation of SCP.
* *
* PHP versions 4 and 5 * PHP version 5
* *
* The API for this library is modeled after the API from PHP's {@link http://php.net/book.ftp FTP extension}. * The API for this library is modeled after the API from PHP's {@link http://php.net/book.ftp FTP extension}.
* *
* Here's a short example of how to use this library: * Here's a short example of how to use this library:
* <code> * <code>
* <?php * <?php
* include 'Net/SCP.php'; * include 'vendor/autoload.php';
* include 'Net/SSH2.php'; *
* * $ssh = new \phpseclib\Net\SSH2('www.domain.tld');
* $ssh = new Net_SSH2('www.domain.tld'); * if (!$ssh->login('username', 'password')) {
* if (!$ssh->login('username', 'password')) { * exit('bad login');
* exit('bad login'); * }
* } * $scp = new \phpseclib\Net\SCP($ssh);
* *
* $scp = new Net_SCP($ssh); * $scp->put('abcd', str_repeat('x', 1024*1024));
* $scp->put('abcd', str_repeat('x', 1024*1024)); * ?>
* ?> * </code>
* </code> *
* * @category Net
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy * @package SCP
* of this software and associated documentation files (the "Software"), to deal * @author Jim Wigginton <terrafrost@php.net>
* in the Software without restriction, including without limitation the rights * @copyright 2010 Jim Wigginton
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * @license http://www.opensource.org/licenses/mit-license.html MIT License
* copies of the Software, and to permit persons to whom the Software is * @link http://phpseclib.sourceforge.net
* furnished to do so, subject to the following conditions: */
*
* The above copyright notice and this permission notice shall be included in namespace phpseclib\Net;
* all copies or substantial portions of the Software.
* /**
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * Pure-PHP implementations of SCP.
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * @package SCP
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * @author Jim Wigginton <terrafrost@php.net>
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * @access public
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */
* THE SOFTWARE. class SCP
* {
* @category Net /**#@+
* @package Net_SCP * @access public
* @author Jim Wigginton <terrafrost@php.net> * @see \phpseclib\Net\SCP::put()
* @copyright 2010 Jim Wigginton */
* @license http://www.opensource.org/licenses/mit-license.html MIT License /**
* @link http://phpseclib.sourceforge.net * Reads data from a local file.
*/ */
const SOURCE_LOCAL_FILE = 1;
/**#@+ /**
* @access public * Reads data from a string.
* @see self::put() */
*/ const SOURCE_STRING = 2;
/** /**#@-*/
* Reads data from a local file.
*/ /**#@+
define('NET_SCP_LOCAL_FILE', 1); * @access private
/** * @see \phpseclib\Net\SCP::_send()
* Reads data from a string. * @see \phpseclib\Net\SCP::_receive()
*/ */
define('NET_SCP_STRING', 2); /**
/**#@-*/ * SSH1 is being used.
*/
/**#@+ const MODE_SSH1 = 1;
* @access private /**
* @see self::_send() * SSH2 is being used.
* @see self::_receive() */
*/ const MODE_SSH2 = 2;
/** /**#@-*/
* SSH1 is being used.
*/ /**
define('NET_SCP_SSH1', 1); * SSH Object
/** *
* SSH2 is being used. * @var object
*/ * @access private
define('NET_SCP_SSH2', 2); */
/**#@-*/ var $ssh;
/** /**
* Pure-PHP implementations of SCP. * Packet Size
* *
* @package Net_SCP * @var int
* @author Jim Wigginton <terrafrost@php.net> * @access private
* @access public */
*/ var $packet_size;
class Net_SCP
{ /**
/** * Mode
* SSH Object *
* * @var int
* @var object * @access private
* @access private */
*/ var $mode;
var $ssh;
/**
/** * Default Constructor.
* Packet Size *
* * Connects to an SSH server
* @var int *
* @access private * @param \phpseclib\Net\SSH1|\phpseclib\Net\SSH2 $ssh
*/ * @return \phpseclib\Net\SCP
var $packet_size; * @access public
*/
/** function __construct($ssh)
* Mode {
* if ($ssh instanceof SSH2) {
* @var int $this->mode = self::MODE_SSH2;
* @access private } elseif ($ssh instanceof SSH1) {
*/ $this->packet_size = 50000;
var $mode; $this->mode = self::MODE_SSH1;
} else {
/** return;
* Default Constructor. }
*
* Connects to an SSH server $this->ssh = $ssh;
* }
* @param string $host
* @param int $port /**
* @param int $timeout * Uploads a file to the SCP server.
* @return Net_SCP *
* @access public * By default, \phpseclib\Net\SCP::put() does not read from the local filesystem. $data is dumped directly into $remote_file.
*/ * So, for example, if you set $data to 'filename.ext' and then do \phpseclib\Net\SCP::get(), you will get a file, twelve bytes
function Net_SCP($ssh) * long, containing 'filename.ext' as its contents.
{ *
if (!is_object($ssh)) { * Setting $mode to self::SOURCE_LOCAL_FILE will change the above behavior. With self::SOURCE_LOCAL_FILE, $remote_file will
return; * contain as many bytes as filename.ext does on your local filesystem. If your filename.ext is 1MB then that is how
} * large $remote_file will be, as well.
*
switch (strtolower(get_class($ssh))) { * Currently, only binary mode is supported. As such, if the line endings need to be adjusted, you will need to take
case 'net_ssh2': * care of that, yourself.
$this->mode = NET_SCP_SSH2; *
break; * @param string $remote_file
case 'net_ssh1': * @param string $data
$this->packet_size = 50000; * @param int $mode
$this->mode = NET_SCP_SSH1; * @param callable $callback
break; * @return bool
default: * @access public
return; */
} function put($remote_file, $data, $mode = self::SOURCE_STRING, $callback = null)
{
$this->ssh = $ssh; if (!isset($this->ssh)) {
} return false;
}
/**
* Uploads a file to the SCP server. if (!$this->ssh->exec('scp -t ' . escapeshellarg($remote_file), false)) { // -t = to
* return false;
* By default, Net_SCP::put() does not read from the local filesystem. $data is dumped directly into $remote_file. }
* So, for example, if you set $data to 'filename.ext' and then do Net_SCP::get(), you will get a file, twelve bytes
* long, containing 'filename.ext' as its contents. $temp = $this->_receive();
* if ($temp !== chr(0)) {
* Setting $mode to NET_SCP_LOCAL_FILE will change the above behavior. With NET_SCP_LOCAL_FILE, $remote_file will return false;
* contain as many bytes as filename.ext does on your local filesystem. If your filename.ext is 1MB then that is how }
* large $remote_file will be, as well.
* if ($this->mode == self::MODE_SSH2) {
* Currently, only binary mode is supported. As such, if the line endings need to be adjusted, you will need to take $this->packet_size = $this->ssh->packet_size_client_to_server[SSH2::CHANNEL_EXEC] - 4;
* care of that, yourself. }
*
* @param string $remote_file $remote_file = basename($remote_file);
* @param string $data
* @param int $mode if ($mode == self::SOURCE_STRING) {
* @param callable $callback $size = strlen($data);
* @return bool } else {
* @access public if (!is_file($data)) {
*/ user_error("$data is not a valid file", E_USER_NOTICE);
function put($remote_file, $data, $mode = NET_SCP_STRING, $callback = null) return false;
{ }
if (!isset($this->ssh)) {
return false; $fp = @fopen($data, 'rb');
} if (!$fp) {
return false;
if (!$this->ssh->exec('scp -t ' . escapeshellarg($remote_file), false)) { // -t = to }
return false; $size = filesize($data);
} }
$temp = $this->_receive(); $this->_send('C0644 ' . $size . ' ' . $remote_file . "\n");
if ($temp !== chr(0)) {
return false; $temp = $this->_receive();
} if ($temp !== chr(0)) {
return false;
if ($this->mode == NET_SCP_SSH2) { }
$this->packet_size = $this->ssh->packet_size_client_to_server[NET_SSH2_CHANNEL_EXEC] - 4;
} $sent = 0;
while ($sent < $size) {
$remote_file = basename($remote_file); $temp = $mode & self::SOURCE_STRING ? substr($data, $sent, $this->packet_size) : fread($fp, $this->packet_size);
$this->_send($temp);
if ($mode == NET_SCP_STRING) { $sent+= strlen($temp);
$size = strlen($data);
} else { if (is_callable($callback)) {
if (!is_file($data)) { call_user_func($callback, $sent);
user_error("$data is not a valid file", E_USER_NOTICE); }
return false; }
} $this->_close();
$fp = @fopen($data, 'rb'); if ($mode != self::SOURCE_STRING) {
if (!$fp) { fclose($fp);
return false; }
}
$size = filesize($data); return true;
} }
$this->_send('C0644 ' . $size . ' ' . $remote_file . "\n"); /**
* Downloads a file from the SCP server.
$temp = $this->_receive(); *
if ($temp !== chr(0)) { * Returns a string containing the contents of $remote_file if $local_file is left undefined or a boolean false if
return false; * the operation was unsuccessful. If $local_file is defined, returns true or false depending on the success of the
} * operation
*
$sent = 0; * @param string $remote_file
while ($sent < $size) { * @param string $local_file
$temp = $mode & NET_SCP_STRING ? substr($data, $sent, $this->packet_size) : fread($fp, $this->packet_size); * @return mixed
$this->_send($temp); * @access public
$sent+= strlen($temp); */
function get($remote_file, $local_file = false)
if (is_callable($callback)) { {
call_user_func($callback, $sent); if (!isset($this->ssh)) {
} return false;
} }
$this->_close();
if (!$this->ssh->exec('scp -f ' . escapeshellarg($remote_file), false)) { // -f = from
if ($mode != NET_SCP_STRING) { return false;
fclose($fp); }
}
$this->_send("\0");
return true;
} if (!preg_match('#(?<perms>[^ ]+) (?<size>\d+) (?<name>.+)#', rtrim($this->_receive()), $info)) {
return false;
/** }
* Downloads a file from the SCP server.
* $this->_send("\0");
* Returns a string containing the contents of $remote_file if $local_file is left undefined or a boolean false if
* the operation was unsuccessful. If $local_file is defined, returns true or false depending on the success of the $size = 0;
* operation
* if ($local_file !== false) {
* @param string $remote_file $fp = @fopen($local_file, 'wb');
* @param string $local_file if (!$fp) {
* @return mixed return false;
* @access public }
*/ }
function get($remote_file, $local_file = false)
{ $content = '';
if (!isset($this->ssh)) { while ($size < $info['size']) {
return false; $data = $this->_receive();
} // SCP usually seems to split stuff out into 16k chunks
$size+= strlen($data);
if (!$this->ssh->exec('scp -f ' . escapeshellarg($remote_file), false)) { // -f = from
return false; if ($local_file === false) {
} $content.= $data;
} else {
$this->_send("\0"); fputs($fp, $data);
}
if (!preg_match('#(?<perms>[^ ]+) (?<size>\d+) (?<name>.+)#', rtrim($this->_receive()), $info)) { }
return false;
} $this->_close();
$this->_send("\0"); if ($local_file !== false) {
fclose($fp);
$size = 0; return true;
}
if ($local_file !== false) {
$fp = @fopen($local_file, 'wb'); return $content;
if (!$fp) { }
return false;
} /**
} * Sends a packet to an SSH server
*
$content = ''; * @param string $data
while ($size < $info['size']) { * @access private
$data = $this->_receive(); */
// SCP usually seems to split stuff out into 16k chunks function _send($data)
$size+= strlen($data); {
switch ($this->mode) {
if ($local_file === false) { case self::MODE_SSH2:
$content.= $data; $this->ssh->_send_channel_packet(SSH2::CHANNEL_EXEC, $data);
} else { break;
fputs($fp, $data); case self::MODE_SSH1:
} $data = pack('CNa*', NET_SSH1_CMSG_STDIN_DATA, strlen($data), $data);
} $this->ssh->_send_binary_packet($data);
}
$this->_close(); }
if ($local_file !== false) { /**
fclose($fp); * Receives a packet from an SSH server
return true; *
} * @return string
* @access private
return $content; */
} function _receive()
{
/** switch ($this->mode) {
* Sends a packet to an SSH server case self::MODE_SSH2:
* return $this->ssh->_get_channel_packet(SSH2::CHANNEL_EXEC, true);
* @param string $data case self::MODE_SSH1:
* @access private if (!$this->ssh->bitmap) {
*/ return false;
function _send($data) }
{ while (true) {
switch ($this->mode) { $response = $this->ssh->_get_binary_packet();
case NET_SCP_SSH2: switch ($response[SSH1::RESPONSE_TYPE]) {
$this->ssh->_send_channel_packet(NET_SSH2_CHANNEL_EXEC, $data); case NET_SSH1_SMSG_STDOUT_DATA:
break; if (strlen($response[SSH1::RESPONSE_DATA]) < 4) {
case NET_SCP_SSH1: return false;
$data = pack('CNa*', NET_SSH1_CMSG_STDIN_DATA, strlen($data), $data); }
$this->ssh->_send_binary_packet($data); extract(unpack('Nlength', $response[SSH1::RESPONSE_DATA]));
} return $this->ssh->_string_shift($response[SSH1::RESPONSE_DATA], $length);
} case NET_SSH1_SMSG_STDERR_DATA:
break;
/** case NET_SSH1_SMSG_EXITSTATUS:
* Receives a packet from an SSH server $this->ssh->_send_binary_packet(chr(NET_SSH1_CMSG_EXIT_CONFIRMATION));
* fclose($this->ssh->fsock);
* @return string $this->ssh->bitmap = 0;
* @access private return false;
*/ default:
function _receive() user_error('Unknown packet received', E_USER_NOTICE);
{ return false;
switch ($this->mode) { }
case NET_SCP_SSH2: }
return $this->ssh->_get_channel_packet(NET_SSH2_CHANNEL_EXEC, true); }
case NET_SCP_SSH1: }
if (!$this->ssh->bitmap) {
return false; /**
} * Closes the connection to an SSH server
while (true) { *
$response = $this->ssh->_get_binary_packet(); * @access private
switch ($response[NET_SSH1_RESPONSE_TYPE]) { */
case NET_SSH1_SMSG_STDOUT_DATA: function _close()
extract(unpack('Nlength', $response[NET_SSH1_RESPONSE_DATA])); {
return $this->ssh->_string_shift($response[NET_SSH1_RESPONSE_DATA], $length); switch ($this->mode) {
case NET_SSH1_SMSG_STDERR_DATA: case self::MODE_SSH2:
break; $this->ssh->_close_channel(SSH2::CHANNEL_EXEC, true);
case NET_SSH1_SMSG_EXITSTATUS: break;
$this->ssh->_send_binary_packet(chr(NET_SSH1_CMSG_EXIT_CONFIRMATION)); case self::MODE_SSH1:
fclose($this->ssh->fsock); $this->ssh->disconnect();
$this->ssh->bitmap = 0; }
return false; }
default: }
user_error('Unknown packet received', E_USER_NOTICE);
return false;
}
}
}
}
/**
* Closes the connection to an SSH server
*
* @access private
*/
function _close()
{
switch ($this->mode) {
case NET_SCP_SSH2:
$this->ssh->_close_channel(NET_SSH2_CHANNEL_EXEC, true);
break;
case NET_SCP_SSH1:
$this->ssh->disconnect();
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,463 +1,308 @@
<?php <?php
/** /**
* Pure-PHP ssh-agent client. * Pure-PHP ssh-agent client.
* *
* PHP versions 4 and 5 * PHP version 5
* *
* Here are some examples of how to use this library: * Here are some examples of how to use this library:
* <code> * <code>
* <?php * <?php
* include 'System/SSH/Agent.php'; * include 'vendor/autoload.php';
* include 'Net/SSH2.php'; *
* * $agent = new \phpseclib\System\SSH\Agent();
* $agent = new System_SSH_Agent(); *
* * $ssh = new \phpseclib\Net\SSH2('www.domain.tld');
* $ssh = new Net_SSH2('www.domain.tld'); * if (!$ssh->login('username', $agent)) {
* if (!$ssh->login('username', $agent)) { * exit('Login Failed');
* exit('Login Failed'); * }
* } *
* * echo $ssh->exec('pwd');
* echo $ssh->exec('pwd'); * echo $ssh->exec('ls -la');
* echo $ssh->exec('ls -la'); * ?>
* ?> * </code>
* </code> *
* * @category System
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy * @package SSH\Agent
* of this software and associated documentation files (the "Software"), to deal * @author Jim Wigginton <terrafrost@php.net>
* in the Software without restriction, including without limitation the rights * @copyright 2014 Jim Wigginton
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * @license http://www.opensource.org/licenses/mit-license.html MIT License
* copies of the Software, and to permit persons to whom the Software is * @link http://phpseclib.sourceforge.net
* furnished to do so, subject to the following conditions: * @internal See http://api.libssh.org/rfc/PROTOCOL.agent
* */
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software. namespace phpseclib\System\SSH;
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR use phpseclib\Crypt\RSA;
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, use phpseclib\System\SSH\Agent\Identity;
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER /**
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * Pure-PHP ssh-agent client identity factory
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN *
* THE SOFTWARE. * requestIdentities() method pumps out \phpseclib\System\SSH\Agent\Identity objects
* *
* @category System * @package SSH\Agent
* @package System_SSH_Agent * @author Jim Wigginton <terrafrost@php.net>
* @author Jim Wigginton <terrafrost@php.net> * @access internal
* @copyright 2014 Jim Wigginton */
* @license http://www.opensource.org/licenses/mit-license.html MIT License class Agent
* @link http://phpseclib.sourceforge.net {
* @internal See http://api.libssh.org/rfc/PROTOCOL.agent /**#@+
*/ * Message numbers
*
/**#@+ * @access private
* Message numbers */
* // to request SSH1 keys you have to use SSH_AGENTC_REQUEST_RSA_IDENTITIES (1)
* @access private const SSH_AGENTC_REQUEST_IDENTITIES = 11;
*/ // this is the SSH2 response; the SSH1 response is SSH_AGENT_RSA_IDENTITIES_ANSWER (2).
// to request SSH1 keys you have to use SSH_AGENTC_REQUEST_RSA_IDENTITIES (1) const SSH_AGENT_IDENTITIES_ANSWER = 12;
define('SYSTEM_SSH_AGENTC_REQUEST_IDENTITIES', 11); // the SSH1 request is SSH_AGENTC_RSA_CHALLENGE (3)
// this is the SSH2 response; the SSH1 response is SSH_AGENT_RSA_IDENTITIES_ANSWER (2). const SSH_AGENTC_SIGN_REQUEST = 13;
define('SYSTEM_SSH_AGENT_IDENTITIES_ANSWER', 12); // the SSH1 response is SSH_AGENT_RSA_RESPONSE (4)
define('SYSTEM_SSH_AGENT_FAILURE', 5); const SSH_AGENT_SIGN_RESPONSE = 14;
// the SSH1 request is SSH_AGENTC_RSA_CHALLENGE (3) /**#@-*/
define('SYSTEM_SSH_AGENTC_SIGN_REQUEST', 13);
// the SSH1 response is SSH_AGENT_RSA_RESPONSE (4) /**@+
define('SYSTEM_SSH_AGENT_SIGN_RESPONSE', 14); * Agent forwarding status
*
* @access private
/**@+ */
* Agent forwarding status // no forwarding requested and not active
* const FORWARD_NONE = 0;
* @access private // request agent forwarding when opportune
*/ const FORWARD_REQUEST = 1;
// no forwarding requested and not active // forwarding has been request and is active
define('SYSTEM_SSH_AGENT_FORWARD_NONE', 0); const FORWARD_ACTIVE = 2;
// request agent forwarding when opportune /**#@-*/
define('SYSTEM_SSH_AGENT_FORWARD_REQUEST', 1);
// forwarding has been request and is active /**
define('SYSTEM_SSH_AGENT_FORWARD_ACTIVE', 2); * Unused
*/
/**#@-*/ const SSH_AGENT_FAILURE = 5;
/** /**
* Pure-PHP ssh-agent client identity object * Socket Resource
* *
* Instantiation should only be performed by System_SSH_Agent class. * @var resource
* This could be thought of as implementing an interface that Crypt_RSA * @access private
* implements. ie. maybe a Net_SSH_Auth_PublicKey interface or something. */
* The methods in this interface would be getPublicKey, setSignatureMode var $fsock;
* and sign since those are the methods phpseclib looks for to perform
* public key authentication. /**
* * Agent forwarding status
* @package System_SSH_Agent *
* @author Jim Wigginton <terrafrost@php.net> * @access private
* @access internal */
*/ var $forward_status = self::FORWARD_NONE;
class System_SSH_Agent_Identity
{ /**
/** * Buffer for accumulating forwarded authentication
* Key Object * agent data arriving on SSH data channel destined
* * for agent unix socket
* @var Crypt_RSA *
* @access private * @access private
* @see self::getPublicKey() */
*/ var $socket_buffer = '';
var $key;
/**
/** * Tracking the number of bytes we are expecting
* Key Blob * to arrive for the agent socket on the SSH data
* * channel
* @var string */
* @access private var $expected_bytes = 0;
* @see self::sign()
*/ /**
var $key_blob; * Default Constructor
*
/** * @return \phpseclib\System\SSH\Agent
* Socket Resource * @access public
* */
* @var resource function __construct()
* @access private {
* @see self::sign() switch (true) {
*/ case isset($_SERVER['SSH_AUTH_SOCK']):
var $fsock; $address = $_SERVER['SSH_AUTH_SOCK'];
break;
/** case isset($_ENV['SSH_AUTH_SOCK']):
* Default Constructor. $address = $_ENV['SSH_AUTH_SOCK'];
* break;
* @param resource $fsock default:
* @return System_SSH_Agent_Identity user_error('SSH_AUTH_SOCK not found');
* @access private return false;
*/ }
function System_SSH_Agent_Identity($fsock)
{ $this->fsock = fsockopen('unix://' . $address, 0, $errno, $errstr);
$this->fsock = $fsock; if (!$this->fsock) {
} user_error("Unable to connect to ssh-agent (Error $errno: $errstr)");
}
/** }
* Set Public Key
* /**
* Called by System_SSH_Agent::requestIdentities() * Request Identities
* *
* @param Crypt_RSA $key * See "2.5.2 Requesting a list of protocol 2 keys"
* @access private * Returns an array containing zero or more \phpseclib\System\SSH\Agent\Identity objects
*/ *
function setPublicKey($key) * @return array
{ * @access public
$this->key = $key; */
$this->key->setPublicKey(); function requestIdentities()
} {
if (!$this->fsock) {
/** return array();
* Set Public Key }
*
* Called by System_SSH_Agent::requestIdentities(). The key blob could be extracted from $this->key $packet = pack('NC', 1, self::SSH_AGENTC_REQUEST_IDENTITIES);
* but this saves a small amount of computation. if (strlen($packet) != fputs($this->fsock, $packet)) {
* user_error('Connection closed while requesting identities');
* @param string $key_blob }
* @access private
*/ $length = current(unpack('N', fread($this->fsock, 4)));
function setPublicKeyBlob($key_blob) $type = ord(fread($this->fsock, 1));
{ if ($type != self::SSH_AGENT_IDENTITIES_ANSWER) {
$this->key_blob = $key_blob; user_error('Unable to request identities');
} }
/** $identities = array();
* Get Public Key $keyCount = current(unpack('N', fread($this->fsock, 4)));
* for ($i = 0; $i < $keyCount; $i++) {
* Wrapper for $this->key->getPublicKey() $length = current(unpack('N', fread($this->fsock, 4)));
* $key_blob = fread($this->fsock, $length);
* @param int $format optional $key_str = 'ssh-rsa ' . base64_encode($key_blob);
* @return mixed $length = current(unpack('N', fread($this->fsock, 4)));
* @access public if ($length) {
*/ $key_str.= ' ' . fread($this->fsock, $length);
function getPublicKey($format = null) }
{ $length = current(unpack('N', substr($key_blob, 0, 4)));
return !isset($format) ? $this->key->getPublicKey() : $this->key->getPublicKey($format); $key_type = substr($key_blob, 4, $length);
} switch ($key_type) {
case 'ssh-rsa':
/** $key = new RSA();
* Set Signature Mode $key->loadKey($key_str);
* break;
* Doesn't do anything as ssh-agent doesn't let you pick and choose the signature mode. ie. case 'ssh-dss':
* ssh-agent's only supported mode is CRYPT_RSA_SIGNATURE_PKCS1 // not currently supported
* break;
* @param int $mode }
* @access public // resources are passed by reference by default
*/ if (isset($key)) {
function setSignatureMode($mode) $identity = new Identity($this->fsock);
{ $identity->setPublicKey($key);
} $identity->setPublicKeyBlob($key_blob);
$identities[] = $identity;
/** unset($key);
* Create a signature }
* }
* See "2.6.2 Protocol 2 private key signature request"
* return $identities;
* @param string $message }
* @return string
* @access public /**
*/ * Signal that agent forwarding should
function sign($message) * be requested when a channel is opened
{ *
// the last parameter (currently 0) is for flags and ssh-agent only defines one flag (for ssh-dss): SSH_AGENT_OLD_SIGNATURE * @param Net_SSH2 $ssh
$packet = pack('CNa*Na*N', SYSTEM_SSH_AGENTC_SIGN_REQUEST, strlen($this->key_blob), $this->key_blob, strlen($message), $message, 0); * @return bool
$packet = pack('Na*', strlen($packet), $packet); * @access public
if (strlen($packet) != fputs($this->fsock, $packet)) { */
user_error('Connection closed during signing'); function startSSHForwarding($ssh)
} {
if ($this->forward_status == self::FORWARD_NONE) {
$length = current(unpack('N', fread($this->fsock, 4))); $this->forward_status = self::FORWARD_REQUEST;
$type = ord(fread($this->fsock, 1)); }
if ($type != SYSTEM_SSH_AGENT_SIGN_RESPONSE) { }
user_error('Unable to retreive signature');
} /**
* Request agent forwarding of remote server
$signature_blob = fread($this->fsock, $length - 1); *
// the only other signature format defined - ssh-dss - is the same length as ssh-rsa * @param Net_SSH2 $ssh
// the + 12 is for the other various SSH added length fields * @return bool
return substr($signature_blob, strlen('ssh-rsa') + 12); * @access private
} */
} function _request_forwarding($ssh)
{
/** $request_channel = $ssh->_get_open_channel();
* Pure-PHP ssh-agent client identity factory if ($request_channel === false) {
* return false;
* requestIdentities() method pumps out System_SSH_Agent_Identity objects }
*
* @package System_SSH_Agent $packet = pack(
* @author Jim Wigginton <terrafrost@php.net> 'CNNa*C',
* @access internal NET_SSH2_MSG_CHANNEL_REQUEST,
*/ $ssh->server_channels[$request_channel],
class System_SSH_Agent strlen('auth-agent-req@openssh.com'),
{ 'auth-agent-req@openssh.com',
/** 1
* Socket Resource );
*
* @var resource $ssh->channel_status[$request_channel] = NET_SSH2_MSG_CHANNEL_REQUEST;
* @access private
*/ if (!$ssh->_send_binary_packet($packet)) {
var $fsock; return false;
}
/**
* Agent forwarding status $response = $ssh->_get_channel_packet($request_channel);
* if ($response === false) {
* @access private return false;
*/ }
var $forward_status = SYSTEM_SSH_AGENT_FORWARD_NONE;
$ssh->channel_status[$request_channel] = NET_SSH2_MSG_CHANNEL_OPEN;
/** $this->forward_status = self::FORWARD_ACTIVE;
* Buffer for accumulating forwarded authentication
* agent data arriving on SSH data channel destined return true;
* for agent unix socket }
*
* @access private /**
*/ * On successful channel open
var $socket_buffer = ''; *
* This method is called upon successful channel
/** * open to give the SSH Agent an opportunity
* Tracking the number of bytes we are expecting * to take further action. i.e. request agent forwarding
* to arrive for the agent socket on the SSH data *
* channel * @param Net_SSH2 $ssh
*/ * @access private
var $expected_bytes = 0; */
function _on_channel_open($ssh)
/** {
* Default Constructor if ($this->forward_status == self::FORWARD_REQUEST) {
* $this->_request_forwarding($ssh);
* @return System_SSH_Agent }
* @access public }
*/
function System_SSH_Agent() /**
{ * Forward data to SSH Agent and return data reply
switch (true) { *
case isset($_SERVER['SSH_AUTH_SOCK']): * @param string $data
$address = $_SERVER['SSH_AUTH_SOCK']; * @return data from SSH Agent
break; * @access private
case isset($_ENV['SSH_AUTH_SOCK']): */
$address = $_ENV['SSH_AUTH_SOCK']; function _forward_data($data)
break; {
default: if ($this->expected_bytes > 0) {
user_error('SSH_AUTH_SOCK not found'); $this->socket_buffer.= $data;
return false; $this->expected_bytes -= strlen($data);
} } else {
$agent_data_bytes = current(unpack('N', $data));
$this->fsock = fsockopen('unix://' . $address, 0, $errno, $errstr); $current_data_bytes = strlen($data);
if (!$this->fsock) { $this->socket_buffer = $data;
user_error("Unable to connect to ssh-agent (Error $errno: $errstr)"); if ($current_data_bytes != $agent_data_bytes + 4) {
} $this->expected_bytes = ($agent_data_bytes + 4) - $current_data_bytes;
} return false;
}
/** }
* Request Identities
* if (strlen($this->socket_buffer) != fwrite($this->fsock, $this->socket_buffer)) {
* See "2.5.2 Requesting a list of protocol 2 keys" user_error('Connection closed attempting to forward data to SSH agent');
* Returns an array containing zero or more System_SSH_Agent_Identity objects }
*
* @return array $this->socket_buffer = '';
* @access public $this->expected_bytes = 0;
*/
function requestIdentities() $agent_reply_bytes = current(unpack('N', fread($this->fsock, 4)));
{
if (!$this->fsock) { $agent_reply_data = fread($this->fsock, $agent_reply_bytes);
return array(); $agent_reply_data = current(unpack('a*', $agent_reply_data));
}
return pack('Na*', $agent_reply_bytes, $agent_reply_data);
$packet = pack('NC', 1, SYSTEM_SSH_AGENTC_REQUEST_IDENTITIES); }
if (strlen($packet) != fputs($this->fsock, $packet)) { }
user_error('Connection closed while requesting identities');
}
$length = current(unpack('N', fread($this->fsock, 4)));
$type = ord(fread($this->fsock, 1));
if ($type != SYSTEM_SSH_AGENT_IDENTITIES_ANSWER) {
user_error('Unable to request identities');
}
$identities = array();
$keyCount = current(unpack('N', fread($this->fsock, 4)));
for ($i = 0; $i < $keyCount; $i++) {
$length = current(unpack('N', fread($this->fsock, 4)));
$key_blob = fread($this->fsock, $length);
$key_str = 'ssh-rsa ' . base64_encode($key_blob);
$length = current(unpack('N', fread($this->fsock, 4)));
if ($length) {
$key_str.= ' ' . fread($this->fsock, $length);
}
$length = current(unpack('N', substr($key_blob, 0, 4)));
$key_type = substr($key_blob, 4, $length);
switch ($key_type) {
case 'ssh-rsa':
if (!class_exists('Crypt_RSA')) {
include_once 'Crypt/RSA.php';
}
$key = new Crypt_RSA();
$key->loadKey($key_str);
break;
case 'ssh-dss':
// not currently supported
break;
}
// resources are passed by reference by default
if (isset($key)) {
$identity = new System_SSH_Agent_Identity($this->fsock);
$identity->setPublicKey($key);
$identity->setPublicKeyBlob($key_blob);
$identities[] = $identity;
unset($key);
}
}
return $identities;
}
/**
* Signal that agent forwarding should
* be requested when a channel is opened
*
* @param Net_SSH2 $ssh
* @return bool
* @access public
*/
function startSSHForwarding($ssh)
{
if ($this->forward_status == SYSTEM_SSH_AGENT_FORWARD_NONE) {
$this->forward_status = SYSTEM_SSH_AGENT_FORWARD_REQUEST;
}
}
/**
* Request agent forwarding of remote server
*
* @param Net_SSH2 $ssh
* @return bool
* @access private
*/
function _request_forwarding($ssh)
{
$request_channel = $ssh->_get_open_channel();
if ($request_channel === false) {
return false;
}
$packet = pack(
'CNNa*C',
NET_SSH2_MSG_CHANNEL_REQUEST,
$ssh->server_channels[$request_channel],
strlen('auth-agent-req@openssh.com'),
'auth-agent-req@openssh.com',
1
);
$ssh->channel_status[$request_channel] = NET_SSH2_MSG_CHANNEL_REQUEST;
if (!$ssh->_send_binary_packet($packet)) {
return false;
}
$response = $ssh->_get_channel_packet($request_channel);
if ($response === false) {
return false;
}
$ssh->channel_status[$request_channel] = NET_SSH2_MSG_CHANNEL_OPEN;
$this->forward_status = SYSTEM_SSH_AGENT_FORWARD_ACTIVE;
return true;
}
/**
* On successful channel open
*
* This method is called upon successful channel
* open to give the SSH Agent an opportunity
* to take further action. i.e. request agent forwarding
*
* @param Net_SSH2 $ssh
* @access private
*/
function _on_channel_open($ssh)
{
if ($this->forward_status == SYSTEM_SSH_AGENT_FORWARD_REQUEST) {
$this->_request_forwarding($ssh);
}
}
/**
* Forward data to SSH Agent and return data reply
*
* @param string $data
* @return data from SSH Agent
* @access private
*/
function _forward_data($data)
{
if ($this->expected_bytes > 0) {
$this->socket_buffer.= $data;
$this->expected_bytes -= strlen($data);
} else {
$agent_data_bytes = current(unpack('N', $data));
$current_data_bytes = strlen($data);
$this->socket_buffer = $data;
if ($current_data_bytes != $agent_data_bytes + 4) {
$this->expected_bytes = ($agent_data_bytes + 4) - $current_data_bytes;
return false;
}
}
if (strlen($this->socket_buffer) != fwrite($this->fsock, $this->socket_buffer)) {
user_error('Connection closed attempting to forward data to SSH agent');
}
$this->socket_buffer = '';
$this->expected_bytes = 0;
$agent_reply_bytes = current(unpack('N', fread($this->fsock, 4)));
$agent_reply_data = fread($this->fsock, $agent_reply_bytes);
$agent_reply_data = current(unpack('a*', $agent_reply_data));
return pack('Na*', $agent_reply_bytes, $agent_reply_data);
}
}

View File

@ -0,0 +1,158 @@
<?php
/**
* Pure-PHP ssh-agent client.
*
* PHP version 5
*
* @category System
* @package SSH\Agent
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2009 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
* @internal See http://api.libssh.org/rfc/PROTOCOL.agent
*/
namespace phpseclib\System\SSH\Agent;
use phpseclib\System\SSH\Agent;
/**
* Pure-PHP ssh-agent client identity object
*
* Instantiation should only be performed by \phpseclib\System\SSH\Agent class.
* This could be thought of as implementing an interface that phpseclib\Crypt\RSA
* implements. ie. maybe a Net_SSH_Auth_PublicKey interface or something.
* The methods in this interface would be getPublicKey and sign since those are the
* methods phpseclib looks for to perform public key authentication.
*
* @package SSH\Agent
* @author Jim Wigginton <terrafrost@php.net>
* @access internal
*/
class Identity
{
/**
* Key Object
*
* @var \phpseclib\Crypt\RSA
* @access private
* @see self::getPublicKey()
*/
var $key;
/**
* Key Blob
*
* @var string
* @access private
* @see self::sign()
*/
var $key_blob;
/**
* Socket Resource
*
* @var resource
* @access private
* @see self::sign()
*/
var $fsock;
/**
* Default Constructor.
*
* @param resource $fsock
* @return \phpseclib\System\SSH\Agent\Identity
* @access private
*/
function __construct($fsock)
{
$this->fsock = $fsock;
}
/**
* Set Public Key
*
* Called by \phpseclib\System\SSH\Agent::requestIdentities()
*
* @param \phpseclib\Crypt\RSA $key
* @access private
*/
function setPublicKey($key)
{
$this->key = $key;
$this->key->setPublicKey();
}
/**
* Set Public Key
*
* Called by \phpseclib\System\SSH\Agent::requestIdentities(). The key blob could be extracted from $this->key
* but this saves a small amount of computation.
*
* @param string $key_blob
* @access private
*/
function setPublicKeyBlob($key_blob)
{
$this->key_blob = $key_blob;
}
/**
* Get Public Key
*
* Wrapper for $this->key->getPublicKey()
*
* @param int $format optional
* @return mixed
* @access public
*/
function getPublicKey($format = null)
{
return !isset($format) ? $this->key->getPublicKey() : $this->key->getPublicKey($format);
}
/**
* Set Signature Mode
*
* Doesn't do anything as ssh-agent doesn't let you pick and choose the signature mode. ie.
* ssh-agent's only supported mode is \phpseclib\Crypt\RSA::SIGNATURE_PKCS1
*
* @param int $mode
* @access public
*/
function setSignatureMode($mode)
{
}
/**
* Create a signature
*
* See "2.6.2 Protocol 2 private key signature request"
*
* @param string $message
* @return string
* @access public
*/
function sign($message)
{
// the last parameter (currently 0) is for flags and ssh-agent only defines one flag (for ssh-dss): SSH_AGENT_OLD_SIGNATURE
$packet = pack('CNa*Na*N', Agent::SSH_AGENTC_SIGN_REQUEST, strlen($this->key_blob), $this->key_blob, strlen($message), $message, 0);
$packet = pack('Na*', strlen($packet), $packet);
if (strlen($packet) != fputs($this->fsock, $packet)) {
user_error('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 retrieve signature');
}
$signature_blob = fread($this->fsock, $length - 1);
// the only other signature format defined - ssh-dss - is the same length as ssh-rsa
// the + 12 is for the other various SSH added length fields
return substr($signature_blob, strlen('ssh-rsa') + 12);
}
}

View File

@ -1,39 +0,0 @@
<?php
/**
* Pure-PHP ssh-agent client wrapper
*
* PHP versions 4 and 5
*
* Originally System_SSH_Agent was accessed as System/SSH_Agent.php instead of
* System/SSH/Agent.php. The problem with this is that PSR0 compatible autoloaders
* don't support that kind of directory layout hence the package being moved and
* this "alias" being created to maintain backwards compatibility.
*
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @category System
* @package System_SSH_Agent
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2014 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
* @internal See http://api.libssh.org/rfc/PROTOCOL.agent
*/
require_once 'SSH/Agent.php';

View File

@ -1,6 +1,6 @@
# minimalist openssl.cnf file for use with phpseclib # minimalist openssl.cnf file for use with phpseclib
HOME = . HOME = .
RANDFILE = $ENV::HOME/.rnd RANDFILE = $ENV::HOME/.rnd
[ v3_ca ] [ v3_ca ]

View File

@ -1,129 +0,0 @@
<?php
/*
$Id$
This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/)
Copyright (C) 2004 - 2016 Roland Gruber
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/**
* This file includes functions to control lamdaemon.
*
* @author Tilo Lutz
* @author Roland Gruber
* @author Thomas Manninger
*
* @package modules
*/
/**
* Sends commands to lamdaemon script.
*
* @param array $command command to execute
* @param string $server remote server
* @return array Output of lamdaemon
*
*/
function lamdaemon($command, $server) {
if ($server == '') {
return array();
}
// add phpseclib to include path
set_include_path(get_include_path() . PATH_SEPARATOR . dirname(__FILE__) . '/3rdParty/phpseclib');
include_once('Net/SSH2.php');
try {
$handle = lamConnectSSH($server);
}
catch (Exception $e) {
return array("ERROR," . $e->getMessage() . "," . $server);
}
$output = $handle->exec("sudo " . $_SESSION['config']->get_scriptPath() . ' ' . escapeshellarg($command));
return array($output);
}
/**
* Connects to the given SSH server.
*
* @param String $server server name (e.g. localhost or localhost,1234)
* @return object handle
*/
function lamConnectSSH($server) {
// add phpseclib to include path
set_include_path(get_include_path() . PATH_SEPARATOR . dirname(__FILE__) . '/3rdParty/phpseclib');
include_once('Net/SSH2.php');
include_once('Crypt/RSA.php');
$serverNameParts = explode(",", $server);
$handle = false;
if (sizeof($serverNameParts) > 1) {
$handle = @new Net_SSH2($serverNameParts[0], $serverNameParts[1]);
}
else {
$handle = @new Net_SSH2($server);
}
if (!$handle) {
throw new Exception(_("Unable to connect to remote server!"));
}
lamLoginSSH($handle);
return $handle;
}
/**
* Performs a login to the provided SSH handle.
*
* @param handle $handle SSH handle
* @throws Exception login failed
*/
function lamLoginSSH($handle) {
$username = $_SESSION['config']->getScriptUserName();
$credentials = $_SESSION['ldap']->decrypt_login();
if (empty($username)) {
// get user name from current LAM user
$sr = @ldap_read($_SESSION['ldap']->server(), $credentials[0], "objectClass=posixAccount", array('uid'), 0, 0, 0, LDAP_DEREF_NEVER);
if ($sr) {
$entry = @ldap_get_entries($_SESSION['ldap']->server(), $sr);
$username = $entry[0]['uid'][0];
}
if (empty($username)) {
throw new Exception(sprintf(_("Your LAM admin user (%s) must be a valid Unix account to work with lamdaemon!"), getAbstractDN($credentials[0])));
}
}
$password = $credentials[1];
$keyPath = $_SESSION['config']->getScriptSSHKey();
if (!empty($keyPath)) {
// use key authentication
if (!file_exists($keyPath) || !is_readable($keyPath)) {
throw new Exception(sprintf(_("Unable to read %s."), htmlspecialchars($keyPath)));
}
$key = file_get_contents($keyPath);
$rsa = new Crypt_RSA();
$keyPassword = $_SESSION['config']->getScriptSSHKeyPassword();
if (!empty($keyPassword)) {
$rsa->setPassword($keyPassword);
}
if (!$rsa->loadKey($key)) {
throw new Exception(sprintf(_("Unable to load key %s."), htmlspecialchars($keyPath)));
}
$password = $rsa;
}
$login = @$handle->login($username, $password);
if (!$login) {
throw new Exception(_("Unable to login to remote server!"));
}
}
?>

View File

@ -45,8 +45,8 @@ include_once("account.inc");
include_once("baseModule.inc"); include_once("baseModule.inc");
/** access to LDAP server */ /** access to LDAP server */
include_once("ldap.inc"); include_once("ldap.inc");
/** lamdaemon functions */ /** remote functions */
include_once("lamdaemon.inc"); include_once("remote.inc");
/** security functions */ /** security functions */
include_once("security.inc"); include_once("security.inc");
/** meta HTML classes */ /** meta HTML classes */

163
lam/lib/remote.inc Normal file
View File

@ -0,0 +1,163 @@
<?php
namespace LAM\REMOTE;
use \Exception;
use \phpseclib\Net\SSH2;
use \phpseclib\Crypt\RSA;
/*
$Id$
This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/)
Copyright (C) 2017 Roland Gruber
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/**
* This file includes functions to control LAM remote executions.
*
* @author Roland Gruber
*
* @package modules
*/
/**
* Runs remote commands.
*
* @author Roland Gruber
*/
class Remote {
/** SSH2 server handle */
private $server = null;
/**
* Constructor, include SSH library.
*/
public function __construct() {
$this->includeSshLibrary();
}
/**
* Sends commands to remote script.
*
* @param string $command command to execute
* @return string output of remote script
*
*/
public function execute($command) {
if ($this->server == null) {
return array();
}
return $this->server->exec("sudo " . $_SESSION['config']->get_scriptPath() . ' ' . escapeshellarg($command));
}
/**
* Connects to the given SSH server.
*
* @param String $server server name (e.g. localhost or localhost,1234)
* @return object handle
*/
public function connect($server) {
$serverNameParts = explode(",", $server);
$handle = false;
if (sizeof($serverNameParts) > 1) {
$handle = @new SSH2($serverNameParts[0], $serverNameParts[1]);
}
else {
$handle = @new SSH2($server);
}
if (!$handle) {
throw new Exception(_("Unable to connect to remote server!"));
}
$this->loginSSH($handle);
$this->server = $handle;
}
/**
* Closes the connection.
*/
public function disconnect() {
$this->server->disconnect();
}
/**
* Performs a login to the provided SSH handle.
*
* @param SSH2 $handle SSH handle
* @throws Exception login failed
*/
private function loginSSH($handle) {
$username = $_SESSION['config']->getScriptUserName();
$credentials = $_SESSION['ldap']->decrypt_login();
if (empty($username)) {
// get user name from current LAM user
$sr = @ldap_read($_SESSION['ldap']->server(), $credentials[0], "objectClass=posixAccount", array('uid'), 0, 0, 0, LDAP_DEREF_NEVER);
if ($sr) {
$entry = @ldap_get_entries($_SESSION['ldap']->server(), $sr);
$username = $entry[0]['uid'][0];
}
if (empty($username)) {
throw new Exception(sprintf(_("Your LAM admin user (%s) must be a valid Unix account to work with lamdaemon!"), getAbstractDN($credentials[0])));
}
}
$password = $credentials[1];
$keyPath = $_SESSION['config']->getScriptSSHKey();
if (!empty($keyPath)) {
// use key authentication
if (!file_exists($keyPath) || !is_readable($keyPath)) {
throw new Exception(sprintf(_("Unable to read %s."), htmlspecialchars($keyPath)));
}
$key = file_get_contents($keyPath);
$rsa = new RSA();
$keyPassword = $_SESSION['config']->getScriptSSHKeyPassword();
if (!empty($keyPassword)) {
$rsa->setPassword($keyPassword);
}
if (!$rsa->loadKey($key)) {
throw new Exception(sprintf(_("Unable to load key %s."), htmlspecialchars($keyPath)));
}
$password = $rsa;
}
$login = @$handle->login($username, $password);
if (!$login) {
throw new Exception(_("Unable to login to remote server!"));
}
}
/**
* Include the SSH files.
*/
private function includeSshLibrary() {
$prefix = dirname(__FILE__) . '/3rdParty/phpseclib/';
require_once($prefix . 'Crypt/Base.php');
require_once($prefix . 'Crypt/Blowfish.php');
require_once($prefix . 'Crypt/Hash.php');
require_once($prefix . 'Crypt/Random.php');
require_once($prefix . 'Crypt/RC4.php');
require_once($prefix . 'Crypt/Rijndael.php');
require_once($prefix . 'Crypt/AES.php');
require_once($prefix . 'Crypt/RSA.php');
require_once($prefix . 'Crypt/DES.php');
require_once($prefix . 'Crypt/TripleDES.php');
require_once($prefix . 'Crypt/Twofish.php');
require_once($prefix . 'Math/BigInteger.php');
require_once($prefix . 'System/SSH/Agent.php');
require_once($prefix . 'Net/SSH2.php');
}
}
?>

View File

@ -42,8 +42,8 @@ include_once('../lib/config.inc');
include_once('../lib/status.inc'); include_once('../lib/status.inc');
/** LDAP connection */ /** LDAP connection */
include_once('../lib/ldap.inc'); include_once('../lib/ldap.inc');
/** lamdaemon interface */ /** remote interface */
include_once('../lib/lamdaemon.inc'); include_once('../lib/remote.inc');
/** module interface */ /** module interface */
include_once('../lib/modules.inc'); include_once('../lib/modules.inc');

View File

@ -1,4 +1,18 @@
<?php <?php
namespace LAM\TOOLS\TESTS;
use \LAM\REMOTE\Remote;
use \htmlTable;
use \htmlTitle;
use \htmlOutputText;
use \htmlSelect;
use \htmlInputCheckbox;
use \htmlSpacer;
use \htmlButton;
use \htmlStatusMessage;
use \htmlImage;
use \htmlSubTitle;
use \Exception;
/* /*
$Id$ $Id$
@ -22,7 +36,7 @@ $Id$
*/ */
/** /**
* Tests the lamdaemon script. * Tests the remote script.
* *
* @author Roland Gruber * @author Roland Gruber
* @author Thomas Manninger * @author Thomas Manninger
@ -67,7 +81,7 @@ for ($i = 0; $i < sizeof($servers); $i++) {
} }
if (isset($_POST['runTest'])) { if (isset($_POST['runTest'])) {
lamRunLamdaemonTestSuite($_POST['server'], $serverTitles[$_POST['server']] , isset($_POST['checkQuotas']), $container); lamRunTestSuite($_POST['server'], $serverTitles[$_POST['server']] , isset($_POST['checkQuotas']), $container);
} }
else if ((sizeof($servers) > 0) && isset($servers[0]) && ($servers[0] != '')) { else if ((sizeof($servers) > 0) && isset($servers[0]) && ($servers[0] != '')) {
$container->addElement(new htmlOutputText(_("Server"))); $container->addElement(new htmlOutputText(_("Server")));
@ -111,22 +125,22 @@ include '../main_footer.php';
* *
* @param string $command test command * @param string $command test command
* @param boolean $stopTest specifies if test should be run * @param boolean $stopTest specifies if test should be run
* @param connection $handle SSH connection * @param Remote $remote SSH connection
* @param string $testText describing text * @param string $testText describing text
* @param htmlTable $container container for HTML output * @param htmlTable $container container for HTML output
* @return boolean true, if errors occured * @return boolean true, if errors occured
*/ */
function lamTestLamdaemon($command, $stopTest, $handle, $testText, $container) { function lamTestLamdaemon($command, $stopTest, $remote, $testText, $container) {
$okImage = "../../graphics/pass.png"; $okImage = "../../graphics/pass.png";
$failImage = "../../graphics/fail.png"; $failImage = "../../graphics/fail.png";
$spacer = new htmlSpacer('10px', null); $spacer = new htmlSpacer('10px', null);
// run lamdaemon and get user quotas // run remote command
if (!$stopTest) { if (!$stopTest) {
$container->addElement(new htmlOutputText($testText)); $container->addElement(new htmlOutputText($testText));
$container->addElement($spacer); $container->addElement($spacer);
flush(); flush();
$lamdaemonOk = false; $lamdaemonOk = false;
$output = $handle->exec("sudo " . $_SESSION['config']->get_scriptPath() . ' ' . escapeshellarg($command)); $output = $remote->execute($command);
if ((stripos(strtolower($output), "error") === false) && ((strpos($output, 'INFO,') === 0) || (strpos($output, 'QUOTA_ENTRY') === 0))) { if ((stripos(strtolower($output), "error") === false) && ((strpos($output, 'INFO,') === 0) || (strpos($output, 'QUOTA_ENTRY') === 0))) {
$lamdaemonOk = true; $lamdaemonOk = true;
} }
@ -170,7 +184,7 @@ function lamTestLamdaemon($command, $stopTest, $handle, $testText, $container) {
* @param boolean $testQuota true, if Quotas should be checked * @param boolean $testQuota true, if Quotas should be checked
* @param htmlTable $container container for HTML output * @param htmlTable $container container for HTML output
*/ */
function lamRunLamdaemonTestSuite($serverName, $serverTitle, $testQuota, $container) { function lamRunTestSuite($serverName, $serverTitle, $testQuota, $container) {
$SPLIT_DELIMITER = "###x##y##x###"; $SPLIT_DELIMITER = "###x##y##x###";
$LAMDAEMON_PROTOCOL_VERSION = '5'; $LAMDAEMON_PROTOCOL_VERSION = '5';
$okImage = "../../graphics/pass.png"; $okImage = "../../graphics/pass.png";
@ -246,13 +260,14 @@ function lamRunLamdaemonTestSuite($serverName, $serverTitle, $testQuota, $contai
flush(); flush();
// check SSH login // check SSH login
$remote = new Remote();
if (!$stopTest) { if (!$stopTest) {
$container->addElement(new htmlOutputText(_("SSH connection"))); $container->addElement(new htmlOutputText(_("SSH connection")));
$container->addElement($spacer); $container->addElement($spacer);
flush(); flush();
$sshOk = false; $sshOk = false;
try { try {
$handle = lamConnectSSH($serverName); $remote->connect($serverName);
$container->addElement(new htmlImage($okImage)); $container->addElement(new htmlImage($okImage));
$container->addElement($spacer); $container->addElement($spacer);
$container->addElement(new htmlOutputText(_("SSH connection established.")), true); $container->addElement(new htmlOutputText(_("SSH connection established.")), true);
@ -268,21 +283,18 @@ function lamRunLamdaemonTestSuite($serverName, $serverTitle, $testQuota, $contai
flush(); flush();
if (!$stopTest) { if (!$stopTest) {
$stopTest = lamTestLamdaemon("+" . $SPLIT_DELIMITER . "test" . $SPLIT_DELIMITER . "basic", $stopTest, $handle, _("Execute lamdaemon"), $container); $stopTest = lamTestLamdaemon("+" . $SPLIT_DELIMITER . "test" . $SPLIT_DELIMITER . "basic", $stopTest, $remote, _("Execute lamdaemon"), $container);
} }
if (!$stopTest) { if (!$stopTest) {
$stopTest = lamTestLamdaemon("+" . $SPLIT_DELIMITER . "test" . $SPLIT_DELIMITER . "version" . $SPLIT_DELIMITER . $LAMDAEMON_PROTOCOL_VERSION, $stopTest, $handle, _("Lamdaemon version"), $container); $stopTest = lamTestLamdaemon("+" . $SPLIT_DELIMITER . "test" . $SPLIT_DELIMITER . "version" . $SPLIT_DELIMITER . $LAMDAEMON_PROTOCOL_VERSION, $stopTest, $remote, _("Lamdaemon version"), $container);
} }
if (!$stopTest) { if (!$stopTest) {
$handle = lamConnectSSH($serverName); $stopTest = lamTestLamdaemon("+" . $SPLIT_DELIMITER . "test" . $SPLIT_DELIMITER . "nss" . $SPLIT_DELIMITER . "$userName", $stopTest, $remote, _("Lamdaemon: check NSS LDAP"), $container);
$stopTest = lamTestLamdaemon("+" . $SPLIT_DELIMITER . "test" . $SPLIT_DELIMITER . "nss" . $SPLIT_DELIMITER . "$userName", $stopTest, $handle, _("Lamdaemon: check NSS LDAP"), $container);
if (!$stopTest && $testQuota) { if (!$stopTest && $testQuota) {
$handle = lamConnectSSH($serverName); $stopTest = lamTestLamdaemon("+" . $SPLIT_DELIMITER . "test" . $SPLIT_DELIMITER . "quota", $stopTest, $remote, _("Lamdaemon: Quota module installed"), $container);
$stopTest = lamTestLamdaemon("+" . $SPLIT_DELIMITER . "test" . $SPLIT_DELIMITER . "quota", $stopTest, $handle, _("Lamdaemon: Quota module installed"), $container); $stopTest = lamTestLamdaemon("+" . $SPLIT_DELIMITER . "quota" . $SPLIT_DELIMITER . "get" . $SPLIT_DELIMITER . "user", $stopTest, $remote, _("Lamdaemon: read quotas"), $container);
$handle = lamConnectSSH($serverName);
$stopTest = lamTestLamdaemon("+" . $SPLIT_DELIMITER . "quota" . $SPLIT_DELIMITER . "get" . $SPLIT_DELIMITER . "user", $stopTest, $handle, _("Lamdaemon: read quotas"), $container);
} }
} }