I’ve written the following behavior for a project I recently completed in Cake, and I thought it would be worth sharing:
class CryptableBehavior extends ModelBehavior { var $settings = array(); function setup(&$model, $settings) { if (!isset($this->settings[$model->alias])) { $this->settings[$model->alias] = array( 'fields' => array() ); } $this->settings[$model->alias] = array_merge($this->settings[$model->alias], $settings); } function beforeFind(&$model, $queryData) { foreach ($this->settings[$model->alias]['fields'] AS $field) { if (isset($queryData['conditions'][$model->alias.'.'.$field])) { $queryData['conditions'][$model->alias.'.'.$field] = $this->encrypt($queryData['conditions'][$model->alias.'.'.$field]); } } return $queryData; } function afterFind(&$model, $results, $primary) { foreach ($this->settings[$model->alias]['fields'] AS $field) { if ($primary) { foreach ($results AS $key => $value) { if (isset($value[$model->alias][$field])) { $results[$key][$model->alias][$field] = $this->decrypt($value[$model->alias][$field]); } } } else { if (isset($results[$field])) { $results[$field] = $this->decrypt($results[$field]); } } } return $results; } function beforeSave(&$model) { foreach ($this->settings[$model->alias]['fields'] AS $field) { if (isset($model->data[$model->alias][$field])) { $model->data[$model->alias]['cleartext_'.$field] = $model->data[$model->alias][$field]; $model->data[$model->alias][$field] = $this->encrypt($model->data[$model->alias][$field]); } } return true; } public function encrypt($data) { if ($data !== '') { return base64_encode(mcrypt_encrypt(Configure::read('Cryptable.cipher'), Configure::read('Cryptable.key'), $data, 'cbc', Configure::read('Cryptable.iv'))); } else { return ''; } } public function decrypt($data, $data2 = null) { if (is_object($data)) { unset($data); $data = $data2; } if ($data != '') { return trim(mcrypt_decrypt(Configure::read('Cryptable.cipher'), Configure::read('Cryptable.key'), base64_decode($data), 'cbc', Configure::read('Cryptable.iv'))); } else { return ''; } } }
All you need to do is add three lines to your bootstrap, and then load the behavior in any model you want to use it.
Here are the lines for your bootstrap:
Configure::write('Cryptable.cipher', 'rijndael-192'); Configure::write('Cryptable.key','random key string here'); Configure::write('Cryptable.iv', base64_decode('base64 encoded IV here')); // Create with mcrypt_create_iv with the appropriate size for your cipher
Here’s an example of how to load it in your model:
var $actsAs = array( 'Cryptable' => array( 'fields' => array( 'password' ) ) );
If you need to encrypt or decrypt a field outside of the normal find methods, you can simply call those methods on the model, passing in the string that needs worked on.
Download Cyptable Behavior









I would suppose you could just use config/core.php salt for this too?
For the encryption key itself, yes. But you still need to set the IV and the encryption scheme to use.
What about the Security::cipher method? Wouldn’t be easier to use that instead?
It would (arguably) be easier, but it’s not as flexible.
This allows you to choose the exact cipher system you want to use, including the IV and the passphrase, and does it all automatically on find and save calls, so you rarely ever have to call the encrypt and decrypt methods manually. It also avoids the extra layer of objects that you would add by using the Security class. Not a major savings, but it adds up.
Also, I just went and looked at the source code for Security::cipher. I’m not confident that it is cryptographically secure. It’s probably secure against a casual attack, but it doesn’t look very robust.
Great behaviour, a part from being useful, it’s very nice to see people that know how to use cake!
Could you elaborate a bit more on creating the IV please? I bet it’s dead obvious, but i’m not sure how to create that.
Thanks
Will
This is the basic idea for creating the IV.
This was EXACTLY what I needed, thank you SO much! You rock!!