updating phpseclib to latest cvs - fixes a bunch of key generation issues

This commit is contained in:
James Walker 2010-03-12 20:01:34 -05:00
parent c5bb41176e
commit 520faaf67d
9 changed files with 10434 additions and 9369 deletions

View File

@ -56,7 +56,7 @@
* @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVIII Jim Wigginton
* @license http://www.gnu.org/licenses/lgpl.txt
* @version $Id: AES.php,v 1.5 2009/11/23 19:06:06 terrafrost Exp $
* @version $Id: AES.php,v 1.7 2010/02/09 06:10:25 terrafrost Exp $
* @link http://phpseclib.sourceforge.net
*/
@ -70,6 +70,14 @@ require_once 'Rijndael.php';
* @see Crypt_AES::encrypt()
* @see Crypt_AES::decrypt()
*/
/**
* Encrypt / decrypt using the Counter mode.
*
* Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
*/
define('CRYPT_AES_MODE_CTR', -1);
/**
* Encrypt / decrypt using the Electronic Code Book mode.
*
@ -108,13 +116,28 @@ define('CRYPT_AES_MODE_MCRYPT', 2);
*/
class Crypt_AES extends Crypt_Rijndael {
/**
* MCrypt parameters
* mcrypt resource for encryption
*
* @see Crypt_AES::setMCrypt()
* @var Array
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
*
* @see Crypt_AES::encrypt()
* @var String
* @access private
*/
var $mcrypt = array('', '');
var $enmcrypt;
/**
* mcrypt resource for decryption
*
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
*
* @see Crypt_AES::decrypt()
* @var String
* @access private
*/
var $demcrypt;
/**
* Default Constructor.
@ -147,6 +170,13 @@ class Crypt_AES extends Crypt_Rijndael {
case CRYPT_AES_MODE_ECB:
$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_CBC:
default:
$this->mode = MCRYPT_MODE_CBC;
@ -158,6 +188,9 @@ class Crypt_AES extends Crypt_Rijndael {
case CRYPT_AES_MODE_ECB:
$this->mode = CRYPT_RIJNDAEL_MODE_ECB;
break;
case CRYPT_AES_MODE_CTR:
$this->mode = CRYPT_RIJNDAEL_MODE_CTR;
break;
case CRYPT_AES_MODE_CBC:
default:
$this->mode = CRYPT_RIJNDAEL_MODE_CBC;
@ -203,18 +236,26 @@ class Crypt_AES extends Crypt_Rijndael {
{
if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) {
$this->_mcryptSetup();
$plaintext = $this->_pad($plaintext);
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, $this->mcrypt[0], $this->mode, $this->mcrypt[1]);
mcrypt_generic_init($td, $this->key, $this->encryptIV);
$ciphertext = mcrypt_generic($td, $plaintext);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
/*
if ($this->mode == CRYPT_AES_MODE_CTR) {
$iv = $this->encryptIV;
$xor = mcrypt_generic($this->enmcrypt, $this->_generate_xor(strlen($plaintext), $iv));
$ciphertext = $plaintext ^ $xor;
if ($this->continuousBuffer) {
$this->encryptIV = substr($ciphertext, -16);
$this->encryptIV = $iv;
}
return $ciphertext;
}
*/
if ($this->mode != 'ctr') {
$plaintext = $this->_pad($plaintext);
}
$ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
if (!$this->continuousBuffer) {
mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv);
}
return $ciphertext;
@ -234,46 +275,38 @@ class Crypt_AES extends Crypt_Rijndael {
*/
function decrypt($ciphertext)
{
if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) {
$this->_mcryptSetup();
/*
if ($this->mode == CRYPT_AES_MODE_CTR) {
$iv = $this->decryptIV;
$xor = mcrypt_generic($this->enmcrypt, $this->_generate_xor(strlen($ciphertext), $iv));
$plaintext = $ciphertext ^ $xor;
if ($this->continuousBuffer) {
$this->decryptIV = $iv;
}
return $plaintext;
}
*/
if ($this->mode != 'ctr') {
// 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));
if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) {
$this->_mcryptSetup();
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, $this->mcrypt[0], $this->mode, $this->mcrypt[1]);
mcrypt_generic_init($td, $this->key, $this->decryptIV);
$plaintext = mdecrypt_generic($td, $ciphertext);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
if ($this->continuousBuffer) {
$this->decryptIV = substr($ciphertext, -16);
}
return $this->_unpad($plaintext);
$plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
if (!$this->continuousBuffer) {
mcrypt_generic_init($this->demcrypt, $this->key, $this->iv);
}
return $this->mode != 'ctr' ? $this->_unpad($plaintext) : $plaintext;
}
return parent::decrypt($ciphertext);
}
/**
* Sets MCrypt parameters. (optional)
*
* If MCrypt is being used, empty strings will be used, unless otherwise specified.
*
* @link http://php.net/function.mcrypt-module-open#function.mcrypt-module-open
* @access public
* @param optional Integer $algorithm_directory
* @param optional Integer $mode_directory
*/
function setMCrypt($algorithm_directory = '', $mode_directory = '')
{
$this->mcrypt = array($algorithm_directory, $mode_directory);
}
/**
* Setup mcrypt
*
@ -315,6 +348,17 @@ class Crypt_AES extends Crypt_Rijndael {
$this->key = substr($this->key, 0, $this->key_size);
$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, '');
} // 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);
$this->changed = false;
}
@ -332,12 +376,19 @@ class Crypt_AES extends Crypt_Rijndael {
{
$state = unpack('N*word', $in);
$Nr = $this->Nr;
$w = $this->w;
$t0 = $this->t0;
$t1 = $this->t1;
$t2 = $this->t2;
$t3 = $this->t3;
// addRoundKey and reindex $state
$state = array(
$state['word1'] ^ $this->w[0][0],
$state['word2'] ^ $this->w[0][1],
$state['word3'] ^ $this->w[0][2],
$state['word4'] ^ $this->w[0][3]
$state['word1'] ^ $w[0][0],
$state['word2'] ^ $w[0][1],
$state['word3'] ^ $w[0][2],
$state['word4'] ^ $w[0][3]
);
// shiftRows + subWord + mixColumns + addRoundKey
@ -345,10 +396,10 @@ class Crypt_AES extends Crypt_Rijndael {
// only a marginal improvement. since that also, imho, hinders the readability of the code, i've opted not to do it.
for ($round = 1; $round < $this->Nr; $round++) {
$state = array(
$this->t0[$state[0] & 0xFF000000] ^ $this->t1[$state[1] & 0x00FF0000] ^ $this->t2[$state[2] & 0x0000FF00] ^ $this->t3[$state[3] & 0x000000FF] ^ $this->w[$round][0],
$this->t0[$state[1] & 0xFF000000] ^ $this->t1[$state[2] & 0x00FF0000] ^ $this->t2[$state[3] & 0x0000FF00] ^ $this->t3[$state[0] & 0x000000FF] ^ $this->w[$round][1],
$this->t0[$state[2] & 0xFF000000] ^ $this->t1[$state[3] & 0x00FF0000] ^ $this->t2[$state[0] & 0x0000FF00] ^ $this->t3[$state[1] & 0x000000FF] ^ $this->w[$round][2],
$this->t0[$state[3] & 0xFF000000] ^ $this->t1[$state[0] & 0x00FF0000] ^ $this->t2[$state[1] & 0x0000FF00] ^ $this->t3[$state[2] & 0x000000FF] ^ $this->w[$round][3]
$t0[$state[0] & 0xFF000000] ^ $t1[$state[1] & 0x00FF0000] ^ $t2[$state[2] & 0x0000FF00] ^ $t3[$state[3] & 0x000000FF] ^ $w[$round][0],
$t0[$state[1] & 0xFF000000] ^ $t1[$state[2] & 0x00FF0000] ^ $t2[$state[3] & 0x0000FF00] ^ $t3[$state[0] & 0x000000FF] ^ $w[$round][1],
$t0[$state[2] & 0xFF000000] ^ $t1[$state[3] & 0x00FF0000] ^ $t2[$state[0] & 0x0000FF00] ^ $t3[$state[1] & 0x000000FF] ^ $w[$round][2],
$t0[$state[3] & 0xFF000000] ^ $t1[$state[0] & 0x00FF0000] ^ $t2[$state[1] & 0x0000FF00] ^ $t3[$state[2] & 0x000000FF] ^ $w[$round][3]
);
}
@ -386,31 +437,38 @@ class Crypt_AES extends Crypt_Rijndael {
{
$state = unpack('N*word', $in);
$Nr = $this->Nr;
$dw = $this->dw;
$dt0 = $this->dt0;
$dt1 = $this->dt1;
$dt2 = $this->dt2;
$dt3 = $this->dt3;
// addRoundKey and reindex $state
$state = array(
$state['word1'] ^ $this->dw[$this->Nr][0],
$state['word2'] ^ $this->dw[$this->Nr][1],
$state['word3'] ^ $this->dw[$this->Nr][2],
$state['word4'] ^ $this->dw[$this->Nr][3]
$state['word1'] ^ $dw[$this->Nr][0],
$state['word2'] ^ $dw[$this->Nr][1],
$state['word3'] ^ $dw[$this->Nr][2],
$state['word4'] ^ $dw[$this->Nr][3]
);
// invShiftRows + invSubBytes + invMixColumns + addRoundKey
for ($round = $this->Nr - 1; $round > 0; $round--) {
$state = array(
$this->dt0[$state[0] & 0xFF000000] ^ $this->dt1[$state[3] & 0x00FF0000] ^ $this->dt2[$state[2] & 0x0000FF00] ^ $this->dt3[$state[1] & 0x000000FF] ^ $this->dw[$round][0],
$this->dt0[$state[1] & 0xFF000000] ^ $this->dt1[$state[0] & 0x00FF0000] ^ $this->dt2[$state[3] & 0x0000FF00] ^ $this->dt3[$state[2] & 0x000000FF] ^ $this->dw[$round][1],
$this->dt0[$state[2] & 0xFF000000] ^ $this->dt1[$state[1] & 0x00FF0000] ^ $this->dt2[$state[0] & 0x0000FF00] ^ $this->dt3[$state[3] & 0x000000FF] ^ $this->dw[$round][2],
$this->dt0[$state[3] & 0xFF000000] ^ $this->dt1[$state[2] & 0x00FF0000] ^ $this->dt2[$state[1] & 0x0000FF00] ^ $this->dt3[$state[0] & 0x000000FF] ^ $this->dw[$round][3]
$dt0[$state[0] & 0xFF000000] ^ $dt1[$state[3] & 0x00FF0000] ^ $dt2[$state[2] & 0x0000FF00] ^ $dt3[$state[1] & 0x000000FF] ^ $dw[$round][0],
$dt0[$state[1] & 0xFF000000] ^ $dt1[$state[0] & 0x00FF0000] ^ $dt2[$state[3] & 0x0000FF00] ^ $dt3[$state[2] & 0x000000FF] ^ $dw[$round][1],
$dt0[$state[2] & 0xFF000000] ^ $dt1[$state[1] & 0x00FF0000] ^ $dt2[$state[0] & 0x0000FF00] ^ $dt3[$state[3] & 0x000000FF] ^ $dw[$round][2],
$dt0[$state[3] & 0xFF000000] ^ $dt1[$state[2] & 0x00FF0000] ^ $dt2[$state[1] & 0x0000FF00] ^ $dt3[$state[0] & 0x000000FF] ^ $dw[$round][3]
);
}
// invShiftRows + invSubWord + addRoundKey
$state = array(
$this->_invSubWord(($state[0] & 0xFF000000) ^ ($state[3] & 0x00FF0000) ^ ($state[2] & 0x0000FF00) ^ ($state[1] & 0x000000FF)) ^ $this->dw[0][0],
$this->_invSubWord(($state[1] & 0xFF000000) ^ ($state[0] & 0x00FF0000) ^ ($state[3] & 0x0000FF00) ^ ($state[2] & 0x000000FF)) ^ $this->dw[0][1],
$this->_invSubWord(($state[2] & 0xFF000000) ^ ($state[1] & 0x00FF0000) ^ ($state[0] & 0x0000FF00) ^ ($state[3] & 0x000000FF)) ^ $this->dw[0][2],
$this->_invSubWord(($state[3] & 0xFF000000) ^ ($state[2] & 0x00FF0000) ^ ($state[1] & 0x0000FF00) ^ ($state[0] & 0x000000FF)) ^ $this->dw[0][3]
$this->_invSubWord(($state[0] & 0xFF000000) ^ ($state[3] & 0x00FF0000) ^ ($state[2] & 0x0000FF00) ^ ($state[1] & 0x000000FF)) ^ $dw[0][0],
$this->_invSubWord(($state[1] & 0xFF000000) ^ ($state[0] & 0x00FF0000) ^ ($state[3] & 0x0000FF00) ^ ($state[2] & 0x000000FF)) ^ $dw[0][1],
$this->_invSubWord(($state[2] & 0xFF000000) ^ ($state[1] & 0x00FF0000) ^ ($state[0] & 0x0000FF00) ^ ($state[3] & 0x000000FF)) ^ $dw[0][2],
$this->_invSubWord(($state[3] & 0xFF000000) ^ ($state[2] & 0x00FF0000) ^ ($state[1] & 0x0000FF00) ^ ($state[0] & 0x000000FF)) ^ $dw[0][3]
);
return pack('N*', $state[0], $state[1], $state[2], $state[3]);

View File

@ -53,7 +53,7 @@
* @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVII Jim Wigginton
* @license http://www.gnu.org/licenses/lgpl.txt
* @version $Id: DES.php,v 1.9 2009/11/23 19:06:06 terrafrost Exp $
* @version $Id: DES.php,v 1.12 2010/02/09 06:10:26 terrafrost Exp $
* @link http://phpseclib.sourceforge.net
*/
@ -77,6 +77,14 @@ define('CRYPT_DES_DECRYPT', 1);
* @see Crypt_DES::encrypt()
* @see Crypt_DES::decrypt()
*/
/**
* Encrypt / decrypt using the Counter mode.
*
* Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
*/
define('CRYPT_DES_MODE_CTR', -1);
/**
* Encrypt / decrypt using the Electronic Code Book mode.
*
@ -178,13 +186,38 @@ class Crypt_DES {
var $decryptIV = "\0\0\0\0\0\0\0\0";
/**
* MCrypt parameters
* mcrypt resource for encryption
*
* @see Crypt_DES::setMCrypt()
* @var Array
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
*
* @see Crypt_AES::encrypt()
* @var String
* @access private
*/
var $mcrypt = array('', '');
var $enmcrypt;
/**
* mcrypt resource for decryption
*
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
*
* @see Crypt_AES::decrypt()
* @var String
* @access private
*/
var $demcrypt;
/**
* Does the (en|de)mcrypt resource need to be (re)initialized?
*
* @see setKey()
* @see setIV()
* @var Boolean
* @access private
*/
var $changed = true;
/**
* Default Constructor.
@ -217,6 +250,10 @@ class Crypt_DES {
case CRYPT_DES_MODE_ECB:
$this->mode = MCRYPT_MODE_ECB;
break;
case CRYPT_DES_MODE_CTR:
$this->mode = 'ctr';
//$this->mode = in_array('ctr', mcrypt_list_modes()) ? 'ctr' : CRYPT_DES_MODE_CTR;
break;
case CRYPT_DES_MODE_CBC:
default:
$this->mode = MCRYPT_MODE_CBC;
@ -226,6 +263,7 @@ class Crypt_DES {
default:
switch ($mode) {
case CRYPT_DES_MODE_ECB:
case CRYPT_DES_MODE_CTR:
case CRYPT_DES_MODE_CBC:
$this->mode = $mode;
break;
@ -252,6 +290,7 @@ class Crypt_DES {
function setKey($key)
{
$this->keys = ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) ? substr($key, 0, 8) : $this->_prepareKey($key);
$this->changed = true;
}
/**
@ -265,22 +304,46 @@ class Crypt_DES {
*/
function setIV($iv)
{
$this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, 8), 8, chr(0));;
$this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, 8), 8, chr(0));
$this->changed = true;
}
/**
* Sets MCrypt parameters. (optional)
* Generate CTR XOR encryption key
*
* If MCrypt is being used, empty strings will be used, unless otherwise specified.
* Encrypt the output of this and XOR it against the ciphertext / plaintext to get the
* plaintext / ciphertext in CTR mode.
*
* @link http://php.net/function.mcrypt-module-open#function.mcrypt-module-open
* @see Crypt_DES::decrypt()
* @see Crypt_DES::encrypt()
* @access public
* @param optional Integer $algorithm_directory
* @param optional Integer $mode_directory
* @param Integer $length
* @param String $iv
*/
function setMCrypt($algorithm_directory = '', $mode_directory = '')
function _generate_xor($length, &$iv)
{
$this->mcrypt = array($algorithm_directory, $mode_directory);
$xor = '';
$num_blocks = ($length + 7) >> 3;
for ($i = 0; $i < $num_blocks; $i++) {
$xor.= $iv;
for ($j = 4; $j <= 8; $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;
}
}
}
return $xor;
}
/**
@ -302,19 +365,23 @@ class Crypt_DES {
*/
function encrypt($plaintext)
{
if ($this->mode != CRYPT_DES_MODE_CTR && $this->mode != 'ctr') {
$plaintext = $this->_pad($plaintext);
}
if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) {
$td = mcrypt_module_open(MCRYPT_DES, $this->mcrypt[0], $this->mode, $this->mcrypt[1]);
mcrypt_generic_init($td, $this->keys, $this->encryptIV);
if ($this->changed) {
if (!isset($this->enmcrypt)) {
$this->enmcrypt = mcrypt_module_open(MCRYPT_DES, '', $this->mode, '');
}
mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV);
$this->changed = false;
}
$ciphertext = mcrypt_generic($td, $plaintext);
$ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
if ($this->continuousBuffer) {
$this->encryptIV = substr($ciphertext, -8);
if (!$this->continuousBuffer) {
mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV);
}
return $ciphertext;
@ -342,6 +409,17 @@ class Crypt_DES {
if ($this->continuousBuffer) {
$this->encryptIV = $xor;
}
break;
case CRYPT_DES_MODE_CTR:
$xor = $this->encryptIV;
for ($i = 0; $i < strlen($plaintext); $i+=8) {
$block = substr($plaintext, $i, 8);
$key = $this->_processBlock($this->_generate_xor(8, $xor), CRYPT_DES_ENCRYPT);
$ciphertext.= $block ^ $key;
}
if ($this->continuousBuffer) {
$this->encryptIV = $xor;
}
}
return $ciphertext;
@ -358,24 +436,28 @@ class Crypt_DES {
*/
function decrypt($ciphertext)
{
if ($this->mode != CRYPT_DES_MODE_CTR && $this->mode != 'ctr') {
// 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 ) {
$td = mcrypt_module_open(MCRYPT_DES, $this->mcrypt[0], $this->mode, $this->mcrypt[1]);
mcrypt_generic_init($td, $this->keys, $this->decryptIV);
$plaintext = mdecrypt_generic($td, $ciphertext);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
if ($this->continuousBuffer) {
$this->decryptIV = substr($ciphertext, -8);
}
return $this->_unpad($plaintext);
if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) {
if ($this->changed) {
if (!isset($this->demcrypt)) {
$this->demcrypt = mcrypt_module_open(MCRYPT_DES, '', $this->mode, '');
}
mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV);
$this->changed = false;
}
$plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
if (!$this->continuousBuffer) {
mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV);
}
return $this->mode != 'ctr' ? $this->_unpad($plaintext) : $plaintext;
}
if (!is_array($this->keys)) {
@ -399,9 +481,20 @@ class Crypt_DES {
if ($this->continuousBuffer) {
$this->decryptIV = $xor;
}
break;
case CRYPT_DES_MODE_CTR:
$xor = $this->decryptIV;
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
$block = substr($ciphertext, $i, 8);
$key = $this->_processBlock($this->_generate_xor(8, $xor), CRYPT_DES_ENCRYPT);
$plaintext.= $block ^ $key;
}
if ($this->continuousBuffer) {
$this->decryptIV = $xor;
}
}
return $this->_unpad($plaintext);
return $this->mode != CRYPT_DES_MODE_CTR ? $this->_unpad($plaintext) : $plaintext;
}
/**
@ -523,7 +616,8 @@ class Crypt_DES {
/**
* Unpads a string
*
* If padding is enabled and the reported padding length is invalid, padding will be, hence forth, disabled.
* If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
* and false will be returned.
*
* @see Crypt_DES::_pad()
* @access private
@ -537,9 +631,7 @@ class Crypt_DES {
$length = ord($text[strlen($text) - 1]);
if (!$length || $length > 8) {
user_error("The number of bytes reported as being padded ($length) is invalid (block size = 8)", E_USER_NOTICE);
$this->padding = false;
return $text;
return false;
}
return substr($text, 0, -$length);
@ -614,6 +706,8 @@ class Crypt_DES {
)
);
$keys = $this->keys;
$temp = unpack('Na/Nb', $block);
$block = array($temp['a'], $temp['b']);
@ -668,14 +762,14 @@ class Crypt_DES {
for ($i = 0; $i < 16; $i++) {
// start of "the Feistel (F) function" - see the following URL:
// http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png
$temp = (($sbox[0][((($block[1] >> 27) & 0x1F) | (($block[1] & 1) << 5)) ^ $this->keys[$mode][$i][0]]) << 28)
| (($sbox[1][(($block[1] & 0x1F800000) >> 23) ^ $this->keys[$mode][$i][1]]) << 24)
| (($sbox[2][(($block[1] & 0x01F80000) >> 19) ^ $this->keys[$mode][$i][2]]) << 20)
| (($sbox[3][(($block[1] & 0x001F8000) >> 15) ^ $this->keys[$mode][$i][3]]) << 16)
| (($sbox[4][(($block[1] & 0x0001F800) >> 11) ^ $this->keys[$mode][$i][4]]) << 12)
| (($sbox[5][(($block[1] & 0x00001F80) >> 7) ^ $this->keys[$mode][$i][5]]) << 8)
| (($sbox[6][(($block[1] & 0x000001F8) >> 3) ^ $this->keys[$mode][$i][6]]) << 4)
| ( $sbox[7][((($block[1] & 0x1F) << 1) | (($block[1] >> 31) & 1)) ^ $this->keys[$mode][$i][7]]);
$temp = (($sbox[0][((($block[1] >> 27) & 0x1F) | (($block[1] & 1) << 5)) ^ $keys[$mode][$i][0]]) << 28)
| (($sbox[1][(($block[1] & 0x1F800000) >> 23) ^ $keys[$mode][$i][1]]) << 24)
| (($sbox[2][(($block[1] & 0x01F80000) >> 19) ^ $keys[$mode][$i][2]]) << 20)
| (($sbox[3][(($block[1] & 0x001F8000) >> 15) ^ $keys[$mode][$i][3]]) << 16)
| (($sbox[4][(($block[1] & 0x0001F800) >> 11) ^ $keys[$mode][$i][4]]) << 12)
| (($sbox[5][(($block[1] & 0x00001F80) >> 7) ^ $keys[$mode][$i][5]]) << 8)
| (($sbox[6][(($block[1] & 0x000001F8) >> 3) ^ $keys[$mode][$i][6]]) << 4)
| ( $sbox[7][((($block[1] & 0x1F) << 1) | (($block[1] >> 31) & 1)) ^ $keys[$mode][$i][7]]);
$msb = ($temp >> 31) & 1;
$temp &= 0x7FFFFFFF;

View File

@ -62,7 +62,7 @@
* @author Jim Wigginton <terrafrost@php.net>
* @copyright MMIX Jim Wigginton
* @license http://www.gnu.org/licenses/lgpl.txt
* @version $Id: RSA.php,v 1.3 2009/12/04 21:05:32 terrafrost Exp $
* @version $Id: RSA.php,v 1.14 2010/03/01 17:28:19 terrafrost Exp $
* @link http://phpseclib.sourceforge.net
*/
@ -332,6 +332,14 @@ class Crypt_RSA {
*/
var $mgfHash;
/**
* Length of MGF hash function output
*
* @var Integer
* @access private
*/
var $mgfHLen;
/**
* Encryption mode
*
@ -393,6 +401,7 @@ class Crypt_RSA {
$this->hLen = $this->hash->getLength();
$this->hashName = 'sha1';
$this->mgfHash = new Crypt_Hash('sha1');
$this->mgfHLen = $this->mgfHash->getLength();
}
/**
@ -409,7 +418,7 @@ class Crypt_RSA {
* @param optional Integer $timeout
* @param optional Math_BigInteger $p
*/
function createKey($bits = 1024, $timeout = false, $primes = array())
function createKey($bits = 1024, $timeout = false, $partial = array())
{
if ( CRYPT_RSA_MODE == CRYPT_RSA_MODE_OPENSSL ) {
$rsa = openssl_pkey_new(array('private_key_bits' => $bits));
@ -460,15 +469,19 @@ class Crypt_RSA {
$finalMax = $max;
extract($this->_generateMinMax($temp));
$exponents = $coefficients = array();
$generator = new Math_BigInteger();
$generator->setRandomGenerator('crypt_random');
$n = $this->one->copy();
if (!empty($partial)) {
extract(unserialize($partial));
} else {
$exponents = $coefficients = $primes = array();
$lcm = array(
'top' => $this->one->copy(),
'bottom' => false
);
}
$start = time();
$i0 = count($primes) + 1;
@ -479,13 +492,19 @@ class Crypt_RSA {
$timeout-= time() - $start;
$start = time();
if ($timeout <= 0) {
return array(
return serialize(array(
'privatekey' => '',
'publickey' => '',
'partialkey' => $primes
);
'partialkey' => array(
'primes' => $primes,
'coefficients' => $coefficients,
'lcm' => $lcm,
'exponents' => $exponents
)
));
}
}
if ($i == $num_primes) {
list($min, $temp) = $absoluteMin->divide($n);
if (!$temp->equals($this->zero)) {
@ -500,7 +519,12 @@ class Crypt_RSA {
return array(
'privatekey' => '',
'publickey' => '',
'partialkey' => array_slice($primes, 0, $i - 1)
'partialkey' => empty($primes) ? '' : serialize(array(
'primes' => array_slice($primes, 0, $i - 1),
'coefficients' => $coefficients,
'lcm' => $lcm,
'exponents' => $exponents
))
);
}
@ -563,7 +587,6 @@ class Crypt_RSA {
function _convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients)
{
$num_primes = count($primes);
$raw = array(
'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi
'modulus' => $n->toBytes(true),
@ -745,34 +768,80 @@ class Crypt_RSA {
implementation are part of the standard, as well.
* OpenSSL is the de facto standard. It's utilized by OpenSSH and other projects */
if (preg_match('#DEK-Info: DES-EDE3-CBC,(.+)#', $key, $matches)) {
$iv = pack('H*', trim($matches[1]));
if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) {
$iv = pack('H*', trim($matches[2]));
$symkey = pack('H*', md5($this->password . $iv)); // symkey is short for symmetric key
$symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8);
$ciphertext = base64_decode(preg_replace('#.+(\r|\n|\r\n)\1|[\r\n]|-.+-#s', '', $key));
$ciphertext = preg_replace('#.+(\r|\n|\r\n)\1|[\r\n]|-.+-#s', '', $key);
$ciphertext = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $ciphertext) ? base64_decode($ciphertext) : false;
if ($ciphertext === false) {
return false;
$ciphertext = $key;
}
switch ($matches[1]) {
case 'DES-EDE3-CBC':
if (!class_exists('Crypt_TripleDES')) {
require_once('Crypt/TripleDES.php');
}
$des = new Crypt_TripleDES();
$des->setKey($symkey);
$des->setIV($iv);
$key = $des->decrypt($ciphertext);
} else {
$key = base64_decode(preg_replace('#-.+-|[\r\n]#', '', $key));
if ($key === false) {
$crypto = new Crypt_TripleDES();
break;
case 'DES-CBC':
if (!class_exists('Crypt_DES')) {
require_once('Crypt/DES.php');
}
$crypto = new Crypt_DES();
break;
default:
return false;
}
$crypto->setKey($symkey);
$crypto->setIV($iv);
$decoded = $crypto->decrypt($ciphertext);
} else {
$decoded = preg_replace('#-.+-|[\r\n]#', '', $key);
$decoded = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $decoded) ? base64_decode($decoded) : false;
}
if ($decoded !== false) {
$key = $decoded;
}
$private = false;
$components = array();
$this->_string_shift($key); // skip over CRYPT_RSA_ASN1_SEQUENCE
$this->_decodeLength($key); // skip over the length of the above sequence
$this->_string_shift($key); // skip over CRYPT_RSA_ASN1_INTEGER
if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
return false;
}
if ($this->_decodeLength($key) != strlen($key)) {
return false;
}
$tag = ord($this->_string_shift($key));
if ($tag == CRYPT_RSA_ASN1_SEQUENCE) {
/* intended for keys for which OpenSSL's asn1parse returns the following:
0:d=0 hl=4 l= 290 cons: SEQUENCE
4:d=1 hl=2 l= 13 cons: SEQUENCE
6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
17:d=2 hl=2 l= 0 prim: NULL
19:d=1 hl=4 l= 271 prim: BIT STRING */
$this->_string_shift($key, $this->_decodeLength($key));
$this->_string_shift($key); // skip over the BIT STRING tag
$this->_decodeLength($key); // skip over the BIT STRING length
// "The initial octet shall encode, as an unsigned binary integer wtih bit 1 as the least significant bit, the number of
// unused bits in teh final subsequent octet. The number shall be in the range zero to seven."
// -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf (section 8.6.2.2)
$this->_string_shift($key);
if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
return false;
}
if ($this->_decodeLength($key) != strlen($key)) {
return false;
}
$tag = ord($this->_string_shift($key));
}
if ($tag != CRYPT_RSA_ASN1_INTEGER) {
return false;
}
$length = $this->_decodeLength($key);
$temp = $this->_string_shift($key, $length);
if (strlen($temp) != 1 || ord($temp) > 2) {
@ -783,7 +852,9 @@ class Crypt_RSA {
return $components;
}
$this->_string_shift($key); // skip over CRYPT_RSA_ASN1_INTEGER
if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_INTEGER) {
return false;
}
$length = $this->_decodeLength($key);
$components['modulus'] = new Math_BigInteger($this->_string_shift($key, $length), -256);
$this->_string_shift($key);
@ -807,11 +878,16 @@ class Crypt_RSA {
$this->_string_shift($key);
$length = $this->_decodeLength($key);
$components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($key, $length), -256));
if (!empty($key)) {
$key = substr($key, 1); // skip over CRYPT_RSA_ASN1_SEQUENCE
if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
return false;
}
$this->_decodeLength($key);
while (!empty($key)) {
$key = substr($key, 1); // skip over CRYPT_RSA_ASN1_SEQUENCE
if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
return false;
}
$this->_decodeLength($key);
$key = substr($key, 1);
$length = $this->_decodeLength($key);
@ -832,19 +908,33 @@ class Crypt_RSA {
return false;
}
$components = array();
extract(unpack('Nlength', $this->_string_shift($key, 4)));
$components['modulus'] = new Math_BigInteger($this->_string_shift($key, $length), -256);
extract(unpack('Nlength', $this->_string_shift($key, 4)));
$components['publicExponent'] = new Math_BigInteger($this->_string_shift($key, $length), -256);
$cleanup = substr($key, 0, 11) == "\0\0\0\7ssh-rsa";
return $components;
extract(unpack('Nlength', $this->_string_shift($key, 4)));
$publicExponent = new Math_BigInteger($this->_string_shift($key, $length), -256);
extract(unpack('Nlength', $this->_string_shift($key, 4)));
$modulus = new Math_BigInteger($this->_string_shift($key, $length), -256);
if ($cleanup && strlen($key)) {
extract(unpack('Nlength', $this->_string_shift($key, 4)));
return array(
'modulus' => new Math_BigInteger($this->_string_shift($key, $length), -256),
'publicExponent' => $modulus
);
} else {
return array(
'modulus' => $modulus,
'publicExponent' => $publicExponent
);
}
}
}
/**
* Loads a public or private key
*
* Returns true on success and false on failure (ie. an incorrect password was provided or the key was malformed)
*
* @access public
* @param String $key
* @param Integer $type optional
@ -852,6 +942,10 @@ class Crypt_RSA {
function loadKey($key, $type = CRYPT_RSA_PRIVATE_FORMAT_PKCS1)
{
$components = $this->_parseKey($key, $type);
if ($components === false) {
return false;
}
$this->modulus = $components['modulus'];
$this->k = strlen($this->modulus->toBytes());
$this->exponent = isset($components['privateExponent']) ? $components['privateExponent'] : $components['publicExponent'];
@ -866,6 +960,8 @@ class Crypt_RSA {
$this->coefficients = array();
$this->publicExponent = false;
}
return true;
}
/**
@ -906,7 +1002,7 @@ class Crypt_RSA {
function setPublicKey($key, $type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
{
$components = $this->_parseKey($key, $type);
if (!$this->modulus->equals($components['modulus'])) {
if (empty($this->modulus) || !$this->modulus->equals($components['modulus'])) {
return false;
}
$this->publicExponent = $components['publicExponent'];
@ -926,6 +1022,10 @@ class Crypt_RSA {
*/
function getPublicKey($type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
{
if (empty($this->modulus) || empty($this->publicExponent)) {
return false;
}
$oldFormat = $this->publicKeyFormat;
$this->publicKeyFormat = $type;
$temp = $this->_convertPublicKey($this->modulus, $this->publicExponent);
@ -945,7 +1045,7 @@ class Crypt_RSA {
$bytes = $bits >> 3;
$min = str_repeat(chr(0), $bytes);
$max = str_repeat(chr(0xFF), $bytes);
$msb = $num_bits & 7;
$msb = $bits & 7;
if ($msb) {
$min = chr(1 << ($msb - 1)) . $min;
$max = chr((1 << $msb) - 1) . $max;
@ -975,7 +1075,6 @@ class Crypt_RSA {
if ( $length & 0x80 ) { // definite length, long form
$length&= 0x7F;
$temp = $this->_string_shift($string, $length);
$start+= $length;
list(, $length) = unpack('N', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4));
}
return $length;
@ -1062,14 +1161,13 @@ class Crypt_RSA {
case 'sha384':
case 'sha512':
$this->hash = new Crypt_Hash($hash);
$this->hLen = $this->hash->getLength();
$this->hashName = $hash;
break;
default:
$this->hash = new Crypt_Hash('sha1');
$this->hLen = $this->hash->getLength();
$this->hashName = 'sha1';
}
$this->hLen = $this->hash->getLength();
}
/**
@ -1096,6 +1194,7 @@ class Crypt_RSA {
default:
$this->mgfHash = new Crypt_Hash('sha1');
}
$this->mgfHLen = $this->mgfHash->getLength();
}
/**
@ -1189,6 +1288,8 @@ class Crypt_RSA {
}
$num_primes = count($this->primes);
if (defined('CRYPT_RSA_DISABLE_BLINDING')) {
$m_i = array(
1 => $x->modPow($this->exponents[1], $this->primes[1]),
2 => $x->modPow($this->exponents[2], $this->primes[2])
@ -1210,10 +1311,70 @@ class Crypt_RSA {
$m = $m->add($r->multiply($h));
}
} else {
$smallest = $this->primes[1];
for ($i = 2; $i <= $num_primes; $i++) {
if ($smallest->compare($this->primes[$i]) > 0) {
$smallest = $this->primes[$i];
}
}
$one = new Math_BigInteger(1);
$one->setRandomGenerator('crypt_random');
$r = $one->random($one, $smallest->subtract($one));
$m_i = array(
1 => $this->_blind($x, $r, 1),
2 => $this->_blind($x, $r, 2)
);
$h = $m_i[1]->subtract($m_i[2]);
$h = $h->multiply($this->coefficients[2]);
list(, $h) = $h->divide($this->primes[1]);
$m = $m_i[2]->add($h->multiply($this->primes[2]));
$r = $this->primes[1];
for ($i = 3; $i <= $num_primes; $i++) {
$m_i = $this->_blind($x, $r, $i);
$r = $r->multiply($this->primes[$i - 1]);
$h = $m_i->subtract($m);
$h = $h->multiply($this->coefficients[$i]);
list(, $h) = $h->divide($this->primes[$i]);
$m = $m->add($r->multiply($h));
}
}
return $m;
}
/**
* Performs RSA Blinding
*
* Protects against timing attacks by employing RSA Blinding.
* Returns $x->modPow($this->exponents[$i], $this->primes[$i])
*
* @access private
* @param Math_BigInteger $x
* @param Math_BigInteger $r
* @param Integer $i
* @return Math_BigInteger
*/
function _blind($x, $r, $i)
{
$x = $x->multiply($r->modPow($this->publicExponent, $this->primes[$i]));
$x = $x->modPow($this->exponents[$i], $this->primes[$i]);
$r = $r->modInverse($this->primes[$i]);
$x = $x->multiply($r);
list(, $x) = $x->divide($this->primes[$i]);
return $x;
}
/**
* RSAEP
*
@ -1289,7 +1450,7 @@ class Crypt_RSA {
/**
* MGF1
*
* See {@link http://tools.ietf.org/html/rfc3447#section-B.2.1 RFC3447#section-B.2.1}.
* See {@link http://tools.ietf.org/html/rfc3447#appendix-B.2.1 RFC3447#appendix-B.2.1}.
*
* @access private
* @param String $mgfSeed
@ -1301,7 +1462,7 @@ class Crypt_RSA {
// if $maskLen would yield strings larger than 4GB, PKCS#1 suggests a "Mask too long" error be output.
$t = '';
$count = ceil($maskLen / $this->hLen);
$count = ceil($maskLen / $this->mgfHLen);
for ($i = 0; $i < $count; $i++) {
$c = pack('N', $i);
$t.= $this->mgfHash->hash($mgfSeed . $c);
@ -1789,7 +1950,7 @@ class Crypt_RSA {
// Compare
return $em == $em2;
return $em === $em2;
}
/**
@ -1834,7 +1995,12 @@ class Crypt_RSA {
{
switch ($this->encryptionMode) {
case CRYPT_RSA_ENCRYPTION_PKCS1:
$plaintext = str_split($plaintext, $this->k - 11);
$length = $this->k - 11;
if ($length <= 0) {
return false;
}
$plaintext = str_split($plaintext, $length);
$ciphertext = '';
foreach ($plaintext as $m) {
$ciphertext.= $this->_rsaes_pkcs1_v1_5_encrypt($m);
@ -1842,7 +2008,12 @@ class Crypt_RSA {
return $ciphertext;
//case CRYPT_RSA_ENCRYPTION_OAEP:
default:
$plaintext = str_split($plaintext, $this->k - 2 * $this->hLen - 2);
$length = $this->k - 2 * $this->hLen - 2;
if ($length <= 0) {
return false;
}
$plaintext = str_split($plaintext, $length);
$ciphertext = '';
foreach ($plaintext as $m) {
$ciphertext.= $this->_rsaes_oaep_encrypt($m);
@ -1861,32 +2032,32 @@ class Crypt_RSA {
*/
function decrypt($ciphertext)
{
if ($this->k <= 0) {
return false;
}
$ciphertext = str_split($ciphertext, $this->k);
$plaintext = '';
switch ($this->encryptionMode) {
case CRYPT_RSA_ENCRYPTION_PKCS1:
$ciphertext = str_split($ciphertext, $this->k);
$plaintext = '';
foreach ($ciphertext as $c) {
$temp = $this->_rsaes_pkcs1_v1_5_decrypt($c);
if ($temp === false) {
return false;
}
$plaintext.= $temp;
}
return $plaintext;
$decrypt = '_rsaes_pkcs1_v1_5_decrypt';
break;
//case CRYPT_RSA_ENCRYPTION_OAEP:
default:
$ciphertext = str_split($ciphertext, $this->k);
$plaintext = '';
$decrypt = '_rsaes_oaep_decrypt';
}
foreach ($ciphertext as $c) {
$temp = $this->_rsaes_oaep_decrypt($c);
$temp = $this->$decrypt($c);
if ($temp === false) {
return false;
}
$plaintext.= $temp;
}
return $plaintext;
}
}
/**
* Create a signature
@ -1898,6 +2069,10 @@ class Crypt_RSA {
*/
function sign($message)
{
if (empty($this->modulus) || empty($this->exponent)) {
return false;
}
switch ($this->signatureMode) {
case CRYPT_RSA_SIGNATURE_PKCS1:
return $this->_rsassa_pkcs1_v1_5_sign($message);
@ -1918,6 +2093,10 @@ class Crypt_RSA {
*/
function verify($message, $signature)
{
if (empty($this->modulus) || empty($this->exponent)) {
return false;
}
switch ($this->signatureMode) {
case CRYPT_RSA_SIGNATURE_PKCS1:
return $this->_rsassa_pkcs1_v1_5_verify($message, $signature);

View File

@ -35,36 +35,91 @@
* @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVII Jim Wigginton
* @license http://www.gnu.org/licenses/lgpl.txt
* @version $Id: Random.php,v 1.4 2008/05/21 05:15:32 terrafrost Exp $
* @version $Id: Random.php,v 1.6 2010/02/28 05:28:38 terrafrost Exp $
* @link http://phpseclib.sourceforge.net
*/
/**
* Generate a random value. Feel free to replace this function with a cryptographically secure PRNG.
* Generate a random value.
*
* On 32-bit machines, the largest distance that can exist between $min and $max is 2**31.
* If $min and $max are farther apart than that then the last ($max - range) numbers.
*
* Depending on how this is being used, it may be worth while to write a replacement. For example,
* a PHP-based web app that stores its data in an SQL database can collect more entropy than this function
* can.
*
* @param optional Integer $min
* @param optional Integer $max
* @param optional String $randomness_path
* @return Integer
* @access public
*/
function crypt_random($min = 0, $max = 0x7FFFFFFF, $randomness_path = '/dev/urandom')
function crypt_random($min = 0, $max = 0x7FFFFFFF)
{
static $seeded = false;
if ($min == $max) {
return $min;
}
if (!$seeded) {
$seeded = true;
if (file_exists($randomness_path)) {
$fp = fopen($randomness_path, 'r');
$temp = unpack('Nint', fread($fp, 4));
mt_srand($temp['int']);
// see http://en.wikipedia.org/wiki//dev/random
if (file_exists('/dev/urandom')) {
$fp = fopen('/dev/urandom', 'rb');
extract(unpack('Nrandom', fread($fp, 4)));
fclose($fp);
} else {
list($sec, $usec) = explode(' ', microtime());
mt_srand((float) $sec + ((float) $usec * 100000));
// say $min = 0 and $max = 3. if we didn't do abs() then we could have stuff like this:
// -4 % 3 + 0 = -1, even though -1 < $min
return abs($random) % ($max - $min) + $min;
}
/* Prior to PHP 4.2.0, mt_srand() had to be called before mt_rand() could be called.
Prior to PHP 5.2.6, mt_rand()'s automatic seeding was subpar, as elaborated here:
http://www.suspekt.org/2008/08/17/mt_srand-and-not-so-random-numbers/
The seeding routine is pretty much ripped from PHP's own internal GENERATE_SEED() macro:
http://svn.php.net/viewvc/php/php-src/branches/PHP_5_3_2/ext/standard/php_rand.h?view=markup */
if (version_compare(PHP_VERSION, '5.2.5', '<=')) {
static $seeded;
if (!isset($seeded)) {
$seeded = true;
mt_srand(fmod(time() * getmypid(), 0x7FFFFFFF) ^ fmod(1000000 * lcg_value(), 0x7FFFFFFF));
}
}
return mt_rand($min, $max);
static $crypto;
// The CSPRNG's Yarrow and Fortuna periodically reseed. This function can be reseeded by hitting F5
// in the browser and reloading the page.
if (!isset($crypto)) {
$key = $iv = '';
for ($i = 0; $i < 8; $i++) {
$key.= pack('n', mt_rand(0, 0xFFFF));
$iv .= pack('n', mt_rand(0, 0xFFFF));
}
switch (true) {
case class_exists('Crypt_AES'):
$crypto = new Crypt_AES(CRYPT_AES_MODE_CTR);
break;
case class_exists('Crypt_TripleDES'):
$crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CTR);
break;
case class_exists('Crypt_DES'):
$crypto = new Crypt_DES(CRYPT_DES_MODE_CTR);
break;
case class_exists('Crypt_RC4'):
$crypto = new Crypt_RC4();
break;
default:
extract(unpack('Nrandom', pack('H*', sha1(mt_rand(0, 0x7FFFFFFF)))));
return abs($random) % ($max - $min) + $min;
}
$crypto->setKey($key);
$crypto->setIV($iv);
}
extract(unpack('Nrandom', $crypto->encrypt("\0\0\0\0")));
return abs($random) % ($max - $min) + $min;
}
?>

View File

@ -64,7 +64,7 @@
* @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVIII Jim Wigginton
* @license http://www.gnu.org/licenses/lgpl.txt
* @version $Id: Rijndael.php,v 1.8 2009/11/23 19:06:07 terrafrost Exp $
* @version $Id: Rijndael.php,v 1.12 2010/02/09 06:10:26 terrafrost Exp $
* @link http://phpseclib.sourceforge.net
*/
@ -73,6 +73,14 @@
* @see Crypt_Rijndael::encrypt()
* @see Crypt_Rijndael::decrypt()
*/
/**
* Encrypt / decrypt using the Counter mode.
*
* Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
*/
define('CRYPT_RIJNDAEL_MODE_CTR', -1);
/**
* Encrypt / decrypt using the Electronic Code Book mode.
*
@ -363,16 +371,27 @@ class Crypt_Rijndael {
switch ($mode) {
case CRYPT_RIJNDAEL_MODE_ECB:
case CRYPT_RIJNDAEL_MODE_CBC:
case CRYPT_RIJNDAEL_MODE_CTR:
$this->mode = $mode;
break;
default:
$this->mode = CRYPT_RIJNDAEL_MODE_CBC;
}
$t3 = &$this->t3;
$t2 = &$this->t2;
$t1 = &$this->t1;
$t0 = &$this->t0;
$dt3 = &$this->dt3;
$dt2 = &$this->dt2;
$dt1 = &$this->dt1;
$dt0 = &$this->dt0;
// according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=19> (section 5.2.1),
// precomputed tables can be used in the mixColumns phase. in that example, they're assigned t0...t3, so
// those are the names we'll use.
$this->t3 = array(
$t3 = array(
0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491,
0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC,
0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB,
@ -407,7 +426,7 @@ class Crypt_Rijndael {
0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C
);
$this->dt3 = array(
$dt3 = array(
0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B,
0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5,
0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B,
@ -443,13 +462,13 @@ class Crypt_Rijndael {
);
for ($i = 0; $i < 256; $i++) {
$this->t2[$i << 8] = (($this->t3[$i] << 8) & 0xFFFFFF00) | (($this->t3[$i] >> 24) & 0x000000FF);
$this->t1[$i << 16] = (($this->t3[$i] << 16) & 0xFFFF0000) | (($this->t3[$i] >> 16) & 0x0000FFFF);
$this->t0[$i << 24] = (($this->t3[$i] << 24) & 0xFF000000) | (($this->t3[$i] >> 8) & 0x00FFFFFF);
$t2[$i << 8] = (($t3[$i] << 8) & 0xFFFFFF00) | (($t3[$i] >> 24) & 0x000000FF);
$t1[$i << 16] = (($t3[$i] << 16) & 0xFFFF0000) | (($t3[$i] >> 16) & 0x0000FFFF);
$t0[$i << 24] = (($t3[$i] << 24) & 0xFF000000) | (($t3[$i] >> 8) & 0x00FFFFFF);
$this->dt2[$i << 8] = (($this->dt3[$i] << 8) & 0xFFFFFF00) | (($this->dt3[$i] >> 24) & 0x000000FF);
$this->dt1[$i << 16] = (($this->dt3[$i] << 16) & 0xFFFF0000) | (($this->dt3[$i] >> 16) & 0x0000FFFF);
$this->dt0[$i << 24] = (($this->dt3[$i] << 24) & 0xFF000000) | (($this->dt3[$i] >> 8) & 0x00FFFFFF);
$dt2[$i << 8] = (($this->dt3[$i] << 8) & 0xFFFFFF00) | (($dt3[$i] >> 24) & 0x000000FF);
$dt1[$i << 16] = (($this->dt3[$i] << 16) & 0xFFFF0000) | (($dt3[$i] >> 16) & 0x0000FFFF);
$dt0[$i << 24] = (($this->dt3[$i] << 24) & 0xFF000000) | (($dt3[$i] >> 8) & 0x00FFFFFF);
}
}
@ -532,6 +551,45 @@ class Crypt_Rijndael {
$this->changed = true;
}
/**
* Generate CTR XOR encryption key
*
* Encrypt the output of this and XOR it against the ciphertext / plaintext to get the
* plaintext / ciphertext in CTR mode.
*
* @see Crypt_Rijndael::decrypt()
* @see Crypt_Rijndael::encrypt()
* @access public
* @param Integer $length
* @param String $iv
*/
function _generate_xor($length, &$iv)
{
$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;
}
}
}
return $xor;
}
/**
* Encrypts a message.
*
@ -553,19 +611,22 @@ class Crypt_Rijndael {
function encrypt($plaintext)
{
$this->_setup();
if ($this->mode != CRYPT_RIJNDAEL_MODE_CTR) {
$plaintext = $this->_pad($plaintext);
}
$block_size = $this->block_size;
$ciphertext = '';
switch ($this->mode) {
case CRYPT_RIJNDAEL_MODE_ECB:
for ($i = 0; $i < strlen($plaintext); $i+=$this->block_size) {
$ciphertext.= $this->_encryptBlock(substr($plaintext, $i, $this->block_size));
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
$ciphertext.= $this->_encryptBlock(substr($plaintext, $i, $block_size));
}
break;
case CRYPT_RIJNDAEL_MODE_CBC:
$xor = $this->encryptIV;
for ($i = 0; $i < strlen($plaintext); $i+=$this->block_size) {
$block = substr($plaintext, $i, $this->block_size);
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
$block = substr($plaintext, $i, $block_size);
$block = $this->_encryptBlock($block ^ $xor);
$xor = $block;
$ciphertext.= $block;
@ -573,6 +634,17 @@ class Crypt_Rijndael {
if ($this->continuousBuffer) {
$this->encryptIV = $xor;
}
break;
case CRYPT_RIJNDAEL_MODE_CTR:
$xor = $this->encryptIV;
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
$block = substr($plaintext, $i, $block_size);
$key = $this->_encryptBlock($this->_generate_xor($block_size, $xor));
$ciphertext.= $block ^ $key;
}
if ($this->continuousBuffer) {
$this->encryptIV = $xor;
}
}
return $ciphertext;
@ -591,30 +663,45 @@ class Crypt_Rijndael {
function decrypt($ciphertext)
{
$this->_setup();
if ($this->mode != CRYPT_RIJNDAEL_MODE_CTR) {
// 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) + $this->block_size - 1) % $this->block_size, chr(0));
}
$block_size = $this->block_size;
$plaintext = '';
switch ($this->mode) {
case CRYPT_RIJNDAEL_MODE_ECB:
for ($i = 0; $i < strlen($ciphertext); $i+=$this->block_size) {
$plaintext.= $this->_decryptBlock(substr($ciphertext, $i, $this->block_size));
for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
$plaintext.= $this->_decryptBlock(substr($ciphertext, $i, $block_size));
}
break;
case CRYPT_RIJNDAEL_MODE_CBC:
$xor = $this->decryptIV;
for ($i = 0; $i < strlen($ciphertext); $i+=$this->block_size) {
$block = substr($ciphertext, $i, $this->block_size);
for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
$block = substr($ciphertext, $i, $block_size);
$plaintext.= $this->_decryptBlock($block) ^ $xor;
$xor = $block;
}
if ($this->continuousBuffer) {
$this->decryptIV = $xor;
}
break;
case CRYPT_RIJNDAEL_MODE_CTR:
$xor = $this->decryptIV;
for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
$block = substr($ciphertext, $i, $block_size);
$key = $this->_encryptBlock($this->_generate_xor($block_size, $xor));
$plaintext.= $block ^ $key;
}
if ($this->continuousBuffer) {
$this->decryptIV = $xor;
}
}
return $this->_unpad($plaintext);
return $this->mode != CRYPT_RIJNDAEL_MODE_CTR ? $this->_unpad($plaintext) : $plaintext;
}
/**
@ -629,9 +716,19 @@ class Crypt_Rijndael {
$state = array();
$words = unpack('N*word', $in);
$w = $this->w;
$t0 = $this->t0;
$t1 = $this->t1;
$t2 = $this->t2;
$t3 = $this->t3;
$Nb = $this->Nb;
$Nr = $this->Nr;
$c = $this->c;
// addRoundKey
$i = 0;
foreach ($words as $word) {
$state[] = $word ^ $this->w[0][count($state)];
$state[] = $word ^ $w[0][$i++];
}
// fips-197.pdf#page=19, "Figure 5. Pseudo Code for the Cipher", states that this loop has four components -
@ -643,49 +740,49 @@ class Crypt_Rijndael {
// [1] http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.v316.pdf
$temp = array();
for ($round = 1; $round < $this->Nr; $round++) {
$i = 0; // $this->c[0] == 0
$j = $this->c[1];
$k = $this->c[2];
$l = $this->c[3];
for ($round = 1; $round < $Nr; $round++) {
$i = 0; // $c[0] == 0
$j = $c[1];
$k = $c[2];
$l = $c[3];
while ($i < $this->Nb) {
$temp[$i] = $this->t0[$state[$i] & 0xFF000000] ^
$this->t1[$state[$j] & 0x00FF0000] ^
$this->t2[$state[$k] & 0x0000FF00] ^
$this->t3[$state[$l] & 0x000000FF] ^
$this->w[$round][$i];
$temp[$i] = $t0[$state[$i] & 0xFF000000] ^
$t1[$state[$j] & 0x00FF0000] ^
$t2[$state[$k] & 0x0000FF00] ^
$t3[$state[$l] & 0x000000FF] ^
$w[$round][$i];
$i++;
$j = ($j + 1) % $this->Nb;
$k = ($k + 1) % $this->Nb;
$l = ($l + 1) % $this->Nb;
$j = ($j + 1) % $Nb;
$k = ($k + 1) % $Nb;
$l = ($l + 1) % $Nb;
}
for ($i = 0; $i < $this->Nb; $i++) {
for ($i = 0; $i < $Nb; $i++) {
$state[$i] = $temp[$i];
}
}
// subWord
for ($i = 0; $i < $this->Nb; $i++) {
for ($i = 0; $i < $Nb; $i++) {
$state[$i] = $this->_subWord($state[$i]);
}
// shiftRows + addRoundKey
$i = 0; // $this->c[0] == 0
$j = $this->c[1];
$k = $this->c[2];
$l = $this->c[3];
$i = 0; // $c[0] == 0
$j = $c[1];
$k = $c[2];
$l = $c[3];
while ($i < $this->Nb) {
$temp[$i] = ($state[$i] & 0xFF000000) ^
($state[$j] & 0x00FF0000) ^
($state[$k] & 0x0000FF00) ^
($state[$l] & 0x000000FF) ^
$this->w[$this->Nr][$i];
$w[$Nr][$i];
$i++;
$j = ($j + 1) % $this->Nb;
$k = ($k + 1) % $this->Nb;
$l = ($l + 1) % $this->Nb;
$j = ($j + 1) % $Nb;
$k = ($k + 1) % $Nb;
$l = ($l + 1) % $Nb;
}
$state = $temp;
@ -706,51 +803,62 @@ class Crypt_Rijndael {
$state = array();
$words = unpack('N*word', $in);
$num_states = count($state);
$dw = $this->dw;
$dt0 = $this->dt0;
$dt1 = $this->dt1;
$dt2 = $this->dt2;
$dt3 = $this->dt3;
$Nb = $this->Nb;
$Nr = $this->Nr;
$c = $this->c;
// addRoundKey
$i = 0;
foreach ($words as $word) {
$state[] = $word ^ $this->dw[0][count($state)];
$state[] = $word ^ $dw[$Nr][$i++];
}
$temp = array();
for ($round = $this->Nr - 1; $round > 0; $round--) {
$i = 0; // $this->c[0] == 0
$j = $this->Nb - $this->c[1];
$k = $this->Nb - $this->c[2];
$l = $this->Nb - $this->c[3];
for ($round = $Nr - 1; $round > 0; $round--) {
$i = 0; // $c[0] == 0
$j = $Nb - $c[1];
$k = $Nb - $c[2];
$l = $Nb - $c[3];
while ($i < $this->Nb) {
$temp[$i] = $this->dt0[$state[$i] & 0xFF000000] ^
$this->dt1[$state[$j] & 0x00FF0000] ^
$this->dt2[$state[$k] & 0x0000FF00] ^
$this->dt3[$state[$l] & 0x000000FF] ^
$this->dw[$round][$i];
while ($i < $Nb) {
$temp[$i] = $dt0[$state[$i] & 0xFF000000] ^
$dt1[$state[$j] & 0x00FF0000] ^
$dt2[$state[$k] & 0x0000FF00] ^
$dt3[$state[$l] & 0x000000FF] ^
$dw[$round][$i];
$i++;
$j = ($j + 1) % $this->Nb;
$k = ($k + 1) % $this->Nb;
$l = ($l + 1) % $this->Nb;
$j = ($j + 1) % $Nb;
$k = ($k + 1) % $Nb;
$l = ($l + 1) % $Nb;
}
for ($i = 0; $i < $this->Nb; $i++) {
for ($i = 0; $i < $Nb; $i++) {
$state[$i] = $temp[$i];
}
}
// invShiftRows + invSubWord + addRoundKey
$i = 0; // $this->c[0] == 0
$j = $this->Nb - $this->c[1];
$k = $this->Nb - $this->c[2];
$l = $this->Nb - $this->c[3];
$i = 0; // $c[0] == 0
$j = $Nb - $c[1];
$k = $Nb - $c[2];
$l = $Nb - $c[3];
while ($i < $this->Nb) {
$temp[$i] = $this->dw[0][$i] ^
while ($i < $Nb) {
$temp[$i] = $dw[0][$i] ^
$this->_invSubWord(($state[$i] & 0xFF000000) |
($state[$j] & 0x00FF0000) |
($state[$k] & 0x0000FF00) |
($state[$l] & 0x000000FF));
$i++;
$j = ($j + 1) % $this->Nb;
$k = ($k + 1) % $this->Nb;
$l = ($l + 1) % $this->Nb;
$j = ($j + 1) % $Nb;
$k = ($k + 1) % $Nb;
$l = ($l + 1) % $Nb;
}
$state = $temp;
@ -1034,7 +1142,8 @@ class Crypt_Rijndael {
/**
* Unpads a string.
*
* If padding is enabled and the reported padding length is invalid, padding will be, hence forth, disabled.
* If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
* and false will be returned.
*
* @see Crypt_Rijndael::_pad()
* @access private
@ -1048,9 +1157,7 @@ class Crypt_Rijndael {
$length = ord($text[strlen($text) - 1]);
if (!$length || $length > $this->block_size) {
user_error("The number of bytes reported as being padded ($length) is invalid (block size = {$this->block_size})", E_USER_NOTICE);
$this->padding = false;
return $text;
return false;
}
return substr($text, 0, -$length);

View File

@ -47,7 +47,7 @@
* @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVII Jim Wigginton
* @license http://www.gnu.org/licenses/lgpl.txt
* @version $Id: TripleDES.php,v 1.9 2009/11/23 19:06:07 terrafrost Exp $
* @version $Id: TripleDES.php,v 1.13 2010/02/26 03:40:25 terrafrost Exp $
* @link http://phpseclib.sourceforge.net
*/
@ -142,15 +142,6 @@ class Crypt_TripleDES {
*/
var $decryptIV = "\0\0\0\0\0\0\0\0";
/**
* MCrypt parameters
*
* @see Crypt_TripleDES::setMCrypt()
* @var Array
* @access private
*/
var $mcrypt = array('', '');
/**
* The Crypt_DES objects
*
@ -159,6 +150,40 @@ class Crypt_TripleDES {
*/
var $des;
/**
* mcrypt resource for encryption
*
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
*
* @see Crypt_AES::encrypt()
* @var String
* @access private
*/
var $enmcrypt;
/**
* mcrypt resource for decryption
*
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
*
* @see Crypt_AES::decrypt()
* @var String
* @access private
*/
var $demcrypt;
/**
* Does the (en|de)mcrypt resource need to be (re)initialized?
*
* @see setKey()
* @see setIV()
* @var Boolean
* @access private
*/
var $changed = true;
/**
* Default Constructor.
*
@ -204,7 +229,11 @@ class Crypt_TripleDES {
case CRYPT_DES_MODE_MCRYPT:
switch ($mode) {
case CRYPT_DES_MODE_ECB:
$this->mode = MCRYPT_MODE_ECB; break;
$this->mode = MCRYPT_MODE_ECB;
break;
case CRYPT_DES_MODE_CTR:
$this->mode = 'ctr';
break;
case CRYPT_DES_MODE_CBC:
default:
$this->mode = MCRYPT_MODE_CBC;
@ -225,6 +254,7 @@ class Crypt_TripleDES {
switch ($mode) {
case CRYPT_DES_MODE_ECB:
case CRYPT_DES_MODE_CTR:
case CRYPT_DES_MODE_CBC:
$this->mode = $mode;
break;
@ -254,7 +284,7 @@ class Crypt_TripleDES {
$key = str_pad($key, 24, chr(0));
// if $key is between 64 and 128-bits, use the first 64-bits as the last, per this:
// http://php.net/function.mcrypt-encrypt#47973
$key = $length <= 16 ? substr_replace($key, substr($key, 0, 8), 16) : substr($key, 0, 24);
//$key = $length <= 16 ? substr_replace($key, substr($key, 0, 8), 16) : substr($key, 0, 24);
}
$this->key = $key;
switch (true) {
@ -264,6 +294,7 @@ class Crypt_TripleDES {
$this->des[1]->setKey(substr($key, 8, 8));
$this->des[2]->setKey(substr($key, 16, 8));
}
$this->changed = true;
}
/**
@ -283,27 +314,46 @@ class Crypt_TripleDES {
$this->des[1]->setIV($iv);
$this->des[2]->setIV($iv);
}
$this->changed = true;
}
/**
* Sets MCrypt parameters. (optional)
* Generate CTR XOR encryption key
*
* If MCrypt is being used, empty strings will be used, unless otherwise specified.
* Encrypt the output of this and XOR it against the ciphertext / plaintext to get the
* plaintext / ciphertext in CTR mode.
*
* @link http://php.net/function.mcrypt-module-open#function.mcrypt-module-open
* @see Crypt_DES::decrypt()
* @see Crypt_DES::encrypt()
* @access public
* @param optional Integer $algorithm_directory
* @param optional Integer $mode_directory
* @param Integer $length
* @param String $iv
*/
function setMCrypt($algorithm_directory = '', $mode_directory = '')
function _generate_xor($length, &$iv)
{
$this->mcrypt = array($algorithm_directory, $mode_directory);
if ( $this->mode == CRYPT_DES_MODE_3CBC ) {
$this->des[0]->setMCrypt($algorithm_directory, $mode_directory);
$this->des[1]->setMCrypt($algorithm_directory, $mode_directory);
$this->des[2]->setMCrypt($algorithm_directory, $mode_directory);
$xor = '';
$num_blocks = ($length + 7) >> 3;
for ($i = 0; $i < $num_blocks; $i++) {
$xor.= $iv;
for ($j = 4; $j <= 8; $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;
}
}
}
return $xor;
}
/**
* Encrypts a message.
@ -313,7 +363,9 @@ class Crypt_TripleDES {
*/
function encrypt($plaintext)
{
if ($this->mode != CRYPT_DES_MODE_CTR && $this->mode != 'ctr') {
$plaintext = $this->_pad($plaintext);
}
// if the key is smaller then 8, do what we'd normally do
if ($this->mode == CRYPT_DES_MODE_3CBC && strlen($this->key) > 8) {
@ -323,16 +375,18 @@ class Crypt_TripleDES {
}
if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) {
$td = mcrypt_module_open(MCRYPT_3DES, $this->mcrypt[0], $this->mode, $this->mcrypt[1]);
mcrypt_generic_init($td, $this->key, $this->encryptIV);
if ($this->changed) {
if (!isset($this->enmcrypt)) {
$this->enmcrypt = mcrypt_module_open(MCRYPT_3DES, '', $this->mode, '');
}
mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
$this->changed = false;
}
$ciphertext = mcrypt_generic($td, $plaintext);
$ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
if ($this->continuousBuffer) {
$this->encryptIV = substr($ciphertext, -8);
if (!$this->continuousBuffer) {
mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
}
return $ciphertext;
@ -348,14 +402,16 @@ class Crypt_TripleDES {
// "The data is padded with "\0" to make sure the length of the data is n * blocksize."
$plaintext = str_pad($plaintext, ceil(strlen($plaintext) / 8) * 8, chr(0));
$des = $this->des;
$ciphertext = '';
switch ($this->mode) {
case CRYPT_DES_MODE_ECB:
for ($i = 0; $i < strlen($plaintext); $i+=8) {
$block = substr($plaintext, $i, 8);
$block = $this->des[0]->_processBlock($block, CRYPT_DES_ENCRYPT);
$block = $this->des[1]->_processBlock($block, CRYPT_DES_DECRYPT);
$block = $this->des[2]->_processBlock($block, CRYPT_DES_ENCRYPT);
$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;
@ -363,15 +419,29 @@ class Crypt_TripleDES {
$xor = $this->encryptIV;
for ($i = 0; $i < strlen($plaintext); $i+=8) {
$block = substr($plaintext, $i, 8) ^ $xor;
$block = $this->des[0]->_processBlock($block, CRYPT_DES_ENCRYPT);
$block = $this->des[1]->_processBlock($block, CRYPT_DES_DECRYPT);
$block = $this->des[2]->_processBlock($block, CRYPT_DES_ENCRYPT);
$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;
for ($i = 0; $i < strlen($plaintext); $i+=8) {
$key = $this->_generate_xor(8, $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);
$block = substr($plaintext, $i, 8);
$ciphertext.= $block ^ $key;
}
if ($this->continuousBuffer) {
$this->encryptIV = $xor;
}
}
return $ciphertext;
@ -396,19 +466,21 @@ class Crypt_TripleDES {
$ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, chr(0));
if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) {
$td = mcrypt_module_open(MCRYPT_3DES, $this->mcrypt[0], $this->mode, $this->mcrypt[1]);
mcrypt_generic_init($td, $this->key, $this->decryptIV);
$plaintext = mdecrypt_generic($td, $ciphertext);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
if ($this->continuousBuffer) {
$this->decryptIV = substr($ciphertext, -8);
if ($this->changed) {
if (!isset($this->demcrypt)) {
$this->demcrypt = mcrypt_module_open(MCRYPT_3DES, '', $this->mode, '');
}
mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
$this->changed = false;
}
return $this->_unpad($plaintext);
$plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
if (!$this->continuousBuffer) {
mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
}
return $this->mode != 'ctr' ? $this->_unpad($plaintext) : $plaintext;
}
if (strlen($this->key) <= 8) {
@ -417,14 +489,16 @@ class Crypt_TripleDES {
return $this->_unpad($this->des[0]->decrypt($plaintext));
}
$des = $this->des;
$plaintext = '';
switch ($this->mode) {
case CRYPT_DES_MODE_ECB:
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
$block = substr($ciphertext, $i, 8);
$block = $this->des[2]->_processBlock($block, CRYPT_DES_DECRYPT);
$block = $this->des[1]->_processBlock($block, CRYPT_DES_ENCRYPT);
$block = $this->des[0]->_processBlock($block, CRYPT_DES_DECRYPT);
$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;
@ -432,18 +506,32 @@ class Crypt_TripleDES {
$xor = $this->decryptIV;
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
$orig = $block = substr($ciphertext, $i, 8);
$block = $this->des[2]->_processBlock($block, CRYPT_DES_DECRYPT);
$block = $this->des[1]->_processBlock($block, CRYPT_DES_ENCRYPT);
$block = $this->des[0]->_processBlock($block, CRYPT_DES_DECRYPT);
$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;
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
$key = $this->_generate_xor(8, $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);
$block = substr($ciphertext, $i, 8);
$plaintext.= $block ^ $key;
}
if ($this->continuousBuffer) {
$this->decryptIV = $xor;
}
}
return $this->_unpad($plaintext);
return $this->mode != CRYPT_DES_MODE_CTR ? $this->_unpad($plaintext) : $plaintext;
}
/**
@ -576,7 +664,8 @@ class Crypt_TripleDES {
/**
* Unpads a string
*
* If padding is enabled and the reported padding length is invalid, padding will be, hence forth, disabled.
* If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
* and false will be returned.
*
* @see Crypt_TripleDES::_pad()
* @access private
@ -590,9 +679,7 @@ class Crypt_TripleDES {
$length = ord($text[strlen($text) - 1]);
if (!$length || $length > 8) {
user_error("The number of bytes reported as being padded ($length) is invalid (block size = 8)", E_USER_NOTICE);
$this->padding = false;
return $text;
return false;
}
return substr($text, 0, -$length);

File diff suppressed because it is too large Load Diff