Cipher Behavior with Zend_Filter for CakePHP 1.3 – Easy Two-Way Encryption
Posted in CakePHP, Zend Framework on February 24th, 2010 by Jamie – Be the first to commentHere’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);