diff --git a/phpseclib/Crypt/AES.php b/phpseclib/Crypt/AES.php index e68bb2d6..7da9144f 100644 --- a/phpseclib/Crypt/AES.php +++ b/phpseclib/Crypt/AES.php @@ -56,7 +56,7 @@ * @author Jim Wigginton * @copyright MMVIII Jim Wigginton * @license http://www.gnu.org/licenses/lgpl.txt - * @version $Id: AES.php,v 1.8 2010-09-12 21:58:54 terrafrost Exp $ + * @version $Id: AES.php,v 1.9 2010-09-26 03:10:20 terrafrost Exp $ * @link http://phpseclib.sourceforge.net */ @@ -191,7 +191,6 @@ class Crypt_AES extends Crypt_Rijndael { //$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: @@ -203,6 +202,8 @@ class Crypt_AES extends Crypt_Rijndael { $this->mode = MCRYPT_MODE_CBC; } + $this->debuffer = $this->enbuffer = ''; + break; default: switch ($mode) { @@ -214,7 +215,6 @@ class Crypt_AES extends Crypt_Rijndael { $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: @@ -265,6 +265,7 @@ class Crypt_AES extends Crypt_Rijndael { function encrypt($plaintext) { if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) { + $changed = $this->changed; $this->_mcryptSetup(); /* if ($this->mode == CRYPT_AES_MODE_CTR) { @@ -277,6 +278,44 @@ class Crypt_AES extends Crypt_Rijndael { return $ciphertext; } */ + // re: http://phpseclib.sourceforge.net/cfb-demo.phps + // using mcrypt's default handing of CFB the above would output two different things. using phpseclib's + // rewritten CFB implementation the above outputs the same thing twice. + if ($this->mode == 'ncfb') { + static $ecb; + + if ($changed) { + $ecb = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, ''); + mcrypt_generic_init($ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); + } + + if (strlen($this->enbuffer)) { + $ciphertext = $plaintext ^ substr($this->encryptIV, strlen($this->enbuffer)); + $this->enbuffer.= $ciphertext; + if (strlen($this->enbuffer) == 16) { + $this->encryptIV = $this->enbuffer; + $this->enbuffer = ''; + mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV); + } + $plaintext = substr($plaintext, strlen($ciphertext)); + } else { + $ciphertext = ''; + } + + $last_pos = strlen($plaintext) & 0xFFFFFFF0; + $ciphertext.= $last_pos ? mcrypt_generic($this->enmcrypt, substr($plaintext, 0, $last_pos)) : ''; + + if (strlen($plaintext) & 0xF) { + if (strlen($ciphertext)) { + $this->encryptIV = substr($ciphertext, -16); + } + $this->encryptIV = mcrypt_generic($ecb, $this->encryptIV); + $this->enbuffer = substr($plaintext, $last_pos) ^ $this->encryptIV; + $ciphertext.= $this->enbuffer; + } + + return $ciphertext; + } if ($this->paddable) { $plaintext = $this->_pad($plaintext); @@ -306,6 +345,7 @@ class Crypt_AES extends Crypt_Rijndael { function decrypt($ciphertext) { if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) { + $changed = $this->changed; $this->_mcryptSetup(); /* if ($this->mode == CRYPT_AES_MODE_CTR) { @@ -318,6 +358,42 @@ class Crypt_AES extends Crypt_Rijndael { return $plaintext; } */ + if ($this->mode == 'ncfb') { + static $ecb; + + if ($changed) { + $ecb = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, ''); + mcrypt_generic_init($ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); + } + + if (strlen($this->debuffer)) { + $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($this->debuffer)); + + $this->debuffer.= substr($ciphertext, 0, strlen($plaintext)); + if (strlen($this->debuffer) == 16) { + $this->decryptIV = $this->debuffer; + $this->debuffer = ''; + mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV); + } + $ciphertext = substr($ciphertext, strlen($plaintext)); + } else { + $plaintext = ''; + } + + $last_pos = strlen($ciphertext) & 0xFFFFFFF0; + $plaintext.= $last_pos ? mdecrypt_generic($this->demcrypt, substr($ciphertext, 0, $last_pos)) : ''; + + if (strlen($ciphertext) & 0xF) { + if (strlen($plaintext)) { + $this->decryptIV = substr($ciphertext, $last_pos - 16, 16); + } + $this->decryptIV = mcrypt_generic($ecb, $this->decryptIV); + $this->debuffer = substr($ciphertext, $last_pos); + $plaintext.= $this->debuffer ^ $this->decryptIV; + } + + return $plaintext; + } if ($this->paddable) { // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic : diff --git a/phpseclib/Crypt/DES.php b/phpseclib/Crypt/DES.php index ca7816e3..acbe1542 100644 --- a/phpseclib/Crypt/DES.php +++ b/phpseclib/Crypt/DES.php @@ -53,7 +53,7 @@ * @author Jim Wigginton * @copyright MMVII Jim Wigginton * @license http://www.gnu.org/licenses/lgpl.txt - * @version $Id: DES.php,v 1.14 2010-09-12 21:58:54 terrafrost Exp $ + * @version $Id: DES.php,v 1.15 2010-09-26 03:10:20 terrafrost Exp $ * @link http://phpseclib.sourceforge.net */ @@ -305,7 +305,6 @@ class Crypt_DES { //$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: @@ -321,12 +320,12 @@ class Crypt_DES { default: switch ($mode) { case CRYPT_DES_MODE_ECB: - case CRYPT_DES_MODE_CFB: + case CRYPT_DES_MODE_CBC: $this->paddable = true; $this->mode = $mode; break; case CRYPT_DES_MODE_CTR: - case CRYPT_DES_MODE_CBC: + case CRYPT_DES_MODE_CFB: case CRYPT_DES_MODE_OFB: $this->mode = $mode; break; @@ -439,10 +438,47 @@ class Crypt_DES { $this->enmcrypt = mcrypt_module_open(MCRYPT_DES, '', $this->mode, ''); } mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV); - $this->enchanged = false; + if ($this->mode != 'ncfb') { + $this->enchanged = false; + } } - $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext); + if ($this->mode != 'ncfb') { + $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext); + } else { + static $ecb; + + if ($this->enchanged) { + $ecb = mcrypt_module_open(MCRYPT_DES, '', MCRYPT_MODE_ECB, ''); + mcrypt_generic_init($ecb, $this->keys, "\0\0\0\0\0\0\0\0"); + $this->enchanged = false; + } + + if (strlen($this->enbuffer)) { + $ciphertext = $plaintext ^ substr($this->encryptIV, strlen($this->enbuffer)); + $this->enbuffer.= $ciphertext; + if (strlen($this->enbuffer) == 8) { + $this->encryptIV = $this->enbuffer; + $this->enbuffer = ''; + mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV); + } + $plaintext = substr($plaintext, strlen($ciphertext)); + } else { + $ciphertext = ''; + } + + $last_pos = strlen($plaintext) & 0xFFFFFFF8; + $ciphertext.= $last_pos ? mcrypt_generic($this->enmcrypt, substr($plaintext, 0, $last_pos)) : ''; + + if (strlen($plaintext) & 0x7) { + if (strlen($ciphertext)) { + $this->encryptIV = substr($ciphertext, -8); + } + $this->encryptIV = mcrypt_generic($ecb, $this->encryptIV); + $this->enbuffer = substr($plaintext, $last_pos) ^ $this->encryptIV; + $ciphertext.= $this->enbuffer; + } + } if (!$this->continuousBuffer) { mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV); @@ -456,6 +492,7 @@ class Crypt_DES { } $buffer = &$this->enbuffer; + $continuousBuffer = $this->continuousBuffer; $ciphertext = ''; switch ($this->mode) { case CRYPT_DES_MODE_ECB: @@ -499,12 +536,31 @@ class Crypt_DES { } break; case CRYPT_DES_MODE_CFB: - $iv = $this->encryptIV; - for ($i = 0; $i < strlen($plaintext); $i+=8) { + if (!empty($buffer['xor'])) { + $ciphertext = $plaintext ^ $buffer['xor']; + $iv = $buffer['encrypted'] . $ciphertext; + $start = strlen($ciphertext); + $buffer['encrypted'].= $ciphertext; + $buffer['xor'] = substr($buffer['xor'], strlen($ciphertext)); + } else { + $ciphertext = ''; + $iv = $this->encryptIV; + $start = 0; + } + + for ($i = $start; $i < strlen($plaintext); $i+=8) { $block = substr($plaintext, $i, 8); - $iv = $block ^ $this->_processBlock($iv, CRYPT_DES_ENCRYPT); + $xor = $this->_processBlock($iv, CRYPT_DES_ENCRYPT); + $iv = $block ^ $xor; + if ($continuousBuffer && strlen($iv) != 8) { + $buffer = array( + 'encrypted' => $iv, + 'xor' => substr($xor, strlen($iv)) + ); + } $ciphertext.= $iv; } + if ($this->continuousBuffer) { $this->encryptIV = $iv; } @@ -559,10 +615,50 @@ class Crypt_DES { $this->demcrypt = mcrypt_module_open(MCRYPT_DES, '', $this->mode, ''); } mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV); - $this->dechanged = false; + if ($this->mode != 'ncfb') { + $this->dechanged = false; + } } - $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext); + if ($this->mode != 'ncfb') { + $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext); + } else { + static $ecb; + + if ($this->dechanged) { + $ecb = mcrypt_module_open(MCRYPT_DES, '', MCRYPT_MODE_ECB, ''); + mcrypt_generic_init($ecb, $this->keys, "\0\0\0\0\0\0\0\0"); + $this->dechanged = false; + } + + if (strlen($this->debuffer)) { + $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($this->debuffer)); + + $this->debuffer.= substr($ciphertext, 0, strlen($plaintext)); + if (strlen($this->debuffer) == 8) { + $this->decryptIV = $this->debuffer; + $this->debuffer = ''; + mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV); + } + $ciphertext = substr($ciphertext, strlen($plaintext)); + } else { + $plaintext = ''; + } + + $last_pos = strlen($ciphertext) & 0xFFFFFFF8; + $plaintext.= $last_pos ? mdecrypt_generic($this->demcrypt, substr($ciphertext, 0, $last_pos)) : ''; + + if (strlen($ciphertext) & 0x7) { + if (strlen($plaintext)) { + $this->decryptIV = substr($ciphertext, $last_pos - 8, 8); + } + $this->decryptIV = mcrypt_generic($ecb, $this->decryptIV); + $this->debuffer = substr($ciphertext, $last_pos); + $plaintext.= $this->debuffer ^ $this->decryptIV; + } + + return $plaintext; + } if (!$this->continuousBuffer) { mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV); @@ -576,6 +672,7 @@ class Crypt_DES { } $buffer = &$this->debuffer; + $continuousBuffer = $this->continuousBuffer; $plaintext = ''; switch ($this->mode) { case CRYPT_DES_MODE_ECB: @@ -618,14 +715,33 @@ class Crypt_DES { } break; case CRYPT_DES_MODE_CFB: - $xor = $this->_processBlock($this->decryptIV, CRYPT_DES_ENCRYPT); - for ($i = 0; $i < strlen($ciphertext); $i+=8) { + if (!empty($buffer['ciphertext'])) { + $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($buffer['ciphertext'])); + $buffer['ciphertext'].= substr($ciphertext, 0, strlen($plaintext)); + if (strlen($buffer['ciphertext']) == 8) { + $xor = $this->_processBlock($buffer['ciphertext'], CRYPT_DES_ENCRYPT); + $buffer['ciphertext'] = ''; + } + $start = strlen($plaintext); + $block = $this->decryptIV; + } else { + $plaintext = ''; + $xor = $this->_processBlock($this->decryptIV, CRYPT_DES_ENCRYPT); + $start = 0; + } + + for ($i = $start; $i < strlen($ciphertext); $i+=8) { $block = substr($ciphertext, $i, 8); $plaintext.= $block ^ $xor; - $xor = $this->_processBlock($block, CRYPT_DES_ENCRYPT); + if ($continuousBuffer && strlen($block) != 8) { + $buffer['ciphertext'].= $block; + $block = $xor; + } else if (strlen($block) == 8) { + $xor = $this->_processBlock($block, CRYPT_DES_ENCRYPT); + } } if ($this->continuousBuffer) { - $this->decryptIV = $xor; + $this->decryptIV = $block; } break; case CRYPT_DES_MODE_OFB: diff --git a/phpseclib/Crypt/RSA.php b/phpseclib/Crypt/RSA.php index 9f9f64ae..5a5150c6 100644 --- a/phpseclib/Crypt/RSA.php +++ b/phpseclib/Crypt/RSA.php @@ -62,7 +62,7 @@ * @author Jim Wigginton * @copyright MMIX Jim Wigginton * @license http://www.gnu.org/licenses/lgpl.txt - * @version $Id: RSA.php,v 1.19 2010-09-12 21:58:54 terrafrost Exp $ + * @version $Id: RSA.php,v 1.20 2010-09-26 03:10:20 terrafrost Exp $ * @link http://phpseclib.sourceforge.net */ @@ -784,13 +784,12 @@ 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-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'); diff --git a/phpseclib/Crypt/Rijndael.php b/phpseclib/Crypt/Rijndael.php index 08b0f090..f81fb78f 100644 --- a/phpseclib/Crypt/Rijndael.php +++ b/phpseclib/Crypt/Rijndael.php @@ -64,7 +64,7 @@ * @author Jim Wigginton * @copyright MMVIII Jim Wigginton * @license http://www.gnu.org/licenses/lgpl.txt - * @version $Id: Rijndael.php,v 1.13 2010-09-12 21:58:54 terrafrost Exp $ + * @version $Id: Rijndael.php,v 1.14 2010-09-26 03:10:20 terrafrost Exp $ * @link http://phpseclib.sourceforge.net */ @@ -384,7 +384,7 @@ class Crypt_Rijndael { * @var String * @access private */ - var $enbuffer = ''; + var $enbuffer = array('encrypted' => '', 'xor' => ''); /** * Decryption buffer for CTR, OFB and CFB modes @@ -393,7 +393,7 @@ class Crypt_Rijndael { * @var String * @access private */ - var $debuffer = ''; + var $debuffer = array('ciphertext' => ''); /** * Default Constructor. @@ -409,12 +409,12 @@ class Crypt_Rijndael { { switch ($mode) { case CRYPT_RIJNDAEL_MODE_ECB: - case CRYPT_RIJNDAEL_MODE_CFB: + case CRYPT_RIJNDAEL_MODE_CBC: $this->paddable = true; $this->mode = $mode; break; - case CRYPT_RIJNDAEL_MODE_CBC: case CRYPT_RIJNDAEL_MODE_CTR: + case CRYPT_RIJNDAEL_MODE_CFB: case CRYPT_RIJNDAEL_MODE_OFB: $this->mode = $mode; break; @@ -662,6 +662,7 @@ class Crypt_Rijndael { $block_size = $this->block_size; $buffer = &$this->enbuffer; + $continuousBuffer = $this->continuousBuffer; $ciphertext = ''; switch ($this->mode) { case CRYPT_RIJNDAEL_MODE_ECB: @@ -705,12 +706,31 @@ class Crypt_Rijndael { } break; case CRYPT_RIJNDAEL_MODE_CFB: - $iv = $this->encryptIV; - for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { + if (!empty($buffer['xor'])) { + $ciphertext = $plaintext ^ $buffer['xor']; + $iv = $buffer['encrypted'] . $ciphertext; + $start = strlen($ciphertext); + $buffer['encrypted'].= $ciphertext; + $buffer['xor'] = substr($buffer['xor'], strlen($ciphertext)); + } else { + $ciphertext = ''; + $iv = $this->encryptIV; + $start = 0; + } + + for ($i = $start; $i < strlen($plaintext); $i+=$block_size) { $block = substr($plaintext, $i, $block_size); - $iv = $block ^ $this->_encryptBlock($iv); + $xor = $this->_encryptBlock($iv); + $iv = $block ^ $xor; + if ($continuousBuffer && strlen($iv) != $block_size) { + $buffer = array( + 'encrypted' => $iv, + 'xor' => substr($xor, strlen($iv)) + ); + } $ciphertext.= $iv; } + if ($this->continuousBuffer) { $this->encryptIV = $iv; } @@ -764,6 +784,7 @@ class Crypt_Rijndael { $block_size = $this->block_size; $buffer = &$this->debuffer; + $continuousBuffer = $this->continuousBuffer; $plaintext = ''; switch ($this->mode) { case CRYPT_RIJNDAEL_MODE_ECB: @@ -806,14 +827,33 @@ class Crypt_Rijndael { } break; case CRYPT_RIJNDAEL_MODE_CFB: - $iv = $this->_encryptBlock($this->decryptIV); - for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { + if (!empty($buffer['ciphertext'])) { + $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($buffer['ciphertext'])); + $buffer['ciphertext'].= substr($ciphertext, 0, strlen($plaintext)); + if (strlen($buffer['ciphertext']) == $block_size) { + $xor = $this->_encryptBlock($buffer['ciphertext']); + $buffer['ciphertext'] = ''; + } + $start = strlen($plaintext); + $block = $this->decryptIV; + } else { + $plaintext = ''; + $xor = $this->_encryptBlock($this->decryptIV); + $start = 0; + } + + for ($i = $start; $i < strlen($ciphertext); $i+=$block_size) { $block = substr($ciphertext, $i, $block_size); - $plaintext.= $block ^ $iv; - $iv = $this->_encryptBlock($block); + $plaintext.= $block ^ $xor; + if ($continuousBuffer && strlen($block) != $block_size) { + $buffer['ciphertext'].= $block; + $block = $xor; + } else if (strlen($block) == $block_size) { + $xor = $this->_encryptBlock($block); + } } if ($this->continuousBuffer) { - $this->decryptIV = $iv; + $this->decryptIV = $block; } break; case CRYPT_RIJNDAEL_MODE_OFB: diff --git a/phpseclib/Crypt/TripleDES.php b/phpseclib/Crypt/TripleDES.php index 50d8490d..ea38288f 100644 --- a/phpseclib/Crypt/TripleDES.php +++ b/phpseclib/Crypt/TripleDES.php @@ -47,7 +47,7 @@ * @author Jim Wigginton * @copyright MMVII Jim Wigginton * @license http://www.gnu.org/licenses/lgpl.txt - * @version $Id: TripleDES.php,v 1.15 2010-09-12 21:58:54 terrafrost Exp $ + * @version $Id: TripleDES.php,v 1.16 2010-09-26 03:10:20 terrafrost Exp $ * @link http://phpseclib.sourceforge.net */ @@ -273,7 +273,6 @@ class Crypt_TripleDES { $this->mode = 'ctr'; break; case CRYPT_DES_MODE_CFB: - $this->paddable = true; $this->mode = 'ncfb'; break; case CRYPT_DES_MODE_OFB: @@ -300,12 +299,12 @@ class Crypt_TripleDES { switch ($mode) { case CRYPT_DES_MODE_ECB: - case CRYPT_DES_MODE_CFB: + case CRYPT_DES_MODE_CBC: $this->paddable = true; $this->mode = $mode; break; case CRYPT_DES_MODE_CTR: - case CRYPT_DES_MODE_CBC: + case CRYPT_DES_MODE_CFB: case CRYPT_DES_MODE_OFB: $this->mode = $mode; break; @@ -432,10 +431,47 @@ class Crypt_TripleDES { $this->enmcrypt = mcrypt_module_open(MCRYPT_3DES, '', $this->mode, ''); } mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV); - $this->enchanged = false; + if ($this->mode != 'ncfb') { + $this->enchanged = false; + } } - $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext); + if ($this->mode != 'ncfb') { + $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext); + } else { + static $ecb; + + if ($this->enchanged) { + $ecb = mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_ECB, ''); + mcrypt_generic_init($ecb, $this->key, "\0\0\0\0\0\0\0\0"); + $this->enchanged = false; + } + + if (strlen($this->enbuffer)) { + $ciphertext = $plaintext ^ substr($this->encryptIV, strlen($this->enbuffer)); + $this->enbuffer.= $ciphertext; + if (strlen($this->enbuffer) == 8) { + $this->encryptIV = $this->enbuffer; + $this->enbuffer = ''; + mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV); + } + $plaintext = substr($plaintext, strlen($ciphertext)); + } else { + $ciphertext = ''; + } + + $last_pos = strlen($plaintext) & 0xFFFFFFF8; + $ciphertext.= $last_pos ? mcrypt_generic($this->enmcrypt, substr($plaintext, 0, $last_pos)) : ''; + + if (strlen($plaintext) & 0x7) { + if (strlen($ciphertext)) { + $this->encryptIV = substr($ciphertext, -8); + } + $this->encryptIV = mcrypt_generic($ecb, $this->encryptIV); + $this->enbuffer = substr($plaintext, $last_pos) ^ $this->encryptIV; + $ciphertext.= $this->enbuffer; + } + } if (!$this->continuousBuffer) { mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV); @@ -453,6 +489,7 @@ class Crypt_TripleDES { $des = $this->des; $buffer = &$this->enbuffer; + $continuousBuffer = $this->continuousBuffer; $ciphertext = ''; switch ($this->mode) { case CRYPT_DES_MODE_ECB: @@ -515,15 +552,34 @@ class Crypt_TripleDES { } break; case CRYPT_DES_MODE_CFB: - $iv = $this->encryptIV; - for ($i = 0; $i < strlen($plaintext); $i+=8) { + if (!empty($buffer['xor'])) { + $ciphertext = $plaintext ^ $buffer['xor']; + $iv = $buffer['encrypted'] . $ciphertext; + $start = strlen($ciphertext); + $buffer['encrypted'].= $ciphertext; + $buffer['xor'] = substr($buffer['xor'], strlen($ciphertext)); + } else { + $ciphertext = ''; + $iv = $this->encryptIV; + $start = 0; + } + + for ($i = $start; $i < strlen($plaintext); $i+=8) { $block = substr($plaintext, $i, 8); $iv = $des[0]->_processBlock($iv, CRYPT_DES_ENCRYPT); $iv = $des[1]->_processBlock($iv, CRYPT_DES_DECRYPT); - $iv = $des[2]->_processBlock($iv, CRYPT_DES_ENCRYPT); - $iv^= $block; + $xor= $des[2]->_processBlock($iv, CRYPT_DES_ENCRYPT); + + $iv = $block ^ $xor; + if ($continuousBuffer && strlen($iv) != 8) { + $buffer = array( + 'encrypted' => $iv, + 'xor' => substr($xor, strlen($iv)) + ); + } $ciphertext.= $iv; } + if ($this->continuousBuffer) { $this->encryptIV = $iv; } @@ -585,10 +641,50 @@ class Crypt_TripleDES { $this->demcrypt = mcrypt_module_open(MCRYPT_3DES, '', $this->mode, ''); } mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV); - $this->dechanged = false; + if ($this->mode != 'ncfb') { + $this->dechanged = false; + } } - $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext); + if ($this->mode != 'ncfb') { + $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext); + } else { + static $ecb; + + if ($this->dechanged) { + $ecb = mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_ECB, ''); + mcrypt_generic_init($ecb, $this->key, "\0\0\0\0\0\0\0\0"); + $this->dechanged = false; + } + + if (strlen($this->debuffer)) { + $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($this->debuffer)); + + $this->debuffer.= substr($ciphertext, 0, strlen($plaintext)); + if (strlen($this->debuffer) == 8) { + $this->decryptIV = $this->debuffer; + $this->debuffer = ''; + mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV); + } + $ciphertext = substr($ciphertext, strlen($plaintext)); + } else { + $plaintext = ''; + } + + $last_pos = strlen($ciphertext) & 0xFFFFFFF8; + $plaintext.= $last_pos ? mdecrypt_generic($this->demcrypt, substr($ciphertext, 0, $last_pos)) : ''; + + if (strlen($ciphertext) & 0x7) { + if (strlen($plaintext)) { + $this->decryptIV = substr($ciphertext, $last_pos - 8, 8); + } + $this->decryptIV = mcrypt_generic($ecb, $this->decryptIV); + $this->debuffer = substr($ciphertext, $last_pos); + $plaintext.= $this->debuffer ^ $this->decryptIV; + } + + return $plaintext; + } if (!$this->continuousBuffer) { mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV); @@ -606,6 +702,7 @@ class Crypt_TripleDES { $des = $this->des; $buffer = &$this->enbuffer; + $continuousBuffer = $this->continuousBuffer; $plaintext = ''; switch ($this->mode) { case CRYPT_DES_MODE_ECB: @@ -662,6 +759,121 @@ class Crypt_TripleDES { } break; case CRYPT_DES_MODE_CFB: + if (!empty($buffer['ciphertext'])) { + $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($buffer['ciphertext'])); + $buffer['ciphertext'].= substr($ciphertext, 0, strlen($plaintext)); + if (strlen($buffer['ciphertext']) == 8) { + $xor = $des[0]->_processBlock($buffer['ciphertext'], CRYPT_DES_ENCRYPT); + $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT); + $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT); + $buffer['ciphertext'] = ''; + } + $start = strlen($plaintext); + $block = $this->decryptIV; + } else { + $plaintext = ''; + $xor = $des[0]->_processBlock($this->decryptIV, CRYPT_DES_ENCRYPT); + $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT); + $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT); + $start = 0; + } + + for ($i = $start; $i < strlen($ciphertext); $i+=8) { + $block = substr($ciphertext, $i, 8); + $plaintext.= $block ^ $xor; + if ($continuousBuffer && strlen($block) != 8) { + $buffer['ciphertext'].= $block; + $block = $xor; + } else if (strlen($block) == 8) { + $xor = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT); + $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT); + $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT); + } + } + if ($this->continuousBuffer) { + $this->decryptIV = $block; + } + break; + + + + + + + + + + + + + + $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); + $plaintext.= $iv ^ $block; + $iv = $block; + } + if ($this->continuousBuffer) { + $this->decryptIV = $block; + } + break; + + + + + + + + + if (!empty($buffer)) { + $plaintext = $ciphertext ^ $buffer['xor']; + $iv = $buffer['decrypted'] . $plaintext; + $start = strlen($plaintext); + $buffer = array(); + } else { + $iv = $this->decryptIV; + $start = 0; + } + + for ($i = $start; $i < strlen($ciphertext); $i+=8) { + $block = substr($ciphertext, $i, 8); + $xor = $des[0]->_processBlock($iv, CRYPT_DES_ENCRYPT); + $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT); + $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT); + +/* + $xor = $des[2]->_processBlock($iv, CRYPT_DES_DECRYPT); + $xor = $des[1]->_processBlock($xor, CRYPT_DES_ENCRYPT); + $xor = $des[0]->_processBlock($xor, CRYPT_DES_DECRYPT); +*/ + + //$xor = $this->_encryptBlock($iv); + $iv = $block ^ $xor; + if ($continuousBuffer && strlen($iv) != 8) { + $buffer = array( + 'decrypted' => $iv, + 'xor' => substr($xor, strlen($iv)) + ); + } + $plaintext.= $iv; + } + + if ($this->continuousBuffer) { + $this->decryptIV = $xor; + } +break; + + + + + + + + + $iv = $this->decryptIV; for ($i = 0; $i < strlen($ciphertext); $i+=8) { $block = substr($ciphertext, $i, 8);