Port to Yii of the encryption library of CI

I may be a beginner at everything that is Yii but that doesn’t keep me from meddling with code and trying to use it with YII. I worked with codeigniter in the past and it certainly isn’t that bad but it’s slow, however to encryption library they got is really easy to use.

WHY?

Well basically two weeks ago I was checking something a triple md5 hash with a decoder an till my surprise he found the encoded text. I already knew that md5 wasn’t secure but people tend to say that doing md5(md5(md5())) or more eliminates the rainbow tables problem that md5 has, so guess again! That’s when i started thinking about the encrypt library of CI and how easy it is to use so I made a port, and with a little guidance from the forums here I had it working in no time. And sharing is caring so here it is:

the lib which is to be located in /protected/extensions/Encrypt.php


<?php

/**

 * Encryption library based upon the CI encrypt library

 */ 


class Encrypt extends CApplicationComponent {


	/**

	 * @var array the configuration

	 */

	public $encryptionKey;

	var $_hash_type	= 'sha1';

	var $_mcrypt_exists = FALSE;

	var $_mcrypt_cipher;

	var $_mcrypt_mode;


	/**

	 * Constructor

	 *

	 * Initializes the application component.

	 */

	public function init()

	{

		parent::init();

	}


	// --------------------------------------------------------------------


	/**

	 * Fetch the encryption key

	 *

	 * Returns it as MD5 in order to have an exact-length 128 bit key.

	 * Mcrypt is sensitive to keys that are not the correct length

	 *

	 * @access	public

	 * @param	string

	 * @return	string

	 */

	function getSalt($encryptionKey = '')

	{

		if ($encryptionKey == '')

		{

			if ($this->encryptionKey != '')

			{

				return $this->encryptionKey;

			}


			$key = $encryptionKey;


			if ($key === FALSE)

			{

				show_error('In order to use the encryption class requires that you set an encryption key in your config file.');

			}

		}


		return md5($encryptionKey);

	}


	// --------------------------------------------------------------------


	/**

	 * Set the encryption key

	 *

	 * @access	public

	 * @param	string

	 * @return	void

	 */

	function setKey($key = '')

	{

		$this->encryptionKey = $key;

	}


	// --------------------------------------------------------------------


	/**

	 * Encode

	 *

	 * Encodes the message string using bitwise XOR encoding.

	 * The key is combined with a random hash, and then it

	 * too gets converted using XOR. The whole thing is then run

	 * through mcrypt (if supported) using the randomized key.

	 * The end result is a double-encrypted message string

	 * that is randomized with each call to this function,

	 * even if the supplied message and key are the same.

	 *

	 * @access	public

	 * @param	string	the string to encode

	 * @param	string	the key

	 * @return	string

	 */

	function encode($string, $key = '')

	{

		$key = $this->getSalt($key);

		$enc = $this->_xor_encode($string, $key);

		

		if ($this->_mcrypt_exists === TRUE)

		{

			$enc = $this->mcrypt_encode($enc, $key);

		}

		return base64_encode($enc);

	}


	// --------------------------------------------------------------------


	/**

	 * Decode

	 *

	 * Reverses the above process

	 *

	 * @access	public

	 * @param	string

	 * @param	string

	 * @return	string

	 */

	function decode($string, $key = '')

	{

		$key = $this->getSalt($key);

		

		if (preg_match('/[^a-zA-Z0-9\/\+=]/', $string))

		{

			return FALSE;

		}


		$dec = base64_decode($string);


		if ($this->_mcrypt_exists === TRUE)

		{

			if (($dec = $this->mcrypt_decode($dec, $key)) === FALSE)

			{

				return FALSE;

			}

		}


		return $this->_xor_decode($dec, $key);

	}


	// --------------------------------------------------------------------


	/**

	 * XOR Encode

	 *

	 * Takes a plain-text string and key as input and generates an

	 * encoded bit-string using XOR

	 *

	 * @access	private

	 * @param	string

	 * @param	string

	 * @return	string

	 */

