diff --git a/lib/Cake/Test/Case/Utility/SecurityTest.php b/lib/Cake/Test/Case/Utility/SecurityTest.php index 9c67c7680e6..57e76375808 100644 --- a/lib/Cake/Test/Case/Utility/SecurityTest.php +++ b/lib/Cake/Test/Case/Utility/SecurityTest.php @@ -256,10 +256,27 @@ public function testRijndael() { $result = Security::rijndael('', $key, 'encrypt'); $this->assertEquals('', Security::rijndael($result, $key, 'decrypt')); - $result = Security::rijndael($txt, $key = 'this is my key of over 32 chars, yes it is', 'encrypt'); + $key = 'this is my key of over 32 chars, yes it is'; + $result = Security::rijndael($txt, $key, 'encrypt'); $this->assertEquals($txt, Security::rijndael($result, $key, 'decrypt')); } +/** + * Test that rijndael() can still decrypt values with a fixed iv. + * + * @return + */ + public function testRijndaelBackwardCompatibility() { + $this->skipIf(!function_exists('mcrypt_encrypt')); + + $txt = 'The quick brown fox jumped over the lazy dog.'; + $key = 'DYhG93b0qyJfIxfs2guVoUubWwvniR2G0FgaC9mi'; + + // Encrypted before random iv + $value = base64_decode('1WPjnq96LMzLGwNgmudHF+cAIqVUN5DaUZEpf5tm1EzSgt5iYY9o3d66iRI/fKJLTlTVGsa8HzW0jDNitmVXoQ=='); + $this->assertEquals($txt, Security::rijndael($value, $key, 'decrypt')); + } + /** * testRijndaelInvalidOperation method * diff --git a/lib/Cake/Utility/Security.php b/lib/Cake/Utility/Security.php index 324b6bb7db4..d871dce3a06 100644 --- a/lib/Cake/Utility/Security.php +++ b/lib/Cake/Utility/Security.php @@ -198,6 +198,10 @@ public static function cipher($text, $key) { /** * Encrypts/Decrypts a text using the given key using rijndael method. * + * Prior to 2.3.1, a fixed initialization vector was used. This was not + * secure. This method now uses a random iv, and will silently upgrade values when + * they are re-encrypted. + * * @param string $text Encrypted string to decrypt, normal string to encrypt * @param string $key Key to use as the encryption key for encrypted data. * @param string $operation Operation to perform, encrypt or decrypt @@ -218,12 +222,21 @@ public static function rijndael($text, $key, $operation) { } $algorithm = MCRYPT_RIJNDAEL_256; $mode = MCRYPT_MODE_CBC; + $ivSize = mcrypt_get_iv_size($algorithm, $mode); + $cryptKey = substr($key, 0, 32); - $iv = substr($key, strlen($key) - 32, 32); if ($operation === 'encrypt') { - return mcrypt_encrypt($algorithm, $cryptKey, $text, $mode, $iv); + $iv = mcrypt_create_iv($ivSize, MCRYPT_RAND); + return $iv . '$$' . mcrypt_encrypt($algorithm, $cryptKey, $text, $mode, $iv); + } + // Backwards compatible decrypt with fixed iv + if (substr($text, $ivSize, 2) !== '$$') { + $iv = substr($key, strlen($key) - 32, 32); + return rtrim(mcrypt_decrypt($algorithm, $cryptKey, $text, $mode, $iv), "\0"); } + $iv = substr($text, 0, $ivSize); + $text = substr($text, $ivSize + 2); return rtrim(mcrypt_decrypt($algorithm, $cryptKey, $text, $mode, $iv), "\0"); }