Crypt_Base

Crypt_Base() implementation
This commit is contained in:
Hans-Jürgen Petrich 2013-05-20 13:19:38 +07:00
parent 1a087b5531
commit 55ff00cc35
8 changed files with 3540 additions and 5888 deletions

View File

@ -42,10 +42,10 @@
* 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
@ -82,31 +82,31 @@ if (!class_exists('Crypt_Rijndael')) {
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
*/
define('CRYPT_AES_MODE_CTR', -1);
define('CRYPT_AES_MODE_CTR', CRYPT_MODE_CTR);
/**
* 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);
define('CRYPT_AES_MODE_ECB', CRYPT_MODE_ECB);
/**
* 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);
define('CRYPT_AES_MODE_CBC', CRYPT_MODE_CBC);
/**
* 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);
define('CRYPT_AES_MODE_CFB', CRYPT_MODE_CFB);
/**
* 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);
define('CRYPT_AES_MODE_OFB', CRYPT_MODE_OFB);
/**#@-*/
/**#@+
@ -116,11 +116,11 @@ define('CRYPT_AES_MODE_OFB', 4);
/**
* Toggles the internal implementation
*/
define('CRYPT_AES_MODE_INTERNAL', 1);
define('CRYPT_AES_MODE_INTERNAL', CRYPT_MODE_INTERNAL);
/**
* Toggles the mcrypt implementation
*/
define('CRYPT_AES_MODE_MCRYPT', 2);
define('CRYPT_AES_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
/**#@-*/
/**
@ -133,114 +133,45 @@ define('CRYPT_AES_MODE_MCRYPT', 2);
*/
class Crypt_AES extends Crypt_Rijndael {
/**
* mcrypt resource for encryption
* The namespace used by the cipher for its constants.
*
* 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()
* @see Crypt_Base::const_namespace
* @var String
* @access private
*/
var $enmcrypt;
var $const_namespace = 'AES';
/**
* mcrypt resource for decryption
* The mcrypt specific name of the cipher
*
* 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()
* @see Crypt_Base::cipher_name_mcrypt
* @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;
var $cipher_name_mcrypt = 'rijndael-128';
/**
* 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.
* Determines whether or not the mcrypt extension should be used.
*
* $mode could be:
* - CRYPT_AES_MODE_ECB
* - CRYPT_AES_MODE_CBC
* - CRYPT_AES_MODE_CTR
* - CRYPT_AES_MODE_CFB
* - CRYPT_AES_MODE_OFB
*
* If not explictly set, CRYPT_AES_MODE_CBC will be used.
*
* @see Crypt_Rijndael::Crypt_Rijndael()
* @see Crypt_Base::Crypt_Base()
* @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);
}
parent::Crypt_Rijndael($mode);
}
/**
@ -248,6 +179,7 @@ class Crypt_AES extends Crypt_Rijndael {
*
* Since Crypt_AES extends Crypt_Rijndael, this function is, technically, available, but it doesn't do anything.
*
* @see Crypt_Rijndael::setBlockLength()
* @access public
* @param Integer $length
*/
@ -257,198 +189,15 @@ class Crypt_AES extends Crypt_Rijndael {
}
/**
* 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
* Setup the CRYPT_MODE_MCRYPT $engine
*
* Validates all the variables.
*
* @see Crypt_Base::_mcryptSetup()
* @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;
@ -474,66 +223,10 @@ class Crypt_AES extends Crypt_Rijndael {
$this->key_size = 32;
}
$this->password_key_size = $this->key_size;
$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);
}
parent::_mcryptSetup();
}
}

1937
phpseclib/Crypt/Base.php Normal file

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

@ -41,10 +41,10 @@
* 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
@ -62,6 +62,15 @@
* @link http://phpseclib.sourceforge.net
*/
/**
* Include Crypt_Base
*
* Base cipher class
*/
if (!class_exists('Crypt_Base')) {
require_once 'Base.php';
}
/**#@+
* @access private
* @see Crypt_RC4::Crypt_RC4()
@ -69,11 +78,11 @@
/**
* Toggles the internal implementation
*/
define('CRYPT_RC4_MODE_INTERNAL', 1);
define('CRYPT_RC4_MODE_INTERNAL', CRYPT_MODE_INTERNAL);
/**
* Toggles the mcrypt implementation
*/
define('CRYPT_RC4_MODE_MCRYPT', 2);
define('CRYPT_RC4_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
/**#@-*/
/**#@+
@ -92,7 +101,57 @@ define('CRYPT_RC4_DECRYPT', 1);
* @access public
* @package Crypt_RC4
*/
class Crypt_RC4 {
class Crypt_RC4 extends Crypt_Base {
/**
* Block Length of the cipher
*
* RC4 is a stream cipher
* so we the block_size to 0
*
* @see Crypt_Base::block_size
* @var Integer
* @access private
*/
var $block_size = 0;
/**
* The default password key_size used by setPassword()
*
* @see Crypt_Base::password_key_size
* @see Crypt_Base::setPassword()
* @var Integer
* @access private
*/
var $password_key_size = 128; // = 1024 bits
/**
* The namespace used by the cipher for its constants.
*
* @see Crypt_Base::const_namespace
* @var String
* @access private
*/
var $const_namespace = 'RC4';
/**
* The mcrypt specific name of the cipher
*
* @see Crypt_Base::cipher_name_mcrypt
* @var String
* @access private
*/
var $cipher_name_mcrypt = 'arcfour';
/**
* Holds whether performance-optimized $inline_crypt() can/should be used.
*
* @see Crypt_Base::inline_crypt
* @var mixed
* @access private
*/
var $use_inline_crypt = false; // currently not available
/**
* The Key
*
@ -103,98 +162,26 @@ class Crypt_RC4 {
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 decryption and encryption
*
* @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;
var $stream;
/**
* Default Constructor.
*
* Determines whether or not the mcrypt extension should be used.
*
* @see Crypt_Base::Crypt_Base()
* @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, '');
}
parent::Crypt_Base(CRYPT_MODE_STREAM);
}
/**
@ -204,18 +191,23 @@ class Crypt_RC4 {
* be used. If no key is explicitly set, it'll be assumed to be a single null byte.
*
* @access public
* @see Crypt_Base::setKey()
* @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;
}
parent::setKey(substr($key, 0, 256));
}
/**
* Setup the key (expansion)
*
* @see Crypt_Base::_setupKey()
* @access private
*/
function _setupKey()
{
$key = $this->key;
$keyLength = strlen($key);
$keyStream = array();
for ($i = 0; $i < 256; $i++) {
@ -229,64 +221,12 @@ class Crypt_RC4 {
$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));
$this->stream = array();
$this->stream[CRYPT_RC4_DECRYPT] = $this->stream[CRYPT_RC4_ENCRYPT] = array(
0, // index $i
0, // index $j
$keyStream
);
}
/**
@ -315,12 +255,17 @@ class Crypt_RC4 {
/**
* Encrypts a message.
*
* @see Crypt_Base::decrypt()
* @see Crypt_RC4::_crypt()
* @access public
* @param String $plaintext
* @return String $ciphertext
*/
function encrypt($plaintext)
{
if ($this->engine == CRYPT_MODE_MCRYPT) {
return parent::encrypt($plaintext);
}
return $this->_crypt($plaintext, CRYPT_RC4_ENCRYPT);
}
@ -330,12 +275,17 @@ class Crypt_RC4 {
* $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)).
* Atleast if the continuous buffer is disabled.
*
* @see Crypt_Base::encrypt()
* @see Crypt_RC4::_crypt()
* @access public
* @param String $ciphertext
* @return String $plaintext
*/
function decrypt($ciphertext)
{
if ($this->engine == CRYPT_MODE_MCRYPT) {
return parent::decrypt($ciphertext);
}
return $this->_crypt($ciphertext, CRYPT_RC4_DECRYPT);
}
@ -347,173 +297,41 @@ class Crypt_RC4 {
* @access private
* @param String $text
* @param Integer $mode
* @return String $text
*/
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->changed) {
$this->_setup();
$this->changed = false;
}
$stream = &$this->stream[$mode];
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);
}
$i = &$stream[0];
$j = &$stream[1];
$keyStream = &$stream[2];
} else {
$i = $stream[0];
$j = $stream[1];
$keyStream = $stream[2];
}
return $newText;
}
$len = strlen($text);
for ($k = 0; $k < $len; ++$k) {
$i = ($i + 1) & 255;
$ksi = $keyStream[$i];
$j = ($j + $ksi) & 255;
$ksj = $keyStream[$j];
/**
* 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, '');
$keyStream[$i] = $ksj;
$keyStream[$j] = $ksi;
$text[$k] = chr(ord($text[$k]) ^ $keyStream[($ksj + $ksi) & 255]);
}
$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()
{
}
/**
* Class destructor.
*
* Will be called, automatically, if you're using PHP5. If you're using PHP4, call it yourself. Only really
* needs to be called if mcrypt is being used.
*
* @access public
*/
function __destruct()
{
if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
$this->_closeMCrypt();
}
}
/**
* Properly close the MCrypt objects.
*
* @access prviate
*/
function _closeMCrypt()
{
mcrypt_module_close($this->encryptStream);
mcrypt_module_close($this->decryptStream);
return $text;
}
}
// vim: ts=4:sw=4:et:
// vim6: fdl=1:
// vim6: fdl=1:

