Permalink
Browse files

Add encrypt() and decrypt() methods.

These methods use AES-256 and provide a simple to use API with easy to
remember names.
  • Loading branch information...
1 parent ad75637 commit 215d43eb066369681b0a7637392a287bd36abf5d @markstory markstory committed Aug 28, 2013
Showing with 132 additions and 0 deletions.
  1. +67 −0 lib/Cake/Test/Case/Utility/SecurityTest.php
  2. +65 −0 lib/Cake/Utility/Security.php
@@ -302,4 +302,71 @@ public function testRijndaelInvalidKey() {
Security::rijndael($txt, $key, 'encrypt');
}
+/**
+ * Test encrypt/decrypt.
+ *
+ * @return void
+ */
+ public function testEncryptDecrypt() {
+ $txt = 'The quick brown fox';
+ $key = 'This key is longer than 32 bytes long.';
+ $result = Security::encrypt($txt, $key);
+ $this->assertNotEquals($txt, $result, 'Should be encrypted.');
+ $this->assertNotEquals($result, Security::encrypt($txt, $key), 'Each result is unique.');
+ $this->assertEquals($txt, Security::decrypt($result, $key));
+ }
+
+/**
+ * Test that short keys cause errors
+ *
+ * @expectedException CakeException
+ * @expectedExceptionMessage Invalid key for encrypt(), key must be at least 256 bits (32 bytes) long.
+ * @return void
+ */
+ public function testEncryptInvalidKey() {
+ $txt = 'The quick brown fox jumped over the lazy dog.';
+ $key = 'this is too short';
+ Security::encrypt($txt, $key);
+ }
+
+/**
+ * Test that empty data cause errors
+ *
+ * @expectedException CakeException
+ * @expectedExceptionMessage The data to encrypt cannot be empty.
+ * @return void
+ */
+ public function testEncryptInvalidData() {
+ $txt = '';
+ $key = 'This is a key that is long enough to be ok.';
+ Security::encrypt($txt, $key);
+ }
+
+
+/**
+ * Test that short keys cause errors
+ *
+ * @expectedException CakeException
+ * @expectedExceptionMessage Invalid key for decrypt(), key must be at least 256 bits (32 bytes) long.
+ * @return void
+ */
+ public function testDecryptInvalidKey() {
+ $txt = 'The quick brown fox jumped over the lazy dog.';
+ $key = 'this is too short';
+ Security::decrypt($txt, $key);
+ }
+
+/**
+ * Test that empty data cause errors
+ *
+ * @expectedException CakeException
+ * @expectedExceptionMessage The data to decrypt cannot be empty.
+ * @return void
+ */
+ public function testDecryptInvalidData() {
+ $txt = '';
+ $key = 'This is a key that is long enough to be ok.';
+ Security::decrypt($txt, $key);
+ }
+
}
@@ -289,4 +289,69 @@ protected static function _crypt($password, $salt = false) {
return crypt($password, $salt);
}
+/**
+ * Encrypt a value using AES-256.
+ *
+ * *Caveat* You cannot properly encrypt/decrypt data with trailing null bytes.
+ * Any trailing null bytes will be removed on decryption due to how PHP pads messages
+ * with nulls prior to encryption.
+ *
+ * @param string $plain The value to encrypt.
+ * @param string $key The 256 bit/32 byte key to use as a cipher key.
+ * @return string Encrypted data.
+ * @throws CakeException On invalid data or key.
+ */
+ public static function encrypt($plain, $key) {
+ static::_checkKey($key, 'encrypt()');
+ if (empty($plain)) {
+ throw new CakeException(__d('cake_dev', 'The data to encrypt cannot be empty.'));
+ }
+ $key = substr($key, 0, 32);
+ $algorithm = MCRYPT_RIJNDAEL_128;
+ $mode = MCRYPT_MODE_CBC;
+
+ $ivSize = mcrypt_get_iv_size($algorithm, $mode);
+ $iv = mcrypt_create_iv($ivSize, MCRYPT_RAND);
+ return $iv . mcrypt_encrypt($algorithm, $key, $plain, $mode, $iv);
+ }
+
+/**
+ * Check the encryption key for proper length.
+ *
+ * @param string $key
+ * @param string $method The method the key is being checked for.
+ * @return void
+ * @throws CakeException When key length is not 256 bit/32 bytes
+ */
+ protected static function _checkKey($key, $method) {
+ if (strlen($key) < 32) {
+ throw new CakeException(__d('cake_dev', 'Invalid key for %s, key must be at least 256 bits (32 bytes) long.', $method));
+ }
+ }
+
+/**
+ * Decrypt a value using AES-256.
+ *
+ * @param string $cipher The ciphertext to decrypt.
+ * @param string $key The 256 bit/32 byte key to use as a cipher key.
+ * @return string Decrypted data. Any trailing null bytes will be removed.
+ * @throws CakeException On invalid data or key.
+ */
+ public static function decrypt($cipher, $key) {
+ static::_checkKey($key, 'decrypt()');
+ if (empty($cipher)) {
+ throw new CakeException(__d('cake_dev', 'The data to decrypt cannot be empty.'));
+ }
+ $key = substr($key, 0, 32);
+
+ $algorithm = MCRYPT_RIJNDAEL_128;
+ $mode = MCRYPT_MODE_CBC;
+ $ivSize = mcrypt_get_iv_size($algorithm, $mode);
+
+ $iv = substr($cipher, 0, $ivSize);
+ $cipher = substr($cipher, $ivSize);
+ $plain = mcrypt_decrypt($algorithm, $key, $cipher, $mode, $iv);
+ return rtrim($plain, "\0");
+ }
+
}

0 comments on commit 215d43e

Please sign in to comment.