	function _xor_encode($string, $key)

	{

		$rand = '';

		while (strlen($rand) < 32)

		{

			$rand .= mt_rand(0, mt_getrandmax());

		}


		$rand = $this->hash($rand);


		$enc = '';

		for ($i = 0; $i < strlen($string); $i++)

		{			

			$enc .= substr($rand, ($i % strlen($rand)), 1).(substr($rand, ($i % strlen($rand)), 1) ^ substr($string, $i, 1));

		}


		return $this->_xor_merge($enc, $key);

	}


	// --------------------------------------------------------------------


	/**

	 * XOR Decode

	 *

	 * Takes an encoded string and key as input and generates the

	 * plain-text original message

	 *

	 * @access	private

	 * @param	string

	 * @param	string

	 * @return	string

	 */

	function _xor_decode($string, $key)

	{

		$string = $this->_xor_merge($string, $key);


		$dec = '';

		for ($i = 0; $i < strlen($string); $i++)

		{

			$dec .= (substr($string, $i++, 1) ^ substr($string, $i, 1));

		}


		return $dec;

	}


	// --------------------------------------------------------------------


	/**

	 * XOR key + string Combiner

	 *

	 * Takes a string and key as input and computes the difference using XOR

	 *

	 * @access	private

	 * @param	string

	 * @param	string

	 * @return	string

	 */

	function _xor_merge($string, $key)

	{

		$hash = $this->hash($key);

		$str = '';

		for ($i = 0; $i < strlen($string); $i++)

		{

			$str .= substr($string, $i, 1) ^ substr($hash, ($i % strlen($hash)), 1);

		}


		return $str;

	}


	// --------------------------------------------------------------------


	/**

	 * Encrypt using Mcrypt

	 *

	 * @access	public

	 * @param	string

	 * @param	string

	 * @return	string

	 */

	function mcrypt_encode($data, $key)

	{

		$init_size = mcrypt_get_iv_size($this->_get_cipher(), $this->_get_mode());

		$init_vect = mcrypt_create_iv($init_size, MCRYPT_RAND);

		return $this->_add_cipher_noise($init_vect.mcrypt_encrypt($this->_get_cipher(), $key, $data, $this->_get_mode(), $init_vect), $key);

	}


	// --------------------------------------------------------------------


	/**

	 * Decrypt using Mcrypt

	 *

	 * @access	public

	 * @param	string

	 * @param	string

	 * @return	string

	 */

	function mcrypt_decode($data, $key)

	{

		$data = $this->_remove_cipher_noise($data, $key);

		$init_size = mcrypt_get_iv_size($this->_get_cipher(), $this->_get_mode());


		if ($init_size > strlen($data))

		{

			return FALSE;

		}


		$init_vect = substr($data, 0, $init_size);

		$data = substr($data, $init_size);

		return rtrim(mcrypt_decrypt($this->_get_cipher(), $key, $data, $this->_get_mode(), $init_vect), "\0");

	}


	// --------------------------------------------------------------------


	/**

	 * Adds permuted noise to the IV + encrypted data to protect

	 * against Man-in-the-middle attacks on CBC mode ciphers

	 * http://www.ciphersbyritter.com/GLOSSARY.HTM#IV

	 *

	 * Function description

	 *

	 * @access	private

	 * @param	string

	 * @param	string

	 * @return	string

	 */

	function _add_cipher_noise($data, $key)

	{

		$keyhash = $this->hash($key);

		$keylen = strlen($keyhash);

		$str = '';


		for ($i = 0, $j = 0, $len = strlen($data); $i < $len; ++$i, ++$j)

		{

			if ($j >= $keylen)

			{

				$j = 0;

			}


			$str .= chr((ord($data[$i]) + ord($keyhash[$j])) % 256);

		}


		return $str;

	}


	// --------------------------------------------------------------------


