AES Encryption

I think it’s here … the clientSocialSecurity is not getting populated:




public function behaviors()

        {

        return array(

        'crypt'=>array(

		// this assumes that the behavior is in the folder: protected/behaviors/

        'class'=>'application.behaviors.CryptBehavior',

       	// this sets that the attributes to be encrypted/decrypted are encryptedfieldname of the model

        'attributes'=>array('clientSocialSecurity'),

        )

        );

        }



Again … wondering if it’s in the wrong place. I have it right below ‘rules’ in my model.

Almost positive now it’s the encryption key not getting passed. I see the other values getting sent to the CryptBehavior but then when it gets to the encrypted value of clientSocialSecurity it stops (but I do see the encrytped value).

This is my components in main.php:




	'components'=>array(

		'user'=>array(

			// enable cookie-based authentication

			'allowAutoLogin'=>true,

		),

		'securityManager'=>array(

        'cryptAlgorithm'=>array(

        'rijndael-128',

        '',

        'ecb',

        ''

        ),

       'encryptionKey'=>'mysecretkeygoeshere',

	),



Hi Antonio.

If you ever come back to this thread :slight_smile: … I’d like to just have you see these two items.

When I print out the $key and $value in the afterFind within the CryptBehavior.php you sent me, I see all the fields and values for the client database table. It looks something like this:

Id -> 238

clientFirstName -> Christopher

clientLastName -> Murray

clientMiddleInitial ->

clientBirthDate -> 1900-11-22

clientStreetAddress -> 29 GReenleaf Road

clientStreetAddress2 ->

clientCity -> Boston

clientState -> MA

clientZip -> 01234

clientHomePhone -> 5083545345

clientHomePhoneMessages -> Yes

clientBusinessPhone -> 508242342

clientBusinessPhoneMessages -> Yes

clientCellPhone -> 5082943243

clientCellPhoneMessages -> Yes

clientEmail -> christomurr@gmail.com

clientEmailMessages -> Yes

clientSocialSecurity -> »º$tÐq!ÀÅtø…µj$è

So, I have two questions really:

I am specifying the clientSocialSecurity in the behavior function you sent me, so am I supposed to be seeing all the fields in the CryptBehavior like this?




public function behaviors()

        {

        return array(

        'crypt'=>array(

        'class'=>'application.behaviors.CryptBehavior',

        'attributes'=>array('clientSocialSecurity'),

        )

        );

        }




Secondly, You can see the output fails right at the clientSocialSecurity value. So, I am assuming it is indeed getting the value of that field but that the error message I mention in a previous post about an empty string is the missing encryption key. I have set that as mentioned previously in my main.php.

Do you have any more thoughts on this? I feel like I’m really close.

Thanks,

Christopher

I have looked around and it seems the encryptionKey is not passed… ??? very weird if its well set on the main.php config file, but lets try one LAST try, if that doesnt happen, then I wont be able to help you :)

Lets be more agressive, and include the encryptionKey right before the securityManager encrypts/decrypts




// so, on your beforeSave / afterFind do the following: 


Yii::app()->securityManager->setEncryptionKey('mysecretkeyhere');


// now lets encrypt or decrypt...



Obviously, this is jus to test if is something wrong with securitymanager or your settings… as this approach is… ehem… no good :)

Cheers

HI Antonio,

Thank you again for looking at this.

I put that code right where you said and here is the output:

mcrypt_generic_init() [<a href=‘function.mcrypt-generic-init’>function.mcrypt-generic-init</a>]: Iv size incorrect; supplied length: 2, needed: 16

Everywhere I look around, it tells me that your encryption key length is incorrect… $IV is created on CSecurityManager depending on the requirements of the module… ????

I do not really understand what is happening… Do you have that data already in the database or is encrypted/decrypted by CSecurityManager from scratch?

It is data already in a database … it was encrytped using AES_ENCRYPT on the insert to MySQL.

