diff --git a/include/class.crypto.php b/include/class.crypto.php index 4b5a8754b93a2b5ef7d57f3901465c1a7f33c77a..6ca0b2b0816dfe9db21d50074ea3b0b913480700 100644 --- a/include/class.crypto.php +++ b/include/class.crypto.php @@ -268,6 +268,7 @@ endif; Class CryptoMcrypt extends CryptoAlgo { + # WARNING: Change and you will lose your passwords ... var $ciphers = array( CRYPTO_CIPHER_MCRYPT_RIJNDAEL_128 => array( 'name' => MCRYPT_RIJNDAEL_128, @@ -365,11 +366,9 @@ Class CryptoMcrypt extends CryptoAlgo { $keysize = mcrypt_enc_get_key_size($td); $ivsize = mcrypt_enc_get_iv_size($td); - if(strlen($ciphertext) <= $ivsize) - return false; - $iv = substr($ciphertext, 0, $ivsize); - $ciphertext = substr($ciphertext, $ivsize); + if (!($ciphertext = substr($ciphertext, $ivsize))) + return false; // Do the decryption. mcrypt_generic_init($td, $this->getKeyHash($iv, $ivsize), $iv); @@ -404,9 +403,11 @@ define('CRYPTO_CIPHER_OPENSSL_AES_128_CBC', 1); class CryptoOpenSSL extends CryptoAlgo { + # WARNING: Change and you will lose your passwords ... var $ciphers = array( CRYPTO_CIPHER_OPENSSL_AES_128_CBC => array( 'method' => 'aes-128-cbc', + 'seed' => 8 ), ); @@ -452,10 +453,12 @@ class CryptoOpenSSL extends CryptoAlgo { return false; $ivlen = openssl_cipher_iv_length($cipher['method']); - $iv = openssl_random_pseudo_bytes($ivlen); + $iv = openssl_random_pseudo_bytes($cipher['seed']); $key = $this->getKeyHash($iv, $ivlen); - if(!($ciphertext = openssl_encrypt($text, $cipher['method'], $key, 0, $iv))) + $options = (defined('OPENSSL_RAW_DATA')) ? OPENSSL_RAW_DATA : true; + if(!($ciphertext = openssl_encrypt($text, $cipher['method'], $key, + $options, $iv))) return false; return sprintf('$%s$%s%s', $cipher['cid'], $iv, $ciphertext); @@ -479,15 +482,17 @@ class CryptoOpenSSL extends CryptoAlgo { if(!$cid || !$ciphertext - || !($method=$this->getMethod($cid))) + || !($cipher=$this->getCipher($cid))) return false; - $ivlen = openssl_cipher_iv_length($method); - $iv = substr($ciphertext, 0, $ivlen); - $ciphertext = substr($ciphertext, $ivlen); + $ivlen = openssl_cipher_iv_length($cipher['method']); + $iv = substr($ciphertext, 0, $cipher['seed']); + $ciphertext = substr($ciphertext, $cipher['seed']); $key = $this->getKeyHash($iv, $ivlen); - $plaintext = openssl_decrypt($ciphertext, $method, $key, 0, $iv); + $options = (defined('OPENSSL_RAW_DATA')) ? OPENSSL_RAW_DATA : true; + $plaintext = openssl_decrypt($ciphertext, $cipher['method'], $key, + $options, $iv); return $plaintext; } @@ -518,7 +523,7 @@ class CryptoPHPSecLib extends CryptoAlgo { var $ciphers = array( //Replace with interface class CRYPTO_CIPHER_PHPSECLIB_AES_CBC => array( 'mode' => CRYPT_AES_MODE_CBC, - 'ivlen' => 16, + 'seed' => 8, 'class' => 'Crypt_AES', ), ); @@ -562,7 +567,7 @@ class CryptoPHPSecLib extends CryptoAlgo { ) return false; - $ivlen = $cipher['ivlen']; + $ivlen = $cipher['seed']; $iv = Crypto::randcode($ivlen); $crypto->setKey($this->getKeyHash($iv, $ivlen)); $crypto->setIV($iv); @@ -583,9 +588,11 @@ class CryptoPHPSecLib extends CryptoAlgo { ) return false; - $ivlen = $cipher['ivlen']; + $ivlen = $cipher['seed']; $iv = substr($ciphertext, 0, $ivlen); - $ciphertext = substr($ciphertext, $ivlen); + if (!($ciphertext = substr($ciphertext, $ivlen))) + return false; + $crypto->setKey($this->getKeyHash($iv, $ivlen)); $crypto->setIV($iv); diff --git a/setup/test/tests/class.test.php b/setup/test/tests/class.test.php index 4a82354cf23b4b1f8b2c40f3bf47db185d877ab1..c7e2fb3fef475841e57865db640480ca587380d9 100644 --- a/setup/test/tests/class.test.php +++ b/setup/test/tests/class.test.php @@ -55,6 +55,32 @@ class Test { fputs(STDOUT, "."); } + function warn($message) { + $this->fails[] = array(get_class($this), '', '', 'WARNING: '.$message); + fputs(STDOUT, 'w'); + } + + function assert($expr, $message) { + if ($expr) + $this->pass(); + elseif ($message) + $this->fail('', '', $message); + else + $this->fail('', '', "assertion: {$a} != {$b}"); + } + + function assertEqual($a, $b, $message=false) { + if (!$message) + $message = "Assertion: {$a} != {$b}"; + return $this->assert($a == $b, $message); + } + + function assertNotEqual($a, $b, $message=false) { + if (!$message) + $message = "Assertion: {$a} == {$b}"; + return $this->assert($a != $b, $message); + } + function run() { $rc = new ReflectionClass(get_class($this)); foreach ($rc->getMethods() as $m) { diff --git a/setup/test/tests/test.crypto.php b/setup/test/tests/test.crypto.php new file mode 100644 index 0000000000000000000000000000000000000000..f406e3097d2f7d6a9138177b4237cb06e1366215 --- /dev/null +++ b/setup/test/tests/test.crypto.php @@ -0,0 +1,93 @@ +<?php +require_once "class.test.php"; +define('INCLUDE_DIR', realpath(dirname(__file__).'/../../../include').'/'); +define('PEAR_DIR', INCLUDE_DIR.'/pear/'); +require_once INCLUDE_DIR."class.crypto.php"; + +class TestCrypto extends Test { + var $name = "Crypto library tests"; + + var $test_data = 'supercalifragilisticexpialidocious'; # notrans + var $master = 'master'; # notrans + + var $passwords = array( + 'english-password', + 'CaseSensitive Password', + '«ταБЬℓσ»', + 'Ù©(-̮̮̃-̃)Û¶ Ù©(â—̮̮̃•̃)Û¶ Ù©(Í¡à¹Ì¯Í¡à¹)Û¶ Ù©(-̮̮̃•̃).', + 'å‘åŒè®²è¯´å®…电的手机告的世全所回广讲说跟', + ); + + function testSimple() { + $tests = array_merge(array($this->test_data), $this->passwords); + foreach ($tests as $subject) { + $enc = Crypto::encrypt($subject, $this->master, 'simple'); + $dec = Crypto::decrypt($enc, $this->master, 'simple'); + $this->assertEqual($dec, $subject, + "{$subject}: Encryption failed closed loop"); + $this->assertNotEqual($enc, $subject, + 'Data was not encrypted'); + $this->assertNotEqual($enc, false, 'Encryption failed'); + $this->assertNotEqual($dec, false, 'Decryption failed'); + + $dec = Crypto::decrypt($enc, $this->master, 'wrong'); + $this->assertNotEqual($dec, $this->test_data, 'Subkeys are broken'); + } + } + + function _testLibrary($c, $tests) { + $name = get_class($c); + foreach ($tests as $id => $subject) { + $dec = $c->decrypt(base64_decode($subject)); + $this->assertEqual($dec, $this->test_data, "$name: decryption incorrect"); + $this->assertNotEqual($dec, false, "$name: decryption FAILED"); + } + $enc = $c->encrypt($this->test_data); + $this->assertNotEqual($enc, $this->test_data, + "$name: encryption cheaped out"); + $this->assertNotEqual($enc, false, "$name: encryption failed"); + + $c->setKeys($this->master, 'wrong'); + $dec = $c->decrypt(base64_decode($subject)); + $this->assertEqual($dec, false, "$name: Subkeys are broken"); + + } + + function testMcrypt() { + $tests = array( + 1 => 'JDEkIEDoeaSiOUEGE5KQ3UmJpQ5+pUaX91HyLMG58GmNU9pZXAdiXXJsfl+7TSDlLczGD98UCD6tLuDIwI9XJLEwew==', + ); + if (!CryptoMcrypt::exists()) + return $this->warn('Not testing mcrypt encryption'); + + $c = new CryptoMcrypt(0); + $c->setKeys($this->master, 'simple'); + $this->_testLibrary($c, $tests); + } + + function testOpenSSL() { + $tests = array( + 1 => 'JDEk4Wt4jRG460XnEIzKhTCKE9I0xfU3UadzF4rvlx++uCAOz0cQXDnRFX+VzHtgvfdabZ0FJ8T3e+M=', + ); + if (!CryptoOpenSSL::exists()) + return $this->warn('Not testing openssl encryption'); + + $c = new CryptoOpenSSL(0); + $c->setKeys($this->master, 'simple'); + $this->_testLibrary($c, $tests); + } + + function testPHPSecLib() { + $tests = array( + 1 => 'JDEkj42jvo2ADNoAGCvtbKoZfsVvFPGNNPDQrlcHOxQV9pjNRTJocsJhguJtjqajFTJX6rMuEVmMgrE=', + ); + if (!CryptoPHPSecLib::exists()) + return $this->warn('Not testing PHPSecLib encryption'); + + $c = new CryptoPHPSecLib(0); + $c->setKeys($this->master, 'simple'); + $this->_testLibrary($c, $tests); + } +} +return 'TestCrypto'; +?>