diff --git a/lib/Cake/Controller/Component/CookieComponent.php b/lib/Cake/Controller/Component/CookieComponent.php index cceda8f3d..9f0879f92 100644 --- a/lib/Cake/Controller/Component/CookieComponent.php +++ b/lib/Cake/Controller/Component/CookieComponent.php @@ -130,11 +130,10 @@ class CookieComponent extends Component { /** * Type of encryption to use. * - * Currently only one method is available + * Currently two methods are available: cipher and rijndael * Defaults to Security::cipher(); * * @var string - * @todo add additional encryption methods */ protected $_type = 'cipher'; @@ -343,14 +342,23 @@ class CookieComponent extends Component { } /** - * Will allow overriding default encryption method. + * Will allow overriding default encryption method. Use this method + * in ex: AppController::beforeFilter() before you have read or + * written any cookies. * * @param string $type Encryption method * @return void - * @todo NOT IMPLEMENTED */ public function type($type = 'cipher') { - $this->_type = 'cipher'; + $availableTypes = array( + 'cipher', + 'rijndael' + ); + if (!in_array($type, $availableTypes)) { + trigger_error(__d('cake_dev', 'You must use cipher or rijndael for cookie encryption type'), E_USER_WARNING); + $type = 'cipher'; + } + $this->_type = $type; } /** @@ -439,7 +447,7 @@ class CookieComponent extends Component { if ($this->_encrypted === true) { $type = $this->_type; - $value = "Q2FrZQ==." . base64_encode(Security::$type($value, $this->key)); + $value = "Q2FrZQ==." . base64_encode(Security::$type($value, $this->key, 'encrypt')); } return $value; } @@ -462,7 +470,7 @@ class CookieComponent extends Component { if ($pos !== false) { $val = substr($val, 8); - $decrypted[$name][$key] = $this->_explode(Security::$type(base64_decode($val), $this->key)); + $decrypted[$name][$key] = $this->_explode(Security::$type(base64_decode($val), $this->key, 'decrypt')); } } } else { @@ -471,7 +479,7 @@ class CookieComponent extends Component { if ($pos !== false) { $value = substr($value, 8); - $decrypted[$name] = $this->_explode(Security::$type(base64_decode($value), $this->key)); + $decrypted[$name] = $this->_explode(Security::$type(base64_decode($value), $this->key, 'decrypt')); } } } diff --git a/lib/Cake/Test/Case/Utility/SecurityTest.php b/lib/Cake/Test/Case/Utility/SecurityTest.php index ca7fb6916..cb323d9dd 100644 --- a/lib/Cake/Test/Case/Utility/SecurityTest.php +++ b/lib/Cake/Test/Case/Utility/SecurityTest.php @@ -157,4 +157,51 @@ class SecurityTest extends CakeTestCase { $key = ''; $result = Security::cipher($txt, $key); } + +/** + * testRijndael method + * + * @return void + */ + public function testRijndael() { + $txt = 'The quick brown fox jumped over the lazy dog.'; + $key = 'DYhG93b0qyJfIxfs2guVoUubWwvniR2G0FgaC9mi'; + + $result = Security::rijndael($txt, $key, 'encrypt'); + $this->assertEquals($txt, Security::rijndael($result, $key, 'decrypt')); + + $result = Security::rijndael($key, $txt, 'encrypt'); + $this->assertEquals($key, Security::rijndael($result, $txt, 'decrypt')); + + $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'); + $this->assertEquals($txt, Security::rijndael($result, $key, 'decrypt')); + } + +/** + * testRijndaelInvalidOperation method + * + * @expectedException PHPUnit_Framework_Error + * @return void + */ + public function testRijndaelInvalidOperation() { + $txt = 'The quick brown fox jumped over the lazy dog.'; + $key = 'DYhG93b0qyJfIxfs2guVoUubWwvniR2G0FgaC9mi'; + $result = Security::rijndael($txt, $key, 'foo'); + } + +/** + * testRijndaelInvalidKey method + * + * @expectedException PHPUnit_Framework_Error + * @return void + */ + public function testRijndaelInvalidKey() { + $txt = 'The quick brown fox jumped over the lazy dog.'; + $key = 'too small'; + $result = Security::rijndael($txt, $key, 'encrypt'); + } + } diff --git a/lib/Cake/Utility/Security.php b/lib/Cake/Utility/Security.php index eb9fa4c6b..6438338a2 100644 --- a/lib/Cake/Utility/Security.php +++ b/lib/Cake/Utility/Security.php @@ -155,4 +155,38 @@ class Security { return $out; } +/** + * Encrypts/Decrypts a text using the given key using rijndael method. + * + * @param string $text Encrypted string to decrypt, normal string to encrypt + * @param string $key Key to use + * @param string $operation Operation to perform, encrypt or decrypt + * @return string Encrypted/Descrypted string + */ + public static function rijndael($text, $key, $operation) { + if (empty($key)) { + trigger_error(__d('cake_dev', 'You cannot use an empty key for Security::rijndael()'), E_USER_WARNING); + return ''; + } + if (empty($operation) || !in_array($operation, array('encrypt', 'decrypt'))) { + trigger_error(__d('cake_dev', 'You must specify the operation for Security::rijndael(), either encrypt or decrypt'), E_USER_WARNING); + return ''; + } + if (strlen($key) < 32) { + trigger_error(__d('cake_dev', 'You must use a key larger than 32 bytes for Security::rijndael()'), E_USER_WARNING); + return ''; + } + $algorithm = 'rijndael-256'; + $mode = 'cbc'; + $cryptKey = substr($key, 0, 32); + $iv = substr($key, strlen($key) - 32, 32); + $out = ''; + if ($operation === 'encrypt') { + $out .= mcrypt_encrypt($algorithm, $cryptKey, $text, $mode, $iv); + } elseif ($operation === 'decrypt') { + $out .= rtrim(mcrypt_decrypt($algorithm, $cryptKey, $text, $mode, $iv), "\0"); + } + return $out; + } + }