From e9470d1fc5c4ae1ce2af9deb1d2d18370b98c80c Mon Sep 17 00:00:00 2001 From: terrafrost Date: Sat, 17 Jan 2015 09:42:47 -0600 Subject: [PATCH] TripleDES: updates to accomodate inner chaining --- phpseclib/Crypt/TripleDES.php | 36 ++++++++++++++++++------------ tests/Unit/Crypt/TripleDESTest.php | 33 +++++++++++++++++++++------ 2 files changed, 48 insertions(+), 21 deletions(-) diff --git a/phpseclib/Crypt/TripleDES.php b/phpseclib/Crypt/TripleDES.php index 35819ba7..5e63f361 100644 --- a/phpseclib/Crypt/TripleDES.php +++ b/phpseclib/Crypt/TripleDES.php @@ -68,13 +68,21 @@ if (!class_exists('Crypt_DES')) { * * Inner chaining is used by SSH-1 and is generally considered to be less secure then outer chaining (CRYPT_DES_MODE_CBC3). */ +define('CRYPT_MODE_3CBC', -2); +/** + * BC version of the above. + */ define('CRYPT_DES_MODE_3CBC', -2); /** * Encrypt / decrypt using outer chaining * * Outer chaining is used by SSH-2 and when the mode is set to CRYPT_DES_MODE_CBC. */ -define('CRYPT_DES_MODE_CBC3', CRYPT_DES_MODE_CBC); +define('CRYPT_MODE_CBC3', CRYPT_MODE_CBC); +/** + * BC version of the above. + */ +define('CRYPT_DES_MODE_CBC3', CRYPT_MODE_CBC3); /**#@-*/ /** @@ -190,20 +198,20 @@ class Crypt_TripleDES extends Crypt_DES * @param optional Integer $mode * @access public */ - function Crypt_TripleDES($mode = CRYPT_DES_MODE_CBC) + function Crypt_TripleDES($mode = CRYPT_MODE_CBC) { switch ($mode) { // In case of CRYPT_DES_MODE_3CBC, we init as CRYPT_DES_MODE_CBC // and additional flag us internally as 3CBC case CRYPT_DES_MODE_3CBC: - parent::Crypt_Base(CRYPT_DES_MODE_CBC); + parent::Crypt_Base(CRYPT_MODE_CBC); $this->mode_3cbc = true; // This three $des'es will do the 3CBC work (if $key > 64bits) $this->des = array( - new Crypt_DES(CRYPT_DES_MODE_CBC), - new Crypt_DES(CRYPT_DES_MODE_CBC), - new Crypt_DES(CRYPT_DES_MODE_CBC), + new Crypt_DES(CRYPT_MODE_CBC), + new Crypt_DES(CRYPT_MODE_CBC), + new Crypt_DES(CRYPT_MODE_CBC), ); // we're going to be doing the padding, ourselves, so disable it in the Crypt_DES objects @@ -308,7 +316,7 @@ class Crypt_TripleDES extends Crypt_DES function encrypt($plaintext) { // parent::en/decrypt() is able to do all the work for all modes and keylengths, - // except for: CRYPT_DES_MODE_3CBC (inner chaining CBC) with a key > 64bits + // except for: CRYPT_MODE_3CBC (inner chaining CBC) with a key > 64bits // if the key is smaller then 8, do what we'd normally do if ($this->mode_3cbc && strlen($this->key) > 8) { @@ -455,19 +463,19 @@ class Crypt_TripleDES extends Crypt_DES * Sets the internal crypt engine * * @see Crypt_Base::Crypt_Base() - * @see Crypt_Base::setEngine() - * @param optional Integer $engine + * @see Crypt_Base::setPreferredEngine() + * @param Integer $engine * @access public * @return Integer */ - function setEngine($engine = CRYPT_DES_MODE_MCRYPT) + function setPreferredEngine($engine) { if ($this->mode_3cbc) { - $this->des[0]->setEngine($engine); - $this->des[1]->setEngine($engine); - $this->des[2]->setEngine($engine); + $this->des[0]->setPreferredEngine($engine); + $this->des[1]->setPreferredEngine($engine); + $this->des[2]->setPreferredEngine($engine); } - return parent::setEngine($engine); + return parent::setPreferredEngine($engine); } } diff --git a/tests/Unit/Crypt/TripleDESTest.php b/tests/Unit/Crypt/TripleDESTest.php index ba650996..d317f716 100644 --- a/tests/Unit/Crypt/TripleDESTest.php +++ b/tests/Unit/Crypt/TripleDESTest.php @@ -9,14 +9,14 @@ require_once 'Crypt/TripleDES.php'; class Unit_Crypt_TripleDESTest extends PhpseclibTestCase { + var $engines = array( + CRYPT_ENGINE_INTERNAL => 'internal', + CRYPT_ENGINE_MCRYPT => 'mcrypt', + CRYPT_ENGINE_OPENSSL => 'OpenSSL', + ); + public function engineVectors() { - $engines = array( - CRYPT_ENGINE_INTERNAL => 'internal', - CRYPT_ENGINE_MCRYPT => 'mcrypt', - CRYPT_ENGINE_OPENSSL => 'OpenSSL', - ); - // tests from http://csrc.nist.gov/publications/nistpubs/800-20/800-20.pdf#page=273 $tests = array( // Table A.1 @@ -88,7 +88,7 @@ class Unit_Crypt_TripleDESTest extends PhpseclibTestCase ); $result = array(); // @codingStandardsIgnoreStart - foreach ($engines as $engine => $engineName) + foreach ($this->engines as $engine => $engineName) foreach ($tests as $test) $result[] = array($engine, $engineName, $test[0], $test[1], $test[2]); // @codingStandardsIgnoreEnd @@ -160,4 +160,23 @@ class Unit_Crypt_TripleDESTest extends PhpseclibTestCase $plaintext = bin2hex($plaintext); $this->assertEquals($result, $expected, "Failed asserting that $plaintext yielded expected output in $engineName engine"); } + + public function testInnerChaining() + { + // regular CBC returns + // e089b6d84708c6bc80be6c2da82bd19a79ffe11f02933ac1 + $expected = 'e089b6d84708c6bc6f04c8971121603d7be2861efae0f3f5'; + + $des = new Crypt_TripleDES(CRYPT_DES_MODE_3CBC); + $des->setKey('abcdefghijklmnopqrstuvwx'); + + for ($this->engines as $engine->$engineName) { + $des->setPreferredEngine($engine); + if (!$des->isValidEngine($engine)) { + self::markTestSkipped('Unable to initialize ' . $engineName . ' engine'); + } + $result = bin2hex($des->encrypt(str_repeat('a', 16)); + $this->assertEquals($result, $expected, "Failed asserting inner chainin worked correctly in $engineName engine"); + } + } }