blob: 656d51b4ae9638bd1d22ec6d3711f2ef45e4326e [file] [log] [blame]
Derek Jones0b59f272008-05-13 04:22:33 +00001<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
Derek Allardd2df9bc2007-04-15 17:41:17 +00002/**
3 * CodeIgniter
4 *
5 * An open source application development framework for PHP 4.3.2 or newer
6 *
7 * @package CodeIgniter
Derek Allard3d879d52008-01-18 19:41:32 +00008 * @author ExpressionEngine Dev Team
Rick Ellise4a7db42008-09-12 23:35:09 +00009 * @copyright Copyright (c) 2008, EllisLab, Inc.
Derek Jones7a9193a2008-01-21 18:39:20 +000010 * @license http://codeigniter.com/user_guide/license.html
11 * @link http://codeigniter.com
Derek Allardd2df9bc2007-04-15 17:41:17 +000012 * @since Version 1.0
13 * @filesource
14 */
15
16// ------------------------------------------------------------------------
17
18/**
19 * CodeIgniter Encryption Class
20 *
21 * Provides two-way keyed encoding using XOR Hashing and Mcrypt
22 *
23 * @package CodeIgniter
24 * @subpackage Libraries
25 * @category Libraries
Derek Allard3d879d52008-01-18 19:41:32 +000026 * @author ExpressionEngine Dev Team
Derek Jones7a9193a2008-01-21 18:39:20 +000027 * @link http://codeigniter.com/user_guide/libraries/encryption.html
Derek Allardd2df9bc2007-04-15 17:41:17 +000028 */
29class CI_Encrypt {
Derek Allard0c9e2702008-09-23 06:06:21 +000030
Derek Jones15130ca2008-01-28 15:54:45 +000031 var $CI;
Derek Allardd2df9bc2007-04-15 17:41:17 +000032 var $encryption_key = '';
33 var $_hash_type = 'sha1';
34 var $_mcrypt_exists = FALSE;
35 var $_mcrypt_cipher;
36 var $_mcrypt_mode;
Derek Allard0c9e2702008-09-23 06:06:21 +000037
Derek Allardd2df9bc2007-04-15 17:41:17 +000038 /**
39 * Constructor
40 *
41 * Simply determines whether the mcrypt library exists.
42 *
43 */
44 function CI_Encrypt()
45 {
Derek Jones15130ca2008-01-28 15:54:45 +000046 $this->CI =& get_instance();
Derek Jones0b59f272008-05-13 04:22:33 +000047 $this->_mcrypt_exists = ( ! function_exists('mcrypt_encrypt')) ? FALSE : TRUE;
Derek Allardd2df9bc2007-04-15 17:41:17 +000048 log_message('debug', "Encrypt Class Initialized");
49 }
Derek Allard0c9e2702008-09-23 06:06:21 +000050
Derek Allardd2df9bc2007-04-15 17:41:17 +000051 // --------------------------------------------------------------------
52
53 /**
54 * Fetch the encryption key
55 *
56 * Returns it as MD5 in order to have an exact-length 128 bit key.
57 * Mcrypt is sensitive to keys that are not the correct length
58 *
59 * @access public
60 * @param string
61 * @return string
62 */
63 function get_key($key = '')
64 {
65 if ($key == '')
Derek Allard0c9e2702008-09-23 06:06:21 +000066 {
Derek Allardd2df9bc2007-04-15 17:41:17 +000067 if ($this->encryption_key != '')
68 {
69 return $this->encryption_key;
70 }
Derek Allard0c9e2702008-09-23 06:06:21 +000071
Derek Allardd2df9bc2007-04-15 17:41:17 +000072 $CI =& get_instance();
73 $key = $CI->config->item('encryption_key');
74
75 if ($key === FALSE)
76 {
77 show_error('In order to use the encryption class requires that you set an encryption key in your config file.');
78 }
79 }
Derek Allard0c9e2702008-09-23 06:06:21 +000080
Derek Allardd2df9bc2007-04-15 17:41:17 +000081 return md5($key);
82 }
83
84 // --------------------------------------------------------------------
85
86 /**
87 * Set the encryption key
88 *
89 * @access public
90 * @param string
91 * @return void
92 */
93 function set_key($key = '')
94 {
95 $this->encryption_key = $key;
96 }
Derek Allard0c9e2702008-09-23 06:06:21 +000097
Derek Allardd2df9bc2007-04-15 17:41:17 +000098 // --------------------------------------------------------------------
99
100 /**
101 * Encode
102 *
103 * Encodes the message string using bitwise XOR encoding.
104 * The key is combined with a random hash, and then it
105 * too gets converted using XOR. The whole thing is then run
106 * through mcrypt (if supported) using the randomized key.
107 * The end result is a double-encrypted message string
108 * that is randomized with each call to this function,
109 * even if the supplied message and key are the same.
110 *
111 * @access public
112 * @param string the string to encode
113 * @param string the key
114 * @return string
115 */
116 function encode($string, $key = '')
117 {
118 $key = $this->get_key($key);
119 $enc = $this->_xor_encode($string, $key);
120
121 if ($this->_mcrypt_exists === TRUE)
122 {
123 $enc = $this->mcrypt_encode($enc, $key);
124 }
Derek Allard0c9e2702008-09-23 06:06:21 +0000125 return base64_encode($enc);
Derek Allardd2df9bc2007-04-15 17:41:17 +0000126 }
Derek Allard0c9e2702008-09-23 06:06:21 +0000127
Derek Allardd2df9bc2007-04-15 17:41:17 +0000128 // --------------------------------------------------------------------
129
130 /**
131 * Decode
132 *
133 * Reverses the above process
134 *
135 * @access public
136 * @param string
137 * @param string
138 * @return string
139 */
140 function decode($string, $key = '')
141 {
142 $key = $this->get_key($key);
Derek Jones15130ca2008-01-28 15:54:45 +0000143
Derek Allard57f9f392008-09-23 20:59:14 +0000144 if ( ! preg_match('/[a-zA-Z0-9\/\+=]/', $string))
Derek Jones15130ca2008-01-28 15:54:45 +0000145 {
146 return FALSE;
147 }
148
Derek Allardd2df9bc2007-04-15 17:41:17 +0000149 $dec = base64_decode($string);
Derek Jones15130ca2008-01-28 15:54:45 +0000150
Derek Allardd2df9bc2007-04-15 17:41:17 +0000151 if ($this->_mcrypt_exists === TRUE)
152 {
Derek Jones15130ca2008-01-28 15:54:45 +0000153 if (($dec = $this->mcrypt_decode($dec, $key)) === FALSE)
154 {
155 return FALSE;
156 }
Derek Allardd2df9bc2007-04-15 17:41:17 +0000157 }
Derek Allard0c9e2702008-09-23 06:06:21 +0000158
Derek Allardd2df9bc2007-04-15 17:41:17 +0000159 return $this->_xor_decode($dec, $key);
160 }
Derek Allard0c9e2702008-09-23 06:06:21 +0000161
Derek Allardd2df9bc2007-04-15 17:41:17 +0000162 // --------------------------------------------------------------------
163
164 /**
165 * XOR Encode
166 *
167 * Takes a plain-text string and key as input and generates an
168 * encoded bit-string using XOR
169 *
170 * @access private
171 * @param string
172 * @param string
173 * @return string
Derek Allard0c9e2702008-09-23 06:06:21 +0000174 */
Derek Allardd2df9bc2007-04-15 17:41:17 +0000175 function _xor_encode($string, $key)
176 {
177 $rand = '';
178 while (strlen($rand) < 32)
179 {
180 $rand .= mt_rand(0, mt_getrandmax());
181 }
Derek Allard0c9e2702008-09-23 06:06:21 +0000182
Derek Allardd2df9bc2007-04-15 17:41:17 +0000183 $rand = $this->hash($rand);
Derek Allard0c9e2702008-09-23 06:06:21 +0000184
Derek Allardd2df9bc2007-04-15 17:41:17 +0000185 $enc = '';
186 for ($i = 0; $i < strlen($string); $i++)
187 {
188 $enc .= substr($rand, ($i % strlen($rand)), 1).(substr($rand, ($i % strlen($rand)), 1) ^ substr($string, $i, 1));
189 }
Derek Allard0c9e2702008-09-23 06:06:21 +0000190
Derek Allardd2df9bc2007-04-15 17:41:17 +0000191 return $this->_xor_merge($enc, $key);
192 }
Derek Allard0c9e2702008-09-23 06:06:21 +0000193
Derek Allardd2df9bc2007-04-15 17:41:17 +0000194 // --------------------------------------------------------------------
195
196 /**
197 * XOR Decode
198 *
199 * Takes an encoded string and key as input and generates the
200 * plain-text original message
201 *
202 * @access private
203 * @param string
204 * @param string
205 * @return string
Derek Allard0c9e2702008-09-23 06:06:21 +0000206 */
Derek Allardd2df9bc2007-04-15 17:41:17 +0000207 function _xor_decode($string, $key)
208 {
209 $string = $this->_xor_merge($string, $key);
Derek Allard0c9e2702008-09-23 06:06:21 +0000210
Derek Allardd2df9bc2007-04-15 17:41:17 +0000211 $dec = '';
212 for ($i = 0; $i < strlen($string); $i++)
213 {
214 $dec .= (substr($string, $i++, 1) ^ substr($string, $i, 1));
215 }
Derek Allard0c9e2702008-09-23 06:06:21 +0000216
Derek Allardd2df9bc2007-04-15 17:41:17 +0000217 return $dec;
218 }
Derek Allard0c9e2702008-09-23 06:06:21 +0000219
Derek Allardd2df9bc2007-04-15 17:41:17 +0000220 // --------------------------------------------------------------------
221
222 /**
223 * XOR key + string Combiner
224 *
225 * Takes a string and key as input and computes the difference using XOR
226 *
227 * @access private
228 * @param string
229 * @param string
230 * @return string
Derek Allard0c9e2702008-09-23 06:06:21 +0000231 */
Derek Allardd2df9bc2007-04-15 17:41:17 +0000232 function _xor_merge($string, $key)
233 {
234 $hash = $this->hash($key);
235 $str = '';
236 for ($i = 0; $i < strlen($string); $i++)
237 {
238 $str .= substr($string, $i, 1) ^ substr($hash, ($i % strlen($hash)), 1);
239 }
Derek Allard0c9e2702008-09-23 06:06:21 +0000240
Derek Allardd2df9bc2007-04-15 17:41:17 +0000241 return $str;
242 }
Derek Allard0c9e2702008-09-23 06:06:21 +0000243
Derek Allardd2df9bc2007-04-15 17:41:17 +0000244 // --------------------------------------------------------------------
245
246 /**
247 * Encrypt using Mcrypt
248 *
249 * @access public
250 * @param string
251 * @param string
252 * @return string
253 */
254 function mcrypt_encode($data, $key)
Derek Allard0c9e2702008-09-23 06:06:21 +0000255 {
Derek Allardd2df9bc2007-04-15 17:41:17 +0000256 $init_size = mcrypt_get_iv_size($this->_get_cipher(), $this->_get_mode());
257 $init_vect = mcrypt_create_iv($init_size, MCRYPT_RAND);
Derek Jonesd32d45c2008-01-17 19:21:03 +0000258 return $this->_add_cipher_noise($init_vect.mcrypt_encrypt($this->_get_cipher(), $key, $data, $this->_get_mode(), $init_vect), $key);
Derek Allardd2df9bc2007-04-15 17:41:17 +0000259 }
Derek Allard0c9e2702008-09-23 06:06:21 +0000260
Derek Allardd2df9bc2007-04-15 17:41:17 +0000261 // --------------------------------------------------------------------
262
263 /**
264 * Decrypt using Mcrypt
265 *
266 * @access public
267 * @param string
268 * @param string
269 * @return string
Derek Allard0c9e2702008-09-23 06:06:21 +0000270 */
Derek Allardd2df9bc2007-04-15 17:41:17 +0000271 function mcrypt_decode($data, $key)
272 {
Derek Jonesd32d45c2008-01-17 19:21:03 +0000273 $data = $this->_remove_cipher_noise($data, $key);
Derek Allardd2df9bc2007-04-15 17:41:17 +0000274 $init_size = mcrypt_get_iv_size($this->_get_cipher(), $this->_get_mode());
Derek Allard0c9e2702008-09-23 06:06:21 +0000275
Derek Jones15130ca2008-01-28 15:54:45 +0000276 if ($init_size > strlen($data))
277 {
278 return FALSE;
279 }
Derek Allard0c9e2702008-09-23 06:06:21 +0000280
Derek Jonesd32d45c2008-01-17 19:21:03 +0000281 $init_vect = substr($data, 0, $init_size);
282 $data = substr($data, $init_size);
Derek Allardd2df9bc2007-04-15 17:41:17 +0000283 return rtrim(mcrypt_decrypt($this->_get_cipher(), $key, $data, $this->_get_mode(), $init_vect), "\0");
284 }
Derek Allard0c9e2702008-09-23 06:06:21 +0000285
Derek Allardd2df9bc2007-04-15 17:41:17 +0000286 // --------------------------------------------------------------------
287
288 /**
Derek Jonesd32d45c2008-01-17 19:21:03 +0000289 * Adds permuted noise to the IV + encrypted data to protect
290 * against Man-in-the-middle attacks on CBC mode ciphers
291 * http://www.ciphersbyritter.com/GLOSSARY.HTM#IV
292 *
293 * Function description
294 *
295 * @access private
296 * @param string
297 * @param string
298 * @return string
299 */
300 function _add_cipher_noise($data, $key)
301 {
302 $keyhash = $this->hash($key);
303 $keylen = strlen($keyhash);
304 $str = '';
Derek Allard0c9e2702008-09-23 06:06:21 +0000305
Derek Jonesd32d45c2008-01-17 19:21:03 +0000306 for ($i = 0, $j = 0, $len = strlen($data); $i < $len; ++$i, ++$j)
Derek Allard0c9e2702008-09-23 06:06:21 +0000307 {
Derek Jonesd32d45c2008-01-17 19:21:03 +0000308 if ($j >= $keylen)
309 {
310 $j = 0;
311 }
Derek Allard0c9e2702008-09-23 06:06:21 +0000312
Derek Jonesd32d45c2008-01-17 19:21:03 +0000313 $str .= chr((ord($data[$i]) + ord($keyhash[$j])) % 256);
314 }
Derek Allard0c9e2702008-09-23 06:06:21 +0000315
Derek Jonesd32d45c2008-01-17 19:21:03 +0000316 return $str;
317 }
318
319 // --------------------------------------------------------------------
Derek Allard0c9e2702008-09-23 06:06:21 +0000320
Derek Jonesd32d45c2008-01-17 19:21:03 +0000321 /**
322 * Removes permuted noise from the IV + encrypted data, reversing
323 * _add_cipher_noise()
324 *
325 * Function description
326 *
327 * @access public
328 * @param type
329 * @return type
330 */
331 function _remove_cipher_noise($data, $key)
332 {
333 $keyhash = $this->hash($key);
334 $keylen = strlen($keyhash);
335 $str = '';
336
337 for ($i = 0, $j = 0, $len = strlen($data); $i < $len; ++$i, ++$j)
338 {
339 if ($j >= $keylen)
340 {
341 $j = 0;
342 }
Derek Allard0c9e2702008-09-23 06:06:21 +0000343
Derek Jonesd32d45c2008-01-17 19:21:03 +0000344 $temp = ord($data[$i]) - ord($keyhash[$j]);
Derek Allard0c9e2702008-09-23 06:06:21 +0000345
Derek Jonesd32d45c2008-01-17 19:21:03 +0000346 if ($temp < 0)
347 {
348 $temp = $temp + 256;
349 }
350
351 $str .= chr($temp);
352 }
Derek Allard0c9e2702008-09-23 06:06:21 +0000353
Derek Jonesd32d45c2008-01-17 19:21:03 +0000354 return $str;
355 }
356
357 // --------------------------------------------------------------------
358
359 /**
Derek Allardd2df9bc2007-04-15 17:41:17 +0000360 * Set the Mcrypt Cipher
361 *
362 * @access public
363 * @param constant
364 * @return string
365 */
366 function set_cipher($cipher)
367 {
368 $this->_mcrypt_cipher = $cipher;
369 }
Derek Allard0c9e2702008-09-23 06:06:21 +0000370
Derek Allardd2df9bc2007-04-15 17:41:17 +0000371 // --------------------------------------------------------------------
372
373 /**
374 * Set the Mcrypt Mode
375 *
376 * @access public
377 * @param constant
378 * @return string
379 */
380 function set_mode($mode)
381 {
382 $this->_mcrypt_mode = $mode;
383 }
Derek Allard0c9e2702008-09-23 06:06:21 +0000384
Derek Allardd2df9bc2007-04-15 17:41:17 +0000385 // --------------------------------------------------------------------
386
387 /**
388 * Get Mcrypt cipher Value
389 *
390 * @access private
391 * @return string
Derek Allard0c9e2702008-09-23 06:06:21 +0000392 */
Derek Allardd2df9bc2007-04-15 17:41:17 +0000393 function _get_cipher()
394 {
395 if ($this->_mcrypt_cipher == '')
396 {
397 $this->_mcrypt_cipher = MCRYPT_RIJNDAEL_256;
398 }
399
400 return $this->_mcrypt_cipher;
401 }
402
403 // --------------------------------------------------------------------
404
405 /**
Derek Allard83ec2402007-06-18 00:14:44 +0000406 * Get Mcrypt Mode Value
Derek Allardd2df9bc2007-04-15 17:41:17 +0000407 *
408 * @access private
409 * @return string
Derek Allard0c9e2702008-09-23 06:06:21 +0000410 */
Derek Allardd2df9bc2007-04-15 17:41:17 +0000411 function _get_mode()
412 {
413 if ($this->_mcrypt_mode == '')
414 {
415 $this->_mcrypt_mode = MCRYPT_MODE_ECB;
416 }
417
418 return $this->_mcrypt_mode;
419 }
Derek Allard0c9e2702008-09-23 06:06:21 +0000420
Derek Allardd2df9bc2007-04-15 17:41:17 +0000421 // --------------------------------------------------------------------
422
423 /**
424 * Set the Hash type
425 *
426 * @access public
427 * @param string
428 * @return string
Derek Allard0c9e2702008-09-23 06:06:21 +0000429 */
Derek Allardd2df9bc2007-04-15 17:41:17 +0000430 function set_hash($type = 'sha1')
431 {
432 $this->_hash_type = ($type != 'sha1' AND $type != 'md5') ? 'sha1' : $type;
433 }
Derek Allard0c9e2702008-09-23 06:06:21 +0000434
Derek Allardd2df9bc2007-04-15 17:41:17 +0000435 // --------------------------------------------------------------------
436
437 /**
438 * Hash encode a string
439 *
440 * @access public
441 * @param string
442 * @return string
Derek Allard0c9e2702008-09-23 06:06:21 +0000443 */
Derek Allardd2df9bc2007-04-15 17:41:17 +0000444 function hash($str)
445 {
446 return ($this->_hash_type == 'sha1') ? $this->sha1($str) : md5($str);
447 }
Derek Allard0c9e2702008-09-23 06:06:21 +0000448
Derek Allardd2df9bc2007-04-15 17:41:17 +0000449 // --------------------------------------------------------------------
450
451 /**
452 * Generate an SHA1 Hash
453 *
454 * @access public
455 * @param string
456 * @return string
Derek Allard0c9e2702008-09-23 06:06:21 +0000457 */
Derek Allardd2df9bc2007-04-15 17:41:17 +0000458 function sha1($str)
459 {
Derek Jones0b59f272008-05-13 04:22:33 +0000460 if ( ! function_exists('sha1'))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000461 {
Derek Jones0b59f272008-05-13 04:22:33 +0000462 if ( ! function_exists('mhash'))
Derek Allard0c9e2702008-09-23 06:06:21 +0000463 {
Derek Allardd2df9bc2007-04-15 17:41:17 +0000464 require_once(BASEPATH.'libraries/Sha1'.EXT);
465 $SH = new CI_SHA;
466 return $SH->generate($str);
467 }
468 else
469 {
470 return bin2hex(mhash(MHASH_SHA1, $str));
471 }
472 }
473 else
474 {
475 return sha1($str);
Derek Allard0c9e2702008-09-23 06:06:21 +0000476 }
Derek Allardd2df9bc2007-04-15 17:41:17 +0000477 }
Derek Allard0c9e2702008-09-23 06:06:21 +0000478
Derek Allardd2df9bc2007-04-15 17:41:17 +0000479}
480
481// END CI_Encrypt class
Derek Jones0b59f272008-05-13 04:22:33 +0000482
483/* End of file Encrypt.php */
Derek Jonesa3ffbbb2008-05-11 18:18:29 +0000484/* Location: ./system/libraries/Encrypt.php */