phpseclib extlib updated from phpseclib.sf.net

This commit is contained in:
Mikael Nordfeldth 2013-09-24 02:09:37 +02:00
parent 49b755912f
commit f7719b57f2
11 changed files with 17019 additions and 10443 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,493 +1,492 @@
<?php <?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/** /**
* Pure-PHP implementation of RC4. * Pure-PHP implementation of RC4.
* *
* Uses mcrypt, if available, and an internal implementation, otherwise. * Uses mcrypt, if available, and an internal implementation, otherwise.
* *
* PHP versions 4 and 5 * PHP versions 4 and 5
* *
* Useful resources are as follows: * Useful resources are as follows:
* *
* - {@link http://www.mozilla.org/projects/security/pki/nss/draft-kaukonen-cipher-arcfour-03.txt ARCFOUR Algorithm} * - {@link http://www.mozilla.org/projects/security/pki/nss/draft-kaukonen-cipher-arcfour-03.txt ARCFOUR Algorithm}
* - {@link http://en.wikipedia.org/wiki/RC4 - Wikipedia: RC4} * - {@link http://en.wikipedia.org/wiki/RC4 - Wikipedia: RC4}
* *
* RC4 is also known as ARCFOUR or ARC4. The reason is elaborated upon at Wikipedia. This class is named RC4 and not * RC4 is also known as ARCFOUR or ARC4. The reason is elaborated upon at Wikipedia. This class is named RC4 and not
* ARCFOUR or ARC4 because RC4 is how it is refered to in the SSH1 specification. * ARCFOUR or ARC4 because RC4 is how it is referred to in the SSH1 specification.
* *
* Here's a short example of how to use this library: * Here's a short example of how to use this library:
* <code> * <code>
* <?php * <?php
* include('Crypt/RC4.php'); * include('Crypt/RC4.php');
* *
* $rc4 = new Crypt_RC4(); * $rc4 = new Crypt_RC4();
* *
* $rc4->setKey('abcdefgh'); * $rc4->setKey('abcdefgh');
* *
* $size = 10 * 1024; * $size = 10 * 1024;
* $plaintext = ''; * $plaintext = '';
* for ($i = 0; $i < $size; $i++) { * for ($i = 0; $i < $size; $i++) {
* $plaintext.= 'a'; * $plaintext.= 'a';
* } * }
* *
* echo $rc4->decrypt($rc4->encrypt($plaintext)); * echo $rc4->decrypt($rc4->encrypt($plaintext));
* ?> * ?>
* </code> * </code>
* *
* LICENSE: This library is free software; you can redistribute it and/or * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
* modify it under the terms of the GNU Lesser General Public * of this software and associated documentation files (the "Software"), to deal
* License as published by the Free Software Foundation; either * in the Software without restriction, including without limitation the rights
* version 2.1 of the License, or (at your option) any later version. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* * copies of the Software, and to permit persons to whom the Software is
* This library is distributed in the hope that it will be useful, * furnished to do so, subject to the following conditions:
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * The above copyright notice and this permission notice shall be included in
* Lesser General Public License for more details. * all copies or substantial portions of the Software.
* *
* You should have received a copy of the GNU Lesser General Public * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* License along with this library; if not, write to the Free Software * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* MA 02111-1307 USA * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* @category Crypt * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* @package Crypt_RC4 * THE SOFTWARE.
* @author Jim Wigginton <terrafrost@php.net> *
* @copyright MMVII Jim Wigginton * @category Crypt
* @license http://www.gnu.org/licenses/lgpl.txt * @package Crypt_RC4
* @version $Id: RC4.php,v 1.8 2009/06/09 04:00:38 terrafrost Exp $ * @author Jim Wigginton <terrafrost@php.net>
* @link http://phpseclib.sourceforge.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() /**#@+
*/ * @access private
/** * @see Crypt_RC4::Crypt_RC4()
* Toggles the internal implementation */
*/ /**
define('CRYPT_RC4_MODE_INTERNAL', 1); * Toggles the internal implementation
/** */
* Toggles the mcrypt implementation define('CRYPT_RC4_MODE_INTERNAL', 1);
*/ /**
define('CRYPT_RC4_MODE_MCRYPT', 2); * Toggles the mcrypt implementation
/**#@-*/ */
define('CRYPT_RC4_MODE_MCRYPT', 2);
/**#@+ /**#@-*/
* @access private
* @see Crypt_RC4::_crypt() /**#@+
*/ * @access private
define('CRYPT_RC4_ENCRYPT', 0); * @see Crypt_RC4::_crypt()
define('CRYPT_RC4_DECRYPT', 1); */
/**#@-*/ define('CRYPT_RC4_ENCRYPT', 0);
define('CRYPT_RC4_DECRYPT', 1);
/** /**#@-*/
* Pure-PHP implementation of RC4.
* /**
* @author Jim Wigginton <terrafrost@php.net> * Pure-PHP implementation of RC4.
* @version 0.1.0 *
* @access public * @author Jim Wigginton <terrafrost@php.net>
* @package Crypt_RC4 * @version 0.1.0
*/ * @access public
class Crypt_RC4 { * @package Crypt_RC4
/** */
* The Key class Crypt_RC4 {
* /**
* @see Crypt_RC4::setKey() * The Key
* @var String *
* @access private * @see Crypt_RC4::setKey()
*/ * @var String
var $key = "\0"; * @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 * The Key Stream for encryption
* *
* @see Crypt_RC4::setKey() * If CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT, this will be equal to the mcrypt object
* @var Array *
* @access private * @see Crypt_RC4::setKey()
*/ * @var Array
var $encryptStream = false; * @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 * The Key Stream for decryption
* *
* @see Crypt_RC4::setKey() * If CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT, this will be equal to the mcrypt object
* @var Array *
* @access private * @see Crypt_RC4::setKey()
*/ * @var Array
var $decryptStream = false; * @access private
*/
/** var $decryptStream = false;
* The $i and $j indexes for encryption
* /**
* @see Crypt_RC4::_crypt() * The $i and $j indexes for encryption
* @var Integer *
* @access private * @see Crypt_RC4::_crypt()
*/ * @var Integer
var $encryptIndex = 0; * @access private
*/
/** var $encryptIndex = 0;
* The $i and $j indexes for decryption
* /**
* @see Crypt_RC4::_crypt() * The $i and $j indexes for decryption
* @var Integer *
* @access private * @see Crypt_RC4::_crypt()
*/ * @var Integer
var $decryptIndex = 0; * @access private
*/
/** var $decryptIndex = 0;
* MCrypt parameters
* /**
* @see Crypt_RC4::setMCrypt() * The Encryption Algorithm
* @var Array *
* @access private * Only used if CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT. Only possible values are MCRYPT_RC4 or MCRYPT_ARCFOUR.
*/ *
var $mcrypt = array('', ''); * @see Crypt_RC4::Crypt_RC4()
* @var Integer
/** * @access private
* The Encryption Algorithm */
* var $mode;
* Only used if CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT. Only possible values are MCRYPT_RC4 or MCRYPT_ARCFOUR.
* /**
* @see Crypt_RC4::Crypt_RC4() * Continuous Buffer status
* @var Integer *
* @access private * @see Crypt_RC4::enableContinuousBuffer()
*/ * @var Boolean
var $mode; * @access private
*/
/** var $continuousBuffer = false;
* Default Constructor.
* /**
* Determines whether or not the mcrypt extension should be used. * Default Constructor.
* *
* @param optional Integer $mode * Determines whether or not the mcrypt extension should be used.
* @return Crypt_RC4 *
* @access public * @return Crypt_RC4
*/ * @access public
function Crypt_RC4() */
{ function Crypt_RC4()
if ( !defined('CRYPT_RC4_MODE') ) { {
switch (true) { if ( !defined('CRYPT_RC4_MODE') ) {
case extension_loaded('mcrypt') && (defined('MCRYPT_ARCFOUR') || defined('MCRYPT_RC4')): switch (true) {
// i'd check to see if rc4 was supported, by doing in_array('arcfour', mcrypt_list_algorithms('')), case extension_loaded('mcrypt') && (defined('MCRYPT_ARCFOUR') || defined('MCRYPT_RC4')) && in_array('arcfour', mcrypt_list_algorithms()):
// but since that can be changed after the object has been created, there doesn't seem to be define('CRYPT_RC4_MODE', CRYPT_RC4_MODE_MCRYPT);
// a lot of point... break;
define('CRYPT_RC4_MODE', CRYPT_RC4_MODE_MCRYPT); default:
break; define('CRYPT_RC4_MODE', CRYPT_RC4_MODE_INTERNAL);
default: }
define('CRYPT_RC4_MODE', CRYPT_RC4_MODE_INTERNAL); }
}
} switch ( CRYPT_RC4_MODE ) {
case CRYPT_RC4_MODE_MCRYPT:
switch ( CRYPT_RC4_MODE ) { switch (true) {
case CRYPT_RC4_MODE_MCRYPT: case defined('MCRYPT_ARCFOUR'):
switch (true) { $this->mode = MCRYPT_ARCFOUR;
case defined('MCRYPT_ARCFOUR'): break;
$this->mode = MCRYPT_ARCFOUR; case defined('MCRYPT_RC4');
break; $this->mode = MCRYPT_RC4;
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. /**
* * 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. * 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 * @access public
*/ * @param String $key
function setKey($key) */
{ function setKey($key)
$this->key = $key; {
$this->key = $key;
if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
return; if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
} mcrypt_generic_init($this->encryptStream, $this->key, '');
mcrypt_generic_init($this->decryptStream, $this->key, '');
$keyLength = strlen($key); return;
$keyStream = array(); }
for ($i = 0; $i < 256; $i++) {
$keyStream[$i] = $i; $keyLength = strlen($key);
} $keyStream = array();
$j = 0; for ($i = 0; $i < 256; $i++) {
for ($i = 0; $i < 256; $i++) { $keyStream[$i] = $i;
$j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255; }
$temp = $keyStream[$i]; $j = 0;
$keyStream[$i] = $keyStream[$j]; for ($i = 0; $i < 256; $i++) {
$keyStream[$j] = $temp; $j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255;
} $temp = $keyStream[$i];
$keyStream[$i] = $keyStream[$j];
$this->encryptIndex = $this->decryptIndex = array(0, 0); $keyStream[$j] = $temp;
$this->encryptStream = $this->decryptStream = $keyStream; }
}
$this->encryptIndex = $this->decryptIndex = array(0, 0);
/** $this->encryptStream = $this->decryptStream = $keyStream;
* 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 * Sets the password.
* calling setKey(). *
* * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
* [1] WEP's initialization vectors (IV's) are used in a somewhat insecure way. Since, in that protocol, * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}:
* the IV's are relatively easy to predict, an attack described by * $hash, $salt, $count, $dkLen
* {@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: * @param String $password
* * @param optional String $method
* {@link http://www.rsa.com/rsalabs/node.asp?id=2009 http://www.rsa.com/rsalabs/node.asp?id=2009} * @access public
* {@link http://en.wikipedia.org/wiki/Related_key_attack http://en.wikipedia.org/wiki/Related_key_attack} */
* function setPassword($password, $method = 'pbkdf2')
* @param String $iv {
* @see Crypt_RC4::setKey() $key = '';
* @access public
*/ switch ($method) {
function setIV($iv) default: // 'pbkdf2'
{ list(, , $hash, $salt, $count) = func_get_args();
} if (!isset($hash)) {
$hash = 'sha1';
/** }
* Sets MCrypt parameters. (optional) // WPA and WPA2 use the SSID as the salt
* if (!isset($salt)) {
* If MCrypt is being used, empty strings will be used, unless otherwise specified. $salt = 'phpseclib/salt';
* }
* @link http://php.net/function.mcrypt-module-open#function.mcrypt-module-open // RFC2898#section-4.2 uses 1,000 iterations by default
* @access public // WPA and WPA2 use 4,096.
* @param optional Integer $algorithm_directory if (!isset($count)) {
* @param optional Integer $mode_directory $count = 1000;
*/ }
function setMCrypt($algorithm_directory = '', $mode_directory = '') if (!isset($dkLen)) {
{ $dkLen = 128;
if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) { }
$this->mcrypt = array($algorithm_directory, $mode_directory);
$this->_closeMCrypt(); if (!class_exists('Crypt_Hash')) {
} require_once('Crypt/Hash.php');
} }
/** $i = 1;
* Encrypts a message. while (strlen($key) < $dkLen) {
* //$dk.= $this->_pbkdf($password, $salt, $count, $i++);
* @see Crypt_RC4::_crypt() $hmac = new Crypt_Hash();
* @access public $hmac->setHash($hash);
* @param String $plaintext $hmac->setKey($password);
*/ $f = $u = $hmac->hash($salt . pack('N', $i++));
function encrypt($plaintext) for ($j = 2; $j <= $count; $j++) {
{ $u = $hmac->hash($u);
return $this->_crypt($plaintext, CRYPT_RC4_ENCRYPT); $f^= $u;
} }
$key.= $f;
/** }
* Decrypts a message. }
*
* $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)). $this->setKey(substr($key, 0, $dkLen));
* Atleast if the continuous buffer is disabled. }
*
* @see Crypt_RC4::_crypt() /**
* @access public * Dummy function.
* @param String $ciphertext *
*/ * Some protocols, such as WEP, prepend an "initialization vector" to the key, effectively creating a new key [1].
function decrypt($ciphertext) * If you need to use an initialization vector in this manner, feel free to prepend it to the key, yourself, before
{ * calling setKey().
return $this->_crypt($ciphertext, CRYPT_RC4_DECRYPT); *
} * [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}
* Encrypts or decrypts a message. * can be used to quickly guess at the rest of the key. The following links elaborate:
* *
* @see Crypt_RC4::encrypt() * {@link http://www.rsa.com/rsalabs/node.asp?id=2009 http://www.rsa.com/rsalabs/node.asp?id=2009}
* @see Crypt_RC4::decrypt() * {@link http://en.wikipedia.org/wiki/Related_key_attack http://en.wikipedia.org/wiki/Related_key_attack}
* @access private *
* @param String $text * @param String $iv
* @param Integer $mode * @see Crypt_RC4::setKey()
*/ * @access public
function _crypt($text, $mode) */
{ function setIV($iv)
if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) { {
$keyStream = $mode == CRYPT_RC4_ENCRYPT ? 'encryptStream' : 'decryptStream'; }
if ($this->$keyStream === false) { /**
$this->$keyStream = mcrypt_module_open($this->mode, $this->mcrypt[0], MCRYPT_MODE_STREAM, $this->mcrypt[1]); * Encrypts a message.
mcrypt_generic_init($this->$keyStream, $this->key, ''); *
} else if (!$this->continuousBuffer) { * @see Crypt_RC4::_crypt()
mcrypt_generic_init($this->$keyStream, $this->key, ''); * @access public
} * @param String $plaintext
$newText = mcrypt_generic($this->$keyStream, $text); */
if (!$this->continuousBuffer) { function encrypt($plaintext)
mcrypt_generic_deinit($this->$keyStream); {
} return $this->_crypt($plaintext, CRYPT_RC4_ENCRYPT);
}
return $newText;
} /**
* Decrypts a message.
if ($this->encryptStream === false) { *
$this->setKey($this->key); * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)).
} * Atleast if the continuous buffer is disabled.
*
switch ($mode) { * @see Crypt_RC4::_crypt()
case CRYPT_RC4_ENCRYPT: * @access public
$keyStream = $this->encryptStream; * @param String $ciphertext
list($i, $j) = $this->encryptIndex; */
break; function decrypt($ciphertext)
case CRYPT_RC4_DECRYPT: {
$keyStream = $this->decryptStream; return $this->_crypt($ciphertext, CRYPT_RC4_DECRYPT);
list($i, $j) = $this->decryptIndex; }
}
/**
$newText = ''; * Encrypts or decrypts a message.
for ($k = 0; $k < strlen($text); $k++) { *
$i = ($i + 1) & 255; * @see Crypt_RC4::encrypt()
$j = ($j + $keyStream[$i]) & 255; * @see Crypt_RC4::decrypt()
$temp = $keyStream[$i]; * @access private
$keyStream[$i] = $keyStream[$j]; * @param String $text
$keyStream[$j] = $temp; * @param Integer $mode
$temp = $keyStream[($keyStream[$i] + $keyStream[$j]) & 255]; */
$newText.= chr(ord($text[$k]) ^ $temp); function _crypt($text, $mode)
} {
if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
if ($this->continuousBuffer) { $keyStream = $mode == CRYPT_RC4_ENCRYPT ? 'encryptStream' : 'decryptStream';
switch ($mode) {
case CRYPT_RC4_ENCRYPT: if (!$this->continuousBuffer) {
$this->encryptStream = $keyStream; mcrypt_generic_init($this->$keyStream, $this->key, '');
$this->encryptIndex = array($i, $j); }
break;
case CRYPT_RC4_DECRYPT: return mcrypt_generic($this->$keyStream, $text);
$this->decryptStream = $keyStream; }
$this->decryptIndex = array($i, $j);
} if ($this->encryptStream === false) {
} $this->setKey($this->key);
}
return $newText;
} switch ($mode) {
case CRYPT_RC4_ENCRYPT:
/** $keyStream = $this->encryptStream;
* Treat consecutive "packets" as if they are a continuous buffer. list($i, $j) = $this->encryptIndex;
* break;
* Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets case CRYPT_RC4_DECRYPT:
* will yield different outputs: $keyStream = $this->decryptStream;
* list($i, $j) = $this->decryptIndex;
* <code> }
* echo $rc4->encrypt(substr($plaintext, 0, 8));
* echo $rc4->encrypt(substr($plaintext, 8, 8)); $newText = '';
* </code> for ($k = 0; $k < strlen($text); $k++) {
* <code> $i = ($i + 1) & 255;
* echo $rc4->encrypt($plaintext); $j = ($j + $keyStream[$i]) & 255;
* </code> $temp = $keyStream[$i];
* $keyStream[$i] = $keyStream[$j];
* The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates $keyStream[$j] = $temp;
* another, as demonstrated with the following: $temp = $keyStream[($keyStream[$i] + $keyStream[$j]) & 255];
* $newText.= chr(ord($text[$k]) ^ $temp);
* <code> }
* $rc4->encrypt(substr($plaintext, 0, 8));
* echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8))); if ($this->continuousBuffer) {
* </code> switch ($mode) {
* <code> case CRYPT_RC4_ENCRYPT:
* echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8))); $this->encryptStream = $keyStream;
* </code> $this->encryptIndex = array($i, $j);
* break;
* With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different case CRYPT_RC4_DECRYPT:
* outputs. The reason is due to the fact that the initialization vector's change after every encryption / $this->decryptStream = $keyStream;
* decryption round when the continuous buffer is enabled. When it's disabled, they remain constant. $this->decryptIndex = array($i, $j);
* }
* 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), return $newText;
* however, they are also less intuitive and more likely to cause you problems. }
*
* @see Crypt_RC4::disableContinuousBuffer() /**
* @access public * Treat consecutive "packets" as if they are a continuous buffer.
*/ *
function enableContinuousBuffer() * Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets
{ * will yield different outputs:
$this->continuousBuffer = true; *
} * <code>
* echo $rc4->encrypt(substr($plaintext, 0, 8));
/** * echo $rc4->encrypt(substr($plaintext, 8, 8));
* Treat consecutive packets as if they are a discontinuous buffer. * </code>
* * <code>
* The default behavior. * echo $rc4->encrypt($plaintext);
* * </code>
* @see Crypt_RC4::enableContinuousBuffer() *
* @access public * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
*/ * another, as demonstrated with the following:
function disableContinuousBuffer() *
{ * <code>
if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_INTERNAL ) { * $rc4->encrypt(substr($plaintext, 0, 8));
$this->encryptIndex = $this->decryptIndex = array(0, 0); * echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8)));
$this->setKey($this->key); * </code>
} * <code>
* echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8)));
$this->continuousBuffer = false; * </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 /
* Dummy function. * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
* *
* Since RC4 is a stream cipher and not a block cipher, no padding is necessary. The only reason this function is * Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each
* included is so that you can switch between a block cipher and a stream cipher transparently. * 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),
* @see Crypt_RC4::disablePadding() * however, they are also less intuitive and more likely to cause you problems.
* @access public *
*/ * @see Crypt_RC4::disableContinuousBuffer()
function enablePadding() * @access public
{ */
} function enableContinuousBuffer()
{
/** if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
* Dummy function. mcrypt_generic_init($this->encryptStream, $this->key, '');
* mcrypt_generic_init($this->decryptStream, $this->key, '');
* @see Crypt_RC4::enablePadding() }
* @access public
*/ $this->continuousBuffer = true;
function disablePadding() }
{
} /**
* Treat consecutive packets as if they are a discontinuous buffer.
/** *
* Class destructor. * The default behavior.
* *
* Will be called, automatically, if you're using PHP5. If you're using PHP4, call it yourself. Only really * @see Crypt_RC4::enableContinuousBuffer()
* needs to be called if mcrypt is being used. * @access public
* */
* @access public function disableContinuousBuffer()
*/ {
function __destruct() if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_INTERNAL ) {
{ $this->encryptIndex = $this->decryptIndex = array(0, 0);
if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) { $this->encryptStream = $this->decryptStream = false;
$this->_closeMCrypt(); }
}
} $this->continuousBuffer = false;
}
/**
* Properly close the MCrypt objects. /**
* * Dummy function.
* @access prviate *
*/ * Since RC4 is a stream cipher and not a block cipher, no padding is necessary. The only reason this function is
function _closeMCrypt() * included is so that you can switch between a block cipher and a stream cipher transparently.
{ *
if ( $this->encryptStream !== false ) { * @see Crypt_RC4::disablePadding()
if ( $this->continuousBuffer ) { * @access public
mcrypt_generic_deinit($this->encryptStream); */
} function enablePadding()
{
mcrypt_module_close($this->encryptStream); }
$this->encryptStream = false; /**
} * Dummy function.
*
if ( $this->decryptStream !== false ) { * @see Crypt_RC4::enablePadding()
if ( $this->continuousBuffer ) { * @access public
mcrypt_generic_deinit($this->decryptStream); */
} function disablePadding()
{
mcrypt_module_close($this->decryptStream); }
}
$this->decryptStream = false;
} // vim: ts=4:sw=4:et:
} // vim6: fdl=1:
}