File diff suppressed because it is too large Load Diff

View File

@ -33,10 +33,10 @@
* 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
@ -84,9 +84,79 @@ define('CRYPT_DES_MODE_CBC3', CRYPT_DES_MODE_CBC);
* @package Crypt_TerraDES
*/
class Crypt_TripleDES extends Crypt_DES {
/**
* The default password key_size used by setPassword()
*
* @see Crypt_DES::password_key_size
* @see Crypt_Base::password_key_size
* @see Crypt_Base::setPassword()
* @var Integer
* @access private
*/
var $password_key_size = 24;
/**
* The default salt used by setPassword()
*
* @see Crypt_Base::password_default_salt
* @see Crypt_Base::setPassword()
* @var String
* @access private
*/
var $password_default_salt = 'phpseclib';
/**
* The namespace used by the cipher for its constants.
*
* @see Crypt_DES::const_namespace
* @see Crypt_Base::const_namespace
* @var String
* @access private
*/
var $const_namespace = 'DES';
/**
* The mcrypt specific name of the cipher
*
* @see Crypt_DES::cipher_name_mcrypt
* @see Crypt_Base::cipher_name_mcrypt
* @var String
* @access private
*/
var $cipher_name_mcrypt = 'tripledes';
/**
* Optimizing value while CFB-encrypting
*
* @see Crypt_Base::cfb_init_len
* @var Integer
* @access private
*/
var $cfb_init_len = 750;
/**
* max possible size of $key
*
* @see Crypt_TripleDES::setKey()
* @see Crypt_DES::setKey()
* @var String
* @access private
*/
var $key_size_max = 24;
/**
* Internal flag whether using CRYPT_DES_MODE_3CBC or not
*
* @var Boolean
* @access private
*/
var $mode_3cbc;
/**
* The Crypt_DES objects
*
* Used only if $mode_3cbc === true
*
* @var Array
* @access private
*/
@ -95,99 +165,47 @@ class Crypt_TripleDES extends Crypt_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.
* Determines whether or not the mcrypt extension should be used.
*
* $mode could be:
* - CRYPT_DES_MODE_ECB
* - CRYPT_DES_MODE_CBC
* - CRYPT_DES_MODE_CTR
* - CRYPT_DES_MODE_CFB
* - CRYPT_DES_MODE_OFB
* - CRYPT_DES_MODE_3CBC
*
* If not explictly set, CRYPT_DES_MODE_CBC will be used.
*
* @see Crypt_DES::Crypt_DES()
* @see Crypt_Base::Crypt_Base()
* @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);
}
}
switch ($mode) {
// In case of CRYPT_DES_MODE_3CBC, we init as CRYPT_DES_MODE_CBC
// and additional flag us internally as 3CBC
case CRYPT_DES_MODE_3CBC:
parent::Crypt_DES(CRYPT_DES_MODE_CBC);
$this->mode_3cbc = true;
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 three $des'es will do the 3CBC work (if $key > 64bits)
$this->des = array(
new Crypt_DES(CRYPT_DES_MODE_ECB),
new Crypt_DES(CRYPT_DES_MODE_ECB),
new Crypt_DES(CRYPT_DES_MODE_ECB)
new Crypt_DES(CRYPT_DES_MODE_CBC),
new Crypt_DES(CRYPT_DES_MODE_CBC),
new Crypt_DES(CRYPT_DES_MODE_CBC),
);
// 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;
}
break;
// If not 3CBC, we init as usual
default:
parent::Crypt_DES($mode);
}
}
@ -199,99 +217,70 @@ class Crypt_TripleDES extends Crypt_DES {
*
* 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.
* If the key is not explicitly set, it'll be assumed to be all null bytes.
*
* @access public
* @see Crypt_DES::setKey()
* @see Crypt_Base::setKey()
* @param String $key
*/
function setKey($key)
{
$length = strlen($key);
if ($length > 8) {
$key = str_pad($key, 24, chr(0));
$key = str_pad(substr($key, 0, 24), 24, chr(0));
// if $key is between 64 and 128-bits, use the first 64-bits as the last, per this:
// http://php.net/function.mcrypt-encrypt#47973
//$key = $length <= 16 ? substr_replace($key, substr($key, 0, 8), 16) : substr($key, 0, 24);
} else {
$key = str_pad($key, 8, chr(0));
}
$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));
parent::setKey($key);
// 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]
),
);
}
// And in case of CRYPT_DES_MODE_3CBC:
// if key <= 64bits we not need the 3 $des to work,
// because we will then act as regular DES-CBC with just a <= 64bit key.
// So only if the key > 64bits (> 8 bytes) we will call setKey() for the 3 $des.
if ($this->mode_3cbc && $length > 8) {
$this->des[0]->setKey(substr($key, 0, 8));
$this->des[1]->setKey(substr($key, 8, 8));
$this->des[2]->setKey(substr($key, 16, 8));
}
$this->enchanged = $this->dechanged = true;
}
/**
* Sets the password.
* Creates the key schedule
*
* 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
* @see Crypt_DES::_setupKey()
* @see Crypt_Base::_setupKey()
* @access private
*/
function setPassword($password, $method = 'pbkdf2')
function _setupKey()
{
$key = '';
switch (true) {
// if $key <= 64bits we configure our internal pure-php cipher engine
// to act as regular [1]DES, not as 3DES. mcrypt.so::tripledes does the same.
case strlen($this->key) <= 8:
$this->des_rounds = 1;
break;
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;
}
// otherwise, if $key > 64bits, we configure our engine to work as 3DES.
default:
$this->des_rounds = 3;
if (!class_exists('Crypt_Hash')) {
require_once('Crypt/Hash.php');
}
// (only) if 3CBC is used we have, of course, to setup the $des[0-2] keys also separately.
if ($this->mode_3cbc) {
$this->des[0]->_setupKey();
$this->des[1]->_setupKey();
$this->des[2]->_setupKey();
$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;
// because $des[0-2] will, now, do all the work we can return here
// not need unnecessary stress parent::_setupKey() with our, now unused, $key.
return;
}
}
$this->setKey($key);
// setup our key
parent::_setupKey();
}
/**
@ -300,470 +289,60 @@ class Crypt_TripleDES extends Crypt_DES {
* 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.
*
* @see Crypt_Base::setIV()
* @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) {
parent::setIV($iv);
if ($this->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.
*
* @see Crypt_Base::encrypt()
* @access public
* @param String $plaintext
* @return String $cipertext
*/
function encrypt($plaintext)
{
if ($this->paddable) {
$plaintext = $this->_pad($plaintext);
}
// parent::en/decrypt() is able to do all the work for all modes and keylengths,
// except for: CRYPT_DES_MODE_3CBC (inner chaining CBC) with a key > 64bits
// 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 ($this->mode_3cbc && strlen($this->key) > 8) {
return $this->des[2]->encrypt(
$this->des[1]->decrypt(
$this->des[0]->encrypt($this->_pad($plaintext))));
}
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;
return parent::encrypt($plaintext);
}
/**
* Decrypts a message.
*
* @see Crypt_Base::decrypt()
* @access public
* @param String $ciphertext
* @return String $plaintext
*/
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->mode_3cbc && strlen($this->key) > 8) {
return $this->_unpad($this->des[0]->decrypt(
$this->des[1]->encrypt(
$this->des[2]->decrypt(str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, "\0")))));
}
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;
return parent::decrypt($ciphertext);
}
/**
@ -800,13 +379,14 @@ class Crypt_TripleDES extends Crypt_DES {
* 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_Base::enableContinuousBuffer()
* @see Crypt_TripleDES::disableContinuousBuffer()
* @access public
*/
function enableContinuousBuffer()
{
$this->continuousBuffer = true;
if ($this->mode == CRYPT_DES_MODE_3CBC) {
parent::enableContinuousBuffer();
if ($this->mode_3cbc) {
$this->des[0]->enableContinuousBuffer();
$this->des[1]->enableContinuousBuffer();
$this->des[2]->enableContinuousBuffer();
@ -818,20 +398,14 @@ class Crypt_TripleDES extends Crypt_DES {
*
* The default behavior.
*
* @see Crypt_Base::disableContinuousBuffer()
* @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) {
parent::disableContinuousBuffer();
if ($this->mode_3cbc) {
$this->des[0]->disableContinuousBuffer();
$this->des[1]->disableContinuousBuffer();
$this->des[2]->disableContinuousBuffer();

File diff suppressed because it is too large Load Diff