commit
6276fb969b
@ -0,0 +1,540 @@ |
||||
<?php |
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
||||
|
||||
/** |
||||
* Pure-PHP implementation of AES. |
||||
* |
||||
* Uses mcrypt, if available, and an internal implementation, otherwise. |
||||
* |
||||
* PHP versions 4 and 5 |
||||
* |
||||
* If {@link Crypt_AES::setKeyLength() setKeyLength()} isn't called, it'll be calculated from |
||||
* {@link Crypt_AES::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 160-bits and 160 bits will be the key length until {@link Crypt_Rijndael::setKey() setKey()} |
||||
* 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 |
||||
* make a whole lot of sense. {@link Crypt_AES::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). |
||||
* |
||||
* Here's a short example of how to use this library: |
||||
* <code> |
||||
* <?php |
||||
* include('Crypt/AES.php'); |
||||
* |
||||
* $aes = new Crypt_AES(); |
||||
* |
||||
* $aes->setKey('abcdefghijklmnop'); |
||||
* |
||||
* $size = 10 * 1024; |
||||
* $plaintext = ''; |
||||
* for ($i = 0; $i < $size; $i++) { |
||||
* $plaintext.= 'a'; |
||||
* } |
||||
* |
||||
* echo $aes->decrypt($aes->encrypt($plaintext)); |
||||
* ?> |
||||
* </code> |
||||
* |
||||
* 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 Crypt |
||||
* @package Crypt_AES |
||||
* @author Jim Wigginton <terrafrost@php.net> |
||||
* @copyright MMVIII Jim Wigginton |
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License |
||||
* @link http://phpseclib.sourceforge.net |
||||
*/ |
||||
|
||||
/** |
||||
* Include Crypt_Rijndael |
||||
*/ |
||||
if (!class_exists('Crypt_Rijndael')) { |
||||
require_once 'Rijndael.php'; |
||||
} |
||||
|
||||
/**#@+ |
||||
* @access public |
||||
* @see Crypt_AES::encrypt() |
||||
* @see Crypt_AES::decrypt() |
||||
*/ |
||||
/** |
||||
* Encrypt / decrypt using the Counter mode. |
||||
* |
||||
* Set to -1 since that's what Crypt/Random.php uses to index the CTR mode. |
||||
* |
||||
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 |
||||
*/ |
||||
define('CRYPT_AES_MODE_CTR', -1); |
||||
/** |
||||
* Encrypt / decrypt using the Electronic Code Book mode. |
||||
* |
||||
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29 |
||||
*/ |
||||
define('CRYPT_AES_MODE_ECB', 1); |
||||
/** |
||||
* Encrypt / decrypt using the Code Book Chaining mode. |
||||
* |
||||
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 |
||||
*/ |
||||
define('CRYPT_AES_MODE_CBC', 2); |
||||
/** |
||||
* Encrypt / decrypt using the Cipher Feedback mode. |
||||
* |
||||
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 |
||||
*/ |
||||
define('CRYPT_AES_MODE_CFB', 3); |
||||
/** |
||||
* Encrypt / decrypt using the Cipher Feedback mode. |
||||
* |
||||
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 |
||||
*/ |
||||
define('CRYPT_AES_MODE_OFB', 4); |
||||
/**#@-*/ |
||||
|
||||
/**#@+ |
||||
* @access private |
||||
* @see Crypt_AES::Crypt_AES() |
||||
*/ |
||||
/** |
||||
* Toggles the internal implementation |
||||
*/ |
||||
define('CRYPT_AES_MODE_INTERNAL', 1); |
||||
/** |
||||
* Toggles the mcrypt implementation |
||||
*/ |
||||
define('CRYPT_AES_MODE_MCRYPT', 2); |
||||
/**#@-*/ |
||||
|
||||
/** |
||||
* Pure-PHP implementation of AES. |
||||
* |
||||
* @author Jim Wigginton <terrafrost@php.net> |
||||
* @version 0.1.0 |
||||
* @access public |
||||
* @package Crypt_AES |
||||
*/ |
||||
class Crypt_AES extends Crypt_Rijndael { |
||||
/** |
||||
* mcrypt resource for encryption |
||||
* |
||||
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once. |
||||
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. |
||||
* |
||||
* @see Crypt_AES::encrypt() |
||||
* @var String |
||||
* @access private |
||||
*/ |
||||
var $enmcrypt; |
||||
|
||||
/** |
||||
* mcrypt resource for decryption |
||||
* |
||||
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once. |
||||
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. |
||||
* |
||||
* @see Crypt_AES::decrypt() |
||||
* @var String |
||||
* @access private |
||||
*/ |
||||
var $demcrypt; |
||||
|
||||
/** |
||||
* mcrypt resource for CFB mode |
||||
* |
||||
* @see Crypt_AES::encrypt() |
||||
* @see Crypt_AES::decrypt() |
||||
* @var String |
||||
* @access private |
||||
*/ |
||||
var $ecb; |
||||
|
||||
/** |
||||
* Default Constructor. |
||||
* |
||||
* Determines whether or not the mcrypt extension should be used. $mode should only, at present, be |
||||
* CRYPT_AES_MODE_ECB or CRYPT_AES_MODE_CBC. If not explictly set, CRYPT_AES_MODE_CBC will be used. |
||||
* |
||||
* @param optional Integer $mode |
||||
* @return Crypt_AES |
||||
* @access public |
||||
*/ |
||||
function Crypt_AES($mode = CRYPT_AES_MODE_CBC) |
||||
{ |
||||
if ( !defined('CRYPT_AES_MODE') ) { |
||||
switch (true) { |
||||
case extension_loaded('mcrypt') && in_array('rijndael-128', mcrypt_list_algorithms()): |
||||
define('CRYPT_AES_MODE', CRYPT_AES_MODE_MCRYPT); |
||||
break; |
||||
default: |
||||
define('CRYPT_AES_MODE', CRYPT_AES_MODE_INTERNAL); |
||||
} |
||||
} |
||||
|
||||
switch ( CRYPT_AES_MODE ) { |
||||
case CRYPT_AES_MODE_MCRYPT: |
||||
switch ($mode) { |
||||
case CRYPT_AES_MODE_ECB: |
||||
$this->paddable = true; |
||||
$this->mode = MCRYPT_MODE_ECB; |
||||
break; |
||||
case CRYPT_AES_MODE_CTR: |
||||
// ctr doesn't have a constant associated with it even though it appears to be fairly widely |
||||
// supported. in lieu of knowing just how widely supported it is, i've, for now, opted not to |
||||
// include a compatibility layer. the layer has been implemented but, for now, is commented out. |
||||
$this->mode = 'ctr'; |
||||
//$this->mode = in_array('ctr', mcrypt_list_modes()) ? 'ctr' : CRYPT_AES_MODE_CTR; |
||||
break; |
||||
case CRYPT_AES_MODE_CFB: |
||||
$this->mode = 'ncfb'; |
||||
break; |
||||
case CRYPT_AES_MODE_OFB: |
||||
$this->mode = MCRYPT_MODE_NOFB; |
||||
break; |
||||
case CRYPT_AES_MODE_CBC: |
||||
default: |
||||
$this->paddable = true; |
||||
$this->mode = MCRYPT_MODE_CBC; |
||||
} |
||||
|
||||
break; |
||||
default: |
||||
switch ($mode) { |
||||
case CRYPT_AES_MODE_ECB: |
||||
$this->paddable = true; |
||||
$this->mode = CRYPT_RIJNDAEL_MODE_ECB; |
||||
break; |
||||
case CRYPT_AES_MODE_CTR: |
||||
$this->mode = CRYPT_RIJNDAEL_MODE_CTR; |
||||
break; |
||||
case CRYPT_AES_MODE_CFB: |
||||
$this->mode = CRYPT_RIJNDAEL_MODE_CFB; |
||||
break; |
||||
case CRYPT_AES_MODE_OFB: |
||||
$this->mode = CRYPT_RIJNDAEL_MODE_OFB; |
||||
break; |
||||
case CRYPT_AES_MODE_CBC: |
||||
default: |
||||
$this->paddable = true; |
||||
$this->mode = CRYPT_RIJNDAEL_MODE_CBC; |
||||
} |
||||
} |
||||
|
||||
if (CRYPT_AES_MODE == CRYPT_AES_MODE_INTERNAL) { |
||||
parent::Crypt_Rijndael($this->mode); |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* Dummy function |
||||
* |
||||
* Since Crypt_AES extends Crypt_Rijndael, this function is, technically, available, but it doesn't do anything. |
||||
* |
||||
* @access public |
||||
* @param Integer $length |
||||
*/ |
||||
function setBlockLength($length) |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
/** |
||||
* Sets the initialization vector. (optional) |
||||
* |
||||
* SetIV is not required when CRYPT_RIJNDAEL_MODE_ECB is being used. If not explictly set, it'll be assumed |
||||
* to be all zero's. |
||||
* |
||||
* @access public |
||||
* @param String $iv |
||||
*/ |
||||
function setIV($iv) |
||||
{ |
||||
parent::setIV($iv); |
||||
if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) { |
||||
$this->changed = true; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Encrypts a message. |
||||
* |
||||
* $plaintext will be padded with up to 16 additional bytes. Other AES implementations may or may not pad in the |
||||
* same manner. Other common approaches to padding and the reasons why it's necessary are discussed in the following |
||||
* URL: |
||||
* |
||||
* {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html} |
||||
* |
||||
* An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does. |
||||
* strlen($plaintext) will still need to be a multiple of 16, however, arbitrary values can be added to make it that |
||||
* length. |
||||
* |
||||
* @see Crypt_AES::decrypt() |
||||
* @access public |
||||
* @param String $plaintext |
||||
*/ |
||||
function encrypt($plaintext) |
||||
{ |
||||
if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) { |
||||
$this->_mcryptSetup(); |
||||
|
||||
// re: http://phpseclib.sourceforge.net/cfb-demo.phps |
||||
// using mcrypt's default handing of CFB the above would output two different things. using phpseclib's |
||||
// rewritten CFB implementation the above outputs the same thing twice. |
||||
if ($this->mode == 'ncfb' && $this->continuousBuffer) { |
||||
$iv = &$this->encryptIV; |
||||
$pos = &$this->enbuffer['pos']; |
||||
$len = strlen($plaintext); |
||||
$ciphertext = ''; |
||||
$i = 0; |
||||
if ($pos) { |
||||
$orig_pos = $pos; |
||||
$max = 16 - $pos; |
||||
if ($len >= $max) { |
||||
$i = $max; |
||||
$len-= $max; |
||||
$pos = 0; |
||||
} else { |
||||
$i = $len; |
||||
$pos+= $len; |
||||
$len = 0; |
||||
} |
||||
$ciphertext = substr($iv, $orig_pos) ^ $plaintext; |
||||
$iv = substr_replace($iv, $ciphertext, $orig_pos, $i); |
||||
$this->enbuffer['enmcrypt_init'] = true; |
||||
} |
||||
if ($len >= 16) { |
||||
if ($this->enbuffer['enmcrypt_init'] === false || $len > 280) { |
||||
if ($this->enbuffer['enmcrypt_init'] === true) { |
||||
mcrypt_generic_init($this->enmcrypt, $this->key, $iv); |
||||
$this->enbuffer['enmcrypt_init'] = false; |
||||
} |
||||
$ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % 16)); |
||||
$iv = substr($ciphertext, -16); |
||||
$len%= 16; |
||||
} else { |
||||
while ($len >= 16) { |
||||
$iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, 16); |
||||
$ciphertext.= $iv; |
||||
$len-= 16; |
||||
$i+= 16; |
||||
} |
||||
} |
||||
} |
||||
|
||||
if ($len) { |
||||
$iv = mcrypt_generic($this->ecb, $iv); |
||||
$block = $iv ^ substr($plaintext, -$len); |
||||
$iv = substr_replace($iv, $block, 0, $len); |
||||
$ciphertext.= $block; |
||||
$pos = $len; |
||||
} |
||||
|
||||
return $ciphertext; |
||||
} |
||||
|
||||
if ($this->paddable) { |
||||
$plaintext = $this->_pad($plaintext); |
||||
} |
||||
|
||||
$ciphertext = mcrypt_generic($this->enmcrypt, $plaintext); |
||||
|
||||
if (!$this->continuousBuffer) { |
||||
mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv); |
||||
} |
||||
|
||||
return $ciphertext; |
||||
} |
||||
|
||||
return parent::encrypt($plaintext); |
||||
} |
||||
|
||||
/** |
||||
* Decrypts a message. |
||||
* |
||||
* If strlen($ciphertext) is not a multiple of 16, null bytes will be added to the end of the string until it is. |
||||
* |
||||
* @see Crypt_AES::encrypt() |
||||
* @access public |
||||
* @param String $ciphertext |
||||
*/ |
||||
function decrypt($ciphertext) |
||||
{ |
||||
if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) { |
||||
$this->_mcryptSetup(); |
||||
|
||||
if ($this->mode == 'ncfb' && $this->continuousBuffer) { |
||||
$iv = &$this->decryptIV; |
||||
$pos = &$this->debuffer['pos']; |
||||
$len = strlen($ciphertext); |
||||
$plaintext = ''; |
||||
$i = 0; |
||||
if ($pos) { |
||||
$orig_pos = $pos; |
||||
$max = 16 - $pos; |
||||
if ($len >= $max) { |
||||
$i = $max; |
||||
$len-= $max; |
||||
$pos = 0; |
||||
} else { |
||||
$i = $len; |
||||
$pos+= $len; |
||||
$len = 0; |
||||
} |
||||
// ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize |
||||
$plaintext = substr($iv, $orig_pos) ^ $ciphertext; |
||||
$iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i); |
||||
} |
||||
if ($len >= 16) { |
||||
$cb = substr($ciphertext, $i, $len - $len % 16); |
||||
$plaintext.= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb; |
||||
$iv = substr($cb, -16); |
||||
$len%= 16; |
||||
} |
||||
if ($len) { |
||||
$iv = mcrypt_generic($this->ecb, $iv); |
||||
$plaintext.= $iv ^ substr($ciphertext, -$len); |
||||
$iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len); |
||||
$pos = $len; |
||||
} |
||||
|
||||
return $plaintext; |
||||
} |
||||
|
||||
if ($this->paddable) { |
||||
// we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic : |
||||
// "The data is padded with "\0" to make sure the length of the data is n * blocksize." |
||||
$ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 15) & 0xFFFFFFF0, chr(0)); |
||||
} |
||||
|
||||
$plaintext = mdecrypt_generic($this->demcrypt, $ciphertext); |
||||
|
||||
if (!$this->continuousBuffer) { |
||||
mcrypt_generic_init($this->demcrypt, $this->key, $this->iv); |
||||
} |
||||
|
||||
return $this->paddable ? $this->_unpad($plaintext) : $plaintext; |
||||
} |
||||
|
||||
return parent::decrypt($ciphertext); |
||||
} |
||||
|
||||
/** |
||||
* Setup mcrypt |
||||
* |
||||
* Validates all the variables. |
||||
* |
||||
* @access private |
||||
*/ |
||||
function _mcryptSetup() |
||||
{ |
||||
if (!$this->changed) { |
||||
return; |
||||
} |
||||
|
||||
if (!$this->explicit_key_length) { |
||||
// this just copied from Crypt_Rijndael::_setup() |
||||
$length = strlen($this->key) >> 2; |
||||
if ($length > 8) { |
||||
$length = 8; |
||||
} else if ($length < 4) { |
||||
$length = 4; |
||||
} |
||||
$this->Nk = $length; |
||||
$this->key_size = $length << 2; |
||||
} |
||||
|
||||
switch ($this->Nk) { |
||||
case 4: // 128 |
||||
$this->key_size = 16; |
||||
break; |
||||
case 5: // 160 |
||||
case 6: // 192 |
||||
$this->key_size = 24; |
||||
break; |
||||
case 7: // 224 |
||||
case 8: // 256 |
||||
$this->key_size = 32; |
||||
} |
||||
|
||||
$this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, chr(0)); |
||||
$this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($this->iv, 0, 16), 16, chr(0)); |
||||
|
||||
if (!isset($this->enmcrypt)) { |
||||
$mode = $this->mode; |
||||
//$mode = $this->mode == CRYPT_AES_MODE_CTR ? MCRYPT_MODE_ECB : $this->mode; |
||||
|
||||
$this->demcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, ''); |
||||
$this->enmcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, ''); |
||||
|
||||
if ($mode == 'ncfb') { |
||||
$this->ecb = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, ''); |
||||
} |
||||
|
||||
} // else should mcrypt_generic_deinit be called? |
||||
|
||||
mcrypt_generic_init($this->demcrypt, $this->key, $this->iv); |
||||
mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv); |
||||
|
||||
if ($this->mode == 'ncfb') { |
||||
mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); |
||||
} |
||||
|
||||
$this->changed = false; |
||||
} |
||||
|
||||
/** |
||||
* Treat consecutive "packets" as if they are a continuous buffer. |
||||
* |
||||
* The default behavior. |
||||
* |
||||
* @see Crypt_Rijndael::disableContinuousBuffer() |
||||
* @access public |
||||
*/ |
||||
function enableContinuousBuffer() |
||||
{ |
||||
parent::enableContinuousBuffer(); |
||||
|
||||
if (CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT) { |
||||
$this->enbuffer['enmcrypt_init'] = true; |
||||
$this->debuffer['demcrypt_init'] = true; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Treat consecutive packets as if they are a discontinuous buffer. |
||||
* |
||||
* The default behavior. |
||||
* |
||||
* @see Crypt_Rijndael::enableContinuousBuffer() |
||||
* @access public |
||||
*/ |
||||
function disableContinuousBuffer() |
||||
{ |
||||
parent::disableContinuousBuffer(); |
||||
|
||||
if (CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT) { |
||||
mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv); |
||||
mcrypt_generic_init($this->demcrypt, $this->key, $this->iv); |
||||
} |
||||
} |
||||
} |
||||
|
||||
// vim: ts=4:sw=4:et: |
||||
// vim6: fdl=1: |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,823 @@ |
||||
<?php |
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
||||
|
||||
/** |
||||
* Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions. |
||||
* |
||||
* Uses hash() or mhash() if available and an internal implementation, otherwise. Currently supports the following: |
||||
* |
||||
* md2, md5, md5-96, sha1, sha1-96, sha256, sha384, and sha512 |
||||
* |
||||
* If {@link Crypt_Hash::setKey() setKey()} is called, {@link Crypt_Hash::hash() hash()} will return the HMAC as opposed to |
||||
* the hash. If no valid algorithm is provided, sha1 will be used. |
||||
* |
||||
* PHP versions 4 and 5 |
||||
* |
||||
* {@internal The variable names are the same as those in |
||||
* {@link http://tools.ietf.org/html/rfc2104#section-2 RFC2104}.}} |
||||
* |
||||
* Here's a short example of how to use this library: |
||||
* <code> |
||||
* <?php |
||||
* include('Crypt/Hash.php'); |
||||
* |
||||
* $hash = new Crypt_Hash('sha1'); |
||||
* |
||||
* $hash->setKey('abcdefg'); |
||||
* |
||||
* echo base64_encode($hash->hash('abcdefg')); |
||||
* ?> |
||||
* </code> |
||||
* |
||||
* 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 Crypt |
||||
* @package Crypt_Hash |
||||
* @author Jim Wigginton <terrafrost@php.net> |
||||
* @copyright MMVII Jim Wigginton |
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License |
||||
* @link http://phpseclib.sourceforge.net |
||||
*/ |
||||
|
||||
/**#@+ |
||||
* @access private |
||||
* @see Crypt_Hash::Crypt_Hash() |
||||
*/ |
||||
/** |
||||
* Toggles the internal implementation |
||||
*/ |
||||
define('CRYPT_HASH_MODE_INTERNAL', 1); |
||||
/** |
||||
* Toggles the mhash() implementation, which has been deprecated on PHP 5.3.0+. |
||||
*/ |
||||
define('CRYPT_HASH_MODE_MHASH', 2); |
||||
/** |
||||
* Toggles the hash() implementation, which works on PHP 5.1.2+. |
||||
*/ |
||||
define('CRYPT_HASH_MODE_HASH', 3); |
||||
/**#@-*/ |
||||
|
||||
/** |
||||
* Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions. |
||||
* |
||||
* @author Jim Wigginton <terrafrost@php.net> |
||||
* @version 0.1.0 |
||||
* @access public |
||||
* @package Crypt_Hash |
||||
*/ |
||||
class Crypt_Hash { |
||||
/** |
||||
* Byte-length of compression blocks / key (Internal HMAC) |
||||
* |
||||
* @see Crypt_Hash::setAlgorithm() |
||||
* @var Integer |
||||
* @access private |
||||
*/ |
||||
var $b; |
||||
|
||||
/** |
||||
* Byte-length of hash output (Internal HMAC) |
||||
* |
||||
* @see Crypt_Hash::setHash() |
||||
* @var Integer |
||||
* @access private |
||||
*/ |
||||
var $l = false; |
||||
|
||||
/** |
||||
* Hash Algorithm |
||||
* |
||||
* @see Crypt_Hash::setHash() |
||||
* @var String |
||||
* @access private |
||||
*/ |
||||
var $hash; |
||||
|
||||
/** |
||||
* Key |
||||
* |
||||
* @see Crypt_Hash::setKey() |
||||
* @var String |
||||
* @access private |
||||
*/ |
||||
var $key = false; |
||||
|
||||
/** |
||||
* Outer XOR (Internal HMAC) |
||||
* |
||||
* @see Crypt_Hash::setKey() |
||||
* @var String |
||||
* @access private |
||||
*/ |
||||
var $opad; |
||||
|
||||
/** |
||||
* Inner XOR (Internal HMAC) |
||||
* |
||||
* @see Crypt_Hash::setKey() |
||||
* @var String |
||||
* @access private |
||||
*/ |
||||
var $ipad; |
||||
|
||||
/** |
||||
* Default Constructor. |
||||
* |
||||
* @param optional String $hash |
||||
* @return Crypt_Hash |
||||
* @access public |
||||
*/ |
||||
function Crypt_Hash($hash = 'sha1') |
||||
{ |
||||
if ( !defined('CRYPT_HASH_MODE') ) { |
||||
switch (true) { |
||||
case extension_loaded('hash'): |
||||
define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_HASH); |
||||
break; |
||||
case extension_loaded('mhash'): |
||||
define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_MHASH); |
||||
break; |
||||
default: |
||||
define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_INTERNAL); |
||||
} |
||||
} |
||||
|
||||
$this->setHash($hash); |
||||
} |
||||
|
||||
/** |
||||
* Sets the key for HMACs |
||||
* |
||||
* Keys can be of any length. |
||||
* |
||||
* @access public |
||||
* @param optional String $key |
||||
*/ |
||||
function setKey($key = false) |
||||
{ |
||||
$this->key = $key; |
||||
} |
||||
|
||||
/** |
||||
* Sets the hash function. |
||||
* |
||||
* @access public |
||||
* @param String $hash |
||||
*/ |
||||
function setHash($hash) |
||||
{ |
||||
$hash = strtolower($hash); |
||||
switch ($hash) { |
||||
case 'md5-96': |
||||
case 'sha1-96': |
||||
$this->l = 12; // 96 / 8 = 12 |
||||
break; |
||||
case 'md2': |
||||
case 'md5': |
||||
$this->l = 16; |
||||
break; |
||||
case 'sha1': |
||||
$this->l = 20; |
||||
break; |
||||
case 'sha256': |
||||
$this->l = 32; |
||||
break; |
||||
case 'sha384': |
||||
$this->l = 48; |
||||
break; |
||||
case 'sha512': |
||||
$this->l = 64; |
||||
} |
||||
|
||||
switch ($hash) { |
||||
case 'md2': |
||||
$mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_HASH && in_array('md2', hash_algos()) ? |
||||
CRYPT_HASH_MODE_HASH : CRYPT_HASH_MODE_INTERNAL; |
||||
break; |
||||
case 'sha384': |
||||
case 'sha512': |
||||
$mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_MHASH ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE; |
||||
break; |
||||
default: |
||||
$mode = CRYPT_HASH_MODE; |
||||
} |
||||
|
||||
switch ( $mode ) { |
||||
case CRYPT_HASH_MODE_MHASH: |
||||
switch ($hash) { |
||||
case 'md5': |
||||
case 'md5-96': |
||||
$this->hash = MHASH_MD5; |
||||
break; |
||||
case 'sha256': |
||||
$this->hash = MHASH_SHA256; |
||||
break; |
||||
case 'sha1': |
||||
case 'sha1-96': |
||||
default: |
||||
$this->hash = MHASH_SHA1; |
||||
} |
||||
return; |
||||
case CRYPT_HASH_MODE_HASH: |
||||
switch ($hash) { |
||||
case 'md5': |
||||
case 'md5-96': |
||||
$this->hash = 'md5'; |
||||
return; |
||||
case 'md2': |
||||
case 'sha256': |
||||
case 'sha384': |
||||
case 'sha512': |
||||
$this->hash = $hash; |
||||
return; |
||||
case 'sha1': |
||||
case 'sha1-96': |
||||
default: |
||||
$this->hash = 'sha1'; |
||||
} |
||||
return; |
||||
} |
||||
|
||||
switch ($hash) { |
||||
case 'md2': |
||||
$this->b = 16; |
||||
$this->hash = array($this, '_md2'); |
||||
break; |
||||
case 'md5': |
||||
case 'md5-96': |
||||
$this->b = 64; |
||||
$this->hash = array($this, '_md5'); |
||||
break; |
||||
case 'sha256': |
||||
$this->b = 64; |
||||
$this->hash = array($this, '_sha256'); |
||||
break; |
||||
case 'sha384': |
||||
case 'sha512': |
||||
$this->b = 128; |
||||
$this->hash = array($this, '_sha512'); |
||||
break; |
||||
case 'sha1': |
||||
case 'sha1-96': |
||||
default: |
||||
$this->b = 64; |
||||
$this->hash = array($this, '_sha1'); |
||||
} |
||||
|
||||
$this->ipad = str_repeat(chr(0x36), $this->b); |
||||
$this->opad = str_repeat(chr(0x5C), $this->b); |
||||
} |
||||
|
||||
/** |
||||
* Compute the HMAC. |
||||
* |
||||
* @access public |
||||
* @param String $text |
||||
* @return String |
||||
*/ |
||||
function hash($text) |
||||
{ |
||||
$mode = is_array($this->hash) ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE; |
||||
|
||||
if (!empty($this->key) || is_string($this->key)) { |
||||
switch ( $mode ) { |
||||
case CRYPT_HASH_MODE_MHASH: |
||||
$output = mhash($this->hash, $text, $this->key); |
||||
break; |
||||
case CRYPT_HASH_MODE_HASH: |
||||
$output = hash_hmac($this->hash, $text, $this->key, true); |
||||
break; |
||||
case CRYPT_HASH_MODE_INTERNAL: |
||||
/* "Applications that use keys longer than B bytes will first hash the key using H and then use the |
||||
resultant L byte string as the actual key to HMAC." |
||||
|
||||
-- http://tools.ietf.org/html/rfc2104#section-2 */ |
||||
$key = strlen($this->key) > $this->b ? call_user_func($this->hash, $this->key) : $this->key; |
||||
|
||||
$key = str_pad($key, $this->b, chr(0)); // step 1 |
||||
$temp = $this->ipad ^ $key; // step 2 |
||||
$temp .= $text; // step 3 |
||||
$temp = call_user_func($this->hash, $temp); // step 4 |
||||
$output = $this->opad ^ $key; // step 5 |
||||
$output.= $temp; // step 6 |
||||
$output = call_user_func($this->hash, $output); // step 7 |
||||
} |
||||
} else { |
||||
switch ( $mode ) { |
||||
case CRYPT_HASH_MODE_MHASH: |
||||
$output = mhash($this->hash, $text); |
||||
break; |
||||
case CRYPT_HASH_MODE_HASH: |
||||
$output = hash($this->hash, $text, true); |
||||
break; |
||||
case CRYPT_HASH_MODE_INTERNAL: |
||||
$output = call_user_func($this->hash, $text); |
||||
} |
||||
} |
||||
|
||||
return substr($output, 0, $this->l); |
||||
} |
||||
|
||||
/** |
||||
* Returns the hash length (in bytes) |
||||
* |
||||
* @access public |
||||
* @return Integer |
||||
*/ |
||||
function getLength() |
||||
{ |
||||
return $this->l; |
||||
} |
||||
|
||||
/** |
||||
* Wrapper for MD5 |
||||
* |
||||
* @access private |
||||
* @param String $m |
||||
*/ |
||||
function _md5($m) |
||||
{ |
||||
return pack('H*', md5($m)); |
||||
} |
||||
|
||||
/** |
||||
* Wrapper for SHA1 |
||||
* |
||||
* @access private |
||||
* @param String $m |
||||
*/ |
||||
function _sha1($m) |
||||
{ |
||||
return pack('H*', sha1($m)); |
||||
} |
||||
|
||||
/** |
||||
* Pure-PHP implementation of MD2 |
||||
* |
||||
* See {@link http://tools.ietf.org/html/rfc1319 RFC1319}. |
||||
* |
||||
* @access private |
||||
* @param String $m |
||||
*/ |
||||
function _md2($m) |
||||
{ |
||||
static $s = array( |
||||
41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, |
||||
19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, |
||||
76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, |
||||
138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251, |
||||
245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63, |
||||
148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50, |
||||
39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165, |
||||
181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210, |
||||
150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157, |
||||
112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27, |
||||
96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15, |
||||
85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197, |
||||
234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65, |
||||
129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, |
||||
8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233, |
||||
203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228, |
||||
166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237, |
||||
31, 26, 219, 153, 141, 51, 159, 17, 131, 20 |
||||
); |
||||
|
||||
// Step 1. Append Padding Bytes |
||||
$pad = 16 - (strlen($m) & 0xF); |
||||
$m.= str_repeat(chr($pad), $pad); |
||||
|
||||
$length = strlen($m); |
||||
|
||||
// Step 2. Append Checksum |
||||
$c = str_repeat(chr(0), 16); |
||||
$l = chr(0); |
||||
for ($i = 0; $i < $length; $i+= 16) { |
||||
for ($j = 0; $j < 16; $j++) { |
||||
// RFC1319 incorrectly states that C[j] should be set to S[c xor L] |
||||
//$c[$j] = chr($s[ord($m[$i + $j] ^ $l)]); |
||||
// per <http://www.rfc-editor.org/errata_search.php?rfc=1319>, however, C[j] should be set to S[c xor L] xor C[j] |
||||
$c[$j] = chr($s[ord($m[$i + $j] ^ $l)] ^ ord($c[$j])); |
||||
$l = $c[$j]; |
||||
} |
||||
} |
||||
$m.= $c; |
||||
|
||||
$length+= 16; |
||||
|
||||
// Step 3. Initialize MD Buffer |
||||
$x = str_repeat(chr(0), 48); |
||||
|
||||
// Step 4. Process Message in 16-Byte Blocks |
||||
for ($i = 0; $i < $length; $i+= 16) { |
||||
for ($j = 0; $j < 16; $j++) { |
||||
$x[$j + 16] = $m[$i + $j]; |
||||
$x[$j + 32] = $x[$j + 16] ^ $x[$j]; |
||||
} |
||||
$t = chr(0); |
||||
for ($j = 0; $j < 18; $j++) { |
||||
for ($k = 0; $k < 48; $k++) { |
||||
$x[$k] = $t = $x[$k] ^ chr($s[ord($t)]); |
||||
//$t = $x[$k] = $x[$k] ^ chr($s[ord($t)]); |
||||
} |
||||
$t = chr(ord($t) + $j); |
||||
} |
||||
} |
||||
|
||||
// Step 5. Output |
||||
return substr($x, 0, 16); |
||||
} |
||||
|
||||
/** |
||||
* Pure-PHP implementation of SHA256 |
||||
* |
||||
* See {@link http://en.wikipedia.org/wiki/SHA_hash_functions#SHA-256_.28a_SHA-2_variant.29_pseudocode SHA-256 (a SHA-2 variant) pseudocode - Wikipedia}. |
||||
* |
||||
* @access private |
||||
* @param String $m |
||||
*/ |
||||
function _sha256($m) |
||||
{ |
||||
if (extension_loaded('suhosin')) { |
||||
return pack('H*', sha256($m)); |
||||
} |
||||
|
||||
// Initialize variables |
||||
$hash = array( |
||||
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 |
||||
); |
||||
// Initialize table of round constants |
||||
// (first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311) |
||||
static $k = array( |
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, |
||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, |
||||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, |
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, |
||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, |
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, |
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, |
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 |
||||
); |
||||
|
||||
// Pre-processing |
||||
$length = strlen($m); |
||||
// to round to nearest 56 mod 64, we'll add 64 - (length + (64 - 56)) % 64 |
||||
$m.= str_repeat(chr(0), 64 - (($length + 8) & 0x3F)); |
||||
$m[$length] = chr(0x80); |
||||
// we don't support hashing strings 512MB long |
||||
$m.= pack('N2', 0, $length << 3); |
||||
|
||||
// Process the message in successive 512-bit chunks |
||||
$chunks = str_split($m, 64); |
||||
foreach ($chunks as $chunk) { |
||||
$w = array(); |
||||
for ($i = 0; $i < 16; $i++) { |
||||
extract(unpack('Ntemp', $this->_string_shift($chunk, 4))); |
||||
$w[] = $temp; |
||||
} |
||||
|
||||
// Extend the sixteen 32-bit words into sixty-four 32-bit words |
||||
for ($i = 16; $i < 64; $i++) { |
||||
$s0 = $this->_rightRotate($w[$i - 15], 7) ^ |
||||
$this->_rightRotate($w[$i - 15], 18) ^ |
||||
$this->_rightShift( $w[$i - 15], 3); |
||||
$s1 = $this->_rightRotate($w[$i - 2], 17) ^ |
||||
$this->_rightRotate($w[$i - 2], 19) ^ |
||||
$this->_rightShift( $w[$i - 2], 10); |
||||
$w[$i] = $this->_add($w[$i - 16], $s0, $w[$i - 7], $s1); |
||||
|
||||
} |
||||
|
||||
// Initialize hash value for this chunk |
||||
list($a, $b, $c, $d, $e, $f, $g, $h) = $hash; |
||||
|
||||
// Main loop |
||||
for ($i = 0; $i < 64; $i++) { |
||||
$s0 = $this->_rightRotate($a, 2) ^ |
||||
$this->_rightRotate($a, 13) ^ |
||||
$this->_rightRotate($a, 22); |
||||
$maj = ($a & $b) ^ |
||||
($a & $c) ^ |
||||
($b & $c); |
||||
$t2 = $this->_add($s0, $maj); |
||||
|
||||
$s1 = $this->_rightRotate($e, 6) ^ |
||||
$this->_rightRotate($e, 11) ^ |
||||
$this->_rightRotate($e, 25); |
||||
$ch = ($e & $f) ^ |
||||
($this->_not($e) & $g); |
||||
$t1 = $this->_add($h, $s1, $ch, $k[$i], $w[$i]); |
||||
|
||||
$h = $g; |
||||
$g = $f; |
||||
$f = $e; |
||||
$e = $this->_add($d, $t1); |
||||
$d = $c; |
||||
$c = $b; |
||||
$b = $a; |
||||
$a = $this->_add($t1, $t2); |
||||
} |
||||
|
||||
// Add this chunk's hash to result so far |
||||
$hash = array( |
||||
$this->_add($hash[0], $a), |
||||
$this->_add($hash[1], $b), |
||||
$this->_add($hash[2], $c), |
||||
$this->_add($hash[3], $d), |
||||
$this->_add($hash[4], $e), |
||||
$this->_add($hash[5], $f), |
||||
$this->_add($hash[6], $g), |
||||
$this->_add($hash[7], $h) |
||||
); |
||||
} |
||||
|
||||
// Produce the final hash value (big-endian) |
||||
return pack('N8', $hash[0], $hash[1], $hash[2], $hash[3], $hash[4], $hash[5], $hash[6], $hash[7]); |
||||
} |
||||
|
||||
/** |
||||
* Pure-PHP implementation of SHA384 and SHA512 |
||||
* |
||||
* @access private |
||||
* @param String $m |
||||
*/ |
||||
function _sha512($m) |
||||
{ |
||||
if (!class_exists('Math_BigInteger')) { |
||||
require_once('Math/BigInteger.php'); |
||||
} |
||||
|
||||
static $init384, $init512, $k; |
||||
|
||||
if (!isset($k)) { |
||||
// Initialize variables |
||||
$init384 = array( // initial values for SHA384 |
||||
'cbbb9d5dc1059ed8', '629a292a367cd507', '9159015a3070dd17', '152fecd8f70e5939', |
||||
'67332667ffc00b31', '8eb44a8768581511', 'db0c2e0d64f98fa7', '47b5481dbefa4fa4' |
||||
); |
||||
$init512 = array( // initial values for SHA512 |
||||
'6a09e667f3bcc908', 'bb67ae8584caa73b', '3c6ef372fe94f82b', 'a54ff53a5f1d36f1', |
||||
'510e527fade682d1', '9b05688c2b3e6c1f', '1f83d9abfb41bd6b', '5be0cd19137e2179' |
||||
); |
||||
|
||||
for ($i = 0; $i < 8; $i++) { |
||||
$init384[$i] = new Math_BigInteger($init384[$i], 16); |
||||
$init384[$i]->setPrecision(64); |
||||
$init512[$i] = new Math_BigInteger($init512[$i], 16); |
||||
$init512[$i]->setPrecision(64); |
||||
} |
||||
|
||||
// Initialize table of round constants |
||||
// (first 64 bits of the fractional parts of the cube roots of the first 80 primes 2..409) |
||||
$k = array( |
||||
'428a2f98d728ae22', '7137449123ef65cd', 'b5c0fbcfec4d3b2f', 'e9b5dba58189dbbc', |
||||
'3956c25bf348b538', '59f111f1b605d019', '923f82a4af194f9b', 'ab1c5ed5da6d8118', |
||||
'd807aa98a3030242', '12835b0145706fbe', '243185be4ee4b28c', '550c7dc3d5ffb4e2', |
||||
'72be5d74f27b896f', '80deb1fe3b1696b1', '9bdc06a725c71235', 'c19bf174cf692694', |
||||
'e49b69c19ef14ad2', 'efbe4786384f25e3', '0fc19dc68b8cd5b5', '240ca1cc77ac9c65', |
||||
'2de92c6f592b0275', '4a7484aa6ea6e483', '5cb0a9dcbd41fbd4', '76f988da831153b5', |
||||
'983e5152ee66dfab', 'a831c66d2db43210', 'b00327c898fb213f', 'bf597fc7beef0ee4', |
||||
'c6e00bf33da88fc2', 'd5a79147930aa725', '06ca6351e003826f', '142929670a0e6e70', |
||||
'27b70a8546d22ffc', '2e1b21385c26c926', '4d2c6dfc5ac42aed', '53380d139d95b3df', |
||||
'650a73548baf63de', '766a0abb3c77b2a8', '81c2c92e47edaee6', '92722c851482353b', |
||||
'a2bfe8a14cf10364', 'a81a664bbc423001', 'c24b8b70d0f89791', 'c76c51a30654be30', |
||||
'd192e819d6ef5218', 'd69906245565a910', 'f40e35855771202a', '106aa07032bbd1b8', |
||||
'19a4c116b8d2d0c8', '1e376c085141ab53', '2748774cdf8eeb99', '34b0bcb5e19b48a8', |
||||
'391c0cb3c5c95a63', '4ed8aa4ae3418acb', '5b9cca4f7763e373', '682e6ff3d6b2b8a3', |
||||
'748f82ee5defb2fc', '78a5636f43172f60', '84c87814a1f0ab72', '8cc702081a6439ec', |
||||
'90befffa23631e28', 'a4506cebde82bde9', 'bef9a3f7b2c67915', 'c67178f2e372532b', |
||||
'ca273eceea26619c', 'd186b8c721c0c207', 'eada7dd6cde0eb1e', 'f57d4f7fee6ed178', |
||||
'06f067aa72176fba', '0a637dc5a2c898a6', '113f9804bef90dae', '1b710b35131c471b', |
||||
'28db77f523047d84', '32caab7b40c72493', '3c9ebe0a15c9bebc', '431d67c49c100d4c', |
||||
'4cc5d4becb3e42b6', '597f299cfc657e2a', '5fcb6fab3ad6faec', '6c44198c4a475817' |
||||
); |
||||
|
||||
for ($i = 0; $i < 80; $i++) { |
||||
$k[$i] = new Math_BigInteger($k[$i], 16); |
||||
} |
||||
} |
||||
|
||||
$hash = $this->l == 48 ? $init384 : $init512; |
||||
|
||||
// Pre-processing |
||||
$length = strlen($m); |
||||
// to round to nearest 112 mod 128, we'll add 128 - (length + (128 - 112)) % 128 |
||||
$m.= str_repeat(chr(0), 128 - (($length + 16) & 0x7F)); |
||||
$m[$length] = chr(0x80); |
||||
// we don't support hashing strings 512MB long |
||||
$m.= pack('N4', 0, 0, 0, $length << 3); |
||||
|
||||
// Process the message in successive 1024-bit chunks |
||||
$chunks = str_split($m, 128); |
||||
foreach ($chunks as $chunk) { |
||||
$w = array(); |
||||
for ($i = 0; $i < 16; $i++) { |
||||
$temp = new Math_BigInteger($this->_string_shift($chunk, 8), 256); |
||||
$temp->setPrecision(64); |
||||
$w[] = $temp; |
||||
} |
||||
|
||||
// Extend the sixteen 32-bit words into eighty 32-bit words |
||||
for ($i = 16; $i < 80; $i++) { |
||||
$temp = array( |
||||
$w[$i - 15]->bitwise_rightRotate(1), |
||||
$w[$i - 15]->bitwise_rightRotate(8), |
||||
$w[$i - 15]->bitwise_rightShift(7) |
||||
); |
||||
$s0 = $temp[0]->bitwise_xor($temp[1]); |
||||
$s0 = $s0->bitwise_xor($temp[2]); |
||||
$temp = array( |
||||
$w[$i - 2]->bitwise_rightRotate(19), |
||||
$w[$i - 2]->bitwise_rightRotate(61), |
||||
$w[$i - 2]->bitwise_rightShift(6) |
||||
); |
||||
$s1 = $temp[0]->bitwise_xor($temp[1]); |
||||
$s1 = $s1->bitwise_xor($temp[2]); |
||||
$w[$i] = $w[$i - 16]->copy(); |
||||
$w[$i] = $w[$i]->add($s0); |
||||
$w[$i] = $w[$i]->add($w[$i - 7]); |
||||
$w[$i] = $w[$i]->add($s1); |
||||
} |
||||
|
||||
// Initialize hash value for this chunk |
||||
$a = $hash[0]->copy(); |
||||
$b = $hash[1]->copy(); |
||||
$c = $hash[2]->copy(); |
||||
$d = $hash[3]->copy(); |
||||
$e = $hash[4]->copy(); |
||||
$f = $hash[5]->copy(); |
||||
$g = $hash[6]->copy(); |
||||
$h = $hash[7]->copy(); |
||||
|
||||
// Main loop |
||||
for ($i = 0; $i < 80; $i++) { |
||||
$temp = array( |
||||
$a->bitwise_rightRotate(28), |
||||
$a->bitwise_rightRotate(34), |
||||
$a->bitwise_rightRotate(39) |
||||
); |
||||
$s0 = $temp[0]->bitwise_xor($temp[1]); |
||||
$s0 = $s0->bitwise_xor($temp[2]); |
||||
$temp = array( |
||||
$a->bitwise_and($b), |
||||
$a->bitwise_and($c), |
||||
$b->bitwise_and($c) |
||||
); |
||||
$maj = $temp[0]->bitwise_xor($temp[1]); |
||||
$maj = $maj->bitwise_xor($temp[2]); |
||||
$t2 = $s0->add($maj); |
||||
|
||||
$temp = array( |
||||
$e->bitwise_rightRotate(14), |
||||
$e->bitwise_rightRotate(18), |
||||
$e->bitwise_rightRotate(41) |
||||
); |
||||
$s1 = $temp[0]->bitwise_xor($temp[1]); |
||||
$s1 = $s1->bitwise_xor($temp[2]); |
||||
$temp = array( |
||||
$e->bitwise_and($f), |
||||
$g->bitwise_and($e->bitwise_not()) |
||||
); |
||||
$ch = $temp[0]->bitwise_xor($temp[1]); |
||||
$t1 = $h->add($s1); |
||||
$t1 = $t1->add($ch); |
||||
$t1 = $t1->add($k[$i]); |
||||
$t1 = $t1->add($w[$i]); |
||||
|
||||
$h = $g->copy(); |
||||
$g = $f->copy(); |
||||
$f = $e->copy(); |
||||
$e = $d->add($t1); |
||||
$d = $c->copy(); |
||||
$c = $b->copy(); |
||||
$b = $a->copy(); |
||||
$a = $t1->add($t2); |
||||
} |
||||
|
||||
// Add this chunk's hash to result so far |
||||
$hash = array( |
||||
$hash[0]->add($a), |
||||
$hash[1]->add($b), |
||||
$hash[2]->add($c), |
||||
$hash[3]->add($d), |
||||
$hash[4]->add($e), |
||||
$hash[5]->add($f), |
||||
$hash[6]->add($g), |
||||
$hash[7]->add($h) |
||||
); |
||||
} |
||||
|
||||
// Produce the final hash value (big-endian) |
||||
// (Crypt_Hash::hash() trims the output for hashes but not for HMACs. as such, we trim the output here) |
||||
$temp = $hash[0]->toBytes() . $hash[1]->toBytes() . $hash[2]->toBytes() . $hash[3]->toBytes() . |
||||
$hash[4]->toBytes() . $hash[5]->toBytes(); |
||||
if ($this->l != 48) { |
||||
$temp.= $hash[6]->toBytes() . $hash[7]->toBytes(); |
||||
} |
||||
|
||||
return $temp; |
||||
} |
||||
|
||||
/** |
||||
* Right Rotate |
||||
* |
||||
* @access private |
||||
* @param Integer $int |
||||
* @param Integer $amt |
||||
* @see _sha256() |
||||
* @return Integer |
||||
*/ |
||||
function _rightRotate($int, $amt) |
||||
{ |
||||
$invamt = 32 - $amt; |
||||
$mask = (1 << $invamt) - 1; |
||||
return (($int << $invamt) & 0xFFFFFFFF) | (($int >> $amt) & $mask); |
||||
} |
||||
|
||||
/** |
||||
* Right Shift |
||||
* |
||||
* @access private |
||||
* @param Integer $int |
||||
* @param Integer $amt |
||||
* @see _sha256() |
||||
* @return Integer |
||||
*/ |
||||
function _rightShift($int, $amt) |
||||
{ |
||||
$mask = (1 << (32 - $amt)) - 1; |
||||
return ($int >> $amt) & $mask; |
||||
} |
||||
|
||||
/** |
||||
* Not |
||||
* |
||||
* @access private |
||||
* @param Integer $int |
||||
* @see _sha256() |
||||
* @return Integer |
||||
*/ |
||||
function _not($int) |
||||
{ |
||||
return ~$int & 0xFFFFFFFF; |
||||
} |
||||
|
||||
/** |
||||
* Add |
||||
* |
||||
* _sha256() adds multiple unsigned 32-bit integers. Since PHP doesn't support unsigned integers and since the |
||||
* possibility of overflow exists, care has to be taken. Math_BigInteger() could be used but this should be faster. |
||||
* |
||||
* @param Integer $... |
||||
* @return Integer |
||||
* @see _sha256() |
||||
* @access private |
||||
*/ |
||||
function _add() |
||||
{ |
||||
static $mod; |
||||
if (!isset($mod)) { |
||||
$mod = pow(2, 32); |
||||
} |
||||
|
||||
$result = 0; |
||||
$arguments = func_get_args(); |
||||
foreach ($arguments as $argument) { |
||||
$result+= $argument < 0 ? ($argument & 0x7FFFFFFF) + 0x80000000 : $argument; |
||||
} |
||||
|
||||
return fmod($result, $mod); |
||||
} |
||||
|
||||
/** |
||||
* String Shift |
||||
* |
||||
* Inspired by array_shift |
||||
* |
||||
* @param String $string |
||||
* @param optional Integer $index |
||||
* @return String |
||||
* @access private |
||||
*/ |
||||
function _string_shift(&$string, $index = 1) |
||||
{ |
||||
$substr = substr($string, 0, $index); |
||||
$string = substr($string, $index); |
||||
return $substr; |
||||
} |
||||
} |
@ -0,0 +1,492 @@ |
||||
<?php |
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
||||
|
||||
/** |
||||
* Pure-PHP implementation of RC4. |
||||
* |
||||
* Uses mcrypt, if available, and an internal implementation, otherwise. |
||||
* |
||||
* PHP versions 4 and 5 |
||||
* |
||||
* Useful resources are as follows: |
||||
* |
||||
* - {@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} |
||||
* |
||||
* 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. |
||||
* |
||||
* Here's a short example of how to use this library: |
||||
* <code> |
||||
* <?php |
||||
* include('Crypt/RC4.php'); |
||||
* |
||||
* $rc4 = new Crypt_RC4(); |
||||
* |
||||
* $rc4->setKey('abcdefgh'); |
||||
* |
||||
* $size = 10 * 1024; |
||||
* $plaintext = ''; |
||||
* for ($i = 0; $i < $size; $i++) { |
||||
* $plaintext.= 'a'; |
||||
* } |
||||
* |
||||
* echo $rc4->decrypt($rc4->encrypt($plaintext)); |
||||
* ?> |
||||
* </code> |
||||
* |
||||
* 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 Crypt |
||||
* @package Crypt_RC4 |
||||
* @author Jim Wigginton <terrafrost@php.net> |
||||
* @copyright MMVII Jim Wigginton |
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License |
||||
* @link http://phpseclib.sourceforge.net |
||||
*/ |
||||
|
||||
/**#@+ |
||||
* @access private |
||||
* @see Crypt_RC4::Crypt_RC4() |
||||
*/ |
||||
/** |
||||
* Toggles the internal implementation |
||||
*/ |
||||
define('CRYPT_RC4_MODE_INTERNAL', 1); |
||||
/** |
||||
* Toggles the mcrypt implementation |
||||
*/ |
||||
define('CRYPT_RC4_MODE_MCRYPT', 2); |
||||
/**#@-*/ |
||||
|
||||
/**#@+ |
||||
* @access private |
||||
* @see Crypt_RC4::_crypt() |
||||
*/ |
||||
define('CRYPT_RC4_ENCRYPT', 0); |
||||
define('CRYPT_RC4_DECRYPT', 1); |
||||
/**#@-*/ |
||||
|
||||
/** |
||||
* Pure-PHP implementation of RC4. |
||||
* |
||||
* @author Jim Wigginton <terrafrost@php.net> |
||||
* @version 0.1.0 |
||||
* @access public |
||||
* @package Crypt_RC4 |
||||
*/ |
||||
class Crypt_RC4 { |
||||
/** |
||||
* The Key |
||||
* |
||||
* @see Crypt_RC4::setKey() |
||||
* @var String |
||||
* @access private |
||||
*/ |
||||
var $key = "\0"; |
||||
|
||||
/** |
||||
* The Key Stream for encryption |
||||
* |
||||
* If CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT, this will be equal to the mcrypt object |
||||
* |
||||
* @see Crypt_RC4::setKey() |
||||
* @var Array |
||||
* @access private |
||||
*/ |
||||
var $encryptStream = false; |
||||
|
||||
/** |
||||
* The Key Stream for decryption |
||||
* |
||||
* If CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT, this will be equal to the mcrypt object |
||||
* |
||||
* @see Crypt_RC4::setKey() |
||||
* @var Array |
||||
* @access private |
||||
*/ |
||||
var $decryptStream = false; |
||||
|
||||
/** |
||||
* The $i and $j indexes for encryption |
||||
* |
||||
* @see Crypt_RC4::_crypt() |
||||
* @var Integer |
||||
* @access private |
||||
*/ |
||||
var $encryptIndex = 0; |
||||
|
||||
/** |
||||
* The $i and $j indexes for decryption |
||||
* |
||||
* @see Crypt_RC4::_crypt() |
||||
* @var Integer |
||||
* @access private |
||||
*/ |
||||
var $decryptIndex = 0; |
||||
|
||||
/** |
||||
* The Encryption Algorithm |
||||
* |
||||
* Only used if CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT. Only possible values are MCRYPT_RC4 or MCRYPT_ARCFOUR. |
||||
* |
||||
* @see Crypt_RC4::Crypt_RC4() |
||||
* @var Integer |
||||
* @access private |
||||
*/ |
||||
var $mode; |
||||
|
||||
/** |
||||
* Continuous Buffer status |
||||
* |
||||
* @see Crypt_RC4::enableContinuousBuffer() |
||||
* @var Boolean |
||||
* @access private |
||||
*/ |
||||
var $continuousBuffer = false; |
||||
|
||||
/** |
||||
* Default Constructor. |
||||
* |
||||
* Determines whether or not the mcrypt extension should be used. |
||||
* |
||||
* @return Crypt_RC4 |
||||
* @access public |
||||
*/ |
||||
function Crypt_RC4() |
||||
{ |
||||
if ( !defined('CRYPT_RC4_MODE') ) { |
||||
switch (true) { |
||||
case extension_loaded('mcrypt') && (defined('MCRYPT_ARCFOUR') || defined('MCRYPT_RC4')) && in_array('arcfour', mcrypt_list_algorithms()): |
||||
define('CRYPT_RC4_MODE', CRYPT_RC4_MODE_MCRYPT); |
||||
break; |
||||
default: |
||||
define('CRYPT_RC4_MODE', CRYPT_RC4_MODE_INTERNAL); |
||||
} |
||||
} |
||||
|
||||
switch ( CRYPT_RC4_MODE ) { |
||||
case CRYPT_RC4_MODE_MCRYPT: |
||||
switch (true) { |
||||
case defined('MCRYPT_ARCFOUR'): |
||||
$this->mode = MCRYPT_ARCFOUR; |
||||
break; |
||||
case defined('MCRYPT_RC4'); |
||||
$this->mode = MCRYPT_RC4; |
||||
} |
||||
$this->encryptStream = mcrypt_module_open($this->mode, '', MCRYPT_MODE_STREAM, ''); |
||||
$this->decryptStream = mcrypt_module_open($this->mode, '', MCRYPT_MODE_STREAM, ''); |
||||
|
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Sets the key. |
||||
* |
||||
* Keys can be between 1 and 256 bytes long. If they are longer then 256 bytes, the first 256 bytes will |
||||
* be used. If no key is explicitly set, it'll be assumed to be a single null byte. |
||||
* |
||||
* @access public |
||||
* @param String $key |
||||
*/ |
||||
function setKey($key) |
||||
{ |
||||
$this->key = $key; |
||||
|
||||
if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) { |
||||
mcrypt_generic_init($this->encryptStream, $this->key, ''); |
||||
mcrypt_generic_init($this->decryptStream, $this->key, ''); |
||||
return; |
||||
} |
||||
|
||||
$keyLength = strlen($key); |
||||
$keyStream = array(); |
||||
for ($i = 0; $i < 256; $i++) { |
||||
$keyStream[$i] = $i; |
||||
} |
||||
$j = 0; |
||||
for ($i = 0; $i < 256; $i++) { |
||||
$j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255; |
||||
$temp = $keyStream[$i]; |
||||
$keyStream[$i] = $keyStream[$j]; |
||||
$keyStream[$j] = $temp; |
||||
} |
||||
|
||||
$this->encryptIndex = $this->decryptIndex = array(0, 0); |
||||
$this->encryptStream = $this->decryptStream = $keyStream; |
||||
} |
||||
|
||||
/** |
||||
* Sets the password. |
||||
* |
||||
* Depending on what $method is set to, setPassword()'s (optional) parameters are as follows: |
||||
* {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}: |
||||
* $hash, $salt, $count, $dkLen |
||||
* |
||||
* @param String $password |
||||
* @param optional String $method |
||||
* @access public |
||||
*/ |
||||
function setPassword($password, $method = 'pbkdf2') |
||||
{ |
||||
$key = ''; |
||||
|
||||
switch ($method) { |
||||
default: // 'pbkdf2' |
||||
list(, , $hash, $salt, $count) = func_get_args(); |
||||
if (!isset($hash)) { |
||||
$hash = 'sha1'; |
||||
} |
||||
// WPA and WPA2 use the SSID as the salt |
||||
if (!isset($salt)) { |
||||
$salt = 'phpseclib/salt'; |
||||
} |
||||
// RFC2898#section-4.2 uses 1,000 iterations by default |
||||
// WPA and WPA2 use 4,096. |
||||
if (!isset($count)) { |
||||
$count = 1000; |
||||
} |
||||
if (!isset($dkLen)) { |
||||
$dkLen = 128; |
||||
} |
||||
|
||||
if (!class_exists('Crypt_Hash')) { |
||||
require_once('Crypt/Hash.php'); |
||||
} |
||||
|
||||
$i = 1; |
||||
while (strlen($key) < $dkLen) { |
||||
//$dk.= $this->_pbkdf($password, $salt, $count, $i++); |
||||
$hmac = new Crypt_Hash(); |
||||
$hmac->setHash($hash); |
||||
$hmac->setKey($password); |
||||
$f = $u = $hmac->hash($salt . pack('N', $i++)); |
||||
for ($j = 2; $j <= $count; $j++) { |
||||
$u = $hmac->hash($u); |
||||
$f^= $u; |
||||
} |
||||
$key.= $f; |
||||
} |
||||
} |
||||
|
||||
$this->setKey(substr($key, 0, $dkLen)); |
||||
} |
||||
|
||||
/** |
||||
* Dummy function. |
||||
* |
||||
* Some protocols, such as WEP, prepend an "initialization vector" to the key, effectively creating a new key [1]. |
||||
* If you need to use an initialization vector in this manner, feel free to prepend it to the key, yourself, before |
||||
* calling setKey(). |
||||
* |
||||
* [1] WEP's initialization vectors (IV's) are used in a somewhat insecure way. Since, in that protocol, |
||||
* the IV's are relatively easy to predict, an attack described by |
||||
* {@link http://www.drizzle.com/~aboba/IEEE/rc4_ksaproc.pdf Scott Fluhrer, Itsik Mantin, and Adi Shamir} |
||||
* can be used to quickly guess at the rest of the key. The following links elaborate: |
||||
* |
||||
* {@link http://www.rsa.com/rsalabs/node.asp?id=2009 http://www.rsa.com/rsalabs/node.asp?id=2009} |
||||
* {@link http://en.wikipedia.org/wiki/Related_key_attack http://en.wikipedia.org/wiki/Related_key_attack} |
||||
* |
||||
* @param String $iv |
||||
* @see Crypt_RC4::setKey() |
||||
* @access public |
||||
*/ |
||||
function setIV($iv) |
||||
{ |
||||
} |
||||
|
||||
/** |
||||
* Encrypts a message. |
||||
* |
||||
* @see Crypt_RC4::_crypt() |
||||
* @access public |
||||
* @param String $plaintext |
||||
*/ |
||||
function encrypt($plaintext) |
||||
{ |
||||
return $this->_crypt($plaintext, CRYPT_RC4_ENCRYPT); |
||||
} |
||||
|
||||
/** |
||||
* Decrypts a message. |
||||
* |
||||
* $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)). |
||||
* Atleast if the continuous buffer is disabled. |
||||
* |
||||
* @see Crypt_RC4::_crypt() |
||||
* @access public |
||||
* @param String $ciphertext |
||||
*/ |
||||
function decrypt($ciphertext) |
||||
{ |
||||
return $this->_crypt($ciphertext, CRYPT_RC4_DECRYPT); |
||||
} |
||||
|
||||
/** |
||||
* Encrypts or decrypts a message. |
||||
* |
||||
* @see Crypt_RC4::encrypt() |
||||
* @see Crypt_RC4::decrypt() |
||||
* @access private |
||||
* @param String $text |
||||
* @param Integer $mode |
||||
*/ |
||||
function _crypt($text, $mode) |
||||
{ |
||||
if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) { |
||||
$keyStream = $mode == CRYPT_RC4_ENCRYPT ? 'encryptStream' : 'decryptStream'; |
||||
|
||||
if (!$this->continuousBuffer) { |
||||
mcrypt_generic_init($this->$keyStream, $this->key, ''); |
||||
} |
||||
|
||||
return mcrypt_generic($this->$keyStream, $text); |
||||
} |
||||
|
||||
if ($this->encryptStream === false) { |
||||
$this->setKey($this->key); |
||||
} |
||||
|
||||
switch ($mode) { |
||||
case CRYPT_RC4_ENCRYPT: |
||||
$keyStream = $this->encryptStream; |
||||
list($i, $j) = $this->encryptIndex; |
||||
break; |
||||
case CRYPT_RC4_DECRYPT: |
||||
$keyStream = $this->decryptStream; |
||||
list($i, $j) = $this->decryptIndex; |
||||
} |
||||
|
||||
$newText = ''; |
||||
for ($k = 0; $k < strlen($text); $k++) { |
||||
$i = ($i + 1) & 255; |
||||
$j = ($j + $keyStream[$i]) & 255; |
||||
$temp = $keyStream[$i]; |
||||
$keyStream[$i] = $keyStream[$j]; |
||||
$keyStream[$j] = $temp; |
||||
$temp = $keyStream[($keyStream[$i] + $keyStream[$j]) & 255]; |
||||
$newText.= chr(ord($text[$k]) ^ $temp); |
||||
} |
||||
|
||||
if ($this->continuousBuffer) { |
||||
switch ($mode) { |
||||
case CRYPT_RC4_ENCRYPT: |
||||
$this->encryptStream = $keyStream; |
||||
$this->encryptIndex = array($i, $j); |
||||
break; |
||||
case CRYPT_RC4_DECRYPT: |
||||
$this->decryptStream = $keyStream; |
||||
$this->decryptIndex = array($i, $j); |
||||
} |
||||
} |
||||
|
||||
return $newText; |
||||
} |
||||
|
||||
/** |
||||
* 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: |
||||
* |
||||
* <code> |
||||
* echo $rc4->encrypt(substr($plaintext, 0, 8)); |
||||
* echo $rc4->encrypt(substr($plaintext, 8, 8)); |
||||
* </code> |
||||
* <code> |
||||
* echo $rc4->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: |
||||
* |
||||
* <code> |
||||
* $rc4->encrypt(substr($plaintext, 0, 8)); |
||||
* echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8))); |
||||
* </code> |
||||
* <code> |
||||
* echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8))); |
||||
* </code> |
||||
* |
||||
* With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different |
||||
* 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. |
||||
* |
||||
* Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each |
||||
* 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), |
||||
* however, they are also less intuitive and more likely to cause you problems. |
||||
* |
||||
* @see Crypt_RC4::disableContinuousBuffer() |
||||
* @access public |
||||
*/ |
||||
function enableContinuousBuffer() |
||||
{ |
||||
if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) { |
||||
mcrypt_generic_init($this->encryptStream, $this->key, ''); |
||||
mcrypt_generic_init($this->decryptStream, $this->key, ''); |
||||
} |
||||
|
||||
$this->continuousBuffer = true; |
||||
} |
||||
|
||||
/** |
||||
* Treat consecutive packets as if they are a discontinuous buffer. |
||||
* |
||||
* The default behavior. |
||||
* |
||||
* @see Crypt_RC4::enableContinuousBuffer() |
||||
* @access public |
||||
*/ |
||||
function disableContinuousBuffer() |
||||
{ |
||||
if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_INTERNAL ) { |
||||
$this->encryptIndex = $this->decryptIndex = array(0, 0); |
||||
$this->encryptStream = $this->decryptStream = false; |
||||
} |
||||
|
||||
$this->continuousBuffer = false; |
||||
} |
||||
|
||||
/** |
||||
* Dummy function. |
||||
* |
||||
* Since RC4 is a stream cipher and not a block cipher, no padding is necessary. The only reason this function is |
||||
* included is so that you can switch between a block cipher and a stream cipher transparently. |
||||
* |
||||
* @see Crypt_RC4::disablePadding() |
||||
* @access public |
||||
*/ |
||||
function enablePadding() |
||||
{ |
||||
} |
||||
|
||||
/** |
||||
* Dummy function. |
||||
* |
||||
* @see Crypt_RC4::enablePadding() |
||||
* @access public |
||||
*/ |
||||
function disablePadding() |
||||
{ |
||||
} |
||||
} |
||||
|
||||
// vim: ts=4:sw=4:et: |
||||
// vim6: fdl=1: |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,249 @@ |
||||
<?php |
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
||||
|
||||
/** |
||||
* Random Number Generator |
||||
* |
||||
* PHP versions 4 and 5 |
||||
* |
||||
* Here's a short example of how to use this library: |
||||
* <code> |
||||
* <?php |
||||
* include('Crypt/Random.php'); |
||||
* |
||||
* echo bin2hex(crypt_random_string(8)); |
||||
* ?> |
||||
* </code> |
||||
* |
||||
* 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 Crypt |
||||
* @package Crypt_Random |
||||
* @author Jim Wigginton <terrafrost@php.net> |
||||
* @copyright MMVII Jim Wigginton |
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License |
||||
* @link http://phpseclib.sourceforge.net |
||||
*/ |
||||
|
||||
/** |
||||
* "Is Windows" test |
||||
* |
||||
* @access private |
||||
*/ |
||||
define('CRYPT_RANDOM_IS_WINDOWS', strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'); |
||||
|
||||
/** |
||||
* 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. |
||||
* eg. for RSA key generation. |
||||
* |
||||
* @param Integer $length |
||||
* @return String |
||||
* @access public |
||||
*/ |
||||
function crypt_random_string($length) |
||||
{ |
||||
if (CRYPT_RANDOM_IS_WINDOWS) { |
||||
// method 1. prior to PHP 5.3 this would call rand() on windows hence the function_exists('class_alias') call. |
||||
// ie. class_alias is a function that was introduced in PHP 5.3 |
||||
if (function_exists('mcrypt_create_iv') && function_exists('class_alias')) { |
||||
return mcrypt_create_iv($length); |
||||
} |
||||
// method 2. openssl_random_pseudo_bytes was introduced in PHP 5.3.0 but prior to PHP 5.3.4 there was, |
||||
// to quote <http://php.net/ChangeLog-5.php#5.3.4>, "possible blocking behavior". as of 5.3.4 |
||||
// openssl_random_pseudo_bytes and mcrypt_create_iv do the exact same thing on Windows. ie. they both |
||||
// call php_win32_get_random_bytes(): |
||||
// |
||||
// https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/openssl/openssl.c#L5008 |
||||
// https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1392 |
||||
// |
||||
// php_win32_get_random_bytes() is defined thusly: |
||||
// |
||||
// https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/win32/winutil.c#L80 |
||||
// |
||||
// we're calling it, all the same, in the off chance that the mcrypt extension is not available |
||||
if (function_exists('openssl_random_pseudo_bytes') && version_compare(PHP_VERSION, '5.3.4', '>=')) { |
||||
return openssl_random_pseudo_bytes($length); |
||||
} |
||||
} else { |
||||
// method 1. the fastest |
||||
if (function_exists('openssl_random_pseudo_bytes')) { |
||||
return openssl_random_pseudo_bytes($length); |
||||
} |
||||
// method 2 |
||||
static $fp = true; |
||||
if ($fp === true) { |
||||
// warning's will be output unles the error suppression operator is used. errors such as |
||||
// "open_basedir restriction in effect", "Permission denied", "No such file or directory", etc. |
||||
$fp = @fopen('/dev/urandom', 'rb'); |
||||
} |
||||
if ($fp !== true && $fp !== false) { // surprisingly faster than !is_bool() or is_resource() |
||||
return fread($fp, $length); |
||||
} |
||||
// method 3. pretty much does the same thing as method 2 per the following url: |
||||
// https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1391 |
||||
// surprisingly slower than method 2. maybe that's because mcrypt_create_iv does a bunch of error checking that we're |
||||
// not doing. regardless, this'll only be called if this PHP script couldn't open /dev/urandom due to open_basedir |
||||
// restrictions or some such |
||||
if (function_exists('mcrypt_create_iv')) { |
||||
return mcrypt_create_iv($length, MCRYPT_DEV_URANDOM); |
||||
} |
||||
} |
||||
// at this point we have no choice but to use a pure-PHP CSPRNG |
||||
|
||||
// cascade entropy across multiple PHP instances by fixing the session and collecting all |
||||
// environmental variables, including the previous session data and the current session |
||||
// data. |
||||
// |
||||
// 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 |
||||
// 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 |
||||
// however. a ton of people visiting the website. obviously you don't want to base your seeding |
||||
// soley on parameters a potential attacker sends but (1) not everything in $_SERVER is controlled |
||||
// 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. |
||||
// another user visits the page and the serialization of their data is utilized along with the |
||||
// server envirnment stuff and a hash of the previous http request data (which itself utilizes |
||||
// a hash of the session data before that). certainly an attacker should be assumed to have |
||||
// full control over his own http requests. he, however, is not going to have control over |
||||
// everyone's http requests. |
||||
static $crypto = false, $v; |
||||
if ($crypto === false) { |
||||
// save old session data |
||||
$old_session_id = session_id(); |
||||
$old_use_cookies = ini_get('session.use_cookies'); |
||||
$old_session_cache_limiter = session_cache_limiter(); |
||||
if (isset($_SESSION)) { |
||||
$_OLD_SESSION = $_SESSION; |
||||
} |
||||
if ($old_session_id != '') { |
||||
session_write_close(); |
||||
} |
||||
|
||||
session_id(1); |
||||
ini_set('session.use_cookies', 0); |
||||
session_cache_limiter(''); |
||||
session_start(); |
||||
|
||||
$v = $seed = $_SESSION['seed'] = pack('H*', sha1( |
||||
serialize($_SERVER) . |
||||
serialize($_POST) . |
||||
serialize($_GET) . |
||||
serialize($_COOKIE) . |
||||
serialize($GLOBALS) . |
||||
serialize($_SESSION) . |
||||
serialize($_OLD_SESSION) |
||||
)); |
||||
if (!isset($_SESSION['count'])) { |
||||
$_SESSION['count'] = 0; |
||||
} |
||||
$_SESSION['count']++; |
||||
|
||||
session_write_close(); |
||||
|
||||
// restore old session data |
||||
if ($old_session_id != '') { |
||||
session_id($old_session_id); |
||||
session_start(); |
||||
ini_set('session.use_cookies', $old_use_cookies); |
||||
session_cache_limiter($old_session_cache_limiter); |
||||
} else { |
||||
if (isset($_OLD_SESSION)) { |
||||
$_SESSION = $_OLD_SESSION; |
||||
unset($_OLD_SESSION); |
||||
} else { |
||||
unset($_SESSION); |
||||
} |
||||
} |
||||
|
||||
// in SSH2 a shared secret and an exchange hash are generated through the key exchange process. |
||||
// 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. |
||||
// 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: |
||||
// |
||||
// http://tools.ietf.org/html/rfc4253#section-7.2 |
||||
// |
||||
// see the is_string($crypto) part for an example of how to expand the keys |
||||
$key = pack('H*', sha1($seed . 'A')); |
||||
$iv = pack('H*', sha1($seed . 'C')); |
||||
|
||||
// ciphers are used as per the nist.gov link below. also, see this link: |
||||
// |
||||
// http://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator#Designs_based_on_cryptographic_primitives |
||||
switch (true) { |
||||
case class_exists('Crypt_AES'): |
||||
$crypto = new Crypt_AES(CRYPT_AES_MODE_CTR); |
||||
break; |
||||
case class_exists('Crypt_TripleDES'): |
||||
$crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CTR); |
||||
break; |
||||
case class_exists('Crypt_DES'): |
||||
$crypto = new Crypt_DES(CRYPT_DES_MODE_CTR); |
||||
break; |
||||
case class_exists('Crypt_RC4'): |
||||
$crypto = new Crypt_RC4(); |
||||
break; |
||||
default: |
||||
$crypto = $seed; |
||||
return crypt_random_string($length); |
||||
} |
||||
|
||||
$crypto->setKey($key); |
||||
$crypto->setIV($iv); |
||||
$crypto->enableContinuousBuffer(); |
||||
} |
||||
|
||||
if (is_string($crypto)) { |
||||
// the following is based off of ANSI X9.31: |
||||
// |
||||
// http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf |
||||
// |
||||
// OpenSSL uses that same standard for it's random numbers: |
||||
// |
||||
// http://www.opensource.apple.com/source/OpenSSL/OpenSSL-38/openssl/fips-1.0/rand/fips_rand.c |
||||
// (do a search for "ANS X9.31 A.2.4") |
||||
// |
||||
// ANSI X9.31 recommends ciphers be used and phpseclib does use them if they're available (see |
||||
// later on in the code) but if they're not we'll use sha1 |
||||
$result = ''; |
||||
while (strlen($result) < $length) { // each loop adds 20 bytes |
||||
// microtime() isn't packed as "densely" as it could be but then neither is that the idea. |
||||
// the idea is simply to ensure that each "block" has a unique element to it. |
||||
$i = pack('H*', sha1(microtime())); |
||||
$r = pack('H*', sha1($i ^ $v)); |
||||
$v = pack('H*', sha1($r ^ $i)); |
||||
$result.= $r; |
||||
} |
||||
return substr($result, 0, $length); |
||||
} |
||||
|
||||
//return $crypto->encrypt(str_repeat("\0", $length)); |
||||
|
||||
$result = ''; |
||||
while (strlen($result) < $length) { |
||||
$i = $crypto->encrypt(microtime()); |
||||
$r = $crypto->encrypt($i ^ $v); |
||||
$v = $crypto->encrypt($r ^ $i); |
||||
$result.= $r; |
||||
} |
||||
return substr($result, 0, $length); |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,842 @@ |
||||
<?php |
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
||||
|
||||
/** |
||||
* Pure-PHP implementation of Triple DES. |
||||
* |
||||
* Uses mcrypt, if available, and an internal implementation, otherwise. Operates in the EDE3 mode (encrypt-decrypt-encrypt). |
||||
* |
||||
* PHP versions 4 and 5 |
||||
* |
||||
* Here's a short example of how to use this library: |
||||
* <code> |
||||
* <?php |
||||
* include('Crypt/TripleDES.php'); |
||||
* |
||||
* $des = new Crypt_TripleDES(); |
||||
* |
||||
* $des->setKey('abcdefghijklmnopqrstuvwx'); |
||||
* |
||||
* $size = 10 * 1024; |
||||
* $plaintext = ''; |
||||
* for ($i = 0; $i < $size; $i++) { |
||||
* $plaintext.= 'a'; |
||||
* } |
||||
* |
||||
* echo $des->decrypt($des->encrypt($plaintext)); |
||||
* ?> |
||||
* </code> |
||||
* |
||||
* 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 Crypt |
||||
* @package Crypt_TripleDES |
||||
* @author Jim Wigginton <terrafrost@php.net> |
||||
* @copyright MMVII Jim Wigginton |
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License |
||||
* @link http://phpseclib.sourceforge.net |
||||
*/ |
||||
|
||||
/** |
||||
* Include Crypt_DES |
||||
*/ |
||||
if (!class_exists('Crypt_DES')) { |
||||
require_once('DES.php'); |
||||
} |
||||
|
||||
/** |
||||
* Encrypt / decrypt using inner chaining |
||||
* |
||||
* Inner chaining is used by SSH-1 and is generally considered to be less secure then outer chaining (CRYPT_DES_MODE_CBC3). |
||||
*/ |
||||
define('CRYPT_DES_MODE_3CBC', -2); |
||||
|
||||
/** |
||||
* Encrypt / decrypt using outer chaining |
||||
* |
||||
* Outer chaining is used by SSH-2 and when the mode is set to CRYPT_DES_MODE_CBC. |
||||
*/ |
||||
define('CRYPT_DES_MODE_CBC3', CRYPT_DES_MODE_CBC); |
||||
|
||||
/** |
||||
* Pure-PHP implementation of Triple DES. |
||||
* |
||||
* @author Jim Wigginton <terrafrost@php.net> |
||||
* @version 0.1.0 |
||||
* @access public |
||||
* @package Crypt_TerraDES |
||||
*/ |
||||
class Crypt_TripleDES extends Crypt_DES { |
||||
/** |
||||
* The Crypt_DES objects |
||||
* |
||||
* @var Array |
||||
* @access private |
||||
*/ |
||||
var $des; |
||||
|
||||
/** |
||||
* Default Constructor. |
||||
* |
||||
* Determines whether or not the mcrypt extension should be used. $mode should only, at present, be |
||||
* CRYPT_DES_MODE_ECB or CRYPT_DES_MODE_CBC. If not explictly set, CRYPT_DES_MODE_CBC will be used. |
||||
* |
||||
* @param optional Integer $mode |
||||
* @return Crypt_TripleDES |
||||
* @access public |
||||
*/ |
||||
function Crypt_TripleDES($mode = CRYPT_DES_MODE_CBC) |
||||
{ |
||||
if ( !defined('CRYPT_DES_MODE') ) { |
||||
switch (true) { |
||||
case extension_loaded('mcrypt') && in_array('tripledes', mcrypt_list_algorithms()): |
||||
define('CRYPT_DES_MODE', CRYPT_DES_MODE_MCRYPT); |
||||
break; |
||||
default: |
||||
define('CRYPT_DES_MODE', CRYPT_DES_MODE_INTERNAL); |
||||
} |
||||
} |
||||
|
||||
if ( $mode == CRYPT_DES_MODE_3CBC ) { |
||||
$this->mode = CRYPT_DES_MODE_3CBC; |
||||
$this->des = array( |
||||
new Crypt_DES(CRYPT_DES_MODE_CBC), |
||||
new Crypt_DES(CRYPT_DES_MODE_CBC), |
||||
new Crypt_DES(CRYPT_DES_MODE_CBC) |
||||
); |
||||
$this->paddable = true; |
||||
|
||||
// we're going to be doing the padding, ourselves, so disable it in the Crypt_DES objects |
||||
$this->des[0]->disablePadding(); |
||||
$this->des[1]->disablePadding(); |
||||
$this->des[2]->disablePadding(); |
||||
|
||||
return; |
||||
} |
||||
|
||||
switch ( CRYPT_DES_MODE ) { |
||||
case CRYPT_DES_MODE_MCRYPT: |
||||
switch ($mode) { |
||||
case CRYPT_DES_MODE_ECB: |
||||
$this->paddable = true; |
||||
$this->mode = MCRYPT_MODE_ECB; |
||||
break; |
||||
case CRYPT_DES_MODE_CTR: |
||||
$this->mode = 'ctr'; |
||||
break; |
||||
case CRYPT_DES_MODE_CFB: |
||||
$this->mode = 'ncfb'; |
||||
$this->ecb = mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_ECB, ''); |
||||
break; |
||||
case CRYPT_DES_MODE_OFB: |
||||
$this->mode = MCRYPT_MODE_NOFB; |
||||
break; |
||||
case CRYPT_DES_MODE_CBC: |
||||
default: |
||||
$this->paddable = true; |
||||
$this->mode = MCRYPT_MODE_CBC; |
||||
} |
||||
$this->enmcrypt = mcrypt_module_open(MCRYPT_3DES, '', $this->mode, ''); |
||||
$this->demcrypt = mcrypt_module_open(MCRYPT_3DES, '', $this->mode, ''); |
||||
|
||||
break; |
||||
default: |
||||
$this->des = array( |
||||
new Crypt_DES(CRYPT_DES_MODE_ECB), |
||||
new Crypt_DES(CRYPT_DES_MODE_ECB), |
||||
new Crypt_DES(CRYPT_DES_MODE_ECB) |
||||
); |
||||
|
||||
// we're going to be doing the padding, ourselves, so disable it in the Crypt_DES objects |
||||
$this->des[0]->disablePadding(); |
||||
$this->des[1]->disablePadding(); |
||||
$this->des[2]->disablePadding(); |
||||
|
||||
switch ($mode) { |
||||
case CRYPT_DES_MODE_ECB: |
||||
case CRYPT_DES_MODE_CBC: |
||||
$this->paddable = true; |
||||
$this->mode = $mode; |
||||
break; |
||||
case CRYPT_DES_MODE_CTR: |
||||
case CRYPT_DES_MODE_CFB: |
||||
case CRYPT_DES_MODE_OFB: |
||||
$this->mode = $mode; |
||||
break; |
||||
default: |
||||
$this->paddable = true; |
||||
$this->mode = CRYPT_DES_MODE_CBC; |
||||
} |
||||
if (function_exists('create_function') && is_callable('create_function')) { |
||||
$this->inline_crypt_setup(3); |
||||
$this->use_inline_crypt = true; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Sets the key. |
||||
* |
||||
* Keys can be of any length. Triple DES, itself, can use 128-bit (eg. strlen($key) == 16) or |
||||
* 192-bit (eg. strlen($key) == 24) keys. This function pads and truncates $key as appropriate. |
||||
* |
||||
* DES also requires that every eighth bit be a parity bit, however, we'll ignore that. |
||||
* |
||||
* If the key is not explicitly set, it'll be assumed to be all zero's. |
||||
* |
||||
* @access public |
||||
* @param String $key |
||||
*/ |
||||
function setKey($key) |
||||
{ |
||||
$length = strlen($key); |
||||
if ($length > 8) { |
||||
$key = str_pad($key, 24, chr(0)); |
||||
// if $key is between 64 and 128-bits, use the first 64-bits as the last, per this: |
||||
// http://php.net/function.mcrypt-encrypt#47973 |
||||
//$key = $length <= 16 ? substr_replace($key, substr($key, 0, 8), 16) : substr($key, 0, 24); |
||||
} else { |
||||
$key = str_pad($key, 8, chr(0)); |
||||
} |
||||
$this->key = $key; |
||||
switch (true) { |
||||
case CRYPT_DES_MODE == CRYPT_DES_MODE_INTERNAL: |
||||
case $this->mode == CRYPT_DES_MODE_3CBC: |
||||
$this->des[0]->setKey(substr($key, 0, 8)); |
||||
$this->des[1]->setKey(substr($key, 8, 8)); |
||||
$this->des[2]->setKey(substr($key, 16, 8)); |
||||
|
||||
// Merge the three DES-1-dim-key-arrays for 3DES-inline-en/decrypting |
||||
if ($this->use_inline_crypt && $this->mode != CRYPT_DES_MODE_3CBC) { |
||||
$this->keys = array( |
||||
CRYPT_DES_ENCRYPT_1DIM => array_merge( |
||||
$this->des[0]->keys[CRYPT_DES_ENCRYPT_1DIM], |
||||
$this->des[1]->keys[CRYPT_DES_DECRYPT_1DIM], |
||||
$this->des[2]->keys[CRYPT_DES_ENCRYPT_1DIM] |
||||
), |
||||
CRYPT_DES_DECRYPT_1DIM => array_merge( |
||||
$this->des[2]->keys[CRYPT_DES_DECRYPT_1DIM], |
||||
$this->des[1]->keys[CRYPT_DES_ENCRYPT_1DIM], |
||||
$this->des[0]->keys[CRYPT_DES_DECRYPT_1DIM] |
||||
), |
||||
); |
||||
} |
||||
} |
||||
$this->enchanged = $this->dechanged = true; |
||||
} |
||||
|
||||
/** |
||||
* Sets the password. |
||||
* |
||||
* Depending on what $method is set to, setPassword()'s (optional) parameters are as follows: |
||||
* {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}: |
||||
* $hash, $salt, $method |
||||
* |
||||
* @param String $password |
||||
* @param optional String $method |
||||
* @access public |
||||
*/ |
||||
function setPassword($password, $method = 'pbkdf2') |
||||
{ |
||||
$key = ''; |
||||
|
||||
switch ($method) { |
||||
default: // 'pbkdf2' |
||||
list(, , $hash, $salt, $count) = func_get_args(); |
||||
if (!isset($hash)) { |
||||
$hash = 'sha1'; |
||||
} |
||||
// WPA and WPA2 use the SSID as the salt |
||||
if (!isset($salt)) { |
||||
$salt = 'phpseclib'; |
||||
} |
||||
// RFC2898#section-4.2 uses 1,000 iterations by default |
||||
// WPA and WPA2 use 4,096. |
||||
if (!isset($count)) { |
||||
$count = 1000; |
||||
} |
||||
|
||||
if (!class_exists('Crypt_Hash')) { |
||||
require_once('Crypt/Hash.php'); |
||||
} |
||||
|
||||
$i = 1; |
||||
while (strlen($key) < 24) { // $dkLen == 24 |
||||
$hmac = new Crypt_Hash(); |
||||
$hmac->setHash($hash); |
||||
$hmac->setKey($password); |
||||
$f = $u = $hmac->hash($salt . pack('N', $i++)); |
||||
for ($j = 2; $j <= $count; $j++) { |
||||
$u = $hmac->hash($u); |
||||
$f^= $u; |
||||
} |
||||
$key.= $f; |
||||
} |
||||
} |
||||
|
||||
$this->setKey($key); |
||||
} |
||||
|
||||
/** |
||||
* Sets the initialization vector. (optional) |
||||
* |
||||
* SetIV is not required when CRYPT_DES_MODE_ECB is being used. If not explictly set, it'll be assumed |
||||
* to be all zero's. |
||||
* |
||||
* @access public |
||||
* @param String $iv |
||||
*/ |
||||
function setIV($iv) |
||||
{ |
||||
$this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, 8), 8, chr(0)); |
||||
if ($this->mode == CRYPT_DES_MODE_3CBC) { |
||||
$this->des[0]->setIV($iv); |
||||
$this->des[1]->setIV($iv); |
||||
$this->des[2]->setIV($iv); |
||||
} |
||||
$this->enchanged = $this->dechanged = true; |
||||
} |
||||
|
||||
/** |
||||
* Encrypts a message. |
||||
* |
||||
* @access public |
||||
* @param String $plaintext |
||||
*/ |
||||
function encrypt($plaintext) |
||||
{ |
||||
if ($this->paddable) { |
||||
$plaintext = $this->_pad($plaintext); |
||||
} |
||||
|
||||
// if the key is smaller then 8, do what we'd normally do |
||||
if ($this->mode == CRYPT_DES_MODE_3CBC && strlen($this->key) > 8) { |
||||
$ciphertext = $this->des[2]->encrypt($this->des[1]->decrypt($this->des[0]->encrypt($plaintext))); |
||||
|
||||
return $ciphertext; |
||||
} |
||||
|
||||
if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) { |
||||
if ($this->enchanged) { |
||||
mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV); |
||||
if ($this->mode == 'ncfb') { |
||||
mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0"); |
||||
} |
||||
$this->enchanged = false; |
||||
} |
||||
|
||||
if ($this->mode != 'ncfb' || !$this->continuousBuffer) { |
||||
$ciphertext = mcrypt_generic($this->enmcrypt, $plaintext); |
||||
} else { |
||||
$iv = &$this->encryptIV; |
||||
$pos = &$this->enbuffer['pos']; |
||||
$len = strlen($plaintext); |
||||
$ciphertext = ''; |
||||
$i = 0; |
||||
if ($pos) { |
||||
$orig_pos = $pos; |
||||
$max = 8 - $pos; |
||||
if ($len >= $max) { |
||||
$i = $max; |
||||
$len-= $max; |
||||
$pos = 0; |
||||
} else { |
||||
$i = $len; |
||||
$pos+= $len; |
||||
$len = 0; |
||||
} |
||||
$ciphertext = substr($iv, $orig_pos) ^ $plaintext; |
||||
$iv = substr_replace($iv, $ciphertext, $orig_pos, $i); |
||||
$this->enbuffer['enmcrypt_init'] = true; |
||||
} |
||||
if ($len >= 8) { |
||||
if ($this->enbuffer['enmcrypt_init'] === false || $len > 950) { |
||||
if ($this->enbuffer['enmcrypt_init'] === true) { |
||||
mcrypt_generic_init($this->enmcrypt, $this->key, $iv); |
||||
$this->enbuffer['enmcrypt_init'] = false; |
||||
} |
||||
$ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % 8)); |
||||
$iv = substr($ciphertext, -8); |
||||
$i = strlen($ciphertext); |
||||
$len%= 8; |
||||
} else { |
||||
while ($len >= 8) { |
||||
$iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, 8); |
||||
$ciphertext.= $iv; |
||||
$len-= 8; |
||||
$i+= 8; |
||||
} |
||||
} |
||||
} |
||||
if ($len) { |
||||
$iv = mcrypt_generic($this->ecb, $iv); |
||||
$block = $iv ^ substr($plaintext, $i); |
||||
$iv = substr_replace($iv, $block, 0, $len); |
||||
$ciphertext.= $block; |
||||
$pos = $len; |
||||
} |
||||
return $ciphertext; |
||||
} |
||||
|
||||
if (!$this->continuousBuffer) { |
||||
mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV); |
||||
} |
||||
|
||||
return $ciphertext; |
||||
} |
||||
|
||||
if (strlen($this->key) <= 8) { |
||||
$this->des[0]->mode = $this->mode; |
||||
|
||||
return $this->des[0]->encrypt($plaintext); |
||||
} |
||||
|
||||
if ($this->use_inline_crypt) { |
||||
$inline = $this->inline_crypt; |
||||
return $inline('encrypt', $this, $plaintext); |
||||
} |
||||
|
||||
$des = $this->des; |
||||
|
||||
$buffer = &$this->enbuffer; |
||||
$continuousBuffer = $this->continuousBuffer; |
||||
$ciphertext = ''; |
||||
switch ($this->mode) { |
||||
case CRYPT_DES_MODE_ECB: |
||||
for ($i = 0; $i < strlen($plaintext); $i+=8) { |
||||
$block = substr($plaintext, $i, 8); |
||||
// all of these _processBlock calls could, in theory, be put in a function - say Crypt_TripleDES::_ede_encrypt() or something. |
||||
// only problem with that: it would slow encryption and decryption down. $this->des would have to be called every time that |
||||
// function is called, instead of once for the whole string of text that's being encrypted, which would, in turn, make |
||||
// encryption and decryption take more time, per this: |
||||
// |
||||
// http://blog.libssh2.org/index.php?/archives/21-Compiled-Variables.html |
||||
$block = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT); |
||||
$block = $des[1]->_processBlock($block, CRYPT_DES_DECRYPT); |
||||
$block = $des[2]->_processBlock($block, CRYPT_DES_ENCRYPT); |
||||
$ciphertext.= $block; |
||||
} |
||||
break; |
||||
case CRYPT_DES_MODE_CBC: |
||||
$xor = $this->encryptIV; |
||||
for ($i = 0; $i < strlen($plaintext); $i+=8) { |
||||
$block = substr($plaintext, $i, 8) ^ $xor; |
||||
$block = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT); |
||||
$block = $des[1]->_processBlock($block, CRYPT_DES_DECRYPT); |
||||
$block = $des[2]->_processBlock($block, CRYPT_DES_ENCRYPT); |
||||
$xor = $block; |
||||
$ciphertext.= $block; |
||||
} |
||||
if ($this->continuousBuffer) { |
||||
$this->encryptIV = $xor; |
||||
} |
||||
break; |
||||
case CRYPT_DES_MODE_CTR: |
||||
$xor = $this->encryptIV; |
||||
if (strlen($buffer['encrypted'])) { |
||||
for ($i = 0; $i < strlen($plaintext); $i+=8) { |
||||
$block = substr($plaintext, $i, 8); |
||||
if (strlen($block) > strlen($buffer['encrypted'])) { |
||||
$key = $this->_generate_xor($xor); |
||||
$key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT); |
||||
$key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT); |
||||
$key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT); |
||||
$buffer['encrypted'].= $key; |
||||
} |
||||
$key = $this->_string_shift($buffer['encrypted']); |
||||
$ciphertext.= $block ^ $key; |
||||
} |
||||
} else { |
||||
for ($i = 0; $i < strlen($plaintext); $i+=8) { |
||||
$block = substr($plaintext, $i, 8); |
||||
$key = $this->_generate_xor($xor); |
||||
$key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT); |
||||
$key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT); |
||||
$key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT); |
||||
$ciphertext.= $block ^ $key; |
||||
} |
||||
} |
||||
if ($this->continuousBuffer) { |
||||
$this->encryptIV = $xor; |
||||
if ($start = strlen($plaintext) & 7) { |
||||
$buffer['encrypted'] = substr($key, $start) . $buffer['encrypted']; |
||||
} |
||||
} |
||||
break; |
||||
case CRYPT_DES_MODE_CFB: |
||||
if (strlen($buffer['xor'])) { |
||||
$ciphertext = $plaintext ^ $buffer['xor']; |
||||
$iv = $buffer['encrypted'] . $ciphertext; |
||||
$start = strlen($ciphertext); |
||||
$buffer['encrypted'].= $ciphertext; |
||||
$buffer['xor'] = substr($buffer['xor'], strlen($ciphertext)); |
||||
} else { |
||||
$ciphertext = ''; |
||||
$iv = $this->encryptIV; |
||||
$start = 0; |
||||
} |
||||
|
||||
for ($i = $start; $i < strlen($plaintext); $i+=8) { |
||||
$block = substr($plaintext, $i, 8); |
||||
$iv = $des[0]->_processBlock($iv, CRYPT_DES_ENCRYPT); |
||||
$iv = $des[1]->_processBlock($iv, CRYPT_DES_DECRYPT); |
||||
$xor= $des[2]->_processBlock($iv, CRYPT_DES_ENCRYPT); |
||||
|
||||
$iv = $block ^ $xor; |
||||
if ($continuousBuffer && strlen($iv) != 8) { |
||||
$buffer = array( |
||||
'encrypted' => $iv, |
||||
'xor' => substr($xor, strlen($iv)) |
||||
); |
||||
} |
||||
$ciphertext.= $iv; |
||||
} |
||||
|
||||
if ($this->continuousBuffer) { |
||||
$this->encryptIV = $iv; |
||||
} |
||||
break; |
||||
case CRYPT_DES_MODE_OFB: |
||||
$xor = $this->encryptIV; |
||||
if (strlen($buffer['xor'])) { |
||||
for ($i = 0; $i < strlen($plaintext); $i+=8) { |
||||
$block = substr($plaintext, $i, 8); |
||||
if (strlen($block) > strlen($buffer['xor'])) { |
||||
$xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT); |
||||
$xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT); |
||||
$xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT); |
||||
$buffer['xor'].= $xor; |
||||
} |
||||
$key = $this->_string_shift($buffer['xor']); |
||||
$ciphertext.= $block ^ $key; |
||||
} |
||||
} else { |
||||
for ($i = 0; $i < strlen($plaintext); $i+=8) { |
||||
$xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT); |
||||
$xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT); |
||||
$xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT); |
||||
$ciphertext.= substr($plaintext, $i, 8) ^ $xor; |
||||
} |
||||
$key = $xor; |
||||
} |
||||
if ($this->continuousBuffer) { |
||||
$this->encryptIV = $xor; |
||||
if ($start = strlen($plaintext) & 7) { |
||||
$buffer['xor'] = substr($key, $start) . $buffer['xor']; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return $ciphertext; |
||||
} |
||||
|
||||
/** |
||||
* Decrypts a message. |
||||
* |
||||
* @access public |
||||
* @param String $ciphertext |
||||
*/ |
||||
function decrypt($ciphertext) |
||||
{ |
||||
if ($this->mode == CRYPT_DES_MODE_3CBC && strlen($this->key) > 8) { |
||||
$plaintext = $this->des[0]->decrypt($this->des[1]->encrypt($this->des[2]->decrypt($ciphertext))); |
||||
|
||||
return $this->_unpad($plaintext); |
||||
} |
||||
|
||||
if ($this->paddable) { |
||||
// we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic : |
||||
// "The data is padded with "\0" to make sure the length of the data is n * blocksize." |
||||
$ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, chr(0)); |
||||
} |
||||
|
||||
if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) { |
||||
if ($this->dechanged) { |
||||
mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV); |
||||
if ($this->mode == 'ncfb') { |
||||
mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0"); |
||||
} |
||||
$this->dechanged = false; |
||||
} |
||||
|
||||
if ($this->mode != 'ncfb' || !$this->continuousBuffer) { |
||||
$plaintext = mdecrypt_generic($this->demcrypt, $ciphertext); |
||||
} else { |
||||
$iv = &$this->decryptIV; |
||||
$pos = &$this->debuffer['pos']; |
||||
$len = strlen($ciphertext); |
||||
$plaintext = ''; |
||||
$i = 0; |
||||
if ($pos) { |
||||
$orig_pos = $pos; |
||||
$max = 8 - $pos; |
||||
if ($len >= $max) { |
||||
$i = $max; |
||||
$len-= $max; |
||||
$pos = 0; |
||||
} else { |
||||
$i = $len; |
||||
$pos+= $len; |
||||
$len = 0; |
||||
} |
||||
$plaintext = substr($iv, $orig_pos) ^ $ciphertext; |
||||
$iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i); |
||||
} |
||||
if ($len >= 8) { |
||||
$cb = substr($ciphertext, $i, $len - $len % 8); |
||||
$plaintext.= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb; |
||||
$iv = substr($cb, -8); |
||||
$len%= 8; |
||||
} |
||||
if ($len) { |
||||
$iv = mcrypt_generic($this->ecb, $iv); |
||||
$cb = substr($ciphertext, -$len); |
||||
$plaintext.= $iv ^ $cb; |
||||
$iv = substr_replace($iv, $cb, 0, $len); |
||||
$pos = $len; |
||||
} |
||||
return $plaintext; |
||||
} |
||||
|
||||
if (!$this->continuousBuffer) { |
||||
mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV); |
||||
} |
||||
|
||||
return $this->paddable ? $this->_unpad($plaintext) : $plaintext; |
||||
} |
||||
|
||||
if (strlen($this->key) <= 8) { |
||||
$this->des[0]->mode = $this->mode; |
||||
$plaintext = $this->des[0]->decrypt($ciphertext); |
||||
return $this->paddable ? $this->_unpad($plaintext) : $plaintext; |
||||
} |
||||
|
||||
if ($this->use_inline_crypt) { |
||||
$inline = $this->inline_crypt; |
||||
return $inline('decrypt', $this, $ciphertext); |
||||
} |
||||
|
||||
$des = $this->des; |
||||
|
||||
$buffer = &$this->debuffer; |
||||
$continuousBuffer = $this->continuousBuffer; |
||||
$plaintext = ''; |
||||
switch ($this->mode) { |
||||
case CRYPT_DES_MODE_ECB: |
||||
for ($i = 0; $i < strlen($ciphertext); $i+=8) { |
||||
$block = substr($ciphertext, $i, 8); |
||||
$block = $des[2]->_processBlock($block, CRYPT_DES_DECRYPT); |
||||
$block = $des[1]->_processBlock($block, CRYPT_DES_ENCRYPT); |
||||
$block = $des[0]->_processBlock($block, CRYPT_DES_DECRYPT); |
||||
$plaintext.= $block; |
||||
} |
||||
break; |
||||
case CRYPT_DES_MODE_CBC: |
||||
$xor = $this->decryptIV; |
||||
for ($i = 0; $i < strlen($ciphertext); $i+=8) { |
||||
$orig = $block = substr($ciphertext, $i, 8); |
||||
$block = $des[2]->_processBlock($block, CRYPT_DES_DECRYPT); |
||||
$block = $des[1]->_processBlock($block, CRYPT_DES_ENCRYPT); |
||||
$block = $des[0]->_processBlock($block, CRYPT_DES_DECRYPT); |
||||
$plaintext.= $block ^ $xor; |
||||
$xor = $orig; |
||||
} |
||||
if ($this->continuousBuffer) { |
||||
$this->decryptIV = $xor; |
||||
} |
||||
break; |
||||
case CRYPT_DES_MODE_CTR: |
||||
$xor = $this->decryptIV; |
||||
if (strlen($buffer['ciphertext'])) { |
||||
for ($i = 0; $i < strlen($ciphertext); $i+=8) { |
||||
$block = substr($ciphertext, $i, 8); |
||||
if (strlen($block) > strlen($buffer['ciphertext'])) { |
||||
$key = $this->_generate_xor($xor); |
||||
$key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT); |
||||
$key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT); |
||||
$key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT); |
||||
$buffer['ciphertext'].= $key; |
||||
} |
||||
$key = $this->_string_shift($buffer['ciphertext']); |
||||
$plaintext.= $block ^ $key; |
||||
} |
||||
} else { |
||||
for ($i = 0; $i < strlen($ciphertext); $i+=8) { |
||||
$block = substr($ciphertext, $i, 8); |
||||
$key = $this->_generate_xor($xor); |
||||
$key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT); |
||||
$key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT); |
||||
$key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT); |
||||
$plaintext.= $block ^ $key; |
||||
} |
||||
} |
||||
if ($this->continuousBuffer) { |
||||
$this->decryptIV = $xor; |
||||
if ($start = strlen($plaintext) & 7) { |
||||
$buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext']; |
||||
} |
||||
} |
||||
break; |
||||
case CRYPT_DES_MODE_CFB: |
||||
if (strlen($buffer['ciphertext'])) { |
||||
$plaintext = $ciphertext ^ substr($this->decryptIV, strlen($buffer['ciphertext'])); |
||||
$buffer['ciphertext'].= substr($ciphertext, 0, strlen($plaintext)); |
||||
if (strlen($buffer['ciphertext']) != 8) { |
||||
$block = $this->decryptIV; |
||||
} else { |
||||
$block = $buffer['ciphertext']; |
||||
$xor = $des[0]->_processBlock($buffer['ciphertext'], CRYPT_DES_ENCRYPT); |
||||
$xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT); |
||||
$xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT); |
||||
$buffer['ciphertext'] = ''; |
||||
} |
||||
$start = strlen($plaintext); |
||||
} else { |
||||
$plaintext = ''; |
||||
$xor = $des[0]->_processBlock($this->decryptIV, CRYPT_DES_ENCRYPT); |
||||
$xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT); |
||||
$xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT); |
||||
$start = 0; |
||||
} |
||||
|
||||
for ($i = $start; $i < strlen($ciphertext); $i+=8) { |
||||
$block = substr($ciphertext, $i, 8); |
||||
$plaintext.= $block ^ $xor; |
||||
if ($continuousBuffer && strlen($block) != 8) { |
||||
$buffer['ciphertext'].= $block; |
||||
$block = $xor; |
||||
} else if (strlen($block) == 8) { |
||||
$xor = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT); |
||||
$xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT); |
||||
$xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT); |
||||
} |
||||
} |
||||
if ($this->continuousBuffer) { |
||||
$this->decryptIV = $block; |
||||
} |
||||
break; |
||||
case CRYPT_DES_MODE_OFB: |
||||
$xor = $this->decryptIV; |
||||
if (strlen($buffer['xor'])) { |
||||
for ($i = 0; $i < strlen($ciphertext); $i+=8) { |
||||
$block = substr($ciphertext, $i, 8); |
||||
if (strlen($block) > strlen($buffer['xor'])) { |
||||
$xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT); |
||||
$xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT); |
||||
$xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT); |
||||
$buffer['xor'].= $xor; |
||||
} |
||||
$key = $this->_string_shift($buffer['xor']); |
||||
$plaintext.= $block ^ $key; |
||||
} |
||||
} else { |
||||
for ($i = 0; $i < strlen($ciphertext); $i+=8) { |
||||
$xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT); |
||||
$xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT); |
||||
$xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT); |
||||
$plaintext.= substr($ciphertext, $i, 8) ^ $xor; |
||||
} |
||||
$key = $xor; |
||||
} |
||||
if ($this->continuousBuffer) { |
||||
$this->decryptIV = $xor; |
||||
if ($start = strlen($ciphertext) & 7) { |
||||
$buffer['xor'] = substr($key, $start) . $buffer['xor']; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return $this->paddable ? $this->_unpad($plaintext) : $plaintext; |
||||
} |
||||
|
||||
/** |
||||
* 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: |
||||
* |
||||
* <code> |
||||
* echo $des->encrypt(substr($plaintext, 0, 8)); |
||||
* echo $des->encrypt(substr($plaintext, 8, 8)); |
||||
* </code> |
||||
* <code> |
||||
* 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: |
||||
* |
||||
* <code> |
||||
* $des->encrypt(substr($plaintext, 0, 8)); |
||||
* echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8))); |
||||
* </code> |
||||
* <code> |
||||
* echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8))); |
||||
* </code> |
||||
* |
||||
* With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different |
||||
* 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. |
||||
* |
||||
* Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each |
||||
* 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), |
||||
* however, they are also less intuitive and more likely to cause you problems. |
||||
* |
||||
* @see Crypt_TripleDES::disableContinuousBuffer() |
||||
* @access public |
||||
*/ |
||||
function enableContinuousBuffer() |
||||
{ |
||||
$this->continuousBuffer = true; |
||||
if ($this->mode == CRYPT_DES_MODE_3CBC) { |
||||
$this->des[0]->enableContinuousBuffer(); |
||||
$this->des[1]->enableContinuousBuffer(); |
||||
$this->des[2]->enableContinuousBuffer(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Treat consecutive packets as if they are a discontinuous buffer. |
||||
* |
||||
* The default behavior. |
||||
* |
||||
* @see Crypt_TripleDES::enableContinuousBuffer() |
||||
* @access public |
||||
*/ |
||||
function disableContinuousBuffer() |
||||
{ |
||||
$this->continuousBuffer = false; |
||||
$this->encryptIV = $this->iv; |
||||
$this->decryptIV = $this->iv; |
||||
$this->enchanged = true; |
||||
$this->dechanged = true; |
||||
$this->enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true); |
||||
$this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true); |
||||
|
||||
if ($this->mode == CRYPT_DES_MODE_3CBC) { |
||||
$this->des[0]->disableContinuousBuffer(); |
||||
$this->des[1]->disableContinuousBuffer(); |
||||
$this->des[2]->disableContinuousBuffer(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
// vim: ts=4:sw=4:et: |
||||
// vim6: fdl=1: |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,560 @@ |
||||
<?php |
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
||||
|
||||
/** |
||||
* Pure-PHP ANSI Decoder |
||||
* |
||||
* PHP versions 4 and 5 |
||||
* |
||||
* If you call read() in Net_SSH2 you may get {@link http://en.wikipedia.org/wiki/ANSI_escape_code ANSI escape codes} back. |
||||
* They'd look like chr(0x1B) . '[00m' or whatever (0x1B = ESC). They tell a |
||||
* {@link http://en.wikipedia.org/wiki/Terminal_emulator terminal emulator} how to format the characters, what |
||||
* color to display them in, etc. File_ANSI is a {@link http://en.wikipedia.org/wiki/VT100 VT100} terminal emulator. |
||||
* |
||||
* 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 File |
||||
* @package File_ANSI |
||||
* @author Jim Wigginton <terrafrost@php.net> |
||||
* @copyright MMXII Jim Wigginton |
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License |
||||
* @link http://phpseclib.sourceforge.net |
||||
*/ |
||||
|
||||
/** |
||||
* Pure-PHP ANSI Decoder |
||||
* |
||||
* @author Jim Wigginton <terrafrost@php.net> |
||||
* @version 0.3.0 |
||||
* @access public |
||||
* @package File_ANSI |
||||
*/ |
||||
class File_ANSI { |
||||
/** |
||||
* Max Width |
||||
* |
||||
* @var Integer |
||||
* @access private |
||||
*/ |
||||
var $max_x; |
||||
|
||||
/** |
||||
* Max Height |
||||
* |
||||
* @var Integer |
||||
* @access private |
||||
*/ |
||||
var $max_y; |
||||
|
||||
/** |
||||
* Max History |
||||
* |
||||
* @var Integer |
||||
* @access private |
||||
*/ |
||||
var $max_history; |
||||
|
||||
/** |
||||
* History |
||||
* |
||||
* @var Array |
||||
* @access private |
||||
*/ |
||||
var $history; |
||||
|
||||
/** |
||||
* History Attributes |
||||
* |
||||
* @var Array |
||||
* @access private |
||||
*/ |
||||
var $history_attrs; |
||||
|
||||
/** |
||||
* Current Column |
||||
* |
||||
* @var Integer |
||||
* @access private |
||||
*/ |
||||
var $x; |
||||
|
||||
/** |
||||
* Current Row |
||||
* |
||||
* @var Integer |
||||
* @access private |
||||
*/ |
||||
var $y; |
||||
|
||||
/** |
||||
* Old Column |
||||
* |
||||
* @var Integer |
||||
* @access private |
||||
*/ |
||||
var $old_x; |
||||
|
||||
/** |
||||
* Old Row |
||||
* |
||||
* @var Integer |
||||
* @access private |
||||
*/ |
||||
var $old_y; |
||||
|
||||
/** |
||||
* An empty attribute row |
||||
* |
||||
* @var Array |
||||
* @access private |
||||
*/ |
||||
var $attr_row; |
||||
|
||||
/** |
||||
* The current screen text |
||||
* |
||||
* @var Array |
||||
* @access private |
||||
*/ |
||||
var $screen; |
||||
|
||||
/** |
||||
* The current screen attributes |
||||
* |
||||
* @var Array |
||||
* @access private |
||||
*/ |
||||
var $attrs; |
||||
|
||||
/** |
||||
* The current foreground color |
||||
* |
||||
* @var String |
||||
* @access private |
||||
*/ |
||||
var $foreground; |
||||
|
||||
/** |
||||
* The current background color |
||||
* |
||||
* @var String |
||||
* @access private |
||||
*/ |
||||
var $background; |
||||
|
||||
/** |
||||
* Bold flag |
||||
* |
||||
* @var Boolean |
||||
* @access private |
||||
*/ |
||||
var $bold; |
||||
|
||||
/** |
||||
* Underline flag |
||||
* |
||||
* @var Boolean |
||||
* @access private |
||||
*/ |
||||
var $underline; |
||||
|
||||
/** |
||||
* Blink flag |
||||
* |
||||
* @var Boolean |
||||
* @access private |
||||
*/ |
||||
var $blink; |
||||
|
||||
/** |
||||
* Reverse flag |
||||
* |
||||
* @var Boolean |
||||
* @access private |
||||
*/ |
||||
var $reverse; |
||||
|
||||
/** |
||||
* Color flag |
||||
* |
||||
* @var Boolean |
||||
* @access private |
||||
*/ |
||||
var $color; |
||||
|
||||
/** |
||||
* Current ANSI code |
||||
* |
||||
* @var String |
||||
* @access private |
||||
*/ |
||||
var $ansi; |
||||
|
||||
/** |
||||
* Default Constructor. |
||||
* |
||||
* @return File_ANSI |
||||
* @access public |
||||
*/ |
||||
function File_ANSI() |
||||
{ |
||||
$this->setHistory(200); |
||||
$this->setDimensions(80, 24); |
||||
} |
||||
|
||||
/** |
||||
* Set terminal width and height |
||||
* |
||||
* Resets the screen as well |
||||
* |
||||
* @param Integer $x |
||||
* @param Integer $y |
||||
* @access public |
||||
*/ |
||||
function setDimensions($x, $y) |
||||
{ |
||||
$this->max_x = $x - 1; |
||||
$this->max_y = $y - 1; |
||||
$this->x = $this->y = 0; |
||||
$this->history = $this->history_attrs = array(); |
||||
$this->attr_row = array_fill(0, $this->max_x + 1, ''); |
||||
$this->screen = array_fill(0, $this->max_y + 1, ''); |
||||
$this->attrs = array_fill(0, $this->max_y + 1, $this->attr_row); |
||||
$this->foreground = 'white'; |
||||
$this->background = 'black'; |
||||
$this->bold = false; |
||||
$this->underline = false; |
||||
$this->blink = false; |
||||
$this->reverse = false; |
||||
$this->color = false; |
||||
|
||||
$this->ansi = ''; |
||||
} |
||||
|
||||
/** |
||||
* Set the number of lines that should be logged past the terminal height |
||||
* |
||||
* @param Integer $x |
||||
* @param Integer $y |
||||
* @access public |
||||
*/ |
||||
function setHistory($history) |
||||
{ |
||||
$this->max_history = $history; |
||||
} |
||||
|
||||
/** |
||||
* Load a string |
||||
* |
||||
* @param String $source |
||||
* @access public |
||||
*/ |
||||
function loadString($source) |
||||
{ |
||||
$this->setDimensions($this->max_x + 1, $this->max_y + 1); |
||||
$this->appendString($source); |
||||
} |
||||
|
||||
/** |
||||
* Appdend a string |
||||
* |
||||
* @param String $source |
||||
* @access public |
||||
*/ |
||||
function appendString($source) |
||||
{ |
||||
for ($i = 0; $i < strlen($source); $i++) { |
||||
if (strlen($this->ansi)) { |
||||
$this->ansi.= $source[$i]; |
||||
$chr = ord($source[$i]); |
||||
// http://en.wikipedia.org/wiki/ANSI_escape_code#Sequence_elements |
||||
// single character CSI's not currently supported |
||||
switch (true) { |
||||
case $this->ansi == "\x1B=": |
||||
$this->ansi = ''; |
||||
continue 2; |
||||
case strlen($this->ansi) == 2 && $chr >= 64 && $chr <= 95 && $chr != ord('['): |
||||
case strlen($this->ansi) > 2 && $chr >= 64 && $chr <= 126: |
||||
break; |
||||
default: |
||||
continue 2; |
||||
} |
||||
// http://ascii-table.com/ansi-escape-sequences-vt-100.php |
||||
switch ($this->ansi) { |
||||
case "\x1B[H": // Move cursor to upper left corner |
||||
$this->old_x = $this->x; |
||||
$this->old_y = $this->y; |
||||
$this->x = $this->y = 0; |
||||
break; |
||||
case "\x1B[J": // Clear screen from cursor down |
||||
$this->history = array_merge($this->history, array_slice(array_splice($this->screen, $this->y + 1), 0, $this->old_y)); |
||||
$this->screen = array_merge($this->screen, array_fill($this->y, $this->max_y, '')); |
||||
|
||||
$this->history_attrs = array_merge($this->history_attrs, array_slice(array_splice($this->attrs, $this->y + 1), 0, $this->old_y)); |
||||
$this->attrs = array_merge($this->attrs, array_fill($this->y, $this->max_y, $this->attr_row)); |
||||
|
||||
if (count($this->history) == $this->max_history) { |
||||
array_shift($this->history); |
||||
array_shift($this->history_attrs); |
||||
} |
||||
case "\x1B[K": // Clear screen from cursor right |
||||
$this->screen[$this->y] = substr($this->screen[$this->y], 0, $this->x); |
||||
|
||||
array_splice($this->attrs[$this->y], $this->x + 1); |
||||
break; |
||||
case "\x1B[2K": // Clear entire line |
||||
$this->screen[$this->y] = str_repeat(' ', $this->x); |
||||
$this->attrs[$this->y] = $this->attr_row; |
||||
break; |
||||
case "\x1B[?1h": // set cursor key to application |
||||
case "\x1B[?25h": // show the cursor |
||||
break; |
||||
case "\x1BE": // Move to next line |
||||
$this->_newLine(); |
||||
$this->x = 0; |
||||
break; |
||||
default: |
||||
switch (true) { |
||||
case preg_match('#\x1B\[(\d+);(\d+)H#', $this->ansi, $match): // Move cursor to screen location v,h |
||||
$this->old_x = $this->x; |
||||
$this->old_y = $this->y; |
||||
$this->x = $match[2] - 1; |
||||
$this->y = $match[1] - 1; |
||||
break; |
||||
case preg_match('#\x1B\[(\d+)C#', $this->ansi, $match): // Move cursor right n lines |
||||
$this->old_x = $this->x; |
||||
$x = $match[1] - 1; |
||||
break; |
||||
case preg_match('#\x1B\[(\d+);(\d+)r#', $this->ansi, $match): // Set top and bottom lines of a window |
||||
break; |
||||
case preg_match('#\x1B\[(\d*(?:;\d*)*)m#', $this->ansi, $match): // character attributes |
||||
$mods = explode(';', $match[1]); |
||||
foreach ($mods as $mod) { |
||||
switch ($mod) { |
||||
case 0: // Turn off character attributes |
||||
$this->attrs[$this->y][$this->x] = ''; |
||||
|
||||
if ($this->bold) $this->attrs[$this->y][$this->x].= '</b>'; |
||||
if ($this->underline) $this->attrs[$this->y][$this->x].= '</underline>'; |
||||
if ($this->blink) $this->attrs[$this->y][$this->x].= '</blink>'; |
||||
if ($this->color) $this->attrs[$this->y][$this->x].= '</span>'; |
||||
|
||||
if ($this->reverse) { |
||||
$temp = $this->background; |
||||
$this->background = $this->foreground; |
||||
$this->foreground = $temp; |
||||
} |
||||
|
||||
$this->bold = $this->underline = $this->blink = $this->color = $this->reverse = false; |
||||
break; |
||||
case 1: // Turn bold mode on |
||||
if (!$this->bold) { |
||||
$this->attrs[$this->y][$this->x] = '<b>'; |
||||
$this->bold = true; |
||||
} |
||||
break; |
||||
case 4: // Turn underline mode on |
||||
if (!$this->underline) { |
||||
$this->attrs[$this->y][$this->x] = '<u>'; |
||||
$this->underline = true; |
||||
} |
||||
break; |
||||
case 5: // Turn blinking mode on |
||||
if (!$this->blink) { |
||||
$this->attrs[$this->y][$this->x] = '<blink>'; |
||||
$this->blink = true; |
||||
} |
||||
break; |
||||
case 7: // Turn reverse video on |
||||
$this->reverse = !$this->reverse; |
||||
$temp = $this->background; |
||||
$this->background = $this->foreground; |
||||
$this->foreground = $temp; |
||||
$this->attrs[$this->y][$this->x] = '<span style="color: ' . $this->foreground . '; background: ' . $this->background . '">'; |
||||
if ($this->color) { |
||||
$this->attrs[$this->y][$this->x] = '</span>' . $this->attrs[$this->y][$this->x]; |
||||
} |
||||
$this->color = true; |
||||
break; |
||||
default: // set colors |
||||
//$front = $this->reverse ? &$this->background : &$this->foreground; |
||||
$front = &$this->{ $this->reverse ? 'background' : 'foreground' }; |
||||
//$back = $this->reverse ? &$this->foreground : &$this->background; |
||||
$back = &$this->{ $this->reverse ? 'foreground' : 'background' }; |
||||
switch ($mod) { |
||||
case 30: $front = 'black'; break; |
||||
case 31: $front = 'red'; break; |
||||
case 32: $front = 'green'; break; |
||||
case 33: $front = 'yellow'; break; |
||||
case 34: $front = 'blue'; break; |
||||
case 35: $front = 'magenta'; break; |
||||
case 36: $front = 'cyan'; break; |
||||
case 37: $front = 'white'; break; |
||||
|
||||
case 40: $back = 'black'; break; |
||||
case 41: $back = 'red'; break; |
||||
case 42: $back = 'green'; break; |
||||
case 43: $back = 'yellow'; break; |
||||
case 44: $back = 'blue'; break; |
||||
case 45: $back = 'magenta'; break; |
||||
case 46: $back = 'cyan'; break; |
||||
case 47: $back = 'white'; break; |
||||
|
||||
default: |
||||
user_error('Unsupported attribute: ' . $mod); |
||||
$this->ansi = ''; |
||||
break 2; |
||||
} |
||||
|
||||
unset($temp); |
||||
$this->attrs[$this->y][$this->x] = '<span style="color: ' . $this->foreground . '; background: ' . $this->background . '">'; |
||||
if ($this->color) { |
||||
$this->attrs[$this->y][$this->x] = '</span>' . $this->attrs[$this->y][$this->x]; |
||||
} |
||||
$this->color = true; |
||||
} |
||||
} |
||||
break; |
||||
default: |
||||
user_error("{$this->ansi} unsupported\r\n"); |
||||
} |
||||
} |
||||
$this->ansi = ''; |
||||
continue; |
||||
} |
||||
|
||||
switch ($source[$i]) { |
||||
case "\r": |
||||
$this->x = 0; |
||||
break; |
||||
case "\n": |
||||
$this->_newLine(); |
||||
break; |
||||
case "\x0F": // shift |
||||
break; |
||||
case "\x1B": // start ANSI escape code |
||||
$this->ansi.= "\x1B"; |
||||
break; |
||||
default: |
||||
$this->screen[$this->y] = substr_replace( |
||||
$this->screen[$this->y], |
||||
$source[$i], |
||||
$this->x, |
||||
1 |
||||
); |
||||
|
||||
if ($this->x > $this->max_x) { |
||||
$this->x = 0; |
||||
$this->y++; |
||||
} else { |
||||
$this->x++; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Add a new line |
||||
* |
||||
* Also update the $this->screen and $this->history buffers |
||||
* |
||||
* @access private |
||||
*/ |
||||
function _newLine() |
||||
{ |
||||
//if ($this->y < $this->max_y) { |
||||
// $this->y++; |
||||
//} |
||||
|
||||
while ($this->y >= $this->max_y) { |
||||
$this->history = array_merge($this->history, array(array_shift($this->screen))); |
||||
$this->screen[] = ''; |
||||
|
||||
$this->history_attrs = array_merge($this->history_attrs, array(array_shift($this->attrs))); |
||||
$this->attrs[] = $this->attr_row; |
||||
|
||||
if (count($this->history) >= $this->max_history) { |
||||
array_shift($this->history); |
||||
array_shift($this->history_attrs); |
||||
} |
||||
|
||||
$this->y--; |
||||
} |
||||
$this->y++; |
||||
} |
||||
|
||||
/** |
||||
* Returns the current screen without preformating |
||||
* |
||||
* @access private |
||||
* @return String |
||||
*/ |
||||
function _getScreen() |
||||
{ |
||||
$output = ''; |
||||
for ($i = 0; $i <= $this->max_y; $i++) { |
||||
for ($j = 0; $j <= $this->max_x + 1; $j++) { |
||||
if (isset($this->attrs[$i][$j])) { |
||||
$output.= $this->attrs[$i][$j]; |
||||
} |
||||
if (isset($this->screen[$i][$j])) { |
||||
$output.= htmlspecialchars($this->screen[$i][$j]); |
||||
} |
||||
} |
||||
$output.= "\r\n"; |
||||
} |
||||
return rtrim($output); |
||||
} |
||||
|
||||
/** |
||||
* Returns the current screen |
||||
* |
||||
* @access public |
||||
* @return String |
||||
*/ |
||||
function getScreen() |
||||
{ |
||||
return '<pre style="color: white; background: black" width="' . ($this->max_x + 1) . '">' . $this->_getScreen() . '</pre>'; |
||||
} |
||||
|
||||
/** |
||||
* Returns the current screen and the x previous lines |
||||
* |
||||
* @access public |
||||
* @return String |
||||
*/ |
||||
function getHistory() |
||||
{ |
||||
$scrollback = ''; |
||||
for ($i = 0; $i < count($this->history); $i++) { |
||||
for ($j = 0; $j <= $this->max_x + 1; $j++) { |
||||
if (isset($this->history_attrs[$i][$j])) { |
||||
$scrollback.= $this->history_attrs[$i][$j]; |
||||
} |
||||
if (isset($this->history[$i][$j])) { |
||||
$scrollback.= htmlspecialchars($this->history[$i][$j]); |
||||
} |
||||
} |
||||
$scrollback.= "\r\n"; |
||||
} |
||||
$scrollback.= $this->_getScreen(); |
||||
|
||||
return '<pre style="color: white; background: black" width="' . ($this->max_x + 1) . '">' . $scrollback . '</pre>'; |
||||
} |
||||
} |
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
@ -0,0 +1,341 @@ |
||||
<?php |
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
||||
|
||||
/** |
||||
* Pure-PHP implementation of SCP. |
||||
* |
||||
* PHP versions 4 and 5 |
||||
* |
||||
* 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: |
||||
* <code> |
||||
* <?php |
||||
* include('Net/SCP.php'); |
||||
* include('Net/SSH2.php'); |
||||
* |
||||
* $ssh = new Net_SSH2('www.domain.tld'); |
||||
* if (!$ssh->login('username', 'password')) { |
||||
* exit('bad login'); |
||||
* } |
||||
|
||||
* $scp = new Net_SCP($ssh); |
||||
* $scp->put('abcd', str_repeat('x', 1024*1024)); |
||||
* ?> |
||||
* </code> |
||||
* |
||||
* 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 Net |
||||
* @package Net_SCP |
||||
* @author Jim Wigginton <terrafrost@php.net> |
||||
* @copyright MMX Jim Wigginton |
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License |
||||
* @link http://phpseclib.sourceforge.net |
||||
*/ |
||||
|
||||
/**#@+ |
||||
* @access public |
||||
* @see Net_SCP::put() |
||||
*/ |
||||
/** |
||||
* Reads data from a local file. |
||||
*/ |
||||
define('NET_SCP_LOCAL_FILE', 1); |
||||
/** |
||||
* Reads data from a string. |
||||
*/ |
||||
define('NET_SCP_STRING', 2); |
||||
/**#@-*/ |
||||
|
||||
/**#@+ |
||||
* @access private |
||||
* @see Net_SCP::_send() |
||||
* @see Net_SCP::_receive() |
||||
*/ |
||||
/** |
||||
* SSH1 is being used. |
||||
*/ |
||||
define('NET_SCP_SSH1', 1); |
||||
/** |
||||
* SSH2 is being used. |
||||
*/ |
||||
define('NET_SCP_SSH2', 2); |
||||
/**#@-*/ |
||||
|
||||
/** |
||||
* Pure-PHP implementations of SCP. |
||||
* |
||||
* @author Jim Wigginton <terrafrost@php.net> |
||||
* @version 0.1.0 |
||||
* @access public |
||||
* @package Net_SCP |
||||
*/ |
||||
class Net_SCP { |
||||
/** |
||||
* SSH Object |
||||
* |
||||
* @var Object |
||||
* @access private |
||||
*/ |
||||
var $ssh; |
||||
|
||||
/** |
||||
* Packet Size |
||||
* |
||||
* @var Integer |
||||
* @access private |
||||
*/ |
||||
var $packet_size; |
||||
|
||||
/** |
||||
* Mode |
||||
* |
||||
* @var Integer |
||||
* @access private |
||||
*/ |
||||
var $mode; |
||||
|
||||
/** |
||||
* Default Constructor. |
||||
* |
||||
* Connects to an SSH server |
||||
* |
||||
* @param String $host |
||||
* @param optional Integer $port |
||||
* @param optional Integer $timeout |
||||
* @return Net_SCP |
||||
* @access public |
||||
*/ |
||||
function Net_SCP($ssh) |
||||
{ |
||||
if (!is_object($ssh)) { |
||||
return; |
||||
} |
||||
|
||||
switch (strtolower(get_class($ssh))) { |
||||
case'net_ssh2': |
||||
$this->mode = NET_SCP_SSH2; |
||||
break; |
||||
case 'net_ssh1': |
||||
$this->packet_size = 50000; |
||||
$this->mode = NET_SCP_SSH1; |
||||
break; |
||||
default: |
||||
return; |
||||
} |
||||
|
||||
$this->ssh = $ssh; |
||||
} |
||||
|
||||
/** |
||||
* Uploads a file to the SCP server. |
||||
* |
||||
* 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. |
||||
* |
||||
* Setting $mode to NET_SFTP_LOCAL_FILE will change the above behavior. With NET_SFTP_LOCAL_FILE, $remote_file will |
||||
* 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. |
||||
* |
||||
* Currently, only binary mode is supported. As such, if the line endings need to be adjusted, you will need to take |
||||
* care of that, yourself. |
||||
* |
||||
* @param String $remote_file |
||||
* @param String $data |
||||
* @param optional Integer $mode |
||||
* @return Boolean |
||||
* @access public |
||||
*/ |
||||
function put($remote_file, $data, $mode = NET_SCP_STRING) |
||||
{ |
||||
if (!isset($this->ssh)) { |
||||
return false; |
||||
} |
||||
|
||||
$this->ssh->exec('scp -t ' . $remote_file, false); // -t = to |
||||
|
||||
$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]; |
||||
} |
||||
|
||||
$remote_file = basename($remote_file); |
||||
$this->_send('C0644 ' . strlen($data) . ' ' . $remote_file . "\n"); |
||||
|
||||
$temp = $this->_receive(); |
||||
if ($temp !== chr(0)) { |
||||
return false; |
||||
} |
||||
|
||||
if ($mode == NET_SCP_STRING) { |
||||
$this->_send($data); |
||||
} else { |
||||
if (!is_file($data)) { |
||||
user_error("$data is not a valid file", E_USER_NOTICE); |
||||
return false; |
||||
} |
||||
$fp = @fopen($data, 'rb'); |
||||
if (!$fp) { |
||||
return false; |
||||
} |
||||
$size = filesize($data); |
||||
for ($i = 0; $i < $size; $i += $this->packet_size) { |
||||
$this->_send(fgets($fp, $this->packet_size)); |
||||
} |
||||
fclose($fp); |
||||
} |
||||
$this->_close(); |
||||
} |
||||
|
||||
/** |
||||
* Downloads a file from the SCP server. |
||||
* |
||||
* 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 |
||||
* operation |
||||
* |
||||
* @param String $remote_file |
||||
* @param optional String $local_file |
||||
* @return Mixed |
||||
* @access public |
||||
*/ |
||||
function get($remote_file, $local_file = false) |
||||
{ |
||||
if (!isset($this->ssh)) { |
||||
return false; |
||||
} |
||||
|
||||
$this->ssh->exec('scp -f ' . $remote_file, false); // -f = from |
||||
|
||||
$this->_send("\0"); |
||||
|
||||
if (!preg_match('#(?<perms>[^ ]+) (?<size>\d+) (?<name>.+)#', rtrim($this->_receive()), $info)) { |
||||
return false; |
||||
} |
||||
|
||||
$this->_send("\0"); |
||||
|
||||
$size = 0; |
||||
|
||||
if ($local_file !== false) { |
||||
$fp = @fopen($local_file, 'wb'); |
||||
if (!$fp) { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
$content = ''; |
||||
while ($size < $info['size']) { |
||||
$data = $this->_receive(); |
||||
// SCP usually seems to split stuff out into 16k chunks |
||||
$size+= strlen($data); |
||||
|
||||
if ($local_file === false) { |
||||
$content.= $data; |
||||
} else { |
||||
fputs($fp, $data); |
||||
} |
||||
} |
||||
|
||||
$this->_close(); |
||||
|
||||
if ($local_file !== false) { |
||||
fclose($fp); |
||||
return true; |
||||
} |
||||
|
||||
return $content; |
||||
} |
||||
|
||||
/** |
||||
* Sends a packet to an SSH server |
||||
* |
||||
* @param String $data |
||||
* @access private |
||||
*/ |
||||
function _send($data) |
||||
{ |
||||
switch ($this->mode) { |
||||
case NET_SCP_SSH2: |
||||
$this->ssh->_send_channel_packet(NET_SSH2_CHANNEL_EXEC, $data); |
||||
break; |
||||
case NET_SCP_SSH1: |
||||
$data = pack('CNa*', NET_SSH1_CMSG_STDIN_DATA, strlen($data), $data); |
||||
$this->ssh->_send_binary_packet($data); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Receives a packet from an SSH server |
||||
* |
||||
* @return String |
||||
* @access private |
||||
*/ |
||||
function _receive() |
||||
{ |
||||
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; |
||||
} |
||||
while (true) { |
||||
$response = $this->ssh->_get_binary_packet(); |
||||
switch ($response[NET_SSH1_RESPONSE_TYPE]) { |
||||
case NET_SSH1_SMSG_STDOUT_DATA: |
||||
extract(unpack('Nlength', $response[NET_SSH1_RESPONSE_DATA])); |
||||
return $this->ssh->_string_shift($response[NET_SSH1_RESPONSE_DATA], $length); |
||||
case NET_SSH1_SMSG_STDERR_DATA: |
||||
break; |
||||
case NET_SSH1_SMSG_EXITSTATUS: |
||||
$this->ssh->_send_binary_packet(chr(NET_SSH1_CMSG_EXIT_CONFIRMATION)); |
||||
fclose($this->ssh->fsock); |
||||
$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); |
||||
break; |
||||
case NET_SCP_SSH1: |
||||
$this->ssh->disconnect(); |
||||
} |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,766 @@ |
||||
<?php |
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
||||
|
||||
/** |
||||
* SFTP Stream Wrapper |
||||
* |
||||
* Creates an sftp:// protocol handler that can be used with, for example, fopen(), dir(), etc. |
||||
* |
||||
* PHP version 5 |
||||
* |
||||
* 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 Net |
||||
* @package Net_SFTP_Stream |
||||
* @author Jim Wigginton <terrafrost@php.net> |
||||
* @copyright MMXIII Jim Wigginton |
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License |
||||
* @link http://phpseclib.sourceforge.net |
||||
*/ |
||||
|
||||
/** |
||||
* SFTP Stream Wrapper |
||||
* |
||||
* @author Jim Wigginton <terrafrost@php.net> |
||||
* @version 0.3.2 |
||||
* @access public |
||||
* @package Net_SFTP_Stream |
||||
*/ |
||||
class Net_SFTP_Stream { |
||||
/** |
||||
* SFTP instances |
||||
* |
||||
* Rather than re-create the connection we re-use instances if possible |
||||
* |
||||
* @var Array |
||||
* @access static |
||||
*/ |
||||
static $instances; |
||||
|
||||
/** |
||||
* SFTP instance |
||||
* |
||||
* @var Object |
||||
* @access private |
||||
*/ |
||||
var $sftp; |
||||
|
||||
/** |
||||
* Path |
||||
* |
||||
* @var String |
||||
* @access private |
||||
*/ |
||||
var $path; |
||||
|
||||
/** |
||||
* Mode |
||||
* |
||||
* @var String |
||||
* @access private |
||||
*/ |
||||
var $mode; |
||||
|
||||
/** |
||||
* Position |
||||
* |
||||
* @var Integer |
||||
* @access private |
||||
*/ |
||||
var $pos; |
||||
|
||||
/** |
||||
* Size |
||||
* |
||||
* @var Integer |
||||
* @access private |
||||
*/ |
||||
var $size; |
||||
|
||||
/** |
||||
* Directory entries |
||||
* |
||||
* @var Array |
||||
* @access private |
||||
*/ |
||||
var $entries; |
||||
|
||||
/** |
||||
* EOF flag |
||||
* |
||||
* @var Boolean |
||||
* @access private |
||||
*/ |
||||
var $eof; |
||||
|
||||
/** |
||||
* Context resource |
||||
* |
||||
* Technically this needs to be publically accessible so PHP can set it directly |
||||
* |
||||
* @var Resource |
||||
* @access public |
||||
*/ |
||||
var $context; |
||||
|
||||
/** |
||||
* Notification callback function |
||||
* |
||||
* @var Callable |
||||
* @access public |
||||
*/ |
||||
var $notification; |
||||
|
||||
/** |
||||
* The Constructor |
||||
* |
||||
* @access public |
||||
*/ |
||||
function Net_SFTP_Stream() |
||||
{ |
||||
if (!class_exists('Net_SFTP')) { |
||||
require_once('Net/SFTP.php'); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Path Parser |
||||
* |
||||
* Extract a path from a URI and actually connect to an SSH server if appropriate |
||||
* |
||||
* If "notification" is set as a context parameter the message code for successful login is |
||||
* NET_SSH2_MSG_USERAUTH_SUCCESS. For a failed login it's NET_SSH2_MSG_USERAUTH_FAILURE. |
||||
* |
||||
* @param String $path |
||||
* @return String |
||||
* @access private |
||||
*/ |
||||
function _parse_path($path) |
||||
{ |
||||
extract(parse_url($path)); |
||||
|
||||
if (!isset($host)) { |
||||
return false; |
||||
} |
||||
|
||||
$context = stream_context_get_params($this->context); |
||||
if (isset($context['notification'])) { |
||||
$this->notification = $context['notification']; |
||||
} |
||||
|
||||
if ($host[0] == '$') { |
||||
$host = substr($host, 1); |
||||
global $$host; |
||||
if (!is_object($$host) || get_class($$host) != 'Net_sFTP') { |
||||
return false; |
||||
} |
||||
$this->sftp = $$host; |
||||
} else { |
||||
$context = stream_context_get_options($this->context); |
||||
if (isset($context['sftp']['session'])) { |
||||
$sftp = $context['sftp']['session']; |
||||
} |
||||
if (isset($context['sftp']['sftp'])) { |
||||
$sftp = $context['sftp']['sftp']; |
||||
} |
||||
if (isset($sftp) && is_object($sftp) && get_class($sftp) == 'Net_SFTP') { |
||||
$this->sftp = $sftp; |
||||
return $path; |
||||
} |
||||
if (isset($context['sftp']['username'])) { |
||||
$user = $context['sftp']['username']; |
||||
} |
||||
if (isset($context['sftp']['password'])) { |
||||
$pass = $context['sftp']['password']; |
||||
} |
||||
if (isset($context['sftp']['privkey']) && is_object($context['sftp']['privkey']) && get_Class($context['sftp']['privkey']) == 'Crypt_RSA') { |
||||
$pass = $context['sftp']['privkey']; |
||||
} |
||||
|
||||
if (!isset($user) || !isset($pass)) { |
||||
return false; |
||||
} |
||||
|
||||
// casting $pass to a string is necessary in the event that it's a Crypt_RSA object |
||||
if (isset(self::$instances[$host][$port][$user][(string) $pass])) { |
||||
$this->sftp = self::$instances[$host][$port][$user][(string) $pass]; |
||||
} else { |
||||
$this->sftp = new Net_SFTP($host, isset($port) ? $port : 22); |
||||
if (isset($this->notification) && is_callable($this->notification)) { |
||||
/* if !is_callable($this->notification) we could do this: |
||||
|
||||
user_error('fopen(): failed to call user notifier', E_USER_WARNING); |
||||
|
||||
the ftp wrapper gives errors like that when the notifier isn't callable. |
||||
i've opted not to do that, however, since the ftp wrapper gives the line |
||||
on which the fopen occurred as the line number - not the line that the |
||||
user_error is on. |
||||
*/ |
||||
call_user_func($this->notification, STREAM_NOTIFY_CONNECT, STREAM_NOTIFY_SEVERITY_INFO, '', 0, 0, 0); |
||||
call_user_func($this->notification, STREAM_NOTIFY_AUTH_REQUIRED, STREAM_NOTIFY_SEVERITY_INFO, '', 0, 0, 0); |
||||
if (!$this->sftp->login($user, $pass)) { |
||||
call_user_func($this->notification, STREAM_NOTIFY_AUTH_RESULT, STREAM_NOTIFY_SEVERITY_ERR, 'Login Failure', NET_SSH2_MSG_USERAUTH_FAILURE, 0, 0); |
||||
return false; |
||||
} |
||||
call_user_func($this->notification, STREAM_NOTIFY_AUTH_RESULT, STREAM_NOTIFY_SEVERITY_INFO, 'Login Success', NET_SSH2_MSG_USERAUTH_SUCCESS, 0, 0); |
||||
} else { |
||||
if (!$this->sftp->login($user, $pass)) { |
||||
return false; |
||||
} |
||||
} |
||||
self::$instances[$host][$port][$user][(string) $pass] = $this->sftp; |
||||
} |
||||
} |
||||
|
||||
return $path; |
||||
} |
||||
|
||||
/** |
||||
* Opens file or URL |
||||
* |
||||
* @param String $path |
||||
* @param String $mode |
||||
* @param Integer $options |
||||
* @param String $opened_path |
||||
* @return Boolean |
||||
* @access public |
||||
*/ |
||||
function _stream_open($path, $mode, $options, &$opened_path) |
||||
{ |
||||
$path = $this->_parse_path($path); |
||||
|
||||
if ($path === false) { |
||||
return false; |
||||
} |
||||
$this->path = $path; |
||||
|
||||
$this->size = $this->sftp->size($path); |
||||
$this->mode = preg_replace('#[bt]$#', '', $mode); |
||||
|
||||
if ($this->size === false) { |
||||
if ($this->mode[0] == 'r') { |
||||
return false; |
||||
} |
||||
} else { |
||||
switch ($this->mode[0]) { |
||||
case 'x': |
||||
return false; |
||||
case 'w': |
||||
case 'c': |
||||
$this->sftp->truncate($path, 0); |
||||
} |
||||
} |
||||
|
||||
$this->pos = $this->mode[0] != 'a' ? 0 : $this->size; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Read from stream |
||||
* |
||||
* @param Integer $count |
||||
* @return Mixed |
||||
* @access public |
||||
*/ |
||||
function _stream_read($count) |
||||
{ |
||||
switch ($this->mode) { |
||||
case 'w': |
||||
case 'a': |
||||
case 'x': |
||||
case 'c': |
||||
return false; |
||||
} |
||||
|
||||
// commented out because some files - eg. /dev/urandom - will say their size is 0 when in fact it's kinda infinite |
||||
//if ($this->pos >= $this->size) { |
||||
// $this->eof = true; |
||||
// return false; |
||||
//} |
||||
|
||||
$result = $this->sftp->get($this->path, false, $this->pos, $count); |
||||
if (isset($this->notification) && is_callable($this->notification)) { |
||||
if ($result === false) { |
||||
call_user_func($this->notification, STREAM_NOTIFY_FAILURE, STREAM_NOTIFY_SEVERITY_ERR, $this->sftp->getLastSFTPError(), NET_SFTP_OPEN, 0, 0); |
||||
return 0; |
||||
} |
||||
// seems that PHP calls stream_read in 8k chunks |
||||
call_user_func($this->notification, STREAM_NOTIFY_PROGRESS, STREAM_NOTIFY_SEVERITY_INFO, '', 0, strlen($result), $this->size); |
||||
} |
||||
|
||||
if (empty($result)) { // ie. false or empty string |
||||
$this->eof = true; |
||||
return false; |
||||
} |
||||
$this->pos+= strlen($result); |
||||
|
||||
return $result; |
||||
} |
||||
|
||||
/** |
||||
* Write to stream |
||||
* |
||||
* @param String $data |
||||
* @return Mixed |
||||
* @access public |
||||
*/ |
||||
function _stream_write($data) |
||||
{ |
||||
switch ($this->mode) { |
||||
case 'r': |
||||
return false; |
||||
} |
||||
|
||||
$result = $this->sftp->put($this->path, $data, NET_SFTP_STRING, $this->pos); |
||||
if (isset($this->notification) && is_callable($this->notification)) { |
||||
if (!$result) { |
||||
call_user_func($this->notification, STREAM_NOTIFY_FAILURE, STREAM_NOTIFY_SEVERITY_ERR, $this->sftp->getLastSFTPError(), NET_SFTP_OPEN, 0, 0); |
||||
return 0; |
||||
} |
||||
// seems that PHP splits up strings into 8k blocks before calling stream_write |
||||
call_user_func($this->notification, STREAM_NOTIFY_PROGRESS, STREAM_NOTIFY_SEVERITY_INFO, '', 0, strlen($data), strlen($data)); |
||||
} |
||||
|
||||
if ($result === false) { |
||||
return false; |
||||
} |
||||
$this->pos+= strlen($data); |
||||
if ($this->pos > $this->size) { |
||||
$this->size = $this->pos; |
||||
} |
||||
$this->eof = false; |
||||
return strlen($data); |
||||
} |
||||
|
||||
/** |
||||
* Retrieve the current position of a stream |
||||
* |
||||
* @return Integer |
||||
* @access public |
||||
*/ |
||||
function _stream_tell() |
||||
{ |
||||
return $this->pos; |
||||
} |
||||
|
||||
/** |
||||
* Tests for end-of-file on a file pointer |
||||
* |
||||
* In my testing there are four classes functions that normally effect the pointer: |
||||
* fseek, fputs / fwrite, fgets / fread and ftruncate. |
||||
* |
||||
* Only fgets / fread, however, results in feof() returning true. do fputs($fp, 'aaa') on a blank file and feof() |
||||
* will return false. do fread($fp, 1) and feof() will then return true. do fseek($fp, 10) on ablank file and feof() |
||||
* will return false. do fread($fp, 1) and feof() will then return true. |
||||
* |
||||
* @return Boolean |
||||
* @access public |
||||
*/ |
||||
function _stream_eof() |
||||
{ |
||||
return $this->eof; |
||||
} |
||||
|
||||
/** |
||||
* Seeks to specific location in a stream |
||||
* |
||||
* @param Integer $offset |
||||
* @param Integer $whence |
||||
* @return Boolean |
||||
* @access public |
||||
*/ |
||||
function _stream_seek($offset, $whence) |
||||
{ |
||||
switch ($whence) { |
||||
case SEEK_SET: |
||||
if ($offset >= $this->size || $offset < 0) { |
||||
return false; |
||||
} |
||||
break; |
||||
case SEEK_CUR: |
||||
$offset+= $this->pos; |
||||
break; |
||||
case SEEK_END: |
||||
$offset+= $this->size; |
||||
} |
||||
|
||||
$this->pos = $offset; |
||||
$this->eof = false; |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Change stream options |
||||
* |
||||
* @param String $path |
||||
* @param Integer $option |
||||
* @param Mixed $var |
||||
* @return Boolean |
||||
* @access public |
||||
*/ |
||||
function _stream_metadata($path, $option, $var) |
||||
{ |
||||
$path = $this->_parse_path($path); |
||||
if ($path === false) { |
||||
return false; |
||||
} |
||||
|
||||
// stream_metadata was introduced in PHP 5.4.0 but as of 5.4.11 the constants haven't been defined |
||||
// see http://www.php.net/streamwrapper.stream-metadata and https://bugs.php.net/64246 |
||||
// and https://github.com/php/php-src/blob/master/main/php_streams.h#L592 |
||||
switch ($option) { |
||||
case 1: // PHP_STREAM_META_TOUCH |
||||
return $this->sftp->touch($path, $var[0], $var[1]); |
||||
case 2: // PHP_STREAM_OWNER_NAME |
||||
case 3: // PHP_STREAM_GROUP_NAME |
||||
return false; |
||||
case 4: // PHP_STREAM_META_OWNER |
||||
return $this->sftp->chown($path, $var); |
||||
case 5: // PHP_STREAM_META_GROUP |
||||
return $this->sftp->chgrp($path, $var); |
||||
case 6: // PHP_STREAM_META_ACCESS |
||||
return $this->sftp->chmod($path, $var) !== false; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Retrieve the underlaying resource |
||||
* |
||||
* @param Integer $cast_as |
||||
* @return Resource |
||||
* @access public |
||||
*/ |
||||
function _stream_cast($cast_as) |
||||
{ |
||||
return $this->sftp->fsock; |
||||
} |
||||
|
||||
/** |
||||
* Advisory file locking |
||||
* |
||||
* @param Integer $operation |
||||
* @return Boolean |
||||
* @access public |
||||
*/ |
||||
function _stream_lock($operation) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* Renames a file or directory |
||||
* |
||||
* Attempts to rename oldname to newname, moving it between directories if necessary. |
||||
* If newname exists, it will be overwritten. This is a departure from what Net_SFTP |
||||
* does. |
||||
* |
||||
* @param String $path_from |
||||
* @param String $path_to |
||||
* @return Boolean |
||||
* @access public |
||||
*/ |
||||
function _rename($path_from, $path_to) |
||||
{ |
||||
$path1 = parse_url($path_from); |
||||
$path2 = parse_url($path_to); |
||||
unset($path1['path'], $path2['path']); |
||||
if ($path1 != $path2) { |
||||
return false; |
||||
} |
||||
|
||||
$path_from = $this->_parse_path($path_from); |
||||
$path_to = parse_url($path_to); |
||||
if ($path_from == false) { |
||||
return false; |
||||
} |
||||
|
||||
$path_to = $path_to['path']; // the $component part of parse_url() was added in PHP 5.1.2 |
||||
// "It is an error if there already exists a file with the name specified by newpath." |
||||
// -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-6.5 |
||||
if (!$this->sftp->rename($path_from, $path_to)) { |
||||
if ($this->sftp->stat($path_to)) { |
||||
return $this->sftp->delete($path_to, true) && $this->sftp->rename($path_from, $path_to); |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Open directory handle |
||||
* |
||||
* The only $options is "whether or not to enforce safe_mode (0x04)". Since safe mode was deprecated in 5.3 and |
||||
* removed in 5.4 I'm just going to ignore it |
||||
* |
||||
* @param String $path |
||||
* @param Integer $options |
||||
* @return Boolean |
||||
* @access public |
||||
*/ |
||||
function _dir_opendir($path, $options) |
||||
{ |
||||
$path = $this->_parse_path($path); |
||||
if ($path === false) { |
||||
return false; |
||||
} |
||||
$this->pos = 0; |
||||
$this->entries = $this->sftp->nlist($path); |
||||
return $this->entries !== false; |
||||
} |
||||
|
||||
/** |
||||
* Read entry from directory handle |
||||
* |
||||
* @return Mixed |
||||
* @access public |
||||
*/ |
||||
function _dir_readdir() |
||||
{ |
||||
if (isset($this->entries[$this->pos])) { |
||||
return $this->entries[$this->pos++]; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* Rewind directory handle |
||||
* |
||||
* @return Boolean |
||||
* @access public |
||||
*/ |
||||
function _dir_rewinddir() |
||||
{ |
||||
$this->pos = 0; |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Close directory handle |
||||
* |
||||
* @return Boolean |
||||
* @access public |
||||
*/ |
||||
function _dir_closedir() |
||||
{ |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Create a directory |
||||
* |
||||
* Only valid $options is STREAM_MKDIR_RECURSIVE |
||||
* |
||||
* @param String $path |
||||
* @param Integer $mode |
||||
* @param Integer $options |
||||
* @return Boolean |
||||
* @access public |
||||
*/ |
||||
function _mkdir($path, $mode, $options) |
||||
{ |
||||
$path = $this->_parse_path($path); |
||||
if ($path === false) { |
||||
return false; |
||||
} |
||||
|
||||
return $this->sftp->mkdir($path, $mode, $options & STREAM_MKDIR_RECURSIVE); |
||||
} |
||||
|
||||
/** |
||||
* Removes a directory |
||||
* |
||||
* Only valid $options is STREAM_MKDIR_RECURSIVE per <http://php.net/streamwrapper.rmdir>, however, |
||||
* <http://php.net/rmdir> does not have a $recursive parameter as mkdir() does so I don't know how |
||||
* STREAM_MKDIR_RECURSIVE is supposed to be set. Also, when I try it out with rmdir() I get 8 as |
||||
* $options. What does 8 correspond to? |
||||
* |
||||
* @param String $path |
||||
* @param Integer $mode |
||||
* @param Integer $options |
||||
* @return Boolean |
||||
* @access public |
||||
*/ |
||||
function _rmdir($path, $options) |
||||
{ |
||||
$path = $this->_parse_path($path); |
||||
if ($path === false) { |
||||
return false; |
||||
} |
||||
|
||||
return $this->sftp->rmdir($path); |
||||
} |
||||
|
||||
/** |
||||
* Flushes the output |
||||
* |
||||
* See <http://php.net/fflush>. Always returns true because Net_SFTP doesn't cache stuff before writing |
||||
* |
||||
* @return Boolean |
||||
* @access public |
||||
*/ |
||||
function _stream_flush() |
||||
{ |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Retrieve information about a file resource |
||||
* |
||||
* @return Mixed |
||||
* @access public |
||||
*/ |
||||
function _stream_stat() |
||||
{ |
||||
$results = $this->sftp->stat($this->path); |
||||
if ($results === false) { |
||||
return false; |
||||
} |
||||
return $results; |
||||
} |
||||
|
||||
/** |
||||
* Delete a file |
||||
* |
||||
* @param String $path |
||||
* @return Boolean |
||||
* @access public |
||||
*/ |
||||
function _unlink($path) |
||||
{ |
||||
$path = $this->_parse_path($path); |
||||
if ($path === false) { |
||||
return false; |
||||
} |
||||
|
||||
return $this->sftp->delete($path, false); |
||||
} |
||||
|
||||
/** |
||||
* Retrieve information about a file |
||||
* |
||||
* Ignores the STREAM_URL_STAT_QUIET flag because the entirety of Net_SFTP_Stream is quiet by default |
||||
* might be worthwhile to reconstruct bits 12-16 (ie. the file type) if mode doesn't have them but we'll |
||||
* cross that bridge when and if it's reached |
||||
* |
||||
* @param String $path |
||||
* @param Integer $flags |
||||
* @return Mixed |
||||
* @access public |
||||
*/ |
||||
function _url_stat($path, $flags) |
||||
{ |
||||
$path = $this->_parse_path($path); |
||||
if ($path === false) { |
||||
return false; |
||||
} |
||||
|
||||
$results = $flags & STREAM_URL_STAT_LINK ? $this->sftp->lstat($path) : $this->sftp->stat($path); |
||||
if ($results === false) { |
||||
return false; |
||||
} |
||||
|
||||
return $results; |
||||
} |
||||
|
||||
/** |
||||
* Truncate stream |
||||
* |
||||
* @param Integer $new_size |
||||
* @return Boolean |
||||
* @access public |
||||
*/ |
||||
function _stream_truncate($new_size) |
||||
{ |
||||
if (!$this->sftp->truncate($this->path, $new_size)) { |
||||
return false; |
||||
} |
||||
|
||||
$this->eof = false; |
||||
$this->size = $new_size; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Change stream options |
||||
* |
||||
* STREAM_OPTION_WRITE_BUFFER isn't supported for the same reason stream_flush isn't. |
||||
* The other two aren't supported because of limitations in Net_SFTP. |
||||
* |
||||
* @param Integer $option |
||||
* @param Integer $arg1 |
||||
* @param Integer $arg2 |
||||
* @return Boolean |
||||
* @access public |
||||
*/ |
||||
function _stream_set_option($option, $arg1, $arg2) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* Close an resource |
||||
* |
||||
* @access public |
||||
*/ |
||||
function _stream_close() |
||||
{ |
||||
} |
||||
|
||||
/** |
||||
* __call Magic Method |
||||
* |
||||
* When you're utilizing an SFTP stream you're not calling the methods in this class directly - PHP is calling them for you. |
||||
* Which kinda begs the question... what methods is PHP calling and what parameters is it passing to them? This function |
||||
* lets you figure that out. |
||||
* |
||||
* If NET_SFTP_STREAM_LOGGING is defined all calls will be output on the screen and then (regardless of whether or not |
||||
* NET_SFTP_STREAM_LOGGING is enabled) the parameters will be passed through to the appropriate method. |
||||
* |
||||
* @param String |
||||
* @param Array |
||||
* @return Mixed |
||||
* @access public |
||||
*/ |
||||
function __call($name, $arguments) |
||||
{ |
||||
if (defined('NET_SFTP_STREAM_LOGGING')) { |
||||
echo $name . '('; |
||||
$last = count($arguments) - 1; |
||||
foreach ($arguments as $i => $argument) { |
||||
var_export($argument); |
||||
if ($i != $last) { |
||||
echo ','; |
||||
} |
||||
} |
||||
echo ")\r\n"; |
||||
} |
||||
$name = '_' . $name; |
||||
if (!method_exists($this, $name)) { |
||||
return false; |
||||
} |
||||
return call_user_func_array(array($this, $name), $arguments); |
||||
} |
||||
} |
||||
|
||||
if (function_exists('stream_wrapper_register')) { |
||||
stream_wrapper_register('sftp', 'Net_SFTP_Stream'); |
||||
} |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,6 @@ |
||||
# minimalist openssl.cnf file for use with phpseclib |
||||
|
||||
HOME = . |
||||
RANDFILE = $ENV::HOME/.rnd |
||||
|
||||
[ v3_ca ] |
Loading…
Reference in new issue