File diff suppressed because it is too large Load Diff

View File

@ -1,125 +1,249 @@
<?php <?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/** /**
* Random Number Generator * Random Number Generator
* *
* PHP versions 4 and 5 * PHP versions 4 and 5
* *
* Here's a short example of how to use this library: * Here's a short example of how to use this library:
* <code> * <code>
* <?php * <?php
* include('Crypt/Random.php'); * include('Crypt/Random.php');
* *
* echo crypt_random(); * echo bin2hex(crypt_random_string(8));
* ?> * ?>
* </code> * </code>
* *
* LICENSE: This library is free software; you can redistribute it and/or * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
* modify it under the terms of the GNU Lesser General Public * of this software and associated documentation files (the "Software"), to deal
* License as published by the Free Software Foundation; either * in the Software without restriction, including without limitation the rights
* version 2.1 of the License, or (at your option) any later version. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* * copies of the Software, and to permit persons to whom the Software is
* This library is distributed in the hope that it will be useful, * furnished to do so, subject to the following conditions:
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * The above copyright notice and this permission notice shall be included in
* Lesser General Public License for more details. * all copies or substantial portions of the Software.
* *
* You should have received a copy of the GNU Lesser General Public * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* License along with this library; if not, write to the Free Software * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* MA 02111-1307 USA * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* @category Crypt * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* @package Crypt_Random * THE SOFTWARE.
* @author Jim Wigginton <terrafrost@php.net> *
* @copyright MMVII Jim Wigginton * @category Crypt
* @license http://www.gnu.org/licenses/lgpl.txt * @package Crypt_Random
* @version $Id: Random.php,v 1.6 2010/02/28 05:28:38 terrafrost Exp $ * @author Jim Wigginton <terrafrost@php.net>
* @link http://phpseclib.sourceforge.net * @copyright MMVII Jim Wigginton
*/ * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
/** */
* Generate a random value.
* /**
* On 32-bit machines, the largest distance that can exist between $min and $max is 2**31. * "Is Windows" test
* If $min and $max are farther apart than that then the last ($max - range) numbers. *
* * @access private
* Depending on how this is being used, it may be worth while to write a replacement. For example, */
* a PHP-based web app that stores its data in an SQL database can collect more entropy than this function define('CRYPT_RANDOM_IS_WINDOWS', strtoupper(substr(PHP_OS, 0, 3)) === 'WIN');
* can.
* /**
* @param optional Integer $min * Generate a random string.
* @param optional Integer $max *
* @return Integer * Although microoptimizations are generally discouraged as they impair readability this function is ripe with
* @access public * microoptimizations because this function has the potential of being called a huge number of times.
*/ * eg. for RSA key generation.
function crypt_random($min = 0, $max = 0x7FFFFFFF) *
{ * @param Integer $length
if ($min == $max) { * @return String
return $min; * @access public
} */
function crypt_random_string($length)
// see http://en.wikipedia.org/wiki//dev/random {
if (file_exists('/dev/urandom')) { if (CRYPT_RANDOM_IS_WINDOWS) {
$fp = fopen('/dev/urandom', 'rb'); // method 1. prior to PHP 5.3 this would call rand() on windows hence the function_exists('class_alias') call.
extract(unpack('Nrandom', fread($fp, 4))); // ie. class_alias is a function that was introduced in PHP 5.3
fclose($fp); if (function_exists('mcrypt_create_iv') && function_exists('class_alias')) {
return mcrypt_create_iv($length);
// say $min = 0 and $max = 3. if we didn't do abs() then we could have stuff like this: }
// -4 % 3 + 0 = -1, even though -1 < $min // method 2. openssl_random_pseudo_bytes was introduced in PHP 5.3.0 but prior to PHP 5.3.4 there was,
return abs($random) % ($max - $min) + $min; // 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():
/* Prior to PHP 4.2.0, mt_srand() had to be called before mt_rand() could be called. //
Prior to PHP 5.2.6, mt_rand()'s automatic seeding was subpar, as elaborated here: // 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
http://www.suspekt.org/2008/08/17/mt_srand-and-not-so-random-numbers/ //
// php_win32_get_random_bytes() is defined thusly:
The seeding routine is pretty much ripped from PHP's own internal GENERATE_SEED() macro: //
// https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/win32/winutil.c#L80
http://svn.php.net/viewvc/php/php-src/branches/PHP_5_3_2/ext/standard/php_rand.h?view=markup */ //
if (version_compare(PHP_VERSION, '5.2.5', '<=')) { // we're calling it, all the same, in the off chance that the mcrypt extension is not available
static $seeded; if (function_exists('openssl_random_pseudo_bytes') && version_compare(PHP_VERSION, '5.3.4', '>=')) {
if (!isset($seeded)) { return openssl_random_pseudo_bytes($length);
$seeded = true; }
mt_srand(fmod(time() * getmypid(), 0x7FFFFFFF) ^ fmod(1000000 * lcg_value(), 0x7FFFFFFF)); } else {
} // method 1. the fastest
} if (function_exists('openssl_random_pseudo_bytes')) {
return openssl_random_pseudo_bytes($length);
static $crypto; }
// method 2
// The CSPRNG's Yarrow and Fortuna periodically reseed. This function can be reseeded by hitting F5 static $fp = true;
// in the browser and reloading the page. if ($fp === true) {
// warning's will be output unles the error suppression operator is used. errors such as
if (!isset($crypto)) { // "open_basedir restriction in effect", "Permission denied", "No such file or directory", etc.
$key = $iv = ''; $fp = @fopen('/dev/urandom', 'rb');
for ($i = 0; $i < 8; $i++) { }
$key.= pack('n', mt_rand(0, 0xFFFF)); if ($fp !== true && $fp !== false) { // surprisingly faster than !is_bool() or is_resource()
$iv .= pack('n', mt_rand(0, 0xFFFF)); return fread($fp, $length);
} }
switch (true) { // method 3. pretty much does the same thing as method 2 per the following url:
case class_exists('Crypt_AES'): // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1391
$crypto = new Crypt_AES(CRYPT_AES_MODE_CTR); // surprisingly slower than method 2. maybe that's because mcrypt_create_iv does a bunch of error checking that we're
break; // not doing. regardless, this'll only be called if this PHP script couldn't open /dev/urandom due to open_basedir
case class_exists('Crypt_TripleDES'): // restrictions or some such
$crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CTR); if (function_exists('mcrypt_create_iv')) {
break; return mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
case class_exists('Crypt_DES'): }
$crypto = new Crypt_DES(CRYPT_DES_MODE_CTR); }
break; // at this point we have no choice but to use a pure-PHP CSPRNG
case class_exists('Crypt_RC4'):
$crypto = new Crypt_RC4(); // cascade entropy across multiple PHP instances by fixing the session and collecting all
break; // environmental variables, including the previous session data and the current session
default: // data.
extract(unpack('Nrandom', pack('H*', sha1(mt_rand(0, 0x7FFFFFFF))))); //
return abs($random) % ($max - $min) + $min; // 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
$crypto->setKey($key); // PHP isn't low level to be able to use those as sources and on a web server there's not likely
$crypto->setIV($iv); // 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
extract(unpack('Nrandom', $crypto->encrypt("\0\0\0\0"))); // by the user and (2) this isn't just looking at the data sent by the current user - it's based
return abs($random) % ($max - $min) + $min; // 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

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