AES Encryption AES Encryption Porting from PHP to Yii
#1
Posted 03 December 2011 - 10:40 AM
I am very new to Yii, but very excited about all the possibilities I see.
I am building an application where several of the fields require encryption (social security number, etc.). In my old, procedural PHP code, I was able to do this when extracting an encrypted field value from MySQL to display in a form:
AES_DECRYPT(insuranceSubscriberSSN,’$key_string’) as insuranceSubscriberSSN
I have looked through the documentation and the forums but have not found a good exmaple of how this works (at least, one that I kind understand).
I would very much appreciate some guidance and examples of the best ways to encrypt and decrypt a couple of fields.
Thanks very much,
Christopher
#2
Posted 03 December 2011 - 01:44 PM
In your model, create a new variable at the top like
public $encoded;
Then, create a scope, (I'm using a defaultScope as an example)
public function defaultScope()
{
return array("select" => array("AES_DECRYPT(id,'yourkey') as encoded"));
}Now you can retrieve the data using regular AR methods
$data = Test::model()->findByPk($id); echo $data->encoded;
#3
Posted 03 December 2011 - 05:11 PM
I have placed this at the top of my 'Clients' model:
public $encoded;
And then I have placed this down in the model where the other functions live:
public function defaultScope()
{
return array("select" => array("AES_DECRYPT(clientSocialSecurity,'C3yZ)pO|RgP|IaBuCT') as encoded"));
}
And then the form display in my view I have this just to see if I get anything:
$data = Clients::model()->findByPk($id);
echo $data->encoded;
But I get nothing visible returned and then also no other data displayed for that client. I also don't see where that function defaultScope actually gets called.
I am sure I have done something incorrect with the code you provided. Please advise.
Regards,
Christopher
wisp, on 03 December 2011 - 01:44 PM, said:
In your model, create a new variable at the top like
public $encoded;
Then, create a scope, (I'm using a defaultScope as an example)
public function defaultScope()
{
return array("select" => array("AES_DECRYPT(id,'yourkey') as encoded"));
}Now you can retrieve the data using regular AR methods
$data = Test::model()->findByPk($id); echo $data->encoded;
#4
Posted 03 December 2011 - 06:41 PM
#5
Posted 03 December 2011 - 06:50 PM
When I put this query into mysql directly I get the proper values:
SELECT AES_DECRYPT( clientSocialSecurity, 'C3yZ)pO|RgP|IaBuCT' ) AS encoded
So, I'm stepping on something else ;-)
I'm not sure what else to provide you that might help. Again, I'm very new to OO and Yii so perhaps I'm just misplacing things.
Christopher
#6
Posted 03 December 2011 - 08:53 PM
#7
Posted 04 December 2011 - 11:48 AM
This is what the query looks like on echoing out:
SELECT AES_DECRYPT(clientSocialSecurity,'C3yZ)pO|RgP|IaBuCT') as encoded FROM `clients` `t` WHERE `t`.`Id`=73 LIMIT 1
This query works. But it also is echoing out this right after:
SELECT AES_DECRYPT(clientSocialSecurity,'C3yZ)pO|RgP|IaBuCT') as encoded FROM `clients` `t` WHERE `t`.`Id` IS NULL LIMIT 1
This is making all the records disappear and the pages throw errors.
So, there's something wrong with how I'm using the code. I guess what I'm missing is how that function gets called (perhaps by default?). Either way, it's not returning anything, and its also making the other information on the page disappear.
#8
Posted 05 December 2011 - 05:44 AM
Thanks,
Christopher
#9
Posted 05 December 2011 - 10:23 AM
Quote
$data = Clients::model()->findByPk($id);
echo $data->encoded;
Usually this code should be in the controller action not in the view.
Did you test the value if the $id variable?
Seems to be null when you have logged an sql query like above:
SELECT AES_DECRYPT(clientSocialSecurity,'C3yZ)pO|RgP|IaBuCT') as encoded FROM `clients` `t` WHERE `t`.`Id` IS NULL LIMIT 1
echo "id=$id"; //<--- add this $data = Clients::model()->findByPk($id); var_dump($data); //<--- add this echo $data->encoded;
#10
Posted 05 December 2011 - 11:10 AM
P.S
I've not done much with encrypting database fields so this is only a query, but is it really the best way to encrypt sending the raw data over to the DB to do the encryption and decryption? I always assumed it was better PHP side as there's never any transfer of unsecured data?
#11
Posted 05 December 2011 - 11:27 AM
The following piece of code should work (beware, I've not tested this!):
class Clients extends CActiveRecord
{
...
public function afterFind()
{
$this->clientSocialSecurity = openssl_decrypt($this->clientSocialSecurity, 'AES-128-CBC', 'mysupersecreptpasswordthatishallnevereverpasteintoapublicforum');
parent::afterFind();
}
}
The clientSocialSecurity property should then have the SSN unencrypted.
#12
Posted 05 December 2011 - 03:30 PM
The other difference in my implementation is that I wrote AES-encrypt and decrypt functions which are compatible with MySQL AES_ENCRYPT/AES_DECRYPT, whereas the previous solution relies on a the openssl library for encryption..
Solution:
/**
* 1. Globals.php
* Define functions used everywhere.
*/
class Globals {
const KEY = 'MySuperSecretKey';
/**
* @return string - AES-decrypt $val, using either key passed in, or local key if no key given.
* Compatible with mysql's aes_decrypt.
*/
public static function aesDecrypt($val, $key=null) {
if ($key == null) $key = self::KEY;
$mode = MCRYPT_MODE_ECB;
$enc = MCRYPT_RIJNDAEL_128;
$dec = @mcrypt_decrypt($enc, $key, $val, $mode, @mcrypt_create_iv( @mcrypt_get_iv_size($enc, $mode),
MCRYPT_DEV_URANDOM ) );
return rtrim( $dec, ( ( ord(substr( $dec, strlen( $dec )-1, 1 )) >= 0 and ord(substr( $dec, strlen( $dec )-1, 1 ) ) <= 16 ) ? chr(ord(substr( $dec, strlen( $dec )-1, 1 ))): null) );
}
/**
* @return string - Reversible, AES-encrypted $val, using either key passed in, or local key if no key given.
* Compatible with mysql's aes_encrypt.
* @param $key - string - The key to use for decryption. If none specified, use the local key.
*/
public static function aesEncrypt($val, $key=null) {
if ($key == null) $key = self::KEY;
$mode=MCRYPT_MODE_ECB;
$enc=MCRYPT_RIJNDAEL_128;
$val=str_pad($val, (16*(floor(strlen($val) / 16)+(strlen($val) % 16==0?2:1))), chr(16-(strlen($val) % 16)));
return @mcrypt_encrypt($enc, $key, $val, $mode, mcrypt_create_iv( mcrypt_get_iv_size($enc, $mode), MCRYPT_DEV_URANDOM));
}
} // Globals
/**
* 2. Model class
*/
class MyModel extends CActiveRecord
/**
* After fetching from db, set social_security_number to the AES-decrypted value.
*/
public function afterFind() {
$val = parent::afterFind();
$this->social_security_number = Globals::aesDecrypt($this->social_security_number);
return $val;
}
/**
* Before attempting to save this record, AES-encrypt social_security_number.
*/
public function beforeSave() {
$val = parent::beforeSave();
$this->social_security_number = Globals::aesEncrypt($this->social_security_number);
return $val;
}
}
#13
Posted 05 December 2011 - 03:46 PM
One newb question: Where do you put the globals.php file and how to do make sure it is loaded (include?)?
Thank you.
Christopher
#14
Posted 05 December 2011 - 04:06 PM
protected/components
will be available for use by your application.
(The rule is, the filename must match the name of the class it contains. So, as a rule of thumb, don't define more than one class per file.)
So, place the file in "protected/components", and call it Globals.php.
No need for pesky require() statements!
#15
Posted 05 December 2011 - 04:08 PM
#16
Posted 05 December 2011 - 04:12 PM
Da:Sourcerer, on 05 December 2011 - 04:08 PM, said:
Hey, I'm always trying to do things the "best practices" way. But I'm confused. I use params for little things like, "adminEmail". What does it mean to make a *class* into a parameter? Did you mean, instead, that Globals.php should be made into an application *component*? If I did that, I could indeed access functions in "Globals.php" via
Yii::app()->globals.
Confused.
#17
Posted 05 December 2011 - 04:23 PM
#18
Posted 05 December 2011 - 04:25 PM
#19
Posted 05 December 2011 - 04:25 PM
Da:Sourcerer, on 05 December 2011 - 04:23 PM, said:
Okay, I think I follow.
I agree that "key", stuffed into Globals.php, is pure laziness on my part; it should be an application param.
I'll read up on behaviors...haven't used them yet, thanks!
Em
#20
Posted 05 December 2011 - 04:27 PM
Da:Sourcerer, on 05 December 2011 - 04:25 PM, said:
So, if I run the "encrypt" method of CSecurityManager with a string and a key, will it give me the same result as running MySQL's AES_ENCRYPT with the same string and key? Lacking that was why I rolled my own in "Globals".

Help












