blob: 48f9d3e514d94e450c9891267cecd0e5baed7f38 [file] [log] [blame]
Derek Allardd2df9bc2007-04-15 17:41:17 +00001<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
2/**
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
Derek Allardd2df9bc2007-04-15 17:41:17 +00009 * @copyright Copyright (c) 2006, 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 Jones15130ca2008-01-28 15:54:45 +000030
31 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;
37
38 /**
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 Allardd2df9bc2007-04-15 17:41:17 +000047 $this->_mcrypt_exists = ( ! function_exists('mcrypt_encrypt')) ? FALSE : TRUE;
48 log_message('debug', "Encrypt Class Initialized");
49 }
50
51 // --------------------------------------------------------------------
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 == '')
66 {
67 if ($this->encryption_key != '')
68 {
69 return $this->encryption_key;
70 }
71
72 $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 }
80
81 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 }
97
98 // --------------------------------------------------------------------
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 }
125 return base64_encode($enc);
126 }
127
128 // --------------------------------------------------------------------
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
144 $this->CI->load->library('validation');
145
146 if ($this->CI->validation->valid_base64($string) === FALSE)
147 {
148 return FALSE;
149 }
150
Derek Allardd2df9bc2007-04-15 17:41:17 +0000151 $dec = base64_decode($string);
Derek Jones15130ca2008-01-28 15:54:45 +0000152
Derek Allardd2df9bc2007-04-15 17:41:17 +0000153 if ($this->_mcrypt_exists === TRUE)
154 {
Derek Jones15130ca2008-01-28 15:54:45 +0000155 if (($dec = $this->mcrypt_decode($dec, $key)) === FALSE)
156 {
157 return FALSE;
158 }
Derek Allardd2df9bc2007-04-15 17:41:17 +0000159 }
160
161 return $this->_xor_decode($dec, $key);
162 }
163
164 // --------------------------------------------------------------------
165
166 /**
167 * XOR Encode
168 *
169 * Takes a plain-text string and key as input and generates an
170 * encoded bit-string using XOR
171 *
172 * @access private
173 * @param string
174 * @param string
175 * @return string
176 */
177 function _xor_encode($string, $key)
178 {
179 $rand = '';
180 while (strlen($rand) < 32)
181 {
182 $rand .= mt_rand(0, mt_getrandmax());
183 }
184
185 $rand = $this->hash($rand);
186
187 $enc = '';
188 for ($i = 0; $i < strlen($string); $i++)
189 {
190 $enc .= substr($rand, ($i % strlen($rand)), 1).(substr($rand, ($i % strlen($rand)), 1) ^ substr($string, $i, 1));
191 }
192
193 return $this->_xor_merge($enc, $key);
194 }
195
196 // --------------------------------------------------------------------
197
198 /**
199 * XOR Decode
200 *
201 * Takes an encoded string and key as input and generates the
202 * plain-text original message
203 *
204 * @access private
205 * @param string
206 * @param string
207 * @return string
208 */
209 function _xor_decode($string, $key)
210 {
211 $string = $this->_xor_merge($string, $key);
212
213 $dec = '';
214 for ($i = 0; $i < strlen($string); $i++)
215 {
216 $dec .= (substr($string, $i++, 1) ^ substr($string, $i, 1));
217 }
218
219 return $dec;
220 }
221
222 // --------------------------------------------------------------------
223
224 /**
225 * XOR key + string Combiner
226 *
227 * Takes a string and key as input and computes the difference using XOR
228 *
229 * @access private
230 * @param string
231 * @param string
232 * @return string
233 */
234 function _xor_merge($string, $key)
235 {
236 $hash = $this->hash($key);
237 $str = '';
238 for ($i = 0; $i < strlen($string); $i++)
239 {
240 $str .= substr($string, $i, 1) ^ substr($hash, ($i % strlen($hash)), 1);
241 }
242
243 return $str;
244 }
245
246 // --------------------------------------------------------------------
247
248 /**
249 * Encrypt using Mcrypt
250 *
251 * @access public
252 * @param string
253 * @param string
254 * @return string
255 */
256 function mcrypt_encode($data, $key)
257 {
258 $init_size = mcrypt_get_iv_size($this->_get_cipher(), $this->_get_mode());
259 $init_vect = mcrypt_create_iv($init_size, MCRYPT_RAND);
Derek Jonesd32d45c2008-01-17 19:21:03 +0000260 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 +0000261 }
262
263 // --------------------------------------------------------------------
264
265 /**
266 * Decrypt using Mcrypt
267 *
268 * @access public
269 * @param string
270 * @param string
271 * @return string
272 */
273 function mcrypt_decode($data, $key)
274 {
Derek Jonesd32d45c2008-01-17 19:21:03 +0000275 $data = $this->_remove_cipher_noise($data, $key);
Derek Allardd2df9bc2007-04-15 17:41:17 +0000276 $init_size = mcrypt_get_iv_size($this->_get_cipher(), $this->_get_mode());
Derek Jones15130ca2008-01-28 15:54:45 +0000277
278 if ($init_size > strlen($data))
279 {
280 return FALSE;
281 }
282
Derek Jonesd32d45c2008-01-17 19:21:03 +0000283 $init_vect = substr($data, 0, $init_size);
284 $data = substr($data, $init_size);
Derek Allardd2df9bc2007-04-15 17:41:17 +0000285 return rtrim(mcrypt_decrypt($this->_get_cipher(), $key, $data, $this->_get_mode(), $init_vect), "\0");
286 }
287
288 // --------------------------------------------------------------------
289
290 /**
Derek Jonesd32d45c2008-01-17 19:21:03 +0000291 * Adds permuted noise to the IV + encrypted data to protect
292 * against Man-in-the-middle attacks on CBC mode ciphers
293 * http://www.ciphersbyritter.com/GLOSSARY.HTM#IV
294 *
295 * Function description
296 *
297 * @access private
298 * @param string
299 * @param string
300 * @return string
301 */
302 function _add_cipher_noise($data, $key)
303 {
304 $keyhash = $this->hash($key);
305 $keylen = strlen($keyhash);
306 $str = '';
307
308 for ($i = 0, $j = 0, $len = strlen($data); $i < $len; ++$i, ++$j)
309 {
310 if ($j >= $keylen)
311 {
312 $j = 0;
313 }
314
315 $str .= chr((ord($data[$i]) + ord($keyhash[$j])) % 256);
316 }
317
318 return $str;
319 }
320
321 // --------------------------------------------------------------------
322
323 /**
324 * Removes permuted noise from the IV + encrypted data, reversing
325 * _add_cipher_noise()
326 *
327 * Function description
328 *
329 * @access public
330 * @param type
331 * @return type
332 */
333 function _remove_cipher_noise($data, $key)
334 {
335 $keyhash = $this->hash($key);
336 $keylen = strlen($keyhash);
337 $str = '';
338
339 for ($i = 0, $j = 0, $len = strlen($data); $i < $len; ++$i, ++$j)
340 {
341 if ($j >= $keylen)
342 {
343 $j = 0;
344 }
345
346 $temp = ord($data[$i]) - ord($keyhash[$j]);
347
348 if ($temp < 0)
349 {
350 $temp = $temp + 256;
351 }
352
353 $str .= chr($temp);
354 }
355
356 return $str;
357 }
358
359 // --------------------------------------------------------------------
360
361 /**
Derek Allardd2df9bc2007-04-15 17:41:17 +0000362 * Set the Mcrypt Cipher
363 *
364 * @access public
365 * @param constant
366 * @return string
367 */
368 function set_cipher($cipher)
369 {
370 $this->_mcrypt_cipher = $cipher;
371 }
372
373 // --------------------------------------------------------------------
374
375 /**
376 * Set the Mcrypt Mode
377 *
378 * @access public
379 * @param constant
380 * @return string
381 */
382 function set_mode($mode)
383 {
384 $this->_mcrypt_mode = $mode;
385 }
386
387 // --------------------------------------------------------------------
388
389 /**
390 * Get Mcrypt cipher Value
391 *
392 * @access private
393 * @return string
394 */
395 function _get_cipher()
396 {
397 if ($this->_mcrypt_cipher == '')
398 {
399 $this->_mcrypt_cipher = MCRYPT_RIJNDAEL_256;
400 }
401
402 return $this->_mcrypt_cipher;
403 }
404
405 // --------------------------------------------------------------------
406
407 /**
Derek Allard83ec2402007-06-18 00:14:44 +0000408 * Get Mcrypt Mode Value
Derek Allardd2df9bc2007-04-15 17:41:17 +0000409 *
410 * @access private
411 * @return string
412 */
413 function _get_mode()
414 {
415 if ($this->_mcrypt_mode == '')
416 {
417 $this->_mcrypt_mode = MCRYPT_MODE_ECB;
418 }
419
420 return $this->_mcrypt_mode;
421 }
422
423 // --------------------------------------------------------------------
424
425 /**
426 * Set the Hash type
427 *
428 * @access public
429 * @param string
430 * @return string
431 */
432 function set_hash($type = 'sha1')
433 {
434 $this->_hash_type = ($type != 'sha1' AND $type != 'md5') ? 'sha1' : $type;
435 }
436
437 // --------------------------------------------------------------------
438
439 /**
440 * Hash encode a string
441 *
442 * @access public
443 * @param string
444 * @return string
445 */
446 function hash($str)
447 {
448 return ($this->_hash_type == 'sha1') ? $this->sha1($str) : md5($str);
449 }
450
451 // --------------------------------------------------------------------
452
453 /**
454 * Generate an SHA1 Hash
455 *
456 * @access public
457 * @param string
458 * @return string
459 */
460 function sha1($str)
461 {
462 if ( ! function_exists('sha1'))
463 {
464 if ( ! function_exists('mhash'))
465 {
466 require_once(BASEPATH.'libraries/Sha1'.EXT);
467 $SH = new CI_SHA;
468 return $SH->generate($str);
469 }
470 else
471 {
472 return bin2hex(mhash(MHASH_SHA1, $str));
473 }
474 }
475 else
476 {
477 return sha1($str);
478 }
479 }
480
481}
482
483// END CI_Encrypt class
adminb0dd10f2006-08-25 17:25:49 +0000484?>