Browse files

Use random iv values in rijndael.

Using fixed iv values has a number of known problems like dictionary
attacks against the cipher key. Use a random iv value for all future
encrpyted values. Provide backwards compatibility for values encrypted
with fixed iv's, and silently upgrade values for enhanced security.
  • Loading branch information...
1 parent 613aa19 commit 974ac44fb43a7ecba9f14d16a0c7e39530f14e88 @markstory markstory committed Feb 9, 2013
Showing with 33 additions and 3 deletions.
  1. +18 −1 lib/Cake/Test/Case/Utility/SecurityTest.php
  2. +15 −2 lib/Cake/Utility/Security.php
View
19 lib/Cake/Test/Case/Utility/SecurityTest.php
@@ -256,11 +256,28 @@ 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
*
* @expectedException PHPUnit_Framework_Error
View
17 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");
}

0 comments on commit 974ac44

Please sign in to comment.