]>
Commit | Line | Data |
---|---|---|
59c06b17 CS |
1 | <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); |
2 | /** | |
3 | * CodeIgniter | |
4 | * | |
5 | * An open source application development framework for PHP 5.1.6 or newer | |
6 | * | |
7 | * @package CodeIgniter | |
8 | * @author ExpressionEngine Dev Team | |
9 | * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. | |
10 | * @license http://codeigniter.com/user_guide/license.html | |
11 | * @link http://codeigniter.com | |
12 | * @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 | |
26 | * @author ExpressionEngine Dev Team | |
27 | * @link http://codeigniter.com/user_guide/libraries/encryption.html | |
28 | */ | |
29 | class CI_Encrypt { | |
30 | ||
31 | var $CI; | |
32 | 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 | public function __construct() | |
45 | { | |
46 | $this->CI =& get_instance(); | |
47 | $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 | ||
120 | if ($this->_mcrypt_exists === TRUE) | |
121 | { | |
122 | $enc = $this->mcrypt_encode($string, $key); | |
123 | } | |
124 | else | |
125 | { | |
126 | $enc = $this->_xor_encode($string, $key); | |
127 | } | |
128 | ||
129 | return base64_encode($enc); | |
130 | } | |
131 | ||
132 | // -------------------------------------------------------------------- | |
133 | ||
134 | /** | |
135 | * Decode | |
136 | * | |
137 | * Reverses the above process | |
138 | * | |
139 | * @access public | |
140 | * @param string | |
141 | * @param string | |
142 | * @return string | |
143 | */ | |
144 | function decode($string, $key = '') | |
145 | { | |
146 | $key = $this->get_key($key); | |
147 | ||
148 | if (preg_match('/[^a-zA-Z0-9\/\+=]/', $string)) | |
149 | { | |
150 | return FALSE; | |
151 | } | |
152 | ||
153 | $dec = base64_decode($string); | |
154 | ||
155 | if ($this->_mcrypt_exists === TRUE) | |
156 | { | |
157 | if (($dec = $this->mcrypt_decode($dec, $key)) === FALSE) | |
158 | { | |
159 | return FALSE; | |
160 | } | |
161 | } | |
162 | else | |
163 | { | |
164 | $dec = $this->_xor_decode($dec, $key); | |
165 | } | |
166 | ||
167 | return $dec; | |
168 | } | |
169 | ||
170 | // -------------------------------------------------------------------- | |
171 | ||
172 | /** | |
173 | * Encode from Legacy | |
174 | * | |
175 | * Takes an encoded string from the original Encryption class algorithms and | |
176 | * returns a newly encoded string using the improved method added in 2.0.0 | |
177 | * This allows for backwards compatibility and a method to transition to the | |
178 | * new encryption algorithms. | |
179 | * | |
180 | * For more details, see http://codeigniter.com/user_guide/installation/upgrade_200.html#encryption | |
181 | * | |
182 | * @access public | |
183 | * @param string | |
184 | * @param int (mcrypt mode constant) | |
185 | * @param string | |
186 | * @return string | |
187 | */ | |
188 | function encode_from_legacy($string, $legacy_mode = MCRYPT_MODE_ECB, $key = '') | |
189 | { | |
190 | if ($this->_mcrypt_exists === FALSE) | |
191 | { | |
192 | log_message('error', 'Encoding from legacy is available only when Mcrypt is in use.'); | |
193 | return FALSE; | |
194 | } | |
195 | ||
196 | // decode it first | |
197 | // set mode temporarily to what it was when string was encoded with the legacy | |
198 | // algorithm - typically MCRYPT_MODE_ECB | |
199 | $current_mode = $this->_get_mode(); | |
200 | $this->set_mode($legacy_mode); | |
201 | ||
202 | $key = $this->get_key($key); | |
203 | ||
204 | if (preg_match('/[^a-zA-Z0-9\/\+=]/', $string)) | |
205 | { | |
206 | return FALSE; | |
207 | } | |
208 | ||
209 | $dec = base64_decode($string); | |
210 | ||
211 | if (($dec = $this->mcrypt_decode($dec, $key)) === FALSE) | |
212 | { | |
213 | return FALSE; | |
214 | } | |
215 | ||
216 | $dec = $this->_xor_decode($dec, $key); | |
217 | ||
218 | // set the mcrypt mode back to what it should be, typically MCRYPT_MODE_CBC | |
219 | $this->set_mode($current_mode); | |
220 | ||
221 | // and re-encode | |
222 | return base64_encode($this->mcrypt_encode($dec, $key)); | |
223 | } | |
224 | ||
225 | // -------------------------------------------------------------------- | |
226 | ||
227 | /** | |
228 | * XOR Encode | |
229 | * | |
230 | * Takes a plain-text string and key as input and generates an | |
231 | * encoded bit-string using XOR | |
232 | * | |
233 | * @access private | |
234 | * @param string | |
235 | * @param string | |
236 | * @return string | |
237 | */ | |
238 | function _xor_encode($string, $key) | |
239 | { | |
240 | $rand = ''; | |
241 | while (strlen($rand) < 32) | |
242 | { | |
243 | $rand .= mt_rand(0, mt_getrandmax()); | |
244 | } | |
245 | ||
246 | $rand = $this->hash($rand); | |
247 | ||
248 | $enc = ''; | |
249 | for ($i = 0; $i < strlen($string); $i++) | |
250 | { | |
251 | $enc .= substr($rand, ($i % strlen($rand)), 1).(substr($rand, ($i % strlen($rand)), 1) ^ substr($string, $i, 1)); | |
252 | } | |
253 | ||
254 | return $this->_xor_merge($enc, $key); | |
255 | } | |
256 | ||
257 | // -------------------------------------------------------------------- | |
258 | ||
259 | /** | |
260 | * XOR Decode | |
261 | * | |
262 | * Takes an encoded string and key as input and generates the | |
263 | * plain-text original message | |
264 | * | |
265 | * @access private | |
266 | * @param string | |
267 | * @param string | |
268 | * @return string | |
269 | */ | |
270 | function _xor_decode($string, $key) | |
271 | { | |
272 | $string = $this->_xor_merge($string, $key); | |
273 | ||
274 | $dec = ''; | |
275 | for ($i = 0; $i < strlen($string); $i++) | |
276 | { | |
277 | $dec .= (substr($string, $i++, 1) ^ substr($string, $i, 1)); | |
278 | } | |
279 | ||
280 | return $dec; | |
281 | } | |
282 | ||
283 | // -------------------------------------------------------------------- | |
284 | ||
285 | /** | |
286 | * XOR key + string Combiner | |
287 | * | |
288 | * Takes a string and key as input and computes the difference using XOR | |
289 | * | |
290 | * @access private | |
291 | * @param string | |
292 | * @param string | |
293 | * @return string | |
294 | */ | |
295 | function _xor_merge($string, $key) | |
296 | { | |
297 | $hash = $this->hash($key); | |
298 | $str = ''; | |
299 | for ($i = 0; $i < strlen($string); $i++) | |
300 | { | |
301 | $str .= substr($string, $i, 1) ^ substr($hash, ($i % strlen($hash)), 1); | |
302 | } | |
303 | ||
304 | return $str; | |
305 | } | |
306 | ||
307 | // -------------------------------------------------------------------- | |
308 | ||
309 | /** | |
310 | * Encrypt using Mcrypt | |
311 | * | |
312 | * @access public | |
313 | * @param string | |
314 | * @param string | |
315 | * @return string | |
316 | */ | |
317 | function mcrypt_encode($data, $key) | |
318 | { | |
319 | $init_size = mcrypt_get_iv_size($this->_get_cipher(), $this->_get_mode()); | |
320 | $init_vect = mcrypt_create_iv($init_size, MCRYPT_RAND); | |
321 | return $this->_add_cipher_noise($init_vect.mcrypt_encrypt($this->_get_cipher(), $key, $data, $this->_get_mode(), $init_vect), $key); | |
322 | } | |
323 | ||
324 | // -------------------------------------------------------------------- | |
325 | ||
326 | /** | |
327 | * Decrypt using Mcrypt | |
328 | * | |
329 | * @access public | |
330 | * @param string | |
331 | * @param string | |
332 | * @return string | |
333 | */ | |
334 | function mcrypt_decode($data, $key) | |
335 | { | |
336 | $data = $this->_remove_cipher_noise($data, $key); | |
337 | $init_size = mcrypt_get_iv_size($this->_get_cipher(), $this->_get_mode()); | |
338 | ||
339 | if ($init_size > strlen($data)) | |
340 | { | |
341 | return FALSE; | |
342 | } | |
343 | ||
344 | $init_vect = substr($data, 0, $init_size); | |
345 | $data = substr($data, $init_size); | |
346 | return rtrim(mcrypt_decrypt($this->_get_cipher(), $key, $data, $this->_get_mode(), $init_vect), "\0"); | |
347 | } | |
348 | ||
349 | // -------------------------------------------------------------------- | |
350 | ||
351 | /** | |
352 | * Adds permuted noise to the IV + encrypted data to protect | |
353 | * against Man-in-the-middle attacks on CBC mode ciphers | |
354 | * http://www.ciphersbyritter.com/GLOSSARY.HTM#IV | |
355 | * | |
356 | * Function description | |
357 | * | |
358 | * @access private | |
359 | * @param string | |
360 | * @param string | |
361 | * @return string | |
362 | */ | |
363 | function _add_cipher_noise($data, $key) | |
364 | { | |
365 | $keyhash = $this->hash($key); | |
366 | $keylen = strlen($keyhash); | |
367 | $str = ''; | |
368 | ||
369 | for ($i = 0, $j = 0, $len = strlen($data); $i < $len; ++$i, ++$j) | |
370 | { | |
371 | if ($j >= $keylen) | |
372 | { | |
373 | $j = 0; | |
374 | } | |
375 | ||
376 | $str .= chr((ord($data[$i]) + ord($keyhash[$j])) % 256); | |
377 | } | |
378 | ||
379 | return $str; | |
380 | } | |
381 | ||
382 | // -------------------------------------------------------------------- | |
383 | ||
384 | /** | |
385 | * Removes permuted noise from the IV + encrypted data, reversing | |
386 | * _add_cipher_noise() | |
387 | * | |
388 | * Function description | |
389 | * | |
390 | * @access public | |
391 | * @param type | |
392 | * @return type | |
393 | */ | |
394 | function _remove_cipher_noise($data, $key) | |
395 | { | |
396 | $keyhash = $this->hash($key); | |
397 | $keylen = strlen($keyhash); | |
398 | $str = ''; | |
399 | ||
400 | for ($i = 0, $j = 0, $len = strlen($data); $i < $len; ++$i, ++$j) | |
401 | { | |
402 | if ($j >= $keylen) | |
403 | { | |
404 | $j = 0; | |
405 | } | |
406 | ||
407 | $temp = ord($data[$i]) - ord($keyhash[$j]); | |
408 | ||
409 | if ($temp < 0) | |
410 | { | |
411 | $temp = $temp + 256; | |
412 | } | |
413 | ||
414 | $str .= chr($temp); | |
415 | } | |
416 | ||
417 | return $str; | |
418 | } | |
419 | ||
420 | // -------------------------------------------------------------------- | |
421 | ||
422 | /** | |
423 | * Set the Mcrypt Cipher | |
424 | * | |
425 | * @access public | |
426 | * @param constant | |
427 | * @return string | |
428 | */ | |
429 | function set_cipher($cipher) | |
430 | { | |
431 | $this->_mcrypt_cipher = $cipher; | |
432 | } | |
433 | ||
434 | // -------------------------------------------------------------------- | |
435 | ||
436 | /** | |
437 | * Set the Mcrypt Mode | |
438 | * | |
439 | * @access public | |
440 | * @param constant | |
441 | * @return string | |
442 | */ | |
443 | function set_mode($mode) | |
444 | { | |
445 | $this->_mcrypt_mode = $mode; | |
446 | } | |
447 | ||
448 | // -------------------------------------------------------------------- | |
449 | ||
450 | /** | |
451 | * Get Mcrypt cipher Value | |
452 | * | |
453 | * @access private | |
454 | * @return string | |
455 | */ | |
456 | function _get_cipher() | |
457 | { | |
458 | if ($this->_mcrypt_cipher == '') | |
459 | { | |
460 | $this->_mcrypt_cipher = MCRYPT_RIJNDAEL_256; | |
461 | } | |
462 | ||
463 | return $this->_mcrypt_cipher; | |
464 | } | |
465 | ||
466 | // -------------------------------------------------------------------- | |
467 | ||
468 | /** | |
469 | * Get Mcrypt Mode Value | |
470 | * | |
471 | * @access private | |
472 | * @return string | |
473 | */ | |
474 | function _get_mode() | |
475 | { | |
476 | if ($this->_mcrypt_mode == '') | |
477 | { | |
478 | $this->_mcrypt_mode = MCRYPT_MODE_CBC; | |
479 | } | |
480 | ||
481 | return $this->_mcrypt_mode; | |
482 | } | |
483 | ||
484 | // -------------------------------------------------------------------- | |
485 | ||
486 | /** | |
487 | * Set the Hash type | |
488 | * | |
489 | * @access public | |
490 | * @param string | |
491 | * @return string | |
492 | */ | |
493 | function set_hash($type = 'sha1') | |
494 | { | |
495 | $this->_hash_type = ($type != 'sha1' AND $type != 'md5') ? 'sha1' : $type; | |
496 | } | |
497 | ||
498 | // -------------------------------------------------------------------- | |
499 | ||
500 | /** | |
501 | * Hash encode a string | |
502 | * | |
503 | * @access public | |
504 | * @param string | |
505 | * @return string | |
506 | */ | |
507 | function hash($str) | |
508 | { | |
509 | return ($this->_hash_type == 'sha1') ? $this->sha1($str) : md5($str); | |
510 | } | |
511 | ||
512 | // -------------------------------------------------------------------- | |
513 | ||
514 | /** | |
515 | * Generate an SHA1 Hash | |
516 | * | |
517 | * @access public | |
518 | * @param string | |
519 | * @return string | |
520 | */ | |
521 | function sha1($str) | |
522 | { | |
523 | if ( ! function_exists('sha1')) | |
524 | { | |
525 | if ( ! function_exists('mhash')) | |
526 | { | |
527 | require_once(BASEPATH.'libraries/Sha1.php'); | |
528 | $SH = new CI_SHA; | |
529 | return $SH->generate($str); | |
530 | } | |
531 | else | |
532 | { | |
533 | return bin2hex(mhash(MHASH_SHA1, $str)); | |
534 | } | |
535 | } | |
536 | else | |
537 | { | |
538 | return sha1($str); | |
539 | } | |
540 | } | |
541 | ||
542 | } | |
543 | ||
544 | // END CI_Encrypt class | |
545 | ||
546 | /* End of file Encrypt.php */ | |
547 | /* Location: ./system/libraries/Encrypt.php */ |