I’m working on a project where I need to store some private sensitive information. I wanted to use CSecurityManager to encrypt/decrypt the data in the database. I had a lot of problems getting it work, and couldn’t find much information, so I thought I’d post what I did. Here are the results.
I’ve set up a simple table to work with.
CREATE TABLE `information` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`record_name` varchar(45) NOT NULL,
`private_info` varchar(255) NOT NULL,
`sensitive_data` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB CHARSET=utf8;
Note the charset, this is important later on.
I’ve used gii to create my models and crud, everything stock but I’ve put the following in my model.
public function beforeSave() {
$this->private_info = Yii::app()->getSecurityManager()->encrypt($this->private_info);
$this->sensitive_data = Yii::app()->getSecurityManager()->encrypt($this->sensitive_data);
return parent::beforeSave();
}
protected function afterFind() {
$this->private_info = Yii::app()->getSecurityManager()->decrypt($this->private_info);
$this->sensitive_data = Yii::app()->getSecurityManager()->decrypt($this->sensitive_data);
parent::afterFind();
}
This saves empty values to the db, so I added the following to my config/main.php under components.
'components' => array(
'securityManager'=>array(
'cryptAlgorithm' => 'rijndael-256',
'encryptionKey' => 'ThisIsMySecretKey',
),
To find a list of valid values for cryptAlgorithm use:
print_r(mcrypt_list_algorithms());
My result was:
Array
(
[0] => cast-128
[1] => gost
[2] => rijndael-128
[3] => twofish
[4] => arcfour
[5] => cast-256
[6] => loki97
[7] => rijndael-192
[8] => saferplus
[9] => wake
[10] => blowfish-compat
[11] => des
[12] => rijndael-256
[13] => serpent
[14] => xtea
[15] => blowfish
[16] => enigma
[17] => rc2
[18] => tripledes
)
Still getting an error however. The problem is the UTF-8 encoding. I tried my db default encodings, and they weren’t working, so UTF-8 and encode/decode seemed to do the trick. So my model now looks like this:
public function beforeSave() {
$this->private_info = utf8_encode(Yii::app()->getSecurityManager()->encrypt($this->private_info));
$this->sensitive_data = utf8_encode(Yii::app()->getSecurityManager()->encrypt($this->sensitive_data));
return parent::beforeSave();
}
protected function afterFind() {
$this->private_info = Yii::app()->getSecurityManager()->decrypt(utf8_decode($this->private_info));
$this->sensitive_data = Yii::app()->getSecurityManager()->decrypt(utf8_decode($this->sensitive_data));
parent::afterFind();
}
Ok, so everything works now. There is one more change I wanted to make, and that was to encrypt each field with a different key. Logic tells me that if the data is compromised and the key for one field is cracked, the other fields will need to be cracked individually, making it harder to get at. Maybe I’m out to lunch. IDK.
So this is what my model looks like now.
public function beforeSave() {
Yii::app()->getSecurityManager()->setEncryptionKey('PrivateInfoEncryptionKey');
$this->private_info = utf8_encode(Yii::app()->getSecurityManager()->encrypt($this->private_info));
Yii::app()->getSecurityManager()->setEncryptionKey('SensitiveDataEncryptionKey');
$this->sensitive_data = utf8_encode(Yii::app()->getSecurityManager()->encrypt($this->sensitive_data));
return parent::beforeSave();
}
protected function afterFind() {
Yii::app()->getSecurityManager()->setEncryptionKey('PrivateInfoEncryptionKey');
$this->private_info = Yii::app()->getSecurityManager()->decrypt(utf8_decode($this->private_info));
Yii::app()->getSecurityManager()->setEncryptionKey('SensitiveDataEncryptionKey');
$this->sensitive_data = Yii::app()->getSecurityManager()->decrypt(utf8_decode($this->sensitive_data));
parent::afterFind();
}
I hope this helps someone. And please if you have any suggestions let me know, I could use them.