Note: The encryption created with Cakephp 2.4.6 Security::rijndael can't be read (by default) using the MySQL AES_DECRYPT() function so once you have it encrypted you can only read and write using the CakePHP application. I believe CakePHP 2.5.x has another couple of AES functions which may allow MySQL to decrypt also but I haven't tried it. See below for the SQL to read AES encrypted columns.
A table with 2 fields you want to make encrypted:
CREATE TABLE `addresses2` ( `id` int(11) NOT NULL AUTO_INCREMENT, `address` varchar(255) DEFAULT NULL, `comment` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`), ) ENGINE=MyISAM AUTO_INCREMENT=136 DEFAULT CHARSET=latin1;
Add the encrypted fields:
ALTER TABLE `mydb`.`addresses2` ADD COLUMN `address_enc` BLOB NULL AFTER `address`, ADD COLUMN `comment_enc` BLOB NULL AFTER `comment`;
Add an update_enc action to Controller/AddressesController.php. This will copy the plain text values from the unecrypted source field to the encrypted field
public function update_enc() { $enc_fields = array( 'address' => 'address_enc', 'comment' => 'comment_enc' ); $this->Address->recursive = -1; $addresses = $this->Address->find('all'); foreach($addresses as $add_key => $add_value){ foreach($enc_fields as $key => $value){ $addresses[$add_key]['Address'][$value] = $address['Address'][$key]; // $this->log($text_str); // rijndael($text, $key, $operation) } } $this->Address->saveAll( $addresses, array( 'fieldList' => array( 'Address' => array('address_enc', 'comment_enc') ) ) ); $addresses = $this->Address->find("all"); $this->set(compact('addresses')); }
Create a view for the update action View/Addresses/update_enc.php
<?php echo '<pre>'; print_r($addresses); echo '</pre>'; // debug doesn't display with encrypted data // debug($addresses); ?>
In the Model/Address.php put the encryption / decryption routines
// include the Security Utility App::uses('Security', 'Utility'); public function beforeSave($options = array()) { foreach($this->encryptedFields as $fieldName){ if(!empty($this->data[$this->alias][$fieldName])){ $this->data[$this->alias][$fieldName] = Security::rijndael( $this->data[$this->alias][$fieldName], Configure::read('Security.key'), 'encrypt' ); } } return true; } public function afterFind($results = array()) { // $this->log(print_r($results, true)); foreach($this->encryptedFields as $fieldName){ foreach($results as $key => $value){ if(!empty($results[$key][$this->alias][$fieldName])){ $results[$key][$this->alias][$fieldName] = Security::rijndael( $results[$key][$this->alias][$fieldName], Configure::read('Security.key'), 'decrypt' ); } } } return $results; }
In Config/core.php near Security.salt / Security.cipher add a value of Security.key
/* 32 chars long */ Configure::write('Security.key', '12345678901234567890123456789012');
Modify all views to include the encrypted fields View/Address/view.php (do index.ctp, edit.ctp, add.ctp etc)
<dt><?php echo __('Address Enc'); ?></dt> <dd> <?php echo h($address['Address']['address_enc']); ?> </dd> <dt><?php echo __('Comment Enc'); ?></dt> <dd> <?php echo h($address['Address']['comment_enc']); ?> </dd> <dt><?php echo __('Address'); ?></dt> <dd> <?php echo h($address['Address']['address']); ?> </dd> <dt><?php echo __('Comment'); ?></dt> <dd> <?php echo h($address['Address']['comment']); ?> </dd>
Run the update_enc code by accessing it via your browser e.g. http://example.com/addresses/update_enc this does the copy and encryption
Finally drop the old fields
ALTER TABLE `mydb`.`addresses2` DROP COLUMN `comment`, DROP COLUMN `address`;
MySQL Reading AES_ENCRYPTed columns
SELECT CAST( aes_decrypt(address_enc, '12345678901234567890123456789012') AS CHAR(255)) AS Decoded FROM addresses
0 Comments