mirror of
https://github.com/phpseclib/phpseclib.git
synced 2025-02-03 12:28:30 +00:00
Crypt: add OpenSSL support
aside from the addition of OpenSSL support a few other changes have been included: - setEngine(), as added by petrich, is depricated (not that it was ever in trunk to begin with) it has been replaced with isValidEngine() and setPreferredEngine(). - replace _generate_xor() with increment_str() _increment_str() had extra functionality that wasn't being used. ie. it could concatenate multiple successive string increments to one another automatically. but not only was that functionality not used - it also made the function less versatile. _increment_str() can be used more easily for iterative brute forcing (for example) - rename Crypt_Base::_stringShift to Crypt_Base::_string_shift (for consistency) - more expansive unit test coverage
This commit is contained in:
parent
e7708b0d20
commit
f6e0c4b506
@ -206,7 +206,7 @@ class Crypt_AES extends Crypt_Rijndael
|
||||
default:
|
||||
$this->key_size = 32;
|
||||
}
|
||||
$this->_setupEngine();
|
||||
$this->_setEngine();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -110,6 +110,10 @@ define('CRYPT_MODE_INTERNAL', 1);
|
||||
* Base value for the mcrypt implementation $engine switch
|
||||
*/
|
||||
define('CRYPT_MODE_MCRYPT', 2);
|
||||
/**
|
||||
* Base value for the OpenSSL implementation $engine switch
|
||||
*/
|
||||
define('CRYPT_MODE_OPENSSL', 3);
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
@ -118,7 +122,7 @@ define('CRYPT_MODE_MCRYPT', 2);
|
||||
* @package Crypt_Base
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @author Hans-Juergen Petrich <petrich@tronic-media.com>
|
||||
* @version 1.0.1
|
||||
* @version 1.0.2
|
||||
* @access public
|
||||
*/
|
||||
class Crypt_Base
|
||||
@ -326,15 +330,11 @@ class Crypt_Base
|
||||
* which will be determined automatically on __construct()
|
||||
*
|
||||
* Currently available $engines are:
|
||||
* - CRYPT_MODE_OPENSSL (very fast, php-extension: openssl, extension_loaded('openssl') required)
|
||||
* - CRYPT_MODE_MCRYPT (fast, php-extension: mcrypt, extension_loaded('mcrypt') required)
|
||||
* - CRYPT_MODE_INTERNAL (slower, pure php-engine, no php-extension required)
|
||||
*
|
||||
* In the pipeline... maybe. But currently not available:
|
||||
* - CRYPT_MODE_OPENSSL (very fast, php-extension: openssl, extension_loaded('openssl') required)
|
||||
*
|
||||
* If possible, CRYPT_MODE_MCRYPT will be used for each cipher.
|
||||
* Otherwise CRYPT_MODE_INTERNAL
|
||||
*
|
||||
* @see Crypt_Base::_setEngine()
|
||||
* @see Crypt_Base::encrypt()
|
||||
* @see Crypt_Base::decrypt()
|
||||
* @var Integer
|
||||
@ -342,6 +342,16 @@ class Crypt_Base
|
||||
*/
|
||||
var $engine;
|
||||
|
||||
/**
|
||||
* Holds the preferred crypt engine
|
||||
*
|
||||
* @see Crypt_Base::_setEngine()
|
||||
* @see Crypt_Base::setPreferredEngine()
|
||||
* @var Integer
|
||||
* @access private
|
||||
*/
|
||||
var $preferredEngine;
|
||||
|
||||
/**
|
||||
* The mcrypt specific name of the cipher
|
||||
*
|
||||
@ -355,6 +365,29 @@ class Crypt_Base
|
||||
*/
|
||||
var $cipher_name_mcrypt;
|
||||
|
||||
/**
|
||||
* The openssl specific name of the cipher
|
||||
*
|
||||
* Only used if $engine == CRYPT_MODE_OPENSSL
|
||||
*
|
||||
* @link http://www.php.net/openssl-get-cipher-methods
|
||||
* @var String
|
||||
* @access private
|
||||
*/
|
||||
var $cipher_name_openssl;
|
||||
|
||||
/**
|
||||
* The openssl specific name of the cipher in ECB mode
|
||||
*
|
||||
* If OpenSSL does not support the mode we're trying to use (CTR)
|
||||
* it can still be emulated with ECB mode.
|
||||
*
|
||||
* @link http://www.php.net/openssl-get-cipher-methods
|
||||
* @var String
|
||||
* @access private
|
||||
*/
|
||||
var $cipher_name_openssl_ecb;
|
||||
|
||||
/**
|
||||
* The default password key_size used by setPassword()
|
||||
*
|
||||
@ -422,6 +455,15 @@ class Crypt_Base
|
||||
*/
|
||||
var $use_inline_crypt;
|
||||
|
||||
/**
|
||||
* If OpenSSL can be used in ECB but not in CTR we can emulate CTR
|
||||
*
|
||||
* @see Crypt_Base::_openssl_ctr_process()
|
||||
* @var Boolean
|
||||
* @access private
|
||||
*/
|
||||
var $openssl_emulate_ctr = false;
|
||||
|
||||
/**
|
||||
* Default Constructor.
|
||||
*
|
||||
@ -448,20 +490,11 @@ class Crypt_Base
|
||||
*/
|
||||
function Crypt_Base($mode = CRYPT_MODE_CBC)
|
||||
{
|
||||
$const_crypt_mode = 'CRYPT_' . $this->const_namespace . '_MODE';
|
||||
|
||||
// Setup the internal crypt engine
|
||||
if (defined($const_crypt_mode)) {
|
||||
$this->engine = constant($const_crypt_mode);
|
||||
} else {
|
||||
define($const_crypt_mode, $this->setEngine());
|
||||
}
|
||||
|
||||
// $mode dependent settings
|
||||
switch ($mode) {
|
||||
case CRYPT_MODE_ECB:
|
||||
$this->paddable = true;
|
||||
$this->mode = $mode;
|
||||
$this->mode = CRYPT_MODE_ECB;
|
||||
break;
|
||||
case CRYPT_MODE_CTR:
|
||||
case CRYPT_MODE_CFB:
|
||||
@ -475,6 +508,8 @@ class Crypt_Base
|
||||
$this->mode = CRYPT_MODE_CBC;
|
||||
}
|
||||
|
||||
$this->_setEngine();
|
||||
|
||||
// Determining whether inline crypting can be used by the cipher
|
||||
if ($this->use_inline_crypt !== false && function_exists('create_function')) {
|
||||
$this->use_inline_crypt = true;
|
||||
@ -519,6 +554,7 @@ class Crypt_Base
|
||||
{
|
||||
$this->key = $key;
|
||||
$this->changed = true;
|
||||
$this->_setEngine();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -631,12 +667,85 @@ class Crypt_Base
|
||||
* @see Crypt_Base::decrypt()
|
||||
* @access public
|
||||
* @param String $plaintext
|
||||
* @return String $cipertext
|
||||
* @return String $ciphertext
|
||||
* @internal Could, but not must, extend by the child Crypt_* class
|
||||
*/
|
||||
function encrypt($plaintext)
|
||||
{
|
||||
if ($this->engine == CRYPT_MODE_MCRYPT) {
|
||||
if ($this->paddable) {
|
||||
$plaintext = $this->_pad($plaintext);
|
||||
}
|
||||
|
||||
if ($this->engine === CRYPT_MODE_OPENSSL) {
|
||||
if ($this->changed) {
|
||||
$this->_clearBuffers();
|
||||
$this->changed = false;
|
||||
}
|
||||
switch ($this->mode) {
|
||||
case CRYPT_MODE_STREAM:
|
||||
case CRYPT_MODE_ECB:
|
||||
return openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
|
||||
case CRYPT_MODE_CBC:
|
||||
$ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->encryptIV);
|
||||
if ($this->continuousBuffer) {
|
||||
$this->encryptIV = substr($ciphertext, -$this->block_size);
|
||||
}
|
||||
return $ciphertext;
|
||||
case CRYPT_MODE_CTR:
|
||||
return $this->_openssl_ctr_process($plaintext, $this->encryptIV, $this->enbuffer);
|
||||
case CRYPT_MODE_CFB:
|
||||
// cfb loosely routines inspired by openssl's:
|
||||
// {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
|
||||
if ($this->continuousBuffer) {
|
||||
$iv = &$this->encryptIV;
|
||||
$pos = &$this->enbuffer['pos'];
|
||||
} else {
|
||||
$iv = &$this->encryptIV;
|
||||
$pos = 0;
|
||||
}
|
||||
$len = strlen($plaintext);
|
||||
$i = 0;
|
||||
if ($pos) {
|
||||
$orig_pos = $pos;
|
||||
$max = $this->block_size - $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
|
||||
$ciphertext = substr($iv, $orig_pos) ^ $plaintext;
|
||||
$iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
|
||||
$plaintext = substr($plaintext, $i);
|
||||
}
|
||||
|
||||
$overflow = $len % $this->block_size;
|
||||
|
||||
if ($overflow) {
|
||||
$ciphertext.= openssl_encrypt(substr($plaintext, 0, -$overflow) . str_repeat("\0", $this->block_size), $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
|
||||
$iv = $this->_string_pop($ciphertext, $this->block_size);
|
||||
|
||||
$size = $len - $overflow;
|
||||
$block = $iv ^ substr($plaintext, -$overflow);
|
||||
$iv = substr_replace($iv, $block, 0, $overflow);
|
||||
$ciphertext.= $block;
|
||||
$pos = $overflow;
|
||||
} else if ($len) {
|
||||
$ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
|
||||
$iv = substr($ciphertext, -$this->block_size);
|
||||
}
|
||||
|
||||
return $ciphertext;
|
||||
case CRYPT_MODE_OFB:
|
||||
return $this->_openssl_ofb_process($plaintext, $this->encryptIV, $this->enbuffer);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->engine === CRYPT_MODE_MCRYPT) {
|
||||
if ($this->changed) {
|
||||
$this->_setupMcrypt();
|
||||
$this->changed = false;
|
||||
@ -702,10 +811,6 @@ class Crypt_Base
|
||||
return $ciphertext;
|
||||
}
|
||||
|
||||
if ($this->paddable) {
|
||||
$plaintext = $this->_pad($plaintext);
|
||||
}
|
||||
|
||||
$ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
|
||||
|
||||
if (!$this->continuousBuffer) {
|
||||
@ -723,9 +828,6 @@ class Crypt_Base
|
||||
$inline = $this->inline_crypt;
|
||||
return $inline('encrypt', $this, $plaintext);
|
||||
}
|
||||
if ($this->paddable) {
|
||||
$plaintext = $this->_pad($plaintext);
|
||||
}
|
||||
|
||||
$buffer = &$this->enbuffer;
|
||||
$block_size = $this->block_size;
|
||||
@ -754,15 +856,17 @@ class Crypt_Base
|
||||
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
|
||||
$block = substr($plaintext, $i, $block_size);
|
||||
if (strlen($block) > strlen($buffer['encrypted'])) {
|
||||
$buffer['encrypted'].= $this->_encryptBlock($this->_generateXor($xor, $block_size));
|
||||
$buffer['encrypted'].= $this->_encryptBlock($xor);
|
||||
}
|
||||
$key = $this->_stringShift($buffer['encrypted'], $block_size);
|
||||
$this->_increment_str($xor);
|
||||
$key = $this->_string_shift($buffer['encrypted'], $block_size);
|
||||
$ciphertext.= $block ^ $key;
|
||||
}
|
||||
} else {
|
||||
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
|
||||
$block = substr($plaintext, $i, $block_size);
|
||||
$key = $this->_encryptBlock($this->_generateXor($xor, $block_size));
|
||||
$key = $this->_encryptBlock($xor);
|
||||
$this->_increment_str($xor);
|
||||
$ciphertext.= $block ^ $key;
|
||||
}
|
||||
}
|
||||
@ -824,7 +928,7 @@ class Crypt_Base
|
||||
$xor = $this->_encryptBlock($xor);
|
||||
$buffer['xor'].= $xor;
|
||||
}
|
||||
$key = $this->_stringShift($buffer['xor'], $block_size);
|
||||
$key = $this->_string_shift($buffer['xor'], $block_size);
|
||||
$ciphertext.= $block ^ $key;
|
||||
}
|
||||
} else {
|
||||
@ -863,7 +967,82 @@ class Crypt_Base
|
||||
*/
|
||||
function decrypt($ciphertext)
|
||||
{
|
||||
if ($this->engine == CRYPT_MODE_MCRYPT) {
|
||||
if ($this->paddable) {
|
||||
// we pad with chr(0) since that's what mcrypt_generic does [...]
|
||||
$ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($this->block_size - strlen($ciphertext) % $this->block_size) % $this->block_size, chr(0));
|
||||
}
|
||||
|
||||
if ($this->engine === CRYPT_MODE_OPENSSL) {
|
||||
if ($this->changed) {
|
||||
$this->_clearBuffers();
|
||||
$this->changed = false;
|
||||
}
|
||||
switch ($this->mode) {
|
||||
case CRYPT_MODE_STREAM:
|
||||
case CRYPT_MODE_ECB:
|
||||
$plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
|
||||
break;
|
||||
case CRYPT_MODE_CBC:
|
||||
$plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->decryptIV);
|
||||
if ($this->continuousBuffer) {
|
||||
$this->decryptIV = substr($ciphertext, -$this->block_size);
|
||||
}
|
||||
break;
|
||||
case CRYPT_MODE_CTR:
|
||||
$plaintext = $this->_openssl_ctr_process($ciphertext, $this->decryptIV, $this->debuffer);
|
||||
break;
|
||||
case CRYPT_MODE_CFB:
|
||||
// cfb loosely routines inspired by openssl's:
|
||||
// {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
|
||||
if ($this->continuousBuffer) {
|
||||
$iv = &$this->decryptIV;
|
||||
$pos = &$this->buffer['pos'];
|
||||
} else {
|
||||
$iv = $this->decryptIV;
|
||||
$pos = 0;
|
||||
}
|
||||
$len = strlen($ciphertext);
|
||||
$i = 0;
|
||||
if ($pos) {
|
||||
$orig_pos = $pos;
|
||||
$max = $this->block_size - $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%= $this->blocksize
|
||||
$plaintext = substr($iv, $orig_pos) ^ $ciphertext;
|
||||
$iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
|
||||
$ciphertext = substr($ciphertext, $i);
|
||||
}
|
||||
$overflow = $len % $this->block_size;
|
||||
if ($overflow) {
|
||||
$plaintext.= openssl_decrypt(substr($ciphertext, 0, -$overflow), $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
|
||||
if ($len - $overflow) {
|
||||
$iv = substr($ciphertext, -$overflow - $this->block_size, -$overflow);
|
||||
}
|
||||
$iv = openssl_encrypt(str_repeat("\0", $this->block_size), $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
|
||||
$plaintext.= $iv ^ substr($ciphertext, -$overflow);
|
||||
$iv = substr_replace($iv, substr($ciphertext, -$overflow), 0, $overflow);
|
||||
$pos = $overflow;
|
||||
} else if ($len) {
|
||||
$plaintext.= openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
|
||||
$iv = substr($ciphertext, -$this->block_size);
|
||||
}
|
||||
break;
|
||||
case CRYPT_MODE_OFB:
|
||||
$plaintext = $this->_openssl_ofb_process($ciphertext, $this->decryptIV, $this->debuffer);
|
||||
}
|
||||
|
||||
return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
|
||||
}
|
||||
|
||||
if ($this->engine === CRYPT_MODE_MCRYPT) {
|
||||
$block_size = $this->block_size;
|
||||
if ($this->changed) {
|
||||
$this->_setupMcrypt();
|
||||
@ -937,10 +1116,6 @@ class Crypt_Base
|
||||
}
|
||||
|
||||
$block_size = $this->block_size;
|
||||
if ($this->paddable) {
|
||||
// we pad with chr(0) since that's what mcrypt_generic does [...]
|
||||
$ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($block_size - strlen($ciphertext) % $block_size) % $block_size, chr(0));
|
||||
}
|
||||
|
||||
$buffer = &$this->debuffer;
|
||||
$plaintext = '';
|
||||
@ -967,15 +1142,17 @@ class Crypt_Base
|
||||
for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
|
||||
$block = substr($ciphertext, $i, $block_size);
|
||||
if (strlen($block) > strlen($buffer['ciphertext'])) {
|
||||
$buffer['ciphertext'].= $this->_encryptBlock($this->_generateXor($xor, $block_size));
|
||||
$buffer['ciphertext'].= $this->_encryptBlock($xor);
|
||||
$this->_increment_str($xor);
|
||||
}
|
||||
$key = $this->_stringShift($buffer['ciphertext'], $block_size);
|
||||
$key = $this->_string_shift($buffer['ciphertext'], $block_size);
|
||||
$plaintext.= $block ^ $key;
|
||||
}
|
||||
} else {
|
||||
for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
|
||||
$block = substr($ciphertext, $i, $block_size);
|
||||
$key = $this->_encryptBlock($this->_generateXor($xor, $block_size));
|
||||
$key = $this->_encryptBlock($xor);
|
||||
$this->_increment_str($xor);
|
||||
$plaintext.= $block ^ $key;
|
||||
}
|
||||
}
|
||||
@ -1036,7 +1213,7 @@ class Crypt_Base
|
||||
$xor = $this->_encryptBlock($xor);
|
||||
$buffer['xor'].= $xor;
|
||||
}
|
||||
$key = $this->_stringShift($buffer['xor'], $block_size);
|
||||
$key = $this->_string_shift($buffer['xor'], $block_size);
|
||||
$plaintext.= $block ^ $key;
|
||||
}
|
||||
} else {
|
||||
@ -1060,6 +1237,164 @@ class Crypt_Base
|
||||
return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
|
||||
}
|
||||
|
||||
/**
|
||||
* OpenSSL CTR Processor
|
||||
*
|
||||
* PHP's OpenSSL bindings do not operate in continuous mode so we'll wrap around it. Since the keystream
|
||||
* for CTR is the same for both encrypting and decrypting this function is re-used by both Crypt_Base::encrypt()
|
||||
* and Crypt_Base::decrypt(). Also, OpenSSL doesn't implement CTR for all of it's symmetric ciphers so this
|
||||
* function will emulate CTR with ECB when necesary.
|
||||
*
|
||||
* @see Crypt_Base::encrypt()
|
||||
* @see Crypt_Base::decrypt()
|
||||
* @param String $plaintext
|
||||
* @param String $encryptIV
|
||||
* @param Array $buffer
|
||||
* @return String
|
||||
* @access private
|
||||
*/
|
||||
function _openssl_ctr_process($plaintext, &$encryptIV, &$buffer)
|
||||
{
|
||||
$ciphertext = '';
|
||||
|
||||
$block_size = $this->block_size;
|
||||
$key = $this->key;
|
||||
|
||||
if ($this->openssl_emulate_ctr) {
|
||||
$xor = $encryptIV;
|
||||
if (strlen($buffer['encrypted'])) {
|
||||
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
|
||||
$block = substr($plaintext, $i, $block_size);
|
||||
if (strlen($block) > strlen($buffer['encrypted'])) {
|
||||
$buffer['encrypted'].= openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
|
||||
}
|
||||
$this->_increment_str($xor);
|
||||
$otp = $this->_string_shift($buffer['encrypted'], $block_size);
|
||||
$ciphertext.= $block ^ $otp;
|
||||
}
|
||||
} else {
|
||||
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
|
||||
$block = substr($plaintext, $i, $block_size);
|
||||
$otp = openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
|
||||
$this->_increment_str($xor);
|
||||
$ciphertext.= $block ^ $otp;
|
||||
}
|
||||
}
|
||||
if ($this->continuousBuffer) {
|
||||
$encryptIV = $xor;
|
||||
if ($start = strlen($plaintext) % $block_size) {
|
||||
$buffer['encrypted'] = substr($key, $start) . $buffer['encrypted'];
|
||||
}
|
||||
}
|
||||
|
||||
return $ciphertext;
|
||||
}
|
||||
|
||||
if (strlen($buffer['encrypted'])) {
|
||||
$ciphertext = $plaintext ^ $this->_string_shift($buffer['encrypted'], strlen($plaintext));
|
||||
$plaintext = substr($plaintext, strlen($ciphertext));
|
||||
|
||||
if (!strlen($plaintext)) {
|
||||
return $ciphertext;
|
||||
}
|
||||
}
|
||||
|
||||
$overflow = strlen($plaintext) % $block_size;
|
||||
if ($overflow) {
|
||||
$plaintext2 = $this->_string_pop($plaintext, $overflow); // ie. trim $plaintext to a multiple of $block_size and put rest of $plaintext in $plaintext2
|
||||
$encrypted = openssl_encrypt($plaintext . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $encryptIV);
|
||||
$encryptIV = $this->_string_pop($encrypted, $block_size);
|
||||
$ciphertext.= $encrypted . ($plaintext2 ^ $encryptIV);
|
||||
$buffer['encrypted'] = substr($encryptIV, $overflow);
|
||||
} else if (!strlen($buffer['encrypted'])) {
|
||||
$ciphertext.= openssl_encrypt($plaintext . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $encryptIV);
|
||||
$encryptIV = $this->_string_pop($ciphertext, $block_size);
|
||||
}
|
||||
$encryptIV = openssl_decrypt($encryptIV, $this->cipher_name_openssl_ecb, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
|
||||
if ($overflow) {
|
||||
$this->_increment_str($encryptIV);
|
||||
}
|
||||
|
||||
return $ciphertext;
|
||||
}
|
||||
|
||||
/**
|
||||
* OpenSSL OFB Processor
|
||||
*
|
||||
* PHP's OpenSSL bindings do not operate in continuous mode so we'll wrap around it. Since the keystream
|
||||
* for OFB is the same for both encrypting and decrypting this function is re-used by both Crypt_Base::encrypt()
|
||||
* and Crypt_Base::decrypt().
|
||||
*
|
||||
* @see Crypt_Base::encrypt()
|
||||
* @see Crypt_Base::decrypt()
|
||||
* @param String $plaintext
|
||||
* @param String $encryptIV
|
||||
* @param Array $buffer
|
||||
* @return String
|
||||
* @access private
|
||||
*/
|
||||
function _openssl_ofb_process($plaintext, &$encryptIV, &$buffer)
|
||||
{
|
||||
if (strlen($buffer['xor'])) {
|
||||
$ciphertext = $plaintext ^ $buffer['xor'];
|
||||
$buffer['xor'] = substr($buffer['xor'], strlen($ciphertext));
|
||||
$plaintext = substr($plaintext, strlen($ciphertext));
|
||||
} else {
|
||||
$ciphertext = '';
|
||||
}
|
||||
|
||||
$block_size = $this->block_size;
|
||||
|
||||
$len = strlen($plaintext);
|
||||
$key = $this->key;
|
||||
$overflow = $len % $block_size;
|
||||
|
||||
if (strlen($plaintext)) {
|
||||
if ($overflow) {
|
||||
$ciphertext.= openssl_encrypt(substr($plaintext, 0, -$overflow) . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $encryptIV);
|
||||
$xor = $this->_string_pop($ciphertext, $block_size);
|
||||
if ($this->continuousBuffer) {
|
||||
$encryptIV = $xor;
|
||||
}
|
||||
$ciphertext.= $this->_string_shift($xor, $overflow) ^ substr($plaintext, -$overflow);
|
||||
if ($this->continuousBuffer) {
|
||||
$buffer['xor'] = $xor;
|
||||
}
|
||||
} else {
|
||||
$ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $encryptIV);
|
||||
if ($this->continuousBuffer) {
|
||||
$encryptIV = substr($ciphertext, -$block_size) ^ substr($plaintext, -$block_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $ciphertext;
|
||||
}
|
||||
|
||||
/**
|
||||
* phpseclib <-> OpenSSL Mode Mapper
|
||||
*
|
||||
* May need to be overwritten by classes extending this one in some cases
|
||||
*
|
||||
* @return Integer
|
||||
* @access private
|
||||
*/
|
||||
function _openssl_translate_mode()
|
||||
{
|
||||
switch ($this->mode) {
|
||||
case CRYPT_MODE_ECB:
|
||||
return 'ecb';
|
||||
case CRYPT_MODE_CBC:
|
||||
return 'cbc';
|
||||
case CRYPT_MODE_CTR:
|
||||
return 'ctr';
|
||||
case CRYPT_MODE_CFB:
|
||||
return 'cfb';
|
||||
case CRYPT_MODE_OFB:
|
||||
return 'ofb';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pad "packets".
|
||||
*
|
||||
@ -1161,53 +1496,113 @@ class Crypt_Base
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the internal crypt engine
|
||||
* Test for engine validity
|
||||
*
|
||||
* Will be called automatically on "__construct()", so normally it's not
|
||||
* necessary to call setEngine() manually, but ie for debuging or testing.
|
||||
* @see Crypt_Base::Crypt_Base()
|
||||
* @param Integer $engine
|
||||
* @access public
|
||||
* @return Boolean
|
||||
*/
|
||||
function isValidEngine($engine)
|
||||
{
|
||||
switch ($engine) {
|
||||
case CRYPT_MODE_OPENSSL:
|
||||
$this->openssl_emulate_ctr = false;
|
||||
$result = $this->cipher_name_openssl &&
|
||||
extension_loaded('openssl') &&
|
||||
version_compare(PHP_VERSION, '5.3.0');
|
||||
if (!$result) {
|
||||
return false;
|
||||
}
|
||||
$methods = openssl_get_cipher_methods();
|
||||
if (in_array($this->cipher_name_openssl, $methods)) {
|
||||
return true;
|
||||
}
|
||||
// not all of openssl's symmetric cipher's support ctr. for those
|
||||
// that don't we'll emulate it
|
||||
switch ($this->mode) {
|
||||
case CRYPT_MODE_CTR:
|
||||
if (in_array($this->cipher_name_openssl_ecb, $methods)) {
|
||||
$this->openssl_emulate_ctr = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
case CRYPT_MODE_MCRYPT:
|
||||
return $this->cipher_name_mcrypt &&
|
||||
extension_loaded('mcrypt') &&
|
||||
in_array($this->cipher_name_mcrypt, mcrypt_list_algorithms());
|
||||
case CRYPT_MODE_INTERNAL:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the preferred crypt engine
|
||||
*
|
||||
* Currently, $engine could be:
|
||||
*
|
||||
* - CRYPT_MODE_OPENSSL [very fast]
|
||||
*
|
||||
* - CRYPT_MODE_MCRYPT [fast]
|
||||
*
|
||||
* - CRYPT_MODE_INTERNAL [slow]
|
||||
*
|
||||
* Respectivly the officially alias constants of the choosen cipher,
|
||||
* ie for AES: CRYPT_AES_MODE_MCRYPT or CRYPT_AES_MODE_INTERNAL
|
||||
*
|
||||
* If $engine is not explictly set, the fastest available $engine
|
||||
* will be set (currently: CRYPT_MODE_MCRYPT)
|
||||
*
|
||||
* If $engine == CRYPT_MODE_MCRYPT but the mcrypt extension is not loaded/available it
|
||||
* will be set the next available fastest $engine (currently: CRYPT_MODE_INTERNAL)
|
||||
*
|
||||
* If called, all internal buffers and cipher states will be reset, so,
|
||||
* for example, switching the $engine while enableContinuousBuffer() will
|
||||
* reset the ContinuousBuffer's.
|
||||
*
|
||||
* setEngine() returns always the $engine which was effectively set.
|
||||
* If the preferred crypt engine is not available the fastest available one will be used
|
||||
*
|
||||
* @see Crypt_Base::Crypt_Base()
|
||||
* @param optional Integer $engine
|
||||
* @param Integer $engine
|
||||
* @access public
|
||||
* @return Integer
|
||||
* @internal Could, but not must, extend by the child Crypt_* class
|
||||
*/
|
||||
function setEngine($engine = CRYPT_MODE_MCRYPT)
|
||||
function setPreferredEngine($engine)
|
||||
{
|
||||
switch ($engine) {
|
||||
//case CRYPT_MODE_OPENSSL:
|
||||
case CRYPT_MODE_MCRYPT:
|
||||
case CRYPT_MODE_INTERNAL:
|
||||
$this->engine = CRYPT_MODE_INTERNAL;
|
||||
$this->preferredEngine = $engine;
|
||||
break;
|
||||
default:
|
||||
if ($this->cipher_name_mcrypt && extension_loaded('mcrypt') && in_array($this->cipher_name_mcrypt, mcrypt_list_algorithms())) {
|
||||
$this->engine = CRYPT_MODE_MCRYPT;
|
||||
} else {
|
||||
$this->engine = CRYPT_MODE_INTERNAL;
|
||||
}
|
||||
$this->preferredEngine = CRYPT_MODE_OPENSSL;
|
||||
}
|
||||
|
||||
if ($this->enmcrypt) {
|
||||
$this->_setEngine();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the engine currently being utilized
|
||||
*
|
||||
* @see Crypt_Base::_setEngine()
|
||||
* @access public
|
||||
*/
|
||||
function getEngine()
|
||||
{
|
||||
return $this->engine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the engine as appropriate
|
||||
*
|
||||
* @see Crypt_Base::Crypt_Base()
|
||||
* @access private
|
||||
*/
|
||||
function _setEngine()
|
||||
{
|
||||
switch (true) {
|
||||
case $this->isValidEngine($this->preferredEngine):
|
||||
$this->engine = $this->preferredEngine;
|
||||
break;
|
||||
case $this->isValidEngine(CRYPT_MODE_OPENSSL):
|
||||
$this->engine = CRYPT_MODE_OPENSSL;
|
||||
break;
|
||||
case $this->isValidEngine(CRYPT_MODE_MCRYPT):
|
||||
$this->engine = CRYPT_MODE_MCRYPT;
|
||||
break;
|
||||
default:
|
||||
$this->engine = CRYPT_MODE_INTERNAL;
|
||||
}
|
||||
|
||||
if ($this->engine != CRYPT_MODE_MCRYPT && $this->enmcrypt) {
|
||||
// Closing the current mcrypt resource(s). _mcryptSetup() will, if needed,
|
||||
// (re)open them with the module named in $this->cipher_name_mcrypt
|
||||
mcrypt_module_close($this->enmcrypt);
|
||||
@ -1222,7 +1617,6 @@ class Crypt_Base
|
||||
}
|
||||
|
||||
$this->changed = true;
|
||||
return $this->engine;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1443,7 +1837,7 @@ class Crypt_Base
|
||||
* @access private
|
||||
* @return String
|
||||
*/
|
||||
function _stringShift(&$string, $index = 1)
|
||||
function _string_shift(&$string, $index = 1)
|
||||
{
|
||||
$substr = substr($string, 0, $index);
|
||||
$string = substr($string, $index);
|
||||
@ -1451,43 +1845,57 @@ class Crypt_Base
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate CTR XOR encryption key
|
||||
* String Pop
|
||||
*
|
||||
* Encrypt the output of this and XOR it against the ciphertext / plaintext to get the
|
||||
* plaintext / ciphertext in CTR mode.
|
||||
* Inspired by array_pop
|
||||
*
|
||||
* @param String $string
|
||||
* @param optional Integer $index
|
||||
* @access private
|
||||
* @return String
|
||||
*/
|
||||
function _string_pop(&$string, $index = 1)
|
||||
{
|
||||
$substr = substr($string, -$index);
|
||||
$string = substr($string, 0, -$index);
|
||||
return $substr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment the current string
|
||||
*
|
||||
* @see Crypt_Base::decrypt()
|
||||
* @see Crypt_Base::encrypt()
|
||||
* @param String $iv
|
||||
* @param Integer $length
|
||||
* @param String $var
|
||||
* @access private
|
||||
* @return String $xor
|
||||
*/
|
||||
function _generateXor(&$iv, $length)
|
||||
function _increment_str(&$var)
|
||||
{
|
||||
$xor = '';
|
||||
$block_size = $this->block_size;
|
||||
$num_blocks = floor(($length + ($block_size - 1)) / $block_size);
|
||||
for ($i = 0; $i < $num_blocks; $i++) {
|
||||
$xor.= $iv;
|
||||
for ($j = 4; $j <= $block_size; $j+= 4) {
|
||||
$temp = substr($iv, -$j, 4);
|
||||
switch ($temp) {
|
||||
case "\xFF\xFF\xFF\xFF":
|
||||
$iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4);
|
||||
break;
|
||||
case "\x7F\xFF\xFF\xFF":
|
||||
$iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4);
|
||||
break 2;
|
||||
default:
|
||||
extract(unpack('Ncount', $temp));
|
||||
$iv = substr_replace($iv, pack('N', $count + 1), -$j, 4);
|
||||
break 2;
|
||||
}
|
||||
for ($i = 4; $i <= strlen($var); $i+= 4) {
|
||||
$temp = substr($var, -$i, 4);
|
||||
switch ($temp) {
|
||||
case "\xFF\xFF\xFF\xFF":
|
||||
$var = substr_replace($var, "\x00\x00\x00\x00", -$i, 4);
|
||||
break;
|
||||
case "\x7F\xFF\xFF\xFF":
|
||||
$var = substr_replace($var, "\x80\x00\x00\x00", -$i, 4);
|
||||
return;
|
||||
default:
|
||||
$temp = unpack('Nnum', $temp);
|
||||
$var = substr_replace($var, pack('N', $temp['num'] + 1), -$i, 4);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return $xor;
|
||||
$remainder = strlen($var) % 4;
|
||||
|
||||
if ($remainder == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$temp = unpack('Nnum', str_pad(substr($var, 0, $remainder), 4, "\0", STR_PAD_LEFT));
|
||||
$temp = substr(pack('N', $temp['num'] + 1), -$remainder);
|
||||
$var = substr_replace($var, $temp, 0, $remainder);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1691,7 +2099,6 @@ class Crypt_Base
|
||||
case CRYPT_MODE_ECB:
|
||||
$encrypt = $init_encrypt . '
|
||||
$_ciphertext = "";
|
||||
$_text = $self->_pad($_text);
|
||||
$_plaintext_len = strlen($_text);
|
||||
|
||||
for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
|
||||
@ -1723,23 +2130,24 @@ class Crypt_Base
|
||||
$_plaintext_len = strlen($_text);
|
||||
$_xor = $self->encryptIV;
|
||||
$_buffer = &$self->enbuffer;
|
||||
|
||||
if (strlen($_buffer["encrypted"])) {
|
||||
for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
|
||||
$_block = substr($_text, $_i, '.$block_size.');
|
||||
if (strlen($_block) > strlen($_buffer["encrypted"])) {
|
||||
$in = $self->_generateXor($_xor, '.$block_size.');
|
||||
$in = $_xor;
|
||||
'.$encrypt_block.'
|
||||
$self->_increment_str($_xor);
|
||||
$_buffer["encrypted"].= $in;
|
||||
}
|
||||
$_key = $self->_stringShift($_buffer["encrypted"], '.$block_size.');
|
||||
$_key = $self->_string_shift($_buffer["encrypted"], '.$block_size.');
|
||||
$_ciphertext.= $_block ^ $_key;
|
||||
}
|
||||
} else {
|
||||
for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
|
||||
$_block = substr($_text, $_i, '.$block_size.');
|
||||
$in = $self->_generateXor($_xor, '.$block_size.');
|
||||
$in = $_xor;
|
||||
'.$encrypt_block.'
|
||||
$self->_increment_str($_xor);
|
||||
$_key = $in;
|
||||
$_ciphertext.= $_block ^ $_key;
|
||||
}
|
||||
@ -1764,18 +2172,20 @@ class Crypt_Base
|
||||
for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
|
||||
$_block = substr($_text, $_i, '.$block_size.');
|
||||
if (strlen($_block) > strlen($_buffer["ciphertext"])) {
|
||||
$in = $self->_generateXor($_xor, '.$block_size.');
|
||||
$in = $_xor;
|
||||
'.$encrypt_block.'
|
||||
$self->_increment_str($_xor);
|
||||
$_buffer["ciphertext"].= $in;
|
||||
}
|
||||
$_key = $self->_stringShift($_buffer["ciphertext"], '.$block_size.');
|
||||
$_key = $self->_string_shift($_buffer["ciphertext"], '.$block_size.');
|
||||
$_plaintext.= $_block ^ $_key;
|
||||
}
|
||||
} else {
|
||||
for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
|
||||
$_block = substr($_text, $_i, '.$block_size.');
|
||||
$in = $self->_generateXor($_xor, '.$block_size.');
|
||||
$in = $_xor;
|
||||
'.$encrypt_block.'
|
||||
$self->_increment_str($_xor);
|
||||
$_key = $in;
|
||||
$_plaintext.= $_block ^ $_key;
|
||||
}
|
||||
@ -1905,7 +2315,7 @@ class Crypt_Base
|
||||
$_xor = $in;
|
||||
$_buffer["xor"].= $_xor;
|
||||
}
|
||||
$_key = $self->_stringShift($_buffer["xor"], '.$block_size.');
|
||||
$_key = $self->_string_shift($_buffer["xor"], '.$block_size.');
|
||||
$_ciphertext.= $_block ^ $_key;
|
||||
}
|
||||
} else {
|
||||
@ -1941,7 +2351,7 @@ class Crypt_Base
|
||||
$_xor = $in;
|
||||
$_buffer["xor"].= $_xor;
|
||||
}
|
||||
$_key = $self->_stringShift($_buffer["xor"], '.$block_size.');
|
||||
$_key = $self->_string_shift($_buffer["xor"], '.$block_size.');
|
||||
$_plaintext.= $_block ^ $_key;
|
||||
}
|
||||
} else {
|
||||
@ -1978,7 +2388,6 @@ class Crypt_Base
|
||||
default:
|
||||
$encrypt = $init_encrypt . '
|
||||
$_ciphertext = "";
|
||||
$_text = $self->_pad($_text);
|
||||
$_plaintext_len = strlen($_text);
|
||||
|
||||
$in = $self->encryptIV;
|
||||
@ -2058,7 +2467,7 @@ class Crypt_Base
|
||||
define('CRYPT_BASE_WHIRLPOOL_AVAILABLE', (bool)(extension_loaded('hash') && in_array('whirlpool', hash_algos())));
|
||||
}
|
||||
|
||||
// return pack('H*', md5($bytes) . sha1($bytes) . (CRYPT_BASE_WHIRLPOOL_AVAILABLE ? hash('whirlpool', $bytes) : '')); // Alternativ
|
||||
// return pack('H*', md5($bytes) . sha1($bytes) . (CRYPT_BASE_WHIRLPOOL_AVAILABLE ? hash('whirlpool', $bytes) : '')); // Alternative
|
||||
|
||||
$result = '';
|
||||
$hash = $bytes;
|
||||
|
@ -101,20 +101,6 @@ define('CRYPT_BLOWFISH_MODE_CFB', CRYPT_MODE_CFB);
|
||||
define('CRYPT_BLOWFISH_MODE_OFB', CRYPT_MODE_OFB);
|
||||
/**#@-*/
|
||||
|
||||
/**#@+
|
||||
* @access private
|
||||
* @see Crypt_Base::Crypt_Base()
|
||||
*/
|
||||
/**
|
||||
* Toggles the internal implementation
|
||||
*/
|
||||
define('CRYPT_BLOWFISH_MODE_INTERNAL', CRYPT_MODE_INTERNAL);
|
||||
/**
|
||||
* Toggles the mcrypt implementation
|
||||
*/
|
||||
define('CRYPT_BLOWFISH_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
* Pure-PHP implementation of Blowfish.
|
||||
*
|
||||
@ -384,7 +370,6 @@ class Crypt_Blowfish extends Crypt_Base
|
||||
* @param String $key
|
||||
*/
|
||||
function setKey($key)
|
||||
{
|
||||
$keylength = strlen($key);
|
||||
|
||||
if (!$keylength) {
|
||||
@ -396,6 +381,29 @@ class Crypt_Blowfish extends Crypt_Base
|
||||
parent::setKey($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for engine validity
|
||||
*
|
||||
* This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine()
|
||||
*
|
||||
* @see Crypt_Base::Crypt_Base()
|
||||
* @param Integer $engine
|
||||
* @access public
|
||||
* @return Boolean
|
||||
*/
|
||||
function isValidEngine($engine)
|
||||
{
|
||||
if ($engine == CRYPT_MODE_OPENSSL) {
|
||||
if (strlen($this->key) != 16) {
|
||||
return false;
|
||||
}
|
||||
$this->cipher_name_openssl_ecb = 'bf-ecb';
|
||||
$this->cipher_name_openssl = 'bf-' . $this->_openssl_translate_mode();
|
||||
}
|
||||
|
||||
return parent::isValidEngine($engine);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the key (expansion)
|
||||
*
|
||||
|
@ -121,20 +121,6 @@ define('CRYPT_DES_MODE_CFB', CRYPT_MODE_CFB);
|
||||
define('CRYPT_DES_MODE_OFB', CRYPT_MODE_OFB);
|
||||
/**#@-*/
|
||||
|
||||
/**#@+
|
||||
* @access private
|
||||
* @see Crypt_Base::Crypt_Base()
|
||||
*/
|
||||
/**
|
||||
* Toggles the internal implementation
|
||||
*/
|
||||
define('CRYPT_DES_MODE_INTERNAL', CRYPT_MODE_INTERNAL);
|
||||
/**
|
||||
* Toggles the mcrypt implementation
|
||||
*/
|
||||
define('CRYPT_DES_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
* Pure-PHP implementation of DES.
|
||||
*
|
||||
@ -192,6 +178,21 @@ class Crypt_DES extends Crypt_Base
|
||||
*/
|
||||
var $cipher_name_mcrypt = 'des';
|
||||
|
||||
/**
|
||||
* The OpenSSL names of the cipher / modes
|
||||
*
|
||||
* @see Crypt_Base::openssl_mode_names
|
||||
* @var Array
|
||||
* @access private
|
||||
*/
|
||||
var $openssl_mode_names = array(
|
||||
CRYPT_MODE_ECB => 'des-ecb',
|
||||
CRYPT_MODE_CBC => 'des-cbc',
|
||||
CRYPT_MODE_CFB => 'des-cfb',
|
||||
CRYPT_MODE_OFB => 'des-ofb'
|
||||
// CRYPT_MODE_CTR is undefined for DES
|
||||
);
|
||||
|
||||
/**
|
||||
* Optimizing value while CFB-encrypting
|
||||
*
|
||||
@ -662,6 +663,26 @@ class Crypt_DES extends Crypt_Base
|
||||
0x00000820, 0x00020020, 0x08000000, 0x08020800
|
||||
);
|
||||
|
||||
/**
|
||||
* Test for engine validity
|
||||
*
|
||||
* This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine()
|
||||
*
|
||||
* @see Crypt_Base::Crypt_Base()
|
||||
* @param Integer $engine
|
||||
* @access public
|
||||
* @return Boolean
|
||||
*/
|
||||
function isValidEngine($engine)
|
||||
{
|
||||
if ($engine == CRYPT_MODE_OPENSSL) {
|
||||
$this->cipher_name_openssl_ecb = 'des-ecb';
|
||||
$this->cipher_name_openssl = 'des-' . $this->_openssl_translate_mode();
|
||||
}
|
||||
|
||||
return parent::isValidEngine($engine);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key.
|
||||
*
|
||||
|
@ -99,20 +99,6 @@ define('CRYPT_RC2_MODE_CFB', CRYPT_MODE_CFB);
|
||||
define('CRYPT_RC2_MODE_OFB', CRYPT_MODE_OFB);
|
||||
/**#@-*/
|
||||
|
||||
/**#@+
|
||||
* @access public
|
||||
* @see Crypt_RC2::Crypt_RC2()
|
||||
*/
|
||||
/**
|
||||
* Toggles the internal implementation
|
||||
*/
|
||||
define('CRYPT_RC2_MODE_INTERNAL', CRYPT_MODE_INTERNAL);
|
||||
/**
|
||||
* Toggles the mcrypt implementation
|
||||
*/
|
||||
define('CRYPT_RC2_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
* Pure-PHP implementation of RC2.
|
||||
*
|
||||
@ -141,6 +127,18 @@ class Crypt_RC2 extends Crypt_Base
|
||||
*/
|
||||
var $key;
|
||||
|
||||
/**
|
||||
* The Original (unpadded) Key
|
||||
*
|
||||
* @see Crypt_Base::key
|
||||
* @see setKey()
|
||||
* @see encrypt()
|
||||
* @see decrypt()
|
||||
* @var String
|
||||
* @access private
|
||||
*/
|
||||
var $orig_key;
|
||||
|
||||
/**
|
||||
* The default password key_size used by setPassword()
|
||||
*
|
||||
@ -190,6 +188,17 @@ class Crypt_RC2 extends Crypt_Base
|
||||
*/
|
||||
var $default_key_length = 1024;
|
||||
|
||||
/**
|
||||
* The key length in bits.
|
||||
*
|
||||
* @see Crypt_RC2::isValidEnine()
|
||||
* @see Crypt_RC2::setKey()
|
||||
* @var Integer
|
||||
* @access private
|
||||
* @internal Should be in range [1..1024].
|
||||
*/
|
||||
var $current_key_length;
|
||||
|
||||
/**
|
||||
* The Key Schedule
|
||||
*
|
||||
@ -344,6 +353,30 @@ class Crypt_RC2 extends Crypt_Base
|
||||
parent::Crypt_Base($mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for engine validity
|
||||
*
|
||||
* This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine()
|
||||
*
|
||||
* @see Crypt_Base::Crypt_Base()
|
||||
* @param Integer $engine
|
||||
* @access public
|
||||
* @return Boolean
|
||||
*/
|
||||
function isValidEngine($engine)
|
||||
{
|
||||
switch ($engine) {
|
||||
case CRYPT_MODE_OPENSSL:
|
||||
if ($this->current_key_length != 128 && strlen($this->orig_key) != 16) {
|
||||
return false;
|
||||
}
|
||||
$this->cipher_name_openssl_ecb = 'rc2-ecb';
|
||||
$this->cipher_name_openssl = 'rc2-' . $this->_openssl_translate_mode();
|
||||
}
|
||||
|
||||
return parent::isValidEngine($engine);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key length
|
||||
*
|
||||
@ -375,15 +408,18 @@ class Crypt_RC2 extends Crypt_Base
|
||||
* @see Crypt_Base::setKey()
|
||||
* @access public
|
||||
* @param String $key
|
||||
* @param Integer $t1 optional Effective key length in bits.
|
||||
* @param Integer $t1 optional Effective key length in bits.
|
||||
*/
|
||||
function setKey($key, $t1 = 0)
|
||||
{
|
||||
$this->orig_key = $key;
|
||||
|
||||
if ($t1 <= 0) {
|
||||
$t1 = $this->default_key_length;
|
||||
} else if ($t1 > 1024) {
|
||||
$t1 = 1024;
|
||||
}
|
||||
$this->current_key_length = $t1;
|
||||
// Key byte count should be 1..128.
|
||||
$key = strlen($key) ? substr($key, 0, 128) : "\x00";
|
||||
$t = strlen($key);
|
||||
@ -416,6 +452,52 @@ class Crypt_RC2 extends Crypt_Base
|
||||
parent::setKey(call_user_func_array('pack', $l));
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts a message.
|
||||
*
|
||||
* Mostly a wrapper for Crypt_Base::encrypt, with some additional OpenSSL handling code
|
||||
*
|
||||
* @see decrypt()
|
||||
* @access public
|
||||
* @param String $plaintext
|
||||
* @return String $ciphertext
|
||||
*/
|
||||
function encrypt($plaintext)
|
||||
{
|
||||
if ($this->engine == CRYPT_MODE_OPENSSL) {
|
||||
$temp = $this->key;
|
||||
$this->key = $this->orig_key;
|
||||
$result = parent::encrypt($plaintext);
|
||||
$this->key = $temp;
|
||||
return $result;
|
||||
}
|
||||
|
||||
return parent::encrypt($plaintext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts a message.
|
||||
*
|
||||
* Mostly a wrapper for Crypt_Base::decrypt, with some additional OpenSSL handling code
|
||||
*
|
||||
* @see encrypt()
|
||||
* @access public
|
||||
* @param String $ciphertext
|
||||
* @return String $plaintext
|
||||
*/
|
||||
function decrypt($ciphertext)
|
||||
{
|
||||
if ($this->engine == CRYPT_MODE_OPENSSL) {
|
||||
$temp = $this->key;
|
||||
$this->key = $this->orig_key;
|
||||
$result = parent::decrypt($ciphertext);
|
||||
$this->key = $temp;
|
||||
return $result;
|
||||
}
|
||||
|
||||
return parent::encrypt($ciphertext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts a block
|
||||
*
|
||||
|
@ -69,20 +69,6 @@ if (!class_exists('Crypt_Base')) {
|
||||
include_once 'Base.php';
|
||||
}
|
||||
|
||||
/**#@+
|
||||
* @access public
|
||||
* @see Crypt_RC4::Crypt_RC4()
|
||||
*/
|
||||
/**
|
||||
* Toggles the internal implementation
|
||||
*/
|
||||
define('CRYPT_RC4_MODE_INTERNAL', CRYPT_MODE_INTERNAL);
|
||||
/**
|
||||
* Toggles the mcrypt implementation
|
||||
*/
|
||||
define('CRYPT_RC4_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
|
||||
/**#@-*/
|
||||
|
||||
/**#@+
|
||||
* @access private
|
||||
* @see Crypt_RC4::_crypt()
|
||||
@ -182,6 +168,38 @@ class Crypt_RC4 extends Crypt_Base
|
||||
parent::Crypt_Base(CRYPT_MODE_STREAM);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for engine validity
|
||||
*
|
||||
* This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine()
|
||||
*
|
||||
* @see Crypt_Base::Crypt_Base()
|
||||
* @param Integer $engine
|
||||
* @access public
|
||||
* @return Boolean
|
||||
*/
|
||||
function isValidEngine($engine)
|
||||
{
|
||||
switch ($engine) {
|
||||
case CRYPT_MODE_OPENSSL:
|
||||
switch (strlen($this->key)) {
|
||||
case 5:
|
||||
$this->cipher_name_openssl = 'rc4-40';
|
||||
break;
|
||||
case 8:
|
||||
$this->cipher_name_openssl = 'rc4-64';
|
||||
break;
|
||||
case 16:
|
||||
$this->cipher_name_openssl = 'rc4';
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return parent::isValidEngine($engine);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dummy function.
|
||||
*
|
||||
|
@ -118,20 +118,6 @@ define('CRYPT_RIJNDAEL_MODE_CFB', CRYPT_MODE_CFB);
|
||||
define('CRYPT_RIJNDAEL_MODE_OFB', CRYPT_MODE_OFB);
|
||||
/**#@-*/
|
||||
|
||||
/**#@+
|
||||
* @access private
|
||||
* @see Crypt_Base::Crypt_Base()
|
||||
*/
|
||||
/**
|
||||
* Toggles the internal implementation
|
||||
*/
|
||||
define('CRYPT_RIJNDAEL_MODE_INTERNAL', CRYPT_MODE_INTERNAL);
|
||||
/**
|
||||
* Toggles the mcrypt implementation
|
||||
*/
|
||||
define('CRYPT_RIJNDAEL_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
* Pure-PHP implementation of Rijndael.
|
||||
*
|
||||
@ -171,7 +157,7 @@ class Crypt_Rijndael extends Crypt_Base
|
||||
*
|
||||
* @see Crypt_Base::cipher_name_mcrypt
|
||||
* @see Crypt_Base::engine
|
||||
* @see _setupEngine()
|
||||
* @see isValidEngine()
|
||||
* @var String
|
||||
* @access private
|
||||
*/
|
||||
@ -323,8 +309,6 @@ class Crypt_Rijndael extends Crypt_Base
|
||||
*/
|
||||
function setKey($key)
|
||||
{
|
||||
parent::setKey($key);
|
||||
|
||||
if (!$this->explicit_key_length) {
|
||||
$length = strlen($key);
|
||||
switch (true) {
|
||||
@ -343,8 +327,8 @@ class Crypt_Rijndael extends Crypt_Base
|
||||
default:
|
||||
$this->key_size = 32;
|
||||
}
|
||||
$this->_setupEngine();
|
||||
}
|
||||
parent::setKey($key);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -388,7 +372,7 @@ class Crypt_Rijndael extends Crypt_Base
|
||||
|
||||
$this->explicit_key_length = true;
|
||||
$this->changed = true;
|
||||
$this->_setupEngine();
|
||||
$this->_setEngine();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -411,33 +395,38 @@ class Crypt_Rijndael extends Crypt_Base
|
||||
$this->Nb = $length;
|
||||
$this->block_size = $length << 2;
|
||||
$this->changed = true;
|
||||
$this->_setupEngine();
|
||||
$this->_setEngine();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the fastest possible $engine
|
||||
* Test for engine validity
|
||||
*
|
||||
* Determines if the mcrypt (MODE_MCRYPT) $engine available
|
||||
* and usable for the current $block_size and $key_size.
|
||||
* This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine()
|
||||
*
|
||||
* If not, the slower MODE_INTERNAL $engine will be set.
|
||||
*
|
||||
* @see setKey()
|
||||
* @see setKeyLength()
|
||||
* @see setBlockLength()
|
||||
* @access private
|
||||
* @see Crypt_Base::Crypt_Base()
|
||||
* @param Integer $engine
|
||||
* @access public
|
||||
* @return Boolean
|
||||
*/
|
||||
function _setupEngine()
|
||||
function isValidEngine($engine)
|
||||
{
|
||||
// Set the mcrypt module name for the current $block_size of rijndael
|
||||
$this->cipher_name_mcrypt = 'rijndael-' . ($this->block_size << 3);
|
||||
|
||||
// Set the engine
|
||||
if ($this->key_size % 8) { // is it a 160/224-bit key?
|
||||
// mcrypt is not usable for them, only for 128/192/256-bit keys
|
||||
// so we are forced to set the slower MODE_INTERNAL $engine
|
||||
$this->setEngine(CRYPT_MODE_INTERNAL);
|
||||
switch ($engine) {
|
||||
case CRYPT_MODE_OPENSSL:
|
||||
if ($this->block_size != 16) {
|
||||
return false;
|
||||
}
|
||||
$this->cipher_name_openssl_ecb = 'aes-' . ($this->key_size << 3) . '-ecb';
|
||||
$this->cipher_name_openssl = 'aes-' . ($this->key_size << 3) . '-' . $this->_openssl_translate_mode();
|
||||
break;
|
||||
case CRYPT_MODE_MCRYPT:
|
||||
$this->cipher_name_mcrypt = 'rijndael-' . ($this->block_size << 3);
|
||||
if ($this->key_size % 8) { // is it a 160/224-bit key?
|
||||
// mcrypt is not usable for them, only for 128/192/256-bit keys
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return parent::isValidEngine($engine);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -218,6 +218,27 @@ class Crypt_TripleDES extends Crypt_DES
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for engine validity
|
||||
*
|
||||
* This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine()
|
||||
*
|
||||
* @see Crypt_Base::Crypt_Base()
|
||||
* @param Integer $engine
|
||||
* @access public
|
||||
* @return Boolean
|
||||
*/
|
||||
function isValidEngine($engine)
|
||||
{
|
||||
if ($engine == CRYPT_MODE_OPENSSL) {
|
||||
$this->cipher_name_openssl_ecb = 'des-ede3';
|
||||
$mode = $this->_openssl_translate_mode();
|
||||
$this->cipher_name_openssl = $mode == 'ecb' ? 'des-ede3' : 'des-ede3-' . $mode;
|
||||
}
|
||||
|
||||
return parent::isValidEngine($engine);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the initialization vector. (optional)
|
||||
*
|
||||
@ -260,7 +281,7 @@ class Crypt_TripleDES extends Crypt_DES
|
||||
$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);
|
||||
$key = $length <= 16 ? substr_replace($key, substr($key, 0, 8), 16) : substr($key, 0, 24);
|
||||
} else {
|
||||
$key = str_pad($key, 8, chr(0));
|
||||
}
|
||||
|
@ -101,20 +101,6 @@ define('CRYPT_TWOFISH_MODE_CFB', CRYPT_MODE_CFB);
|
||||
define('CRYPT_TWOFISH_MODE_OFB', CRYPT_MODE_OFB);
|
||||
/**#@-*/
|
||||
|
||||
/**#@+
|
||||
* @access private
|
||||
* @see Crypt_Base::Crypt_Base()
|
||||
*/
|
||||
/**
|
||||
* Toggles the internal implementation
|
||||
*/
|
||||
define('CRYPT_TWOFISH_MODE_INTERNAL', CRYPT_MODE_INTERNAL);
|
||||
/**
|
||||
* Toggles the mcrypt implementation
|
||||
*/
|
||||
define('CRYPT_TWOFISH_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
* Pure-PHP implementation of Twofish.
|
||||
*
|
||||
|
@ -7,10 +7,8 @@
|
||||
|
||||
class Unit_Crypt_AES_InternalTest extends Unit_Crypt_AES_TestCase
|
||||
{
|
||||
static public function setUpBeforeClass()
|
||||
protected function setUp()
|
||||
{
|
||||
self::$engine = CRYPT_MODE_INTERNAL;
|
||||
|
||||
parent::setUpBeforeClass();
|
||||
$this->engine = CRYPT_MODE_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
@ -7,14 +7,8 @@
|
||||
|
||||
class Unit_Crypt_AES_McryptTest extends Unit_Crypt_AES_TestCase
|
||||
{
|
||||
static public function setUpBeforeClass()
|
||||
protected function setUp()
|
||||
{
|
||||
if (!extension_loaded('mcrypt')) {
|
||||
self::markTestSkipped('mcrypt extension is not available.');
|
||||
}
|
||||
|
||||
self::$engine = CRYPT_MODE_MCRYPT;
|
||||
|
||||
parent::setUpBeforeClass();
|
||||
$this->engine = CRYPT_MODE_MCRYPT;
|
||||
}
|
||||
}
|
||||
|
14
tests/Unit/Crypt/AES/OpenSSLTest.php
Normal file
14
tests/Unit/Crypt/AES/OpenSSLTest.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Andreas Fischer <bantu@phpbb.com>
|
||||
* @copyright MMXIII Andreas Fischer
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
*/
|
||||
|
||||
class Unit_Crypt_AES_OpenSSLTest extends Unit_Crypt_AES_TestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
$this->engine = CRYPT_MODE_OPENSSL;
|
||||
}
|
||||
}
|
@ -9,11 +9,21 @@ require_once 'Crypt/AES.php';
|
||||
|
||||
abstract class Unit_Crypt_AES_TestCase extends PhpseclibTestCase
|
||||
{
|
||||
protected static $engine;
|
||||
protected $engine;
|
||||
|
||||
static public function setUpBeforeClass()
|
||||
private function checkEngine($aes)
|
||||
{
|
||||
parent::setUpBeforeClass();
|
||||
if ($aes->getEngine() != $this->engine) {
|
||||
$engine = 'internal';
|
||||
switch ($this->engine) {
|
||||
case CRYPT_MODE_OPENSSL:
|
||||
$engine = 'OpenSSL';
|
||||
break;
|
||||
case CRYPT_MODE_MCRYPT:
|
||||
$engine = 'mcrypt';
|
||||
}
|
||||
self::markTestSkipped('Unable to initialize ' . $engine . ' engine');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -63,11 +73,13 @@ abstract class Unit_Crypt_AES_TestCase extends PhpseclibTestCase
|
||||
public function testEncryptDecryptWithContinuousBuffer($mode, $plaintext, $iv, $key)
|
||||
{
|
||||
$aes = new Crypt_AES(constant($mode));
|
||||
$aes->setEngine(self::$engine);
|
||||
$aes->setPreferredEngine($this->engine);
|
||||
$aes->enableContinuousBuffer();
|
||||
$aes->setIV($iv);
|
||||
$aes->setKey($key);
|
||||
|
||||
$this->checkEngine($aes);
|
||||
|
||||
$actual = '';
|
||||
for ($i = 0, $strlen = strlen($plaintext); $i < $strlen; ++$i) {
|
||||
$actual .= $aes->decrypt($aes->encrypt($plaintext[$i]));
|
||||
@ -85,9 +97,10 @@ abstract class Unit_Crypt_AES_TestCase extends PhpseclibTestCase
|
||||
// https://web.archive.org/web/20070209120224/http://fp.gladman.plus.com/cryptography_technology/rijndael/aesdvec.zip
|
||||
|
||||
$aes = new Crypt_Rijndael();
|
||||
$aes->setEngine(self::$engine);
|
||||
$aes->setPreferredEngine($this->engine);
|
||||
$aes->disablePadding();
|
||||
$aes->setKey(pack('H*', '2b7e151628aed2a6abf7158809cf4f3c762e7160')); // 160-bit key. Valid in Rijndael.
|
||||
//$this->checkEngine($aes); // should only work in internal mode
|
||||
$ciphertext = $aes->encrypt(pack('H*', '3243f6a8885a308d313198a2e0370734'));
|
||||
$this->assertEquals($ciphertext, pack('H*', '231d844639b31b412211cfe93712b880'));
|
||||
}
|
||||
@ -100,10 +113,96 @@ abstract class Unit_Crypt_AES_TestCase extends PhpseclibTestCase
|
||||
// same as the above - just with a different ciphertext
|
||||
|
||||
$aes = new Crypt_AES();
|
||||
$aes->setEngine(self::$engine);
|
||||
$aes->setPreferredEngine($this->engine);
|
||||
$aes->disablePadding();
|
||||
$aes->setKey(pack('H*', '2b7e151628aed2a6abf7158809cf4f3c762e7160')); // 160-bit key. AES should null pad to 192-bits
|
||||
$this->checkEngine($aes);
|
||||
$ciphertext = $aes->encrypt(pack('H*', '3243f6a8885a308d313198a2e0370734'));
|
||||
$this->assertEquals($ciphertext, pack('H*', 'c109292b173f841b88e0ee49f13db8c0'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces all combinations of test values.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function continuousBufferBatteryCombos()
|
||||
{
|
||||
$modes = array(
|
||||
'CRYPT_MODE_CTR',
|
||||
'CRYPT_MODE_OFB',
|
||||
'CRYPT_MODE_CFB',
|
||||
);
|
||||
|
||||
$combos = array(
|
||||
array(16),
|
||||
array(17),
|
||||
array(1, 16),
|
||||
array(3, 6, 7), // (3 to test the openssl_encrypt call and the buffer creation, 6 to test the exclusive use of the buffer and 7 to test the buffer's exhaustion and recreation)
|
||||
array(15, 4), // (15 to test openssl_encrypt call and buffer creation and 4 to test something that spans multpile bloc
|
||||
array(3, 6, 10, 16), // this is why the strlen check in the buffer-only code was needed
|
||||
array(16, 16), // two full size blocks
|
||||
array(3, 6, 7, 16), // partial block + full size block
|
||||
array(16, 3, 6, 7),
|
||||
// a few others just for fun
|
||||
array(32,32),
|
||||
array(31,31),
|
||||
array(17,17),
|
||||
array(99, 99)
|
||||
);
|
||||
|
||||
$result = array();
|
||||
|
||||
// @codingStandardsIgnoreStart
|
||||
foreach ($modes as $mode)
|
||||
foreach ($combos as $combo)
|
||||
foreach (array('encrypt', 'decrypt') as $op)
|
||||
$result[] = array($op, $mode, $combo);
|
||||
// @codingStandardsIgnoreEnd
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider continuousBufferBatteryCombos
|
||||
*/
|
||||
public function testContinuousBufferBattery($op, $mode, $test)
|
||||
{
|
||||
$iv = str_repeat('x', 16);
|
||||
$key = str_repeat('a', 16);
|
||||
|
||||
$aes = new Crypt_AES(constant($mode));
|
||||
$aes->setPreferredEngine($this->engine);
|
||||
$aes->setKey($key);
|
||||
$aes->setIV($iv);
|
||||
|
||||
$this->checkEngine($aes);
|
||||
|
||||
$str = '';
|
||||
$result = '';
|
||||
foreach ($test as $len) {
|
||||
$temp = str_repeat('d', $len);
|
||||
$str.= $temp;
|
||||
}
|
||||
|
||||
$c1 = $aes->$op($str);
|
||||
|
||||
$aes = new Crypt_AES(constant($mode));
|
||||
$aes->setPreferredEngine($this->engine);
|
||||
$aes->enableContinuousBuffer();
|
||||
$aes->setKey($key);
|
||||
$aes->setIV($iv);
|
||||
|
||||
$this->checkEngine($aes);
|
||||
|
||||
foreach ($test as $len) {
|
||||
$temp = str_repeat('d', $len);
|
||||
$output = $aes->$op($temp);
|
||||
$result.= $output;
|
||||
}
|
||||
|
||||
$c2 = $result;
|
||||
|
||||
$this->assertSame(bin2hex($c1), bin2hex($c2));
|
||||
}
|
||||
}
|
69
tests/Unit/Crypt/DES.php
Normal file
69
tests/Unit/Crypt/DES.php
Normal file
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Andreas Fischer <bantu@phpbb.com>
|
||||
* @copyright MMXIII Andreas Fischer
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
*/
|
||||
|
||||
require_once 'Crypt/DES.php';
|
||||
|
||||
// the AES tests establish the correctness of the modes of operation. this test is inteded to establish the consistency of
|
||||
// key and iv padding between the multiple engines
|
||||
class Unit_Crypt_DES_TestCase extends PhpseclibTestCase
|
||||
{
|
||||
public function testEncryptPadding()
|
||||
{
|
||||
$des = new Crypt_DES(CRYPT_MODE_CBC);
|
||||
$des->setKey('d');
|
||||
$des->setIV('d');
|
||||
|
||||
$des->setPreferredEngine(CRYPT_MODE_INTERNAL);
|
||||
$internal = $des->encrypt('d');
|
||||
|
||||
$des->setPreferredEngine(CRYPT_MODE_MCRYPT);
|
||||
if ($des->getEngine() == CRYPT_MODE_MCRYPT) {
|
||||
$mcrypt = $des->encrypt('d');
|
||||
$this->assertEquals($internal, $mcrypt, 'Failed asserting that the internal and mcrypt engines produce identical results');
|
||||
} else {
|
||||
self::markTestSkipped('Unable to initialize mcrypt engine');
|
||||
}
|
||||
|
||||
$des->setPreferredEngine(CRYPT_MODE_OPENSSL);
|
||||
if ($des->getEngine() == CRYPT_MODE_OPENSSL) {
|
||||
$openssl = $des->encrypt('d');
|
||||
$this->assertEquals($internal, $openssl, 'Failed asserting that the internal and OpenSSL engines produce identical results');
|
||||
} else {
|
||||
self::markTestSkipped('Unable to initialize OpenSSL engine');
|
||||
}
|
||||
}
|
||||
|
||||
// phpseclib null pads ciphertext's if they're not long enough and you're in ecb / cbc mode. this silent failure mode is consistent
|
||||
// with mcrypt's behavior. maybe throwing an exception would be better but whatever. this test is more intended to establish consistent
|
||||
// behavior between the various engine's
|
||||
public function testDecryptPadding()
|
||||
{
|
||||
$des = new Crypt_DES(CRYPT_MODE_CBC);
|
||||
// when the key and iv are not specified they should be null padded
|
||||
//$des->setKey();
|
||||
//$des->setIV();
|
||||
|
||||
$des->setPreferredEngine(CRYPT_MODE_INTERNAL);
|
||||
$internal = $des->decrypt('d');
|
||||
|
||||
$des->setPreferredEngine(CRYPT_MODE_MCRYPT);
|
||||
if ($des->getEngine() == CRYPT_MODE_MCRYPT) {
|
||||
$mcrypt = $des->decrypt('d');
|
||||
$this->assertEquals($internal, $mcrypt, 'Failed asserting that the internal and mcrypt engines produce identical results');
|
||||
} else {
|
||||
self::markTestSkipped('Unable to initialize mcrypt engine');
|
||||
}
|
||||
|
||||
$des->setPreferredEngine(CRYPT_MODE_OPENSSL);
|
||||
if ($des->getEngine() == CRYPT_MODE_OPENSSL) {
|
||||
$openssl = $des->decrypt('d');
|
||||
$this->assertEquals($internal, $openssl, 'Failed asserting that the internal and OpenSSL engines produce identical results');
|
||||
} else {
|
||||
self::markTestSkipped('Unable to initialize OpenSSL engine');
|
||||
}
|
||||
}
|
||||
}
|
71
tests/Unit/Crypt/RC2.php
Normal file
71
tests/Unit/Crypt/RC2.php
Normal file
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Andreas Fischer <bantu@phpbb.com>
|
||||
* @copyright MMXIII Andreas Fischer
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
*/
|
||||
|
||||
require_once 'Crypt/RC2.php';
|
||||
|
||||
// this test is just confirming RC2's key expansion
|
||||
class Unit_Crypt_RC2_TestCase extends PhpseclibTestCase
|
||||
{
|
||||
public function testEncryptPadding()
|
||||
{
|
||||
$rc2 = new Crypt_RC2(CRYPT_MODE_ECB);
|
||||
|
||||
// unlike Crypt_AES / Crypt_Rijndael, when you tell Crypt_RC2 that the key length is 128-bits the key isn't null padded to that length.
|
||||
// instead, RC2 key expansion is used to extend it out to that length. this isn't done for AES / Rijndael since that doesn't define any
|
||||
// sort of key expansion algorithm.
|
||||
|
||||
// admittedly, phpseclib is inconsistent in this regard. RC4 and Blowfish support arbitrary key lengths between a certain range, as well,
|
||||
// and they don't have any way to set the key length. but then again, neither do those algorithms have their own key expansion algorithm,
|
||||
// whereas RC2 does. and technically, AES / Rijndael (and even Twofish) don't support arbitrary key lengths - they support variable key
|
||||
// lengths. so in some ways, i suppose this inconsistency somewhat makes sense, although the fact that Crypt_Twofish doesn't have a
|
||||
// setKeyLength() function whereas Crypt_AES / Crypt_Rijndael do not is, itself, an inconsistency.
|
||||
|
||||
// but that said, Crypt_RC2 is inconsistent in other ways: if you pass a 128-bit (16-byte) key to it via setKey() the key is not treated
|
||||
// as a 128-bit key but rather as a 1024-bit key and is expanded accordingly, not via null padding, but via RC2's key expansion algorithm.
|
||||
|
||||
// this behavior is in contrast to mcrypt, which extends keys via null padding to 1024 bits. it is also in contrast to OpenSSL, which
|
||||
// extends keys, via null padding, to 128 bits. mcrypt's approach seems preferable as one can simulate 128 bit keys by using RC2's
|
||||
// key expansion algorithm to extend the key to 1024 bits and then changing the first byte of the new key with an inverse pitable mapping.
|
||||
// in contrast, to my knowledge, there is no technique for expanding a key less than 128 bits to 128 bits, via RC2 key expansion. the only
|
||||
// scenario in that regard is null padding.
|
||||
|
||||
// simple truncation is insufficient, since, quoting RFC2268, "the purpose of th key-expansion algorithm [in RC2] is to modify the key buffer
|
||||
// so that each bit of the expanded key depends in a complicated way on every bit of the supplied input key".
|
||||
|
||||
// now, to OpenSSL's credit, null padding is internally consistent with OpenSSL. OpenSSL only supports fixed length keys. For rc2, rc4 and
|
||||
// bf (blowfish), all keys are 128 bits (or are null padded / truncated accordingly). to use 40-bit or 64-bit keys with RC4 with OpenSSL you
|
||||
// don't use the rc4 algorithm - you use the rc4-40 or rc4-64 algorithm. and similarily, it's not aes-cbc that you use - it's either aes-128-cbc
|
||||
// or aes-192-cbc or aes-256-cbc. this is in contrast to mcrypt, which (with the exception of RC2) actually supports variable and arbitrary
|
||||
// length keys.
|
||||
|
||||
// superficially, it seens like Rijndael would be another exception to mcrypt's key length handling, but it in fact is not. the reason being that,
|
||||
// with mcrypt, when you specify MCRYPT_RIJNDAEL_128 or MCRYPT_RIJNDAEL_192 or MCRYPT_RIJNDAEL_256 the numbers at the end aren't referring to the
|
||||
// key length, but rather, the block length. ie. Rijndael, unlike most block ciphers, doesn't just have a variable (but not arbitrary) key length -
|
||||
// it also has a variable block length. AES's block length, however, is not variable, so technically, only MCRYPT_RIJNDAEL_128 is AES.
|
||||
|
||||
$rc2->setKey(str_repeat('d', 16), 128);
|
||||
|
||||
$rc2->setPreferredEngine(CRYPT_MODE_INTERNAL);
|
||||
$internal = $rc2->encrypt('d');
|
||||
|
||||
$rc2->setPreferredEngine(CRYPT_MODE_MCRYPT);
|
||||
if ($rc2->getEngine() == CRYPT_MODE_MCRYPT) {
|
||||
$mcrypt = $rc2->encrypt('d');
|
||||
$this->assertEquals($internal, $mcrypt, 'Failed asserting that the internal and mcrypt engines produce identical results');
|
||||
} else {
|
||||
self::markTestSkipped('Unable to initialize mcrypt engine');
|
||||
}
|
||||
|
||||
$rc2->setPreferredEngine(CRYPT_MODE_OPENSSL);
|
||||
if ($rc2->getEngine() == CRYPT_MODE_OPENSSL) {
|
||||
$openssl = $rc2->encrypt('d');
|
||||
$this->assertEquals($internal, $openssl, 'Failed asserting that the internal and OpenSSL engines produce identical results');
|
||||
} else {
|
||||
self::markTestSkipped('Unable to initialize OpenSSL engine');
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user