When I run this command directly from the database it works:




SELECT clientFirstName, AES_DECRYPT( clientSocialSecurity, 'C3yZ)pO|RgP|IaBuCT' ) AS socsec

FROM clients



Give me a couple of minutes… will post a mysql_aes_encrypt / mysql_aes_decrypt compliant behavior :)

Emily DIckison wrote you a perfect solution for your problem. I didn’t know the data was already encrypted there!!!

Here the steps




// on your main.php config file

'components'=>array(

                'user'=>array(

                        // enable cookie-based authentication

                        'allowAutoLogin'=>true,

                ),

                'securityManager'=>array(

                        'cryptAlgorithm'=>array(

                        'rijndael-128',

                        '',

                        'ecb',

                        ''

                       ),

                      // the above is not needed, but this is highly important

                      'encryptionKey'=>'mysecretkeygoeshere',

        ),



The behavior, replace the one i sent you with this one




<?php


/**

 * CryptBehavior class

 *

 * Encrypts specific attributes with CSecurityManager

 * 

 * @author Antonio Ramirez <antonio@ramirezcobos.com>

 */

class CryptBehavior extends CActiveRecordBehavior {


	public $attributes = array();

	public $useAESMySql = false;


	/**

	 * Encrypts the value of specified attributes before saving to database

	 * @param CEvent $event

	 * @return parent::beforeSave

	 */

	public function beforeSave($event)

	{


		foreach ($this->getOwner()->getAttributes() as $key => $value)

		{

			if (in_array($key, $this->attributes) && !empty($value))

			{

				if ($this->useAESMySql)

					$this->getOwner()->{$key} = $this->mysqlAESEncrypt($value, Yii::app()->securityManager->getEncryptionKey());

				else

					$this->getOwner()->{$key} = utf8_encode(Yii::app()->securityManager->encrypt($value));

			}

		}

		return parent::beforeSave($event);

	}


	/**

	 * Decripts the values of specified attributes after finding from database

	 * @param CEvent $event

	 * @return parent::afterFind

	 */

	public function afterFind($event)

	{

		foreach ($this->getOwner()->getAttributes() as $key => $value)

		{

			if (in_array($key, $this->attributes) && !empty($value))

			{

				if ($this->useAESMySql)

					$this->getOwner()->{$key} = $this->mysqlAESDecrypt($value, Yii::app()->securityManager->getEncryptionKey());

				else

					$this->getOwner()->{$key} = Yii::app()->securityManager->decrypt(utf8_decode($value));

			}

		}

		return parent::afterFind($event);

	}


	/**

	 * MySQL compliant functions

	 * Thanks Emily!!!

         * ----------------------------------

	 * @param string $val the value to decrypt

	 * @param string $ky the key

	 * @return string the values decrypted 

	 */

	public function mysqlAESDecrypt($val, $ky)

	{

		$key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";

		for ($a = 0; $a < strlen($ky); $a++)

			$key[$a % 16] = chr(ord($key[$a % 16]) ^ ord($ky[$a]));

		$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));

	}

        /**	

        * MySQL compliant functions	

        * Thanks Emily!!!         

        * ----------------------------------	

        * @param string $val the value to encrypt	 

        * @param string $ky the key	 

        * @return string the values encrypted 	 */	

        public function mysqlAESEncrypt($val, $ky)

	{

		$key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";

		for ($a = 0; $a < strlen($ky); $a++)

			$key[$a % 16] = chr(ord($key[$a % 16]) ^ ord($ky[$a]));

		$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));

	}


}



Now, to use it on your model:




public function behaviors()

{

        return array(

        'crypt'=>array(

                // this assumes that the behavior is in the folder: protected/behaviors/

                'class'=>'application.behaviors.CryptBehavior',

                // this sets that the attributes to be encrypted/decrypted are encryptedfieldname of the model

               'attributes'=>array('clientSocialSecurity'),

               'useAESMySql'=>true

               )

        );

}




