Here’s a quickie – a Cipher behavior for CakePHP to handle two-way encryption of sensitive data. If you want to store, say, credit card information, you’ll need a way to retrieve it later; Cake’s built-in security hashing is one-way, meaning that once it’s encrypted it ain’t comin’ back. So, I turned to the Zend Framework and brought in Zend_Filter_Encrypt and Zend_Filter_Decrypt to handle the heavy lifting. This behavior uses mcrypt, so you need to have that PHP extension installed, which (as far as I can tell) is fairly standard.
Download the Cipher Behavior Source on Github
First things first – you need to throw a couple of libraries from the Zend Framework into your vendors folder. Yup, I love my Zend! CakePHP teams up very well with ZF.
You’ll need the following Zend Framework libraries (download the framework):
- Zend_Filter (Zend/Filter.php and Zend/Filter)
- Zend_Loader (Zend/Loader.php and Zend/Loader)
Put those files in your vendors folder. You’ll also need to update your include_path somewhere (say, app/bootstrap.php) with the following:
ini_set('include_path', ini_get('include_path') . ':' . APP . '/vendors');
I also recommend defining an autoload function somewhere for Zend classes (again, bootstrap.php is a good choice). A simple, Zend-only autoloader might look like this:
function __autoload($path) {
if (substr($path, 0, 5) == 'Zend_') {
include str_replace('_', '/', $path) . '.php';
}
return $path;
}
The behavior has three config options:
- key: the encryption key to use. If null (default), then it’ll use the value of Configure::read(‘Security.salt’).
- automatic: whether to automatically encrypt and decrypt data as it’s saved/retrieved. Defaults to true.
- fields: an array of fields belong to the model that should be encrypted
Usage of the behavior itself is straightforward: just add Cipher to the $actsAs array of any model you’d like:
Class User extends AppModel {
var $actsAs = array('Cipher');
}
Class Order extends AppModel {
var $actsAs = array('Cipher' => array('fields' => array('credit_card', 'expiry')));
}
You can also manually decrypt and encrypt data, either by passing an array of find results (in which case the fields specified in ‘fields’ will be encrypted/decrypted), or by passing a string:
// Manually encrypt/decrypt the results of Model::find()
$encrypted = $this->encrypt($findResults);
$decrypted = $this->decrypt($encrypted );
// Manually encrypt/decrypt a string
$encryptedSecretString= $this->encrypt('my secret string');
$decryptedString = $this->decrypt($encryptedSecretString);

I like what you have done here. I was wondering though, is there a way to achieve this using the built in cipher($key)? Sorry, I am pretty new to cake php, and I was told to use the cipher behavior that was in the cakephp bakery and modify it from using “blowfish” to using the built in “cipher” and to be honest I am quite lost.
I highly recommend not using Cake’s cipher function, which is found in the Security class. It’s not true encryption. My behavior uses mcrypt, which is a very good php extension that handles two-way encryption. Blowfish is another decent encryption engine. I’d say that you should use either of those before you resort to Cake’s Security::cipher() function, which is a pretty weak encryption tool. Otherwise, I wouldn’t have written this behavior!
Is there a reason why you don’t want to use mcrypt or blowfish?