From 18d5fadccea36d8026b77830a2c6442b2856bb47 Mon Sep 17 00:00:00 2001 From: Jaime Perez Crespo <jaime.perez@uninett.no> Date: Sat, 20 Jun 2015 16:50:39 +0200 Subject: [PATCH] Move the aes[En|De]crypt() functionality in \SimpleSAML\Utils\Crypto to internal methods where the secret is passed as a parameter. Then we don't need a working configuration to test the functionality. --- lib/SimpleSAML/Utils/Crypto.php | 53 ++++++++++++++--- tests/lib/SimpleSAML/Utils/CryptoTest.php | 72 +++++++++++++++++++++++ 2 files changed, 116 insertions(+), 9 deletions(-) create mode 100644 tests/lib/SimpleSAML/Utils/CryptoTest.php diff --git a/lib/SimpleSAML/Utils/Crypto.php b/lib/SimpleSAML/Utils/Crypto.php index e09bbfea5..d704a6241 100644 --- a/lib/SimpleSAML/Utils/Crypto.php +++ b/lib/SimpleSAML/Utils/Crypto.php @@ -14,15 +14,15 @@ class Crypto * Decrypt data using AES and the system-wide secret salt as key. * * @param string $ciphertext The encrypted data to decrypt. + * @param string $secret The secret to use to decrypt the data. * * @return string The decrypted data. * @htorws \InvalidArgumentException If $ciphertext is not a string. * @throws \SimpleSAML_Error_Exception If the mcrypt module is not loaded. * - * @author Andreas Solberg, UNINETT AS <andreas.solberg@uninett.no> - * @author Jaime Perez, UNINETT AS <jaime.perez@uninett.no> + * @see \SimpleSAML\Utils\Crypto::aesDecrypt() */ - public static function aesDecrypt($ciphertext) + private static function _aesDecrypt($ciphertext, $secret) { if (!is_string($ciphertext)) { throw new \InvalidArgumentException('Input parameter "$ciphertext" must be a string.'); @@ -37,7 +37,7 @@ class Crypto $ivSize = mcrypt_get_iv_size($enc, $mode); $keySize = mcrypt_get_key_size($enc, $mode); - $key = hash('sha256', Config::getSecretSalt(), true); + $key = hash('sha256', $secret, true); $key = substr($key, 0, $keySize); $iv = substr($ciphertext, 0, $ivSize); @@ -54,22 +54,39 @@ class Crypto /** - * Encrypt data using AES and the system-wide secret salt as key. + * Decrypt data using AES and the system-wide secret salt as key. + * + * @param string $ciphertext The encrypted data to decrypt. + * + * @return string The decrypted data. + * @htorws \InvalidArgumentException If $ciphertext is not a string. + * @throws \SimpleSAML_Error_Exception If the mcrypt module is not loaded. * + * @author Andreas Solberg, UNINETT AS <andreas.solberg@uninett.no> + * @author Jaime Perez, UNINETT AS <jaime.perez@uninett.no> + */ + public static function aesDecrypt($ciphertext) + { + return self::_aesDecrypt($ciphertext, Config::getSecretSalt()); + } + + + /** * @param string $data The data to encrypt. + * @param string $secret The secret to use to encrypt the data. * * @return string The encrypted data and IV. * @throws \InvalidArgumentException If $data is not a string. * @throws \SimpleSAML_Error_Exception If the mcrypt module is not loaded. * - * @author Andreas Solberg, UNINETT AS <andreas.solberg@uninett.no> - * @author Jaime Perez, UNINETT AS <jaime.perez@uninett.no> + * @see \SimpleSAML\Utils\Crypto::aesEncrypt() */ - public static function aesEncrypt($data) + private static function _aesEncrypt($data, $secret) { if (!is_string($data)) { throw new \InvalidArgumentException('Input parameter "$data" must be a string.'); } + if (!function_exists("mcrypt_encrypt")) { throw new \SimpleSAML_Error_Exception('The mcrypt PHP module is not loaded.'); } @@ -81,7 +98,7 @@ class Crypto $ivSize = mcrypt_get_iv_size($enc, $mode); $keySize = mcrypt_get_key_size($enc, $mode); - $key = hash('sha256', Config::getSecretSalt(), true); + $key = hash('sha256', $secret, true); $key = substr($key, 0, $keySize); $len = strlen($data); @@ -96,6 +113,24 @@ class Crypto } + /** + * Encrypt data using AES and the system-wide secret salt as key. + * + * @param string $data The data to encrypt. + * + * @return string The encrypted data and IV. + * @throws \InvalidArgumentException If $data is not a string. + * @throws \SimpleSAML_Error_Exception If the mcrypt module is not loaded. + * + * @author Andreas Solberg, UNINETT AS <andreas.solberg@uninett.no> + * @author Jaime Perez, UNINETT AS <jaime.perez@uninett.no> + */ + public static function aesEncrypt($data) + { + return self::_aesEncrypt($data, Config::getSecretSalt()); + } + + /** * Load a private key from metadata. * diff --git a/tests/lib/SimpleSAML/Utils/CryptoTest.php b/tests/lib/SimpleSAML/Utils/CryptoTest.php new file mode 100644 index 000000000..abd090c17 --- /dev/null +++ b/tests/lib/SimpleSAML/Utils/CryptoTest.php @@ -0,0 +1,72 @@ +<?php + + +/** + * Tests for SimpleSAML\Utils\Crypto. + */ +class CryptoTest extends PHPUnit_Framework_TestCase +{ + + /** + * Test invalid input provided to the aesDecrypt() method. + * + * @expectedException InvalidArgumentException + */ + public function testAesDecryptBadInput() + { + \SimpleSAML\Utils\Crypto::aesDecrypt(array()); + } + + + /** + * Test invalid input provided to the aesEncrypt() method. + * + * @expectedException InvalidArgumentException + */ + public function testAesEncryptBadInput() + { + \SimpleSAML\Utils\Crypto::aesEncrypt(array()); + } + + + /** + * Test that aesDecrypt() works properly, being able to decrypt some previously known (and correct) + * ciphertext. + */ + public function testAesDecrypt() + { + if (!extension_loaded('mcrypt')) { + $this->setExpectedException('\SimpleSAML_Error_Exception'); + } + + $secret = 'SUPER_SECRET_SALT'; + $m = new ReflectionMethod('\SimpleSAML\Utils\Crypto', '_aesDecrypt'); + $m->setAccessible(true); + + $plaintext = 'SUPER_SECRET_TEXT'; + $ciphertext = 'J5/rmhc54DpEbnP4rLD3IUUiSOE28165Gpr8BzNF4bFHjjesCe6mnHRZ6EiRbQE41ZDB/qg3ilWlw1gWzlKKww=='; + $this->assertEquals($plaintext, $m->invokeArgs(null, array(base64_decode($ciphertext), $secret))); + } + + + /** + * Test that aesEncrypt() produces ciphertexts that aesDecrypt() can decrypt. + */ + public function testAesEncrypt() + { + if (!extension_loaded('mcrypt')) { + $this->setExpectedException('\SimpleSAML_Error_Exception'); + } + + $secret = 'SUPER_SECRET_SALT'; + $e = new ReflectionMethod('\SimpleSAML\Utils\Crypto', '_aesEncrypt'); + $d = new ReflectionMethod('\SimpleSAML\Utils\Crypto', '_aesDecrypt'); + $e->setAccessible(true); + $d->setAccessible(true); + + $original_plaintext = 'SUPER_SECRET_TEXT'; + $ciphertext = $e->invokeArgs(null, array($original_plaintext, $secret)); + $decrypted_plaintext = $d->invokeArgs(null, array($ciphertext, $secret)); + $this->assertEquals($original_plaintext, $decrypted_plaintext); + } +} -- GitLab