Let’s see if it works!

The social security field is empty :frowning:

I’ll keep checking to see if I’ve done something wrong …

I see this in some debug output:




securityManager 	array

(

'class' => 'CSecurityManager'

'hashAlgorithm' => 'sha1'

'cryptAlgorithm' => array

(

'0' => 'rijndael-128'

'1' => ''

'2' => 'ecb'

'3' => ''

)

'behaviors' => array()

) 



Which make me wonder in main.php is not being read, because I have the encrypt key in there/.

Chris, your main.php file is the config file of the whole application Yii… not reading that file is not even running the first page of your Yii powered application… so, what is that behaviors variable in your main?¿ I am truly sorry, but it seems that you are not setting your main.php config file properly…

That file is in protected/config

Double check the steps i sent you… i cannot be more clear than that… if that fails, i apologize as i am not useful for you

Good luck

No, you’ve been wonderfully helpful. I think that output is coming directly from the secutirymanager …

I believe my main.php is set right.

Is you main.php like this?




'securityManager'=>array(

                        'cryptAlgorithm'=>array(

                        'rijndael-128',

                        '',

                        'ecb',

                        ''

                       ),

                      // the above is not needed, but this is highly important

                      'encryptionKey'=>'C3yZ)pO|RgP|IaBuCT',



Yes.

When I echo ‘$dec’ from the CryptBehavior.php I get this:

uEڼ�KeM|����u�1z�Œ�Lr��TD&l�Q

which is not the decrypted value. So, I’m looking into what else in there might be the issue.

Hi christomurr,

This is going to be my last post on this threat :)

I was curious so I setup a full test on my end and, I am truly sorry to say… Everything went fantastic. This is what I did:

1- I created a new field in one of my tables name it test_field and made it VARBINARY type

2- I runned the following script against my table, as I wanted to decrypt already encrypted data in my database




UPDATE tbl_country SET test_field=AES_ENCRYPT('testing AES encryption','C3yZ)pO|RgP|IaBuCT')  WHERE id=241



3- Then I setup on my configuration file main.php the SecurityManager to have the encryptionKey as the one above. Exactly as specified previously to you…

4- Setup the behaviors of MY MODEL to work with attributes to be ‘test_field’ and ‘useAESMySql’=>true, as specified to you

5- Tested with the following code, and guess what?




$country = Country::model()->findByPk(241);


echo $country->test_field;



It works like a charm…

So, please, follow the instructions above very carefully, they are the correct ones and the behavior works perfect.

Cheers and good luck!

Antonio,

I can’t thank you enough for all your help and patience. Truly, I’m amazed that you stuck with me through all of that.

I finally set aside my install and began an entire new clean one. I stepped through your instructions and, voila, it works like a charm. Very nice solution. Thank you again for helping me.

Can I ask one last question? How would I structure the behavior in my model to accommodate multiple fields to be encrypted/decrytped?

Now, off to read some documentation on Yii :wink: I’d like to return the favor and help others here.

Regards,

Christopher

Just a quick answer in case it’s as simple as I think it is at a glance.

Add whichever field it is to the attributes array where the behaviour is set on the model (in the model file):





public function behaviors()

{

        return array(

        'crypt'=>array(

                // this assumes that the behavior is in the folder: protected/behaviors/

                'class'=>'application.behaviors.CryptBehavior',

                // this sets that the attributes to be encrypted/decrypted are encryptedfieldname of the model

       		'attributes'=>array('clientSocialSecurity', 'Some', 'More', 'Attribute', 'Names'),

       		'useAESMySql'=>true

       		)

        );

}

[i]( ‘attributes’=>array(‘clientSocialSecurity’, ‘Some’, ‘More’, ‘Attribute’, ‘Names’),) [/i]

If that doesn’t work maybe wait for antonio or I can take a harder look in the morning :)