1
0
mirror of https://github.com/danog/phpseclib.git synced 2025-01-22 04:51:19 +01:00

- added support for OFB and CFB modes (with the caveat that CFB mode isn't currently supported as a stream cipher)

- improvements to the fix to the bug Suby found
- fixed bug whereby CTR mode gave different results in mcrypt and internal modes when the continuous buffer was enabled and the plaintext being encrypted wasn't a multiple of the block size
- undid the fix for the bug f.dammassa found (thanks, j31!)


git-svn-id: http://phpseclib.svn.sourceforge.net/svnroot/phpseclib/trunk@120 21d32557-59b3-4da0-833f-c5933fad653e
This commit is contained in:
Jim Wigginton 2010-09-12 21:58:54 +00:00
parent b3690e0fde
commit 202c3b64e9
6 changed files with 614 additions and 111 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.7 2010-02-09 06:10:25 terrafrost Exp $
* @version $Id: AES.php,v 1.8 2010-09-12 21:58:54 terrafrost Exp $
* @link http://phpseclib.sourceforge.net
*/
@ -90,6 +90,18 @@ define('CRYPT_AES_MODE_ECB', 1);
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
*/
define('CRYPT_AES_MODE_CBC', 2);
/**
* Encrypt / decrypt using the Cipher Feedback mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
*/
define('CRYPT_AES_MODE_CFB', 3);
/**
* Encrypt / decrypt using the Cipher Feedback mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
*/
define('CRYPT_AES_MODE_OFB', 4);
/**#@-*/
/**#@+
@ -168,6 +180,7 @@ class Crypt_AES extends Crypt_Rijndael {
case CRYPT_AES_MODE_MCRYPT:
switch ($mode) {
case CRYPT_AES_MODE_ECB:
$this->paddable = true;
$this->mode = MCRYPT_MODE_ECB;
break;
case CRYPT_AES_MODE_CTR:
@ -177,8 +190,16 @@ class Crypt_AES extends Crypt_Rijndael {
$this->mode = 'ctr';
//$this->mode = in_array('ctr', mcrypt_list_modes()) ? 'ctr' : CRYPT_AES_MODE_CTR;
break;
case CRYPT_AES_MODE_CFB:
$this->paddable = true;
$this->mode = 'ncfb';
break;
case CRYPT_AES_MODE_OFB:
$this->mode = MCRYPT_MODE_NOFB;
break;
case CRYPT_AES_MODE_CBC:
default:
$this->paddable = true;
$this->mode = MCRYPT_MODE_CBC;
}
@ -186,13 +207,22 @@ class Crypt_AES extends Crypt_Rijndael {
default:
switch ($mode) {
case CRYPT_AES_MODE_ECB:
$this->paddable = true;
$this->mode = CRYPT_RIJNDAEL_MODE_ECB;
break;
case CRYPT_AES_MODE_CTR:
$this->mode = CRYPT_RIJNDAEL_MODE_CTR;
break;
case CRYPT_AES_MODE_CFB:
$this->paddable = true;
$this->mode = CRYPT_RIJNDAEL_MODE_CFB;
break;
case CRYPT_AES_MODE_OFB:
$this->mode = CRYPT_RIJNDAEL_MODE_OFB;
break;
case CRYPT_AES_MODE_CBC:
default:
$this->paddable = true;
$this->mode = CRYPT_RIJNDAEL_MODE_CBC;
}
}
@ -248,7 +278,7 @@ class Crypt_AES extends Crypt_Rijndael {
}
*/
if ($this->mode != 'ctr') {
if ($this->paddable) {
$plaintext = $this->_pad($plaintext);
}
@ -289,7 +319,7 @@ class Crypt_AES extends Crypt_Rijndael {
}
*/
if ($this->mode != 'ctr') {
if ($this->paddable) {
// we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
// "The data is padded with "\0" to make sure the length of the data is n * blocksize."
$ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 15) & 0xFFFFFFF0, chr(0));
@ -301,7 +331,7 @@ class Crypt_AES extends Crypt_Rijndael {
mcrypt_generic_init($this->demcrypt, $this->key, $this->iv);
}
return $this->mode != 'ctr' ? $this->_unpad($plaintext) : $plaintext;
return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
}
return parent::decrypt($ciphertext);

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.13 2010-08-08 05:06:38 terrafrost Exp $
* @version $Id: DES.php,v 1.14 2010-09-12 21:58:54 terrafrost Exp $
* @link http://phpseclib.sourceforge.net
*/
@ -97,6 +97,18 @@ define('CRYPT_DES_MODE_ECB', 1);
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
*/
define('CRYPT_DES_MODE_CBC', 2);
/**
* Encrypt / decrypt using the Cipher Feedback mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
*/
define('CRYPT_DES_MODE_CFB', 3);
/**
* Encrypt / decrypt using the Cipher Feedback mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
*/
define('CRYPT_DES_MODE_OFB', 4);
/**#@-*/
/**#@+
@ -191,7 +203,7 @@ class Crypt_DES {
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
*
* @see Crypt_AES::encrypt()
* @see Crypt_DES::encrypt()
* @var String
* @access private
*/
@ -203,7 +215,7 @@ class Crypt_DES {
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
*
* @see Crypt_AES::decrypt()
* @see Crypt_DES::decrypt()
* @var String
* @access private
*/
@ -212,8 +224,8 @@ class Crypt_DES {
/**
* Does the enmcrypt resource need to be (re)initialized?
*
* @see setKey()
* @see setIV()
* @see Crypt_DES::setKey()
* @see Crypt_DES::setIV()
* @var Boolean
* @access private
*/
@ -222,13 +234,40 @@ class Crypt_DES {
/**
* Does the demcrypt resource need to be (re)initialized?
*
* @see setKey()
* @see setIV()
* @see Crypt_DES::setKey()
* @see Crypt_DES::setIV()
* @var Boolean
* @access private
*/
var $dechanged = true;
/**
* Is the mode one that is paddable?
*
* @see Crypt_DES::Crypt_DES()
* @var Boolean
* @access private
*/
var $paddable = false;
/**
* Encryption buffer for CTR, OFB and CFB modes
*
* @see Crypt_DES::encrypt()
* @var String
* @access private
*/
var $enbuffer = '';
/**
* Decryption buffer for CTR, OFB and CFB modes
*
* @see Crypt_DES::decrypt()
* @var String
* @access private
*/
var $debuffer = '';
/**
* Default Constructor.
*
@ -258,14 +297,23 @@ class Crypt_DES {
case CRYPT_DES_MODE_MCRYPT:
switch ($mode) {
case CRYPT_DES_MODE_ECB:
$this->paddable = true;
$this->mode = MCRYPT_MODE_ECB;
break;
case CRYPT_DES_MODE_CTR:
$this->mode = 'ctr';
//$this->mode = in_array('ctr', mcrypt_list_modes()) ? 'ctr' : CRYPT_DES_MODE_CTR;
break;
case CRYPT_DES_MODE_CFB:
$this->paddable = true;
$this->mode = 'ncfb';
break;
case CRYPT_DES_MODE_OFB:
$this->mode = MCRYPT_MODE_NOFB;
break;
case CRYPT_DES_MODE_CBC:
default:
$this->paddable = true;
$this->mode = MCRYPT_MODE_CBC;
}
@ -273,11 +321,17 @@ class Crypt_DES {
default:
switch ($mode) {
case CRYPT_DES_MODE_ECB:
case CRYPT_DES_MODE_CFB:
$this->paddable = true;
$this->mode = $mode;
break;
case CRYPT_DES_MODE_CTR:
case CRYPT_DES_MODE_CBC:
case CRYPT_DES_MODE_OFB:
$this->mode = $mode;
break;
default:
$this->paddable = true;
$this->mode = CRYPT_DES_MODE_CBC;
}
}
@ -375,7 +429,7 @@ class Crypt_DES {
*/
function encrypt($plaintext)
{
if ($this->mode != CRYPT_DES_MODE_CTR && $this->mode != 'ctr') {
if ($this->paddable) {
$plaintext = $this->_pad($plaintext);
}
@ -401,6 +455,7 @@ class Crypt_DES {
$this->keys = $this->_prepareKey("\0\0\0\0\0\0\0\0");
}
$buffer = &$this->enbuffer;
$ciphertext = '';
switch ($this->mode) {
case CRYPT_DES_MODE_ECB:
@ -422,13 +477,59 @@ class Crypt_DES {
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 (strlen($buffer)) {
for ($i = 0; $i < strlen($plaintext); $i+=8) {
$block = substr($plaintext, $i, 8);
$buffer.= $this->_processBlock($this->_generate_xor(8, $xor), CRYPT_DES_ENCRYPT);
$key = $this->_string_shift($buffer, 8);
$ciphertext.= $block ^ $key;
}
} else {
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;
if ($start = strlen($plaintext) & 7) {
$buffer = substr($key, $start) . $buffer;
}
}
break;
case CRYPT_DES_MODE_CFB:
$iv = $this->encryptIV;
for ($i = 0; $i < strlen($plaintext); $i+=8) {
$block = substr($plaintext, $i, 8);
$iv = $block ^ $this->_processBlock($iv, CRYPT_DES_ENCRYPT);
$ciphertext.= $iv;
}
if ($this->continuousBuffer) {
$this->encryptIV = $iv;
}
break;
case CRYPT_DES_MODE_OFB:
$xor = $this->encryptIV;
if (strlen($buffer)) {
for ($i = 0; $i < strlen($plaintext); $i+=8) {
$xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT);
$buffer.= $xor;
$key = $this->_string_shift($buffer, 8);
$ciphertext.= substr($plaintext, $i, 8) ^ $key;
}
} else {
for ($i = 0; $i < strlen($plaintext); $i+=8) {
$xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT);
$ciphertext.= substr($plaintext, $i, 8) ^ $xor;
}
$key = $xor;
}
if ($this->continuousBuffer) {
$this->encryptIV = $xor;
if ($start = strlen($plaintext) & 7) {
$buffer = substr($key, $start) . $buffer;
}
}
}
@ -446,7 +547,7 @@ class Crypt_DES {
*/
function decrypt($ciphertext)
{
if ($this->mode != CRYPT_DES_MODE_CTR && $this->mode != 'ctr') {
if ($this->paddable) {
// we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
// "The data is padded with "\0" to make sure the length of the data is n * blocksize."
$ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, chr(0));
@ -474,6 +575,7 @@ class Crypt_DES {
$this->keys = $this->_prepareKey("\0\0\0\0\0\0\0\0");
}
$buffer = &$this->debuffer;
$plaintext = '';
switch ($this->mode) {
case CRYPT_DES_MODE_ECB:
@ -494,17 +596,63 @@ class Crypt_DES {
break;
case CRYPT_DES_MODE_CTR:
$xor = $this->decryptIV;
if (strlen($buffer)) {
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
$block = substr($ciphertext, $i, 8);
$buffer.= $this->_processBlock($this->_generate_xor(8, $xor), CRYPT_DES_ENCRYPT);
$key = $this->_string_shift($buffer, 8);
$plaintext.= $block ^ $key;
}
} else {
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;
if ($start = strlen($ciphertext) % 8) {
$buffer = substr($key, $start) . $buffer;
}
}
break;
case CRYPT_DES_MODE_CFB:
$xor = $this->_processBlock($this->decryptIV, CRYPT_DES_ENCRYPT);
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;
$plaintext.= $block ^ $xor;
$xor = $this->_processBlock($block, CRYPT_DES_ENCRYPT);
}
if ($this->continuousBuffer) {
$this->decryptIV = $xor;
}
break;
case CRYPT_DES_MODE_OFB:
$xor = $this->decryptIV;
if (strlen($buffer)) {
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
$xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT);
$buffer.= $xor;
$key = $this->_string_shift($buffer, 8);
$plaintext.= substr($ciphertext, $i, 8) ^ $key;
}
} else {
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
$xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT);
$plaintext.= substr($ciphertext, $i, 8) ^ $xor;
}
$key = $xor;
}
if ($this->continuousBuffer) {
$this->decryptIV = $xor;
if ($start = strlen($ciphertext) % 8) {
$buffer = substr($key, $start) . $buffer;
}
}
}
return $this->mode != CRYPT_DES_MODE_CTR ? $this->_unpad($plaintext) : $plaintext;
return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
}
/**
@ -949,6 +1097,23 @@ class Crypt_DES {
return $temp;
}
/**
* String Shift
*
* Inspired by array_shift
*
* @param String $string
* @param optional Integer $index
* @return String
* @access private
*/
function _string_shift(&$string, $index = 1)
{
$substr = substr($string, 0, $index);
$string = substr($string, $index);
return $substr;
}
}
// vim: ts=4:sw=4:et:

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.18 2010-09-05 03:04:29 terrafrost Exp $
* @version $Id: RSA.php,v 1.19 2010-09-12 21:58:54 terrafrost Exp $
* @link http://phpseclib.sourceforge.net
*/
@ -784,6 +784,13 @@ class Crypt_RSA {
}
$symkey = substr($symkey, 0, 16);
break;
// CFB mode needs to work as a stream cipher for this to work
//case 'DES-EDE3-CFB':
// if (!class_exists('Crypt_TripleDES')) {
// require_once('Crypt/TripleDES.php');
// }
// $crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CFB);
// break;
case 'DES-EDE3-CBC':
if (!class_exists('Crypt_TripleDES')) {
require_once('Crypt/TripleDES.php');

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.12 2010-02-09 06:10:26 terrafrost Exp $
* @version $Id: Rijndael.php,v 1.13 2010-09-12 21:58:54 terrafrost Exp $
* @link http://phpseclib.sourceforge.net
*/
@ -93,6 +93,18 @@ define('CRYPT_RIJNDAEL_MODE_ECB', 1);
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
*/
define('CRYPT_RIJNDAEL_MODE_CBC', 2);
/**
* Encrypt / decrypt using the Cipher Feedback mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
*/
define('CRYPT_RIJNDAEL_MODE_CFB', 3);
/**
* Encrypt / decrypt using the Cipher Feedback mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
*/
define('CRYPT_RIJNDAEL_MODE_OFB', 4);
/**#@-*/
/**#@+
@ -356,6 +368,33 @@ class Crypt_Rijndael {
*/
var $dt3;
/**
* Is the mode one that is paddable?
*
* @see Crypt_Rijndael::Crypt_Rijndael()
* @var Boolean
* @access private
*/
var $paddable = false;
/**
* Encryption buffer for CTR, OFB and CFB modes
*
* @see Crypt_Rijndael::encrypt()
* @var String
* @access private
*/
var $enbuffer = '';
/**
* Decryption buffer for CTR, OFB and CFB modes
*
* @see Crypt_Rijndael::decrypt()
* @var String
* @access private
*/
var $debuffer = '';
/**
* Default Constructor.
*
@ -370,11 +409,17 @@ class Crypt_Rijndael {
{
switch ($mode) {
case CRYPT_RIJNDAEL_MODE_ECB:
case CRYPT_RIJNDAEL_MODE_CFB:
$this->paddable = true;
$this->mode = $mode;
break;
case CRYPT_RIJNDAEL_MODE_CBC:
case CRYPT_RIJNDAEL_MODE_CTR:
case CRYPT_RIJNDAEL_MODE_OFB:
$this->mode = $mode;
break;
default:
$this->paddable = true;
$this->mode = CRYPT_RIJNDAEL_MODE_CBC;
}
@ -611,11 +656,12 @@ class Crypt_Rijndael {
function encrypt($plaintext)
{
$this->_setup();
if ($this->mode != CRYPT_RIJNDAEL_MODE_CTR) {
if ($this->paddable) {
$plaintext = $this->_pad($plaintext);
}
$block_size = $this->block_size;
$buffer = &$this->enbuffer;
$ciphertext = '';
switch ($this->mode) {
case CRYPT_RIJNDAEL_MODE_ECB:
@ -637,13 +683,59 @@ class Crypt_Rijndael {
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 (strlen($buffer)) {
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
$block = substr($plaintext, $i, $block_size);
$buffer.= $this->_encryptBlock($this->_generate_xor($block_size, $xor));
$key = $this->_string_shift($buffer, $block_size);
$ciphertext.= $block ^ $key;
}
} else {
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
$block = substr($plaintext, $i, $block_size);
$key = $this->_encryptBlock($this->_generate_xor($block_size, $xor));
$ciphertext.= $block ^ $key;
}
}
if ($this->continuousBuffer) {
$this->encryptIV = $xor;
if ($start = strlen($plaintext) % $block_size) {
$buffer = substr($key, $start) . $buffer;
}
}
break;
case CRYPT_RIJNDAEL_MODE_CFB:
$iv = $this->encryptIV;
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
$block = substr($plaintext, $i, $block_size);
$iv = $block ^ $this->_encryptBlock($iv);
$ciphertext.= $iv;
}
if ($this->continuousBuffer) {
$this->encryptIV = $iv;
}
break;
case CRYPT_RIJNDAEL_MODE_OFB:
$xor = $this->encryptIV;
if (strlen($buffer)) {
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
$xor = $this->_encryptBlock($xor);
$buffer.= $xor;
$key = $this->_string_shift($buffer, $block_size);
$ciphertext.= substr($plaintext, $i, $block_size) ^ $key;
}
} else {
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
$xor = $this->_encryptBlock($xor);
$ciphertext.= substr($plaintext, $i, $block_size) ^ $xor;
}
$key = $xor;
}
if ($this->continuousBuffer) {
$this->encryptIV = $xor;
if ($start = strlen($plaintext) % $block_size) {
$buffer = substr($key, $start) . $buffer;
}
}
}
@ -664,13 +756,14 @@ class Crypt_Rijndael {
{
$this->_setup();
if ($this->mode != CRYPT_RIJNDAEL_MODE_CTR) {
if ($this->paddable) {
// we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
// "The data is padded with "\0" to make sure the length of the data is n * blocksize."
$ciphertext = str_pad($ciphertext, (strlen($ciphertext) + $this->block_size - 1) % $this->block_size, chr(0));
}
$block_size = $this->block_size;
$buffer = &$this->debuffer;
$plaintext = '';
switch ($this->mode) {
case CRYPT_RIJNDAEL_MODE_ECB:
@ -691,17 +784,63 @@ class Crypt_Rijndael {
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 (strlen($buffer)) {
for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
$block = substr($ciphertext, $i, $block_size);
$buffer.= $this->_encryptBlock($this->_generate_xor($block_size, $xor));
$key = $this->_string_shift($buffer, $block_size);
$plaintext.= $block ^ $key;
}
} else {
for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
$block = substr($ciphertext, $i, $block_size);
$key = $this->_encryptBlock($this->_generate_xor($block_size, $xor));
$plaintext.= $block ^ $key;
}
}
if ($this->continuousBuffer) {
$this->decryptIV = $xor;
if ($start = strlen($ciphertext) % $block_size) {
$buffer = substr($key, $start) . $buffer;
}
}
break;
case CRYPT_RIJNDAEL_MODE_CFB:
$iv = $this->_encryptBlock($this->decryptIV);
for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
$block = substr($ciphertext, $i, $block_size);
$plaintext.= $block ^ $iv;
$iv = $this->_encryptBlock($block);
}
if ($this->continuousBuffer) {
$this->decryptIV = $iv;
}
break;
case CRYPT_RIJNDAEL_MODE_OFB:
$xor = $this->decryptIV;
if (strlen($buffer)) {
for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
$xor = $this->_encryptBlock($xor);
$buffer.= $xor;
$key = $this->_string_shift($buffer, $block_size);
$plaintext.= substr($ciphertext, $i, $block_size) ^ $key;
}
} else {
for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
$xor = $this->_encryptBlock($xor);
$plaintext.= substr($ciphertext, $i, $block_size) ^ $xor;
}
$key = $xor;
}
if ($this->continuousBuffer) {
$this->decryptIV = $xor;
if ($start = strlen($ciphertext) % $block_size) {
$buffer = substr($key, $start) . $buffer;
}
}
}
return $this->mode != CRYPT_RIJNDAEL_MODE_CTR ? $this->_unpad($plaintext) : $plaintext;
return $this->paddable ? $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.14 2010-08-08 05:06:38 terrafrost Exp $
* @version $Id: TripleDES.php,v 1.15 2010-09-12 21:58:54 terrafrost Exp $
* @link http://phpseclib.sourceforge.net
*/
@ -61,7 +61,7 @@ require_once('DES.php');
*
* Inner chaining is used by SSH-1 and is generally considered to be less secure then outer chaining (CRYPT_DES_MODE_CBC3).
*/
define('CRYPT_DES_MODE_3CBC', 3);
define('CRYPT_DES_MODE_3CBC', -2);
/**
* Encrypt / decrypt using outer chaining
@ -156,7 +156,7 @@ class Crypt_TripleDES {
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
*
* @see Crypt_AES::encrypt()
* @see Crypt_TripleDES::encrypt()
* @var String
* @access private
*/
@ -168,21 +168,58 @@ class Crypt_TripleDES {
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
*
* @see Crypt_AES::decrypt()
* @see Crypt_TripleDES::decrypt()
* @var String
* @access private
*/
var $demcrypt;
/**
* Does the (en|de)mcrypt resource need to be (re)initialized?
* Does the enmcrypt resource need to be (re)initialized?
*
* @see setKey()
* @see setIV()
* @see Crypt_TripleDES::setKey()
* @see Crypt_TripleDES::setIV()
* @var Boolean
* @access private
*/
var $changed = true;
var $enchanged = true;
/**
* Does the demcrypt resource need to be (re)initialized?
*
* @see Crypt_TripleDES::setKey()
* @see Crypt_TripleDES::setIV()
* @var Boolean
* @access private
*/
var $dechanged = true;
/**
* Is the mode one that is paddable?
*
* @see Crypt_TripleDES::Crypt_TripleDES()
* @var Boolean
* @access private
*/
var $paddable = false;
/**
* Encryption buffer for CTR, OFB and CFB modes
*
* @see Crypt_TripleDES::encrypt()
* @var String
* @access private
*/
var $enbuffer = '';
/**
* Decryption buffer for CTR, OFB and CFB modes
*
* @see Crypt_TripleDES::decrypt()
* @var String
* @access private
*/
var $debuffer = '';
/**
* Default Constructor.
@ -229,13 +266,22 @@ class Crypt_TripleDES {
case CRYPT_DES_MODE_MCRYPT:
switch ($mode) {
case CRYPT_DES_MODE_ECB:
$this->paddable = true;
$this->mode = MCRYPT_MODE_ECB;
break;
case CRYPT_DES_MODE_CTR:
$this->mode = 'ctr';
break;
case CRYPT_DES_MODE_CFB:
$this->paddable = true;
$this->mode = 'ncfb';
break;
case CRYPT_DES_MODE_OFB:
$this->mode = MCRYPT_MODE_NOFB;
break;
case CRYPT_DES_MODE_CBC:
default:
$this->paddable = true;
$this->mode = MCRYPT_MODE_CBC;
}
@ -254,11 +300,17 @@ class Crypt_TripleDES {
switch ($mode) {
case CRYPT_DES_MODE_ECB:
case CRYPT_DES_MODE_CFB:
$this->paddable = true;
$this->mode = $mode;
break;
case CRYPT_DES_MODE_CTR:
case CRYPT_DES_MODE_CBC:
case CRYPT_DES_MODE_OFB:
$this->mode = $mode;
break;
default:
$this->paddable = true;
$this->mode = CRYPT_DES_MODE_CBC;
}
}
@ -294,7 +346,7 @@ class Crypt_TripleDES {
$this->des[1]->setKey(substr($key, 8, 8));
$this->des[2]->setKey(substr($key, 16, 8));
}
$this->changed = true;
$this->enchanged = $this->dechanged = true;
}
/**
@ -314,7 +366,7 @@ class Crypt_TripleDES {
$this->des[1]->setIV($iv);
$this->des[2]->setIV($iv);
}
$this->changed = true;
$this->enchanged = $this->dechanged = true;
}
/**
@ -323,9 +375,9 @@ class Crypt_TripleDES {
* Encrypt the output of this and XOR it against the ciphertext / plaintext to get the
* plaintext / ciphertext in CTR mode.
*
* @see Crypt_DES::decrypt()
* @see Crypt_DES::encrypt()
* @access public
* @see Crypt_TripleDES::decrypt()
* @see Crypt_TripleDES::encrypt()
* @access private
* @param Integer $length
* @param String $iv
*/
@ -363,7 +415,7 @@ class Crypt_TripleDES {
*/
function encrypt($plaintext)
{
if ($this->mode != CRYPT_DES_MODE_CTR && $this->mode != 'ctr') {
if ($this->paddable) {
$plaintext = $this->_pad($plaintext);
}
@ -375,12 +427,12 @@ class Crypt_TripleDES {
}
if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) {
if ($this->changed) {
if ($this->enchanged) {
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;
$this->enchanged = false;
}
$ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
@ -398,17 +450,20 @@ class Crypt_TripleDES {
return $this->des[0]->encrypt($plaintext);
}
// 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."
$plaintext = str_pad($plaintext, ceil(strlen($plaintext) / 8) * 8, chr(0));
$des = $this->des;
$buffer = &$this->enbuffer;
$ciphertext = '';
switch ($this->mode) {
case CRYPT_DES_MODE_ECB:
for ($i = 0; $i < strlen($plaintext); $i+=8) {
$block = substr($plaintext, $i, 8);
// all of these _processBlock calls could, in theory, be put in a function - say Crypt_TripleDES::_ede_encrypt() or something.
// only problem with that: it would slow encryption and decryption down. $this->des would have to be called every time that
// function is called, instead of once for the whole string of text that's being encrypted, which would, in turn, make
// encryption and decryption take more time, per this:
//
// http://blog.libssh2.org/index.php?/archives/21-Compiled-Variables.html
$block = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT);
$block = $des[1]->_processBlock($block, CRYPT_DES_DECRYPT);
$block = $des[2]->_processBlock($block, CRYPT_DES_ENCRYPT);
@ -431,16 +486,73 @@ class Crypt_TripleDES {
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 (strlen($buffer)) {
for ($i = 0; $i < strlen($plaintext); $i+=8) {
$block = substr($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);
$buffer.= $key;
$key = $this->_string_shift($buffer, 8);
$ciphertext.= $block ^ $key;
}
} else {
for ($i = 0; $i < strlen($plaintext); $i+=8) {
$block = substr($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);
$ciphertext.= $block ^ $key;
}
}
if ($this->continuousBuffer) {
$this->encryptIV = $xor;
if ($start = strlen($plaintext) & 7) {
$buffer = substr($key, $start) . $buffer;
}
}
break;
case CRYPT_DES_MODE_CFB:
$iv = $this->encryptIV;
for ($i = 0; $i < strlen($plaintext); $i+=8) {
$block = substr($plaintext, $i, 8);
$iv = $des[0]->_processBlock($iv, CRYPT_DES_ENCRYPT);
$iv = $des[1]->_processBlock($iv, CRYPT_DES_DECRYPT);
$iv = $des[2]->_processBlock($iv, CRYPT_DES_ENCRYPT);
$iv^= $block;
$ciphertext.= $iv;
}
if ($this->continuousBuffer) {
$this->encryptIV = $iv;
}
break;
case CRYPT_DES_MODE_OFB:
$xor = $this->encryptIV;
if (strlen($buffer)) {
for ($i = 0; $i < strlen($plaintext); $i+=8) {
$xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT);
$xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
$xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
$buffer.= $xor;
$key = $this->_string_shift($buffer, 8);
$ciphertext.= substr($plaintext, $i, 8) ^ $key;
}
} else {
for ($i = 0; $i < strlen($plaintext); $i+=8) {
$xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT);
$xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
$xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
$ciphertext.= substr($plaintext, $i, 8) ^ $xor;
}
$key = $xor;
}
if ($this->continuousBuffer) {
$this->encryptIV = $xor;
if ($start = strlen($plaintext) & 7) {
$buffer = substr($key, $start) . $buffer;
}
}
}
@ -461,17 +573,19 @@ class Crypt_TripleDES {
return $this->_unpad($plaintext);
}
// 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->paddable) {
// we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
// "The data is padded with "\0" to make sure the length of the data is n * blocksize."
$ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, chr(0));
}
if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) {
if ($this->changed) {
if ($this->dechanged) {
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;
$this->dechanged = false;
}
$plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
@ -480,17 +594,18 @@ class Crypt_TripleDES {
mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
}
return $this->mode != 'ctr' ? $this->_unpad($plaintext) : $plaintext;
return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
}
if (strlen($this->key) <= 8) {
$this->des[0]->mode = $this->mode;
return $this->_unpad($this->des[0]->decrypt($plaintext));
$plaintext = $this->des[0]->decrypt($ciphertext);
return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
}
$des = $this->des;
$buffer = &$this->enbuffer;
$plaintext = '';
switch ($this->mode) {
case CRYPT_DES_MODE_ECB:
@ -518,20 +633,77 @@ class Crypt_TripleDES {
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 (strlen($buffer)) {
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
$block = substr($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);
$buffer.= $key;
$key = $this->_string_shift($buffer, 8);
$plaintext.= $block ^ $key;
}
} else {
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
$block = substr($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);
$plaintext.= $block ^ $key;
}
}
if ($this->continuousBuffer) {
$this->decryptIV = $xor;
if ($start = strlen($plaintext) & 7) {
$buffer = substr($key, $start) . $buffer;
}
}
break;
case CRYPT_DES_MODE_CFB:
$iv = $this->decryptIV;
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
$block = substr($ciphertext, $i, 8);
$iv = $des[0]->_processBlock($iv, CRYPT_DES_ENCRYPT);
$iv = $des[1]->_processBlock($iv, CRYPT_DES_DECRYPT);
$iv = $des[2]->_processBlock($iv, CRYPT_DES_ENCRYPT);
$iv^= $block;
$plaintext.= $iv;
}
if ($this->continuousBuffer) {
$this->decryptIV = $iv;
}
break;
case CRYPT_DES_MODE_OFB:
$xor = $this->decryptIV;
if (strlen($buffer)) {
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
$xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT);
$xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
$xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
$buffer.= $xor;
$key = $this->_string_shift($buffer, 8);
$plaintext.= substr($ciphertext, $i, 8) ^ $key;
}
} else {
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
$xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT);
$xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
$xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
$plaintext.= substr($ciphertext, $i, 8) ^ $xor;
}
$key = $xor;
}
if ($this->continuousBuffer) {
$this->decryptIV = $xor;
if ($start = strlen($ciphertext) & 7) {
$buffer = substr($key, $start) . $buffer;
}
}
}
return $this->mode != CRYPT_DES_MODE_CTR ? $this->_unpad($plaintext) : $plaintext;
return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
}
/**
@ -684,6 +856,23 @@ class Crypt_TripleDES {
return substr($text, 0, -$length);
}
/**
* String Shift
*
* Inspired by array_shift
*
* @param String $string
* @param optional Integer $index
* @return String
* @access private
*/
function _string_shift(&$string, $index = 1)
{
$substr = substr($string, 0, $index);
$string = substr($string, $index);
return $substr;
}
}
// vim: ts=4:sw=4:et:

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.50 2010-08-29 03:27:02 terrafrost Exp $
* @version $Id: SSH2.php,v 1.51 2010-09-12 21:58:54 terrafrost Exp $
* @link http://phpseclib.sourceforge.net
*/
@ -563,23 +563,6 @@ class Net_SSH2 {
*/
var $signature_format = '';
/**
* Key size fix
*
* Portable OpenSSH 4.4 and earlier use faulty key sizes for aes256-ctr, aes192-ctr and arcfour256.
* These algorithms could be removed from $encryption_algorithms in Net_SSH2::_key_exchange() but we'll
* adjust the key sizes instead to confirm that the version detection technique we're using is correct.
* If it isn't correct than we'll get decryption / encryption errors. We wouldn't get any errors, in
* contrast, if the algorithms were simply removed, and would never know if the version detection
* technique we were using was correct.
*
* @link http://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/ssh2-aesctr-openssh
* @see Net_SSH2::Net_SSH2()
* @var Boolean
* @access private
*/
var $adjust_key_fix = false;
/**
* Default Constructor.
*
@ -725,8 +708,6 @@ class Net_SSH2 {
return;
}
$this->adjust_key_fix = preg_match('#SSH-' . $matches[1] . '\-OpenSSH_([\d\.]+)#', $this->server_identifier, $matches) && $matches[1] < 4.6;
fputs($this->fsock, $this->identifier . "\r\n");
$response = $this->_get_binary_packet();
@ -885,16 +866,12 @@ class Net_SSH2 {
$decryptKeyLength = 24; // eg. 192 / 8
break;
case 'aes256-cbc':
case 'aes256-ctr':
$decryptKeyLength = 32; // eg. 256 / 8
break;
case 'aes256-ctr':
$decryptKeyLength = !$this->adjust_key_fix ? 32 : 16;
break;
case 'aes192-cbc':
$decryptKeyLength = 24;
break;
case 'aes192-ctr':
$decryptKeyLength = !$this->adjust_key_fix ? 24 : 16;
$decryptKeyLength = 24; // eg. 192 / 8
break;
case 'aes128-cbc':
case 'aes128-ctr':
@ -902,10 +879,10 @@ class Net_SSH2 {
break;
case 'arcfour':
case 'arcfour128':
$decryptKeyLength = 16;
$decryptKeyLength = 16; // eg. 128 / 8
break;
case 'arcfour256':
$decryptKeyLength = !$this->adjust_key_fix ? 32 : 16;
$decryptKeyLength = 32; // eg. 128 / 8
break;
case 'none';
$decryptKeyLength = 0;
@ -924,16 +901,12 @@ class Net_SSH2 {
$encryptKeyLength = 24;
break;
case 'aes256-cbc':
case 'aes256-ctr':
$encryptKeyLength = 32;
break;
case 'aes256-ctr':
$encryptKeyLength = !$this->adjust_key_fix ? 32 : 16;
break;
case 'aes192-cbc':
$encryptKeyLength = 24;
break;
case 'aes192-ctr':
$encryptKeyLength = !$this->adjust_key_fix ? 24 : 16;
$encryptKeyLength = 24;
break;
case 'aes128-cbc':
case 'aes128-ctr':
@ -944,7 +917,7 @@ class Net_SSH2 {
$encryptKeyLength = 16;
break;
case 'arcfour256':
$encryptKeyLength = !$this->adjust_key_fix ? 32 : 16;
$encryptKeyLength = 32;
break;
case 'none';
$encryptKeyLength = 0;