- removed setMCrypt from the Crypt_* objects (you can achieve the same effect by doing ini_set('mcrypt.algorithms_dir', $path))

- added support for CTR mode to the various Crypt_* objects


git-svn-id: http://phpseclib.svn.sourceforge.net/svnroot/phpseclib/trunk@83 21d32557-59b3-4da0-833f-c5933fad653e
This commit is contained in:
Jim Wigginton 2010-02-09 06:10:26 +00:00
parent ea4fd863d4
commit d77c85218d
5 changed files with 504 additions and 153 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.6 2010-01-04 07:59:01 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);
/*
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 = $iv;
}
return $ciphertext;
}
*/
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, $this->mcrypt[0], $this->mode, $this->mcrypt[1]);
mcrypt_generic_init($td, $this->key, $this->encryptIV);
if ($this->mode != 'ctr') {
$plaintext = $this->_pad($plaintext);
}
$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, -16);
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)
{
// 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();
/*
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;
}
*/
$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);
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));
}
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;
}

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.11 2010-01-04 07:59:01 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)
{
$plaintext = $this->_pad($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)
{
// 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 ($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);
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;
}
return $this->_unpad($plaintext);
$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;
}
/**

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.11 2010-01-23 17:36:49 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,6 +371,7 @@ 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:
@ -542,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.
*
@ -563,19 +611,22 @@ class Crypt_Rijndael {
function encrypt($plaintext)
{
$this->_setup();
$plaintext = $this->_pad($plaintext);
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;
@ -583,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;
@ -601,30 +663,45 @@ class Crypt_Rijndael {
function decrypt($ciphertext)
{
$this->_setup();
// 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));
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;
}
/**

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.11 2010-01-04 07:59:01 terrafrost Exp $
* @version $Id: TripleDES.php,v 1.12 2010-02-09 06:10:26 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;
@ -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,26 +314,45 @@ 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;
}
/**
@ -313,7 +363,9 @@ class Crypt_TripleDES {
*/
function encrypt($plaintext)
{
$plaintext = $this->_pad($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->keys, $this->encryptIV);
}
return $ciphertext;
@ -374,6 +428,20 @@ class Crypt_TripleDES {
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;
@ -398,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->keys, $this->decryptIV);
}
return $this->mode != 'ctr' ? $this->_unpad($plaintext) : $plaintext;
}
if (strlen($this->key) <= 8) {
@ -445,9 +515,23 @@ class Crypt_TripleDES {
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;
}
/**

View File

@ -60,7 +60,7 @@
* @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVII Jim Wigginton
* @license http://www.gnu.org/licenses/lgpl.txt
* @version $Id: SSH2.php,v 1.34 2010-01-21 07:33:05 terrafrost Exp $
* @version $Id: SSH2.php,v 1.35 2010-02-09 06:10:26 terrafrost Exp $
* @link http://phpseclib.sourceforge.net
*/
@ -674,10 +674,22 @@ class Net_SSH2 {
);
static $encryption_algorithms = array(
'arcfour', // OPTIONAL the ARCFOUR stream cipher with a 128-bit key
'aes128-cbc', // RECOMMENDED AES with a 128-bit key
'aes192-cbc', // OPTIONAL AES with a 192-bit key
'aes256-cbc', // OPTIONAL AES in CBC mode, with a 256-bit key
// from <http://tools.ietf.org/html/rfc4344#section-4>:
'aes128-ctr', // RECOMMENDED AES (Rijndael) in SDCTR mode, with 128-bit key
'aes192-ctr', // RECOMMENDED AES with 192-bit key
'aes256-ctr', // RECOMMENDED AES with 256-bit key
'3des-ctr', // RECOMMENDED Three-key 3DES in SDCTR mode
// from <http://tools.ietf.org/html/rfc4345#section-4>:
// (commented out since i don't know of any ssh servers that support them and thus am unable to test them)
//'arcfour128',
//'arcfour256',
'arcfour', // OPTIONAL the ARCFOUR stream cipher with a 128-bit key
'3des-cbc', // REQUIRED three-key 3DES in CBC mode
'none' // OPTIONAL no encryption; NOT RECOMMENDED
);
@ -777,20 +789,28 @@ class Net_SSH2 {
$decrypt = $encryption_algorithms[$i];
switch ($decrypt) {
case '3des-cbc':
case '3des-ctr':
$decryptKeyLength = 24; // eg. 192 / 8
break;
case 'aes256-cbc':
case 'aes256-ctr':
$decryptKeyLength = 32; // eg. 256 / 8
break;
case 'aes192-cbc':
case 'aes192-ctr':
$decryptKeyLength = 24; // eg. 192 / 8
break;
case 'aes128-cbc':
case 'aes128-ctr':
$decryptKeyLength = 16; // eg. 128 / 8
break;
case 'arcfour':
case 'arcfour128':
$decryptKeyLength = 16; // eg. 128 / 8
break;
case 'arcfour256':
$decryptKeyLength = 32; // eg. 128 / 8
break;
case 'none';
$decryptKeyLength = 0;
}
@ -804,20 +824,28 @@ class Net_SSH2 {
$encrypt = $encryption_algorithms[$i];
switch ($encrypt) {
case '3des-cbc':
case '3des-ctr':
$encryptKeyLength = 24;
break;
case 'aes256-cbc':
case 'aes256-ctr':
$encryptKeyLength = 32;
break;
case 'aes192-cbc':
case 'aes192-ctr':
$encryptKeyLength = 24;
break;
case 'aes128-cbc':
case 'aes128-ctr':
$encryptKeyLength = 16;
break;
case 'arcfour':
case 'arcfour128':
$encryptKeyLength = 16;
break;
case 'arcfour256':
$encryptKeyLength = 32;
break;
case 'none';
$encryptKeyLength = 0;
}
@ -1073,19 +1101,25 @@ class Net_SSH2 {
$this->encrypt = new Crypt_TripleDES();
// $this->encrypt_block_size = 64 / 8 == the default
break;
case '3des-ctr':
$this->encrypt = new Crypt_TripleDES(CRYPT_DES_MODE_CTR);
// $this->encrypt_block_size = 64 / 8 == the default
break;
case 'aes256-cbc':
case 'aes192-cbc':
case 'aes128-cbc':
$this->encrypt = new Crypt_AES();
$this->encrypt_block_size = 16; // eg. 128 / 8
break;
case 'aes192-cbc':
$this->encrypt = new Crypt_AES();
$this->encrypt_block_size = 16;
break;
case 'aes128-cbc':
$this->encrypt = new Crypt_AES();
$this->encrypt_block_size = 16;
case 'aes256-ctr':
case 'aes192-ctr':
case 'aes128-ctr':
$this->encrypt = new Crypt_AES(CRYPT_AES_MODE_CTR);
$this->encrypt_block_size = 16; // eg. 128 / 8
break;
case 'arcfour':
case 'arcfour128':
case 'arcfour256':
$this->encrypt = new Crypt_RC4();
break;
case 'none';
@ -1096,19 +1130,24 @@ class Net_SSH2 {
case '3des-cbc':
$this->decrypt = new Crypt_TripleDES();
break;
case '3des-ctr':
$this->decrypt = new Crypt_TripleDES(CRYPT_DES_MODE_CTR);
break;
case 'aes256-cbc':
$this->decrypt = new Crypt_AES();
$this->decrypt_block_size = 16;
break;
case 'aes192-cbc':
$this->decrypt = new Crypt_AES();
$this->decrypt_block_size = 16;
break;
case 'aes128-cbc':
$this->decrypt = new Crypt_AES();
$this->decrypt_block_size = 16;
break;
case 'aes256-ctr':
case 'aes192-ctr':
case 'aes128-ctr':
$this->decrypt = new Crypt_AES(CRYPT_AES_MODE_CTR);
$this->decrypt_block_size = 16;
break;
case 'arcfour':
case 'arcfour128':
case 'arcfour256':
$this->decrypt = new Crypt_RC4();
break;
case 'none';
@ -1151,6 +1190,20 @@ class Net_SSH2 {
$this->decrypt->setKey(substr($key, 0, $decryptKeyLength));
}
/* The "arcfour128" algorithm is the RC4 cipher, as described in
[SCHNEIER], using a 128-bit key. The first 1536 bytes of keystream
generated by the cipher MUST be discarded, and the first byte of the
first encrypted packet MUST be encrypted using the 1537th byte of
keystream.
-- http://tools.ietf.org/html/rfc4345#section-4 */
if ($encrypt == 'arcfour128' || $encrypt == 'arcfour256') {
$this->encrypt->encrypt(str_repeat("\0", 1536));
}
if ($decrypt == 'arcfour128' || $decrypt == 'arcfour256') {
$this->decrypt->decrypt(str_repeat("\0", 1536));
}
for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_client_to_server); $i++);
if ($i == count($mac_algorithms)) {
user_error('No compatible client to server message authentication algorithms found', E_USER_NOTICE);