	/**

	 * Removes permuted noise from the IV + encrypted data, reversing

	 * _add_cipher_noise()

	 *

	 * Function description

	 *

	 * @access	public

	 * @param	type

	 * @return	type

	 */

	function _remove_cipher_noise($data, $key)

	{

		$keyhash = $this->hash($key);

		$keylen = strlen($keyhash);

		$str = '';


		for ($i = 0, $j = 0, $len = strlen($data); $i < $len; ++$i, ++$j)

		{

			if ($j >= $keylen)

			{

				$j = 0;

			}


			$temp = ord($data[$i]) - ord($keyhash[$j]);


			if ($temp < 0)

			{

				$temp = $temp + 256;

			}

			

			$str .= chr($temp);

		}


		return $str;

	}


	// --------------------------------------------------------------------

	

	/**

	 * Set the Mcrypt Cipher

	 *

	 * @access	public

	 * @param	constant

	 * @return	string

	 */

	function set_cipher($cipher)

	{

		$this->_mcrypt_cipher = $cipher;

	}


	// --------------------------------------------------------------------


	/**

	 * Set the Mcrypt Mode

	 *

	 * @access	public

	 * @param	constant

	 * @return	string

	 */

	function set_mode($mode)

	{

		$this->_mcrypt_mode = $mode;

	}


	// --------------------------------------------------------------------


	/**

	 * Get Mcrypt cipher Value

	 *

	 * @access	private

	 * @return	string

	 */

	function _get_cipher()

	{

		if ($this->_mcrypt_cipher == '')

		{

			$this->_mcrypt_cipher = MCRYPT_RIJNDAEL_256;

		}


		return $this->_mcrypt_cipher;

	}


	// --------------------------------------------------------------------


	/**

	 * Get Mcrypt Mode Value

	 *

	 * @access	private

	 * @return	string

	 */

	function _get_mode()

	{

		if ($this->_mcrypt_mode == '')

		{

			$this->_mcrypt_mode = MCRYPT_MODE_ECB;

		}

		

		return $this->_mcrypt_mode;

	}


	// --------------------------------------------------------------------


	/**

	 * Set the Hash type

	 *

	 * @access	public

	 * @param	string

	 * @return	string

	 */

	function set_hash($type = 'sha1')

	{

		$this->_hash_type = ($type != 'sha1' AND $type != 'md5') ? 'sha1' : $type;

	}


	// --------------------------------------------------------------------


	/**

	 * Hash encode a string

	 *

	 * @access	public

	 * @param	string

	 * @return	string

	 */	

	function hash($str)

	{

		return ($this->_hash_type == 'sha1') ? $this->sha1($str) : md5($str);

	}


	// --------------------------------------------------------------------


	/**

	 * Generate an SHA1 Hash

	 *

	 * @access	public

	 * @param	string

	 * @return	string

	 */

	function sha1($str)

	{

		if ( ! function_exists('sha1'))

		{

			if ( ! function_exists('mhash'))

			{

				require_once(BASEPATH.'libraries/Sha1'.EXT);

				$SH = new CI_SHA;

				return $SH->generate($str);

			}

			else

			{

				return bin2hex(mhash(MHASH_SHA1, $str));

			}

		}

		else

		{

			return sha1($str);

		}

	}


}

HOW TO USE:

in the config file, in the components array of main.php:


'encrypt'=>array(

			  'class'=>'Encrypt',

			  'encryptionKey'=> '',

			  ),

using in the code:

to encode


Yii::app()->encrypt->encode()

to decode


Yii::app()->encrypt->decode()

BY DEFAULT IT USES RIJNDAEL_256 but you can change it it you want to but but know that you’ll have to use a symmetric encoding or decode won’t work!!!!

It’s FREE as in BEER :P but use it wisely. This code is given AS IS!

http://code.google.com/p/yii/source/browse/branches/1.0/framework/base/CSecurityManager.php

Hmmm, didn’t see that in the guide :huh:

Maybe you could add a little think or two about the CSecurityManager to the security or authentication topic of the guide?