blob: 92b0b3c4acac86c21676985d03e361d3a2a66952 [file] [log] [blame]
Derek Jones37f4b9c2011-07-01 17:56:50 -05001<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
Derek Allard2067d1a2008-11-13 22:59:24 +00002/**
3 * CodeIgniter
4 *
Greg Aker741de1c2010-11-10 14:52:57 -06005 * An open source application development framework for PHP 5.1.6 or newer
Derek Allard2067d1a2008-11-13 22:59:24 +00006 *
Derek Jonesf4a4bd82011-10-20 12:18:42 -05007 * NOTICE OF LICENSE
8 *
9 * Licensed under the Open Software License version 3.0
10 *
11 * This source file is subject to the Open Software License (OSL 3.0) that is
12 * bundled with this package in the files license.txt / license.rst. It is
13 * also available through the world wide web at this URL:
14 * http://opensource.org/licenses/OSL-3.0
15 * If you did not receive a copy of the license and are unable to obtain it
16 * through the world wide web, please send an email to
17 * licensing@ellislab.com so we can send you a copy immediately.
18 *
Derek Allard2067d1a2008-11-13 22:59:24 +000019 * @package CodeIgniter
Derek Jonesf4a4bd82011-10-20 12:18:42 -050020 * @author EllisLab Dev Team
21 * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. (http://ellislab.com/)
22 * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
Derek Allard2067d1a2008-11-13 22:59:24 +000023 * @link http://codeigniter.com
24 * @since Version 1.0
25 * @filesource
26 */
27
28// ------------------------------------------------------------------------
29
30/**
31 * CodeIgniter Encryption Class
32 *
33 * Provides two-way keyed encoding using XOR Hashing and Mcrypt
34 *
35 * @package CodeIgniter
36 * @subpackage Libraries
37 * @category Libraries
Derek Jonesf4a4bd82011-10-20 12:18:42 -050038 * @author EllisLab Dev Team
Derek Allard2067d1a2008-11-13 22:59:24 +000039 * @link http://codeigniter.com/user_guide/libraries/encryption.html
40 */
41class CI_Encrypt {
42
Greg Akerd1af1852011-12-25 21:59:30 -060043 public $encryption_key = '';
44 protected $_hash_type = 'sha1';
45 protected $_mcrypt_exists = FALSE;
46 protected $_mcrypt_cipher;
47 protected $_mcrypt_mode;
Derek Allard2067d1a2008-11-13 22:59:24 +000048
49 /**
50 * Constructor
51 *
52 * Simply determines whether the mcrypt library exists.
Derek Allard2067d1a2008-11-13 22:59:24 +000053 */
Greg Akera9263282010-11-10 15:26:43 -060054 public function __construct()
Derek Allard2067d1a2008-11-13 22:59:24 +000055 {
Derek Allard2067d1a2008-11-13 22:59:24 +000056 $this->_mcrypt_exists = ( ! function_exists('mcrypt_encrypt')) ? FALSE : TRUE;
57 log_message('debug', "Encrypt Class Initialized");
58 }
59
60 // --------------------------------------------------------------------
61
62 /**
63 * Fetch the encryption key
64 *
65 * Returns it as MD5 in order to have an exact-length 128 bit key.
66 * Mcrypt is sensitive to keys that are not the correct length
67 *
Derek Allard2067d1a2008-11-13 22:59:24 +000068 * @param string
69 * @return string
70 */
Greg Akerd1af1852011-12-25 21:59:30 -060071 public function get_key($key = '')
Derek Allard2067d1a2008-11-13 22:59:24 +000072 {
73 if ($key == '')
74 {
75 if ($this->encryption_key != '')
76 {
77 return $this->encryption_key;
78 }
79
80 $CI =& get_instance();
81 $key = $CI->config->item('encryption_key');
82
Greg Akerd1af1852011-12-25 21:59:30 -060083 if ($key === FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +000084 {
85 show_error('In order to use the encryption class requires that you set an encryption key in your config file.');
86 }
87 }
88
89 return md5($key);
90 }
91
92 // --------------------------------------------------------------------
93
94 /**
95 * Set the encryption key
96 *
Derek Allard2067d1a2008-11-13 22:59:24 +000097 * @param string
98 * @return void
99 */
Greg Akerd1af1852011-12-25 21:59:30 -0600100 public function set_key($key = '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000101 {
102 $this->encryption_key = $key;
Greg Akerd1af1852011-12-25 21:59:30 -0600103 return $this;
Derek Allard2067d1a2008-11-13 22:59:24 +0000104 }
105
106 // --------------------------------------------------------------------
107
108 /**
109 * Encode
110 *
111 * Encodes the message string using bitwise XOR encoding.
112 * The key is combined with a random hash, and then it
113 * too gets converted using XOR. The whole thing is then run
114 * through mcrypt (if supported) using the randomized key.
115 * The end result is a double-encrypted message string
116 * that is randomized with each call to this function,
117 * even if the supplied message and key are the same.
118 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000119 * @param string the string to encode
120 * @param string the key
121 * @return string
122 */
Greg Akerd1af1852011-12-25 21:59:30 -0600123 public function encode($string, $key = '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000124 {
125 $key = $this->get_key($key);
Derek Jones09c77932010-08-31 13:17:10 -0500126
Derek Allard2067d1a2008-11-13 22:59:24 +0000127 if ($this->_mcrypt_exists === TRUE)
128 {
Derek Jones09c77932010-08-31 13:17:10 -0500129 $enc = $this->mcrypt_encode($string, $key);
Derek Allard2067d1a2008-11-13 22:59:24 +0000130 }
Derek Jones09c77932010-08-31 13:17:10 -0500131 else
132 {
133 $enc = $this->_xor_encode($string, $key);
134 }
135
Derek Allard2067d1a2008-11-13 22:59:24 +0000136 return base64_encode($enc);
137 }
138
139 // --------------------------------------------------------------------
140
141 /**
142 * Decode
143 *
144 * Reverses the above process
145 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000146 * @param string
147 * @param string
148 * @return string
149 */
Greg Akerd1af1852011-12-25 21:59:30 -0600150 public function decode($string, $key = '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000151 {
152 $key = $this->get_key($key);
Barry Mienydd671972010-10-04 16:33:58 +0200153
Derek Allard2067d1a2008-11-13 22:59:24 +0000154 if (preg_match('/[^a-zA-Z0-9\/\+=]/', $string))
155 {
156 return FALSE;
157 }
158
159 $dec = base64_decode($string);
160
161 if ($this->_mcrypt_exists === TRUE)
162 {
163 if (($dec = $this->mcrypt_decode($dec, $key)) === FALSE)
164 {
165 return FALSE;
166 }
167 }
Derek Jones09c77932010-08-31 13:17:10 -0500168 else
169 {
170 $dec = $this->_xor_decode($dec, $key);
171 }
Barry Mienydd671972010-10-04 16:33:58 +0200172
Derek Jones09c77932010-08-31 13:17:10 -0500173 return $dec;
Derek Allard2067d1a2008-11-13 22:59:24 +0000174 }
175
176 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200177
Derek Jones09c77932010-08-31 13:17:10 -0500178 /**
179 * Encode from Legacy
180 *
181 * Takes an encoded string from the original Encryption class algorithms and
182 * returns a newly encoded string using the improved method added in 2.0.0
183 * This allows for backwards compatibility and a method to transition to the
184 * new encryption algorithms.
Barry Mienydd671972010-10-04 16:33:58 +0200185 *
Derek Jones09c77932010-08-31 13:17:10 -0500186 * For more details, see http://codeigniter.com/user_guide/installation/upgrade_200.html#encryption
187 *
Derek Jones09c77932010-08-31 13:17:10 -0500188 * @param string
189 * @param int (mcrypt mode constant)
190 * @param string
191 * @return string
192 */
Greg Akerd1af1852011-12-25 21:59:30 -0600193 public function encode_from_legacy($string, $legacy_mode = MCRYPT_MODE_ECB, $key = '')
Derek Jones09c77932010-08-31 13:17:10 -0500194 {
195 if ($this->_mcrypt_exists === FALSE)
196 {
197 log_message('error', 'Encoding from legacy is available only when Mcrypt is in use.');
198 return FALSE;
199 }
Barry Mienydd671972010-10-04 16:33:58 +0200200
Derek Jones09c77932010-08-31 13:17:10 -0500201 // decode it first
202 // set mode temporarily to what it was when string was encoded with the legacy
Barry Mienydd671972010-10-04 16:33:58 +0200203 // algorithm - typically MCRYPT_MODE_ECB
Derek Jones09c77932010-08-31 13:17:10 -0500204 $current_mode = $this->_get_mode();
205 $this->set_mode($legacy_mode);
Barry Mienydd671972010-10-04 16:33:58 +0200206
Derek Jones09c77932010-08-31 13:17:10 -0500207 $key = $this->get_key($key);
Barry Mienydd671972010-10-04 16:33:58 +0200208
Derek Jones09c77932010-08-31 13:17:10 -0500209 if (preg_match('/[^a-zA-Z0-9\/\+=]/', $string))
210 {
211 return FALSE;
212 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000213
Derek Jones09c77932010-08-31 13:17:10 -0500214 $dec = base64_decode($string);
Barry Mienydd671972010-10-04 16:33:58 +0200215
Derek Jones09c77932010-08-31 13:17:10 -0500216 if (($dec = $this->mcrypt_decode($dec, $key)) === FALSE)
217 {
218 return FALSE;
219 }
220
221 $dec = $this->_xor_decode($dec, $key);
222
223 // set the mcrypt mode back to what it should be, typically MCRYPT_MODE_CBC
Derek Jones092103e2010-09-02 11:11:58 -0500224 $this->set_mode($current_mode);
Derek Jones09c77932010-08-31 13:17:10 -0500225
226 // and re-encode
227 return base64_encode($this->mcrypt_encode($dec, $key));
228 }
229
230 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200231
Derek Allard2067d1a2008-11-13 22:59:24 +0000232 /**
233 * XOR Encode
234 *
235 * Takes a plain-text string and key as input and generates an
236 * encoded bit-string using XOR
237 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000238 * @param string
239 * @param string
240 * @return string
241 */
Greg Akerd1af1852011-12-25 21:59:30 -0600242 protected function _xor_encode($string, $key)
Derek Allard2067d1a2008-11-13 22:59:24 +0000243 {
244 $rand = '';
245 while (strlen($rand) < 32)
246 {
247 $rand .= mt_rand(0, mt_getrandmax());
248 }
249
250 $rand = $this->hash($rand);
251
252 $enc = '';
253 for ($i = 0; $i < strlen($string); $i++)
Barry Mienydd671972010-10-04 16:33:58 +0200254 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000255 $enc .= substr($rand, ($i % strlen($rand)), 1).(substr($rand, ($i % strlen($rand)), 1) ^ substr($string, $i, 1));
256 }
257
258 return $this->_xor_merge($enc, $key);
259 }
260
261 // --------------------------------------------------------------------
262
263 /**
264 * XOR Decode
265 *
266 * Takes an encoded string and key as input and generates the
267 * plain-text original message
268 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000269 * @param string
270 * @param string
271 * @return string
272 */
Greg Akerd1af1852011-12-25 21:59:30 -0600273 protected function _xor_decode($string, $key)
Derek Allard2067d1a2008-11-13 22:59:24 +0000274 {
275 $string = $this->_xor_merge($string, $key);
276
277 $dec = '';
278 for ($i = 0; $i < strlen($string); $i++)
279 {
280 $dec .= (substr($string, $i++, 1) ^ substr($string, $i, 1));
281 }
282
283 return $dec;
284 }
285
286 // --------------------------------------------------------------------
287
288 /**
289 * XOR key + string Combiner
290 *
291 * Takes a string and key as input and computes the difference using XOR
292 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000293 * @param string
294 * @param string
295 * @return string
296 */
Greg Akerd1af1852011-12-25 21:59:30 -0600297 protected function _xor_merge($string, $key)
Derek Allard2067d1a2008-11-13 22:59:24 +0000298 {
299 $hash = $this->hash($key);
300 $str = '';
301 for ($i = 0; $i < strlen($string); $i++)
302 {
303 $str .= substr($string, $i, 1) ^ substr($hash, ($i % strlen($hash)), 1);
304 }
305
306 return $str;
307 }
308
309 // --------------------------------------------------------------------
310
311 /**
312 * Encrypt using Mcrypt
313 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000314 * @param string
315 * @param string
316 * @return string
317 */
Greg Akerd1af1852011-12-25 21:59:30 -0600318 public function mcrypt_encode($data, $key)
Derek Allard2067d1a2008-11-13 22:59:24 +0000319 {
320 $init_size = mcrypt_get_iv_size($this->_get_cipher(), $this->_get_mode());
321 $init_vect = mcrypt_create_iv($init_size, MCRYPT_RAND);
322 return $this->_add_cipher_noise($init_vect.mcrypt_encrypt($this->_get_cipher(), $key, $data, $this->_get_mode(), $init_vect), $key);
323 }
324
325 // --------------------------------------------------------------------
326
327 /**
328 * Decrypt using Mcrypt
329 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000330 * @param string
331 * @param string
332 * @return string
333 */
Greg Akerd1af1852011-12-25 21:59:30 -0600334 public function mcrypt_decode($data, $key)
Derek Allard2067d1a2008-11-13 22:59:24 +0000335 {
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 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000356 * @param string
357 * @param string
358 * @return string
359 */
Greg Akerd1af1852011-12-25 21:59:30 -0600360 protected function _add_cipher_noise($data, $key)
Derek Allard2067d1a2008-11-13 22:59:24 +0000361 {
362 $keyhash = $this->hash($key);
363 $keylen = strlen($keyhash);
364 $str = '';
365
366 for ($i = 0, $j = 0, $len = strlen($data); $i < $len; ++$i, ++$j)
367 {
368 if ($j >= $keylen)
369 {
370 $j = 0;
371 }
372
373 $str .= chr((ord($data[$i]) + ord($keyhash[$j])) % 256);
374 }
375
376 return $str;
377 }
378
379 // --------------------------------------------------------------------
380
381 /**
382 * Removes permuted noise from the IV + encrypted data, reversing
383 * _add_cipher_noise()
384 *
385 * Function description
386 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000387 * @param type
388 * @return type
389 */
Greg Akerd1af1852011-12-25 21:59:30 -0600390 protected function _remove_cipher_noise($data, $key)
Derek Allard2067d1a2008-11-13 22:59:24 +0000391 {
392 $keyhash = $this->hash($key);
393 $keylen = strlen($keyhash);
394 $str = '';
395
396 for ($i = 0, $j = 0, $len = strlen($data); $i < $len; ++$i, ++$j)
397 {
398 if ($j >= $keylen)
399 {
400 $j = 0;
401 }
402
403 $temp = ord($data[$i]) - ord($keyhash[$j]);
404
405 if ($temp < 0)
406 {
407 $temp = $temp + 256;
408 }
Barry Mienydd671972010-10-04 16:33:58 +0200409
Derek Allard2067d1a2008-11-13 22:59:24 +0000410 $str .= chr($temp);
411 }
412
413 return $str;
414 }
415
416 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200417
Derek Allard2067d1a2008-11-13 22:59:24 +0000418 /**
419 * Set the Mcrypt Cipher
420 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000421 * @param constant
422 * @return string
423 */
Greg Akerd1af1852011-12-25 21:59:30 -0600424 public function set_cipher($cipher)
Derek Allard2067d1a2008-11-13 22:59:24 +0000425 {
426 $this->_mcrypt_cipher = $cipher;
Greg Akerd1af1852011-12-25 21:59:30 -0600427 return $this;
Derek Allard2067d1a2008-11-13 22:59:24 +0000428 }
429
430 // --------------------------------------------------------------------
431
432 /**
433 * Set the Mcrypt Mode
434 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000435 * @param constant
436 * @return string
437 */
438 function set_mode($mode)
439 {
440 $this->_mcrypt_mode = $mode;
Greg Akerd1af1852011-12-25 21:59:30 -0600441 return $this;
Derek Allard2067d1a2008-11-13 22:59:24 +0000442 }
443
444 // --------------------------------------------------------------------
445
446 /**
447 * Get Mcrypt cipher Value
448 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000449 * @return string
450 */
Greg Akerd1af1852011-12-25 21:59:30 -0600451 protected function _get_cipher()
Derek Allard2067d1a2008-11-13 22:59:24 +0000452 {
453 if ($this->_mcrypt_cipher == '')
454 {
455 $this->_mcrypt_cipher = MCRYPT_RIJNDAEL_256;
456 }
457
458 return $this->_mcrypt_cipher;
459 }
460
461 // --------------------------------------------------------------------
462
463 /**
464 * Get Mcrypt Mode Value
465 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000466 * @return string
467 */
Greg Akerd1af1852011-12-25 21:59:30 -0600468 protected function _get_mode()
Derek Allard2067d1a2008-11-13 22:59:24 +0000469 {
470 if ($this->_mcrypt_mode == '')
471 {
Derek Jones09c77932010-08-31 13:17:10 -0500472 $this->_mcrypt_mode = MCRYPT_MODE_CBC;
Derek Allard2067d1a2008-11-13 22:59:24 +0000473 }
Barry Mienydd671972010-10-04 16:33:58 +0200474
Derek Allard2067d1a2008-11-13 22:59:24 +0000475 return $this->_mcrypt_mode;
476 }
477
478 // --------------------------------------------------------------------
479
480 /**
481 * Set the Hash type
482 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000483 * @param string
484 * @return string
485 */
Greg Akerd1af1852011-12-25 21:59:30 -0600486 public function set_hash($type = 'sha1')
Derek Allard2067d1a2008-11-13 22:59:24 +0000487 {
488 $this->_hash_type = ($type != 'sha1' AND $type != 'md5') ? 'sha1' : $type;
489 }
490
491 // --------------------------------------------------------------------
492
493 /**
494 * Hash encode a string
495 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000496 * @param string
497 * @return string
Barry Mienydd671972010-10-04 16:33:58 +0200498 */
Greg Akerd1af1852011-12-25 21:59:30 -0600499 public function hash($str)
Derek Allard2067d1a2008-11-13 22:59:24 +0000500 {
Greg Akerd1af1852011-12-25 21:59:30 -0600501 return ($this->_hash_type == 'sha1') ? sha1($str) : md5($str);
Derek Allard2067d1a2008-11-13 22:59:24 +0000502 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000503}
504
505// END CI_Encrypt class
506
507/* End of file Encrypt.php */
Derek Jonesa3ffbbb2008-05-11 18:18:29 +0000508/* Location: ./system/libraries/Encrypt.php */