blob: d9f40b0d5eafb1564791facba7e63b4e2cf3a506 [file] [log] [blame]
Andrey Andreev7c251b32011-12-27 16:37:23 +02001<?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
Andrey Andreev7c251b32011-12-27 16:37:23 +02008 *
Derek Jonesf4a4bd82011-10-20 12:18:42 -05009 * Licensed under the Open Software License version 3.0
Andrey Andreev7c251b32011-12-27 16:37:23 +020010 *
Derek Jonesf4a4bd82011-10-20 12:18:42 -050011 * 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 {
Andrey Andreev7c251b32011-12-27 16:37:23 +0200125 $method = ($this->_mcrypt_exists === TRUE) ? 'mcrypt_encode' : '_xor_encode';
126 return base64_encode($this->$method($string, $this->get_key($key)));
Derek Allard2067d1a2008-11-13 22:59:24 +0000127 }
128
129 // --------------------------------------------------------------------
130
131 /**
132 * Decode
133 *
134 * Reverses the above process
135 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000136 * @param string
137 * @param string
138 * @return string
139 */
Greg Akerd1af1852011-12-25 21:59:30 -0600140 public function decode($string, $key = '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000141 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000142 if (preg_match('/[^a-zA-Z0-9\/\+=]/', $string))
143 {
144 return FALSE;
145 }
146
Andrey Andreev7c251b32011-12-27 16:37:23 +0200147 $method = ($this->_mcrypt_exists === TRUE) ? 'mcrypt_decode' : '_xor_decode';
148 return $this->$method(base64_decode($string), $this->get_key($key));
Derek Allard2067d1a2008-11-13 22:59:24 +0000149 }
150
151 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200152
Derek Jones09c77932010-08-31 13:17:10 -0500153 /**
154 * Encode from Legacy
155 *
156 * Takes an encoded string from the original Encryption class algorithms and
157 * returns a newly encoded string using the improved method added in 2.0.0
158 * This allows for backwards compatibility and a method to transition to the
159 * new encryption algorithms.
Barry Mienydd671972010-10-04 16:33:58 +0200160 *
Derek Jones09c77932010-08-31 13:17:10 -0500161 * For more details, see http://codeigniter.com/user_guide/installation/upgrade_200.html#encryption
162 *
Derek Jones09c77932010-08-31 13:17:10 -0500163 * @param string
164 * @param int (mcrypt mode constant)
165 * @param string
166 * @return string
167 */
Greg Akerd1af1852011-12-25 21:59:30 -0600168 public function encode_from_legacy($string, $legacy_mode = MCRYPT_MODE_ECB, $key = '')
Derek Jones09c77932010-08-31 13:17:10 -0500169 {
170 if ($this->_mcrypt_exists === FALSE)
171 {
172 log_message('error', 'Encoding from legacy is available only when Mcrypt is in use.');
173 return FALSE;
174 }
Andrey Andreev7c251b32011-12-27 16:37:23 +0200175 elseif (preg_match('/[^a-zA-Z0-9\/\+=]/', $string))
176 {
177 return FALSE;
178 }
Barry Mienydd671972010-10-04 16:33:58 +0200179
Derek Jones09c77932010-08-31 13:17:10 -0500180 // decode it first
181 // set mode temporarily to what it was when string was encoded with the legacy
Barry Mienydd671972010-10-04 16:33:58 +0200182 // algorithm - typically MCRYPT_MODE_ECB
Derek Jones09c77932010-08-31 13:17:10 -0500183 $current_mode = $this->_get_mode();
184 $this->set_mode($legacy_mode);
Barry Mienydd671972010-10-04 16:33:58 +0200185
Derek Jones09c77932010-08-31 13:17:10 -0500186 $key = $this->get_key($key);
Derek Jones09c77932010-08-31 13:17:10 -0500187 $dec = base64_decode($string);
Barry Mienydd671972010-10-04 16:33:58 +0200188
Derek Jones09c77932010-08-31 13:17:10 -0500189 if (($dec = $this->mcrypt_decode($dec, $key)) === FALSE)
190 {
191 return FALSE;
192 }
193
194 $dec = $this->_xor_decode($dec, $key);
195
196 // set the mcrypt mode back to what it should be, typically MCRYPT_MODE_CBC
Derek Jones092103e2010-09-02 11:11:58 -0500197 $this->set_mode($current_mode);
Derek Jones09c77932010-08-31 13:17:10 -0500198
199 // and re-encode
200 return base64_encode($this->mcrypt_encode($dec, $key));
201 }
202
203 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200204
Derek Allard2067d1a2008-11-13 22:59:24 +0000205 /**
206 * XOR Encode
207 *
208 * Takes a plain-text string and key as input and generates an
209 * encoded bit-string using XOR
210 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000211 * @param string
212 * @param string
213 * @return string
214 */
Greg Akerd1af1852011-12-25 21:59:30 -0600215 protected function _xor_encode($string, $key)
Derek Allard2067d1a2008-11-13 22:59:24 +0000216 {
217 $rand = '';
Andrey Andreev7c251b32011-12-27 16:37:23 +0200218 do
Derek Allard2067d1a2008-11-13 22:59:24 +0000219 {
220 $rand .= mt_rand(0, mt_getrandmax());
221 }
Andrey Andreev7c251b32011-12-27 16:37:23 +0200222 while (strlen($rand) < 32);
Derek Allard2067d1a2008-11-13 22:59:24 +0000223
224 $rand = $this->hash($rand);
225
226 $enc = '';
Andrey Andreev7c251b32011-12-27 16:37:23 +0200227 for ($i = 0, $ls = strlen($string), $lr = strlen($rand); $i < $ls; $i++)
Barry Mienydd671972010-10-04 16:33:58 +0200228 {
Andrey Andreev7c251b32011-12-27 16:37:23 +0200229 $enc .= $rand[($i % $lr)].($rand[($i % $lr)] ^ $string[$i]);
Derek Allard2067d1a2008-11-13 22:59:24 +0000230 }
231
232 return $this->_xor_merge($enc, $key);
233 }
234
235 // --------------------------------------------------------------------
236
237 /**
238 * XOR Decode
239 *
240 * Takes an encoded string and key as input and generates the
241 * plain-text original message
242 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000243 * @param string
244 * @param string
245 * @return string
246 */
Greg Akerd1af1852011-12-25 21:59:30 -0600247 protected function _xor_decode($string, $key)
Derek Allard2067d1a2008-11-13 22:59:24 +0000248 {
249 $string = $this->_xor_merge($string, $key);
250
251 $dec = '';
Andrey Andreev7c251b32011-12-27 16:37:23 +0200252 for ($i = 0, $l = strlen($string); $i < $l; $i++)
Derek Allard2067d1a2008-11-13 22:59:24 +0000253 {
Andrey Andreev7c251b32011-12-27 16:37:23 +0200254 $dec .= ($string[$i++] ^ $string[$i]);
Derek Allard2067d1a2008-11-13 22:59:24 +0000255 }
256
257 return $dec;
258 }
259
260 // --------------------------------------------------------------------
261
262 /**
263 * XOR key + string Combiner
264 *
265 * Takes a string and key as input and computes the difference using XOR
266 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000267 * @param string
268 * @param string
269 * @return string
270 */
Greg Akerd1af1852011-12-25 21:59:30 -0600271 protected function _xor_merge($string, $key)
Derek Allard2067d1a2008-11-13 22:59:24 +0000272 {
273 $hash = $this->hash($key);
274 $str = '';
Andrey Andreev7c251b32011-12-27 16:37:23 +0200275 for ($i = 0, $ls = strlen($string), $lh = strlen($hash); $i < $ls; $i++)
Derek Allard2067d1a2008-11-13 22:59:24 +0000276 {
Andrey Andreev7c251b32011-12-27 16:37:23 +0200277 $str .= $string[$i] ^ $hash[($i % $lh)];
Derek Allard2067d1a2008-11-13 22:59:24 +0000278 }
279
280 return $str;
281 }
282
283 // --------------------------------------------------------------------
284
285 /**
286 * Encrypt using Mcrypt
287 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000288 * @param string
289 * @param string
290 * @return string
291 */
Greg Akerd1af1852011-12-25 21:59:30 -0600292 public function mcrypt_encode($data, $key)
Derek Allard2067d1a2008-11-13 22:59:24 +0000293 {
294 $init_size = mcrypt_get_iv_size($this->_get_cipher(), $this->_get_mode());
295 $init_vect = mcrypt_create_iv($init_size, MCRYPT_RAND);
296 return $this->_add_cipher_noise($init_vect.mcrypt_encrypt($this->_get_cipher(), $key, $data, $this->_get_mode(), $init_vect), $key);
297 }
298
299 // --------------------------------------------------------------------
300
301 /**
302 * Decrypt using Mcrypt
303 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000304 * @param string
305 * @param string
306 * @return string
307 */
Greg Akerd1af1852011-12-25 21:59:30 -0600308 public function mcrypt_decode($data, $key)
Derek Allard2067d1a2008-11-13 22:59:24 +0000309 {
310 $data = $this->_remove_cipher_noise($data, $key);
311 $init_size = mcrypt_get_iv_size($this->_get_cipher(), $this->_get_mode());
312
313 if ($init_size > strlen($data))
314 {
315 return FALSE;
316 }
317
318 $init_vect = substr($data, 0, $init_size);
319 $data = substr($data, $init_size);
320 return rtrim(mcrypt_decrypt($this->_get_cipher(), $key, $data, $this->_get_mode(), $init_vect), "\0");
321 }
322
323 // --------------------------------------------------------------------
324
325 /**
326 * Adds permuted noise to the IV + encrypted data to protect
327 * against Man-in-the-middle attacks on CBC mode ciphers
328 * http://www.ciphersbyritter.com/GLOSSARY.HTM#IV
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 protected function _add_cipher_noise($data, $key)
Derek Allard2067d1a2008-11-13 22:59:24 +0000335 {
Andrey Andreev7c251b32011-12-27 16:37:23 +0200336 $key = $this->hash($key);
Derek Allard2067d1a2008-11-13 22:59:24 +0000337 $str = '';
338
Andrey Andreev7c251b32011-12-27 16:37:23 +0200339 for ($i = 0, $j = 0, $ld = strlen($data), $lk = strlen($key); $i < $ld; ++$i, ++$j)
Derek Allard2067d1a2008-11-13 22:59:24 +0000340 {
Andrey Andreev7c251b32011-12-27 16:37:23 +0200341 if ($j >= $lk)
Derek Allard2067d1a2008-11-13 22:59:24 +0000342 {
343 $j = 0;
344 }
345
Andrey Andreev7c251b32011-12-27 16:37:23 +0200346 $str .= chr((ord($data[$i]) + ord($key[$j])) % 256);
Derek Allard2067d1a2008-11-13 22:59:24 +0000347 }
348
349 return $str;
350 }
351
352 // --------------------------------------------------------------------
353
354 /**
355 * Removes permuted noise from the IV + encrypted data, reversing
356 * _add_cipher_noise()
357 *
358 * Function description
359 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000360 * @param type
361 * @return type
362 */
Greg Akerd1af1852011-12-25 21:59:30 -0600363 protected function _remove_cipher_noise($data, $key)
Derek Allard2067d1a2008-11-13 22:59:24 +0000364 {
Andrey Andreev7c251b32011-12-27 16:37:23 +0200365 $key = $this->hash($key);
Derek Allard2067d1a2008-11-13 22:59:24 +0000366 $str = '';
367
Andrey Andreev7c251b32011-12-27 16:37:23 +0200368 for ($i = 0, $j = 0, $ld = strlen($data), $lk = strlen($key); $i < $ld; ++$i, ++$j)
Derek Allard2067d1a2008-11-13 22:59:24 +0000369 {
Andrey Andreev7c251b32011-12-27 16:37:23 +0200370 if ($j >= $lk)
Derek Allard2067d1a2008-11-13 22:59:24 +0000371 {
372 $j = 0;
373 }
374
Andrey Andreev7c251b32011-12-27 16:37:23 +0200375 $temp = ord($data[$i]) - ord($key[$j]);
Derek Allard2067d1a2008-11-13 22:59:24 +0000376
377 if ($temp < 0)
378 {
Andrey Andreev7c251b32011-12-27 16:37:23 +0200379 $temp += 256;
Derek Allard2067d1a2008-11-13 22:59:24 +0000380 }
Barry Mienydd671972010-10-04 16:33:58 +0200381
Derek Allard2067d1a2008-11-13 22:59:24 +0000382 $str .= chr($temp);
383 }
384
385 return $str;
386 }
387
388 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200389
Derek Allard2067d1a2008-11-13 22:59:24 +0000390 /**
391 * Set the Mcrypt Cipher
392 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000393 * @param constant
394 * @return string
395 */
Greg Akerd1af1852011-12-25 21:59:30 -0600396 public function set_cipher($cipher)
Derek Allard2067d1a2008-11-13 22:59:24 +0000397 {
398 $this->_mcrypt_cipher = $cipher;
Greg Akerd1af1852011-12-25 21:59:30 -0600399 return $this;
Derek Allard2067d1a2008-11-13 22:59:24 +0000400 }
401
402 // --------------------------------------------------------------------
403
404 /**
405 * Set the Mcrypt Mode
406 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000407 * @param constant
408 * @return string
409 */
Andrey Andreev7c251b32011-12-27 16:37:23 +0200410 public function set_mode($mode)
Derek Allard2067d1a2008-11-13 22:59:24 +0000411 {
412 $this->_mcrypt_mode = $mode;
Greg Akerd1af1852011-12-25 21:59:30 -0600413 return $this;
Derek Allard2067d1a2008-11-13 22:59:24 +0000414 }
415
416 // --------------------------------------------------------------------
417
418 /**
419 * Get Mcrypt cipher Value
420 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000421 * @return string
422 */
Greg Akerd1af1852011-12-25 21:59:30 -0600423 protected function _get_cipher()
Derek Allard2067d1a2008-11-13 22:59:24 +0000424 {
425 if ($this->_mcrypt_cipher == '')
426 {
427 $this->_mcrypt_cipher = MCRYPT_RIJNDAEL_256;
428 }
429
430 return $this->_mcrypt_cipher;
431 }
432
433 // --------------------------------------------------------------------
434
435 /**
436 * Get Mcrypt Mode Value
437 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000438 * @return string
439 */
Greg Akerd1af1852011-12-25 21:59:30 -0600440 protected function _get_mode()
Derek Allard2067d1a2008-11-13 22:59:24 +0000441 {
442 if ($this->_mcrypt_mode == '')
443 {
Derek Jones09c77932010-08-31 13:17:10 -0500444 $this->_mcrypt_mode = MCRYPT_MODE_CBC;
Derek Allard2067d1a2008-11-13 22:59:24 +0000445 }
Barry Mienydd671972010-10-04 16:33:58 +0200446
Derek Allard2067d1a2008-11-13 22:59:24 +0000447 return $this->_mcrypt_mode;
448 }
449
450 // --------------------------------------------------------------------
451
452 /**
453 * Set the Hash type
454 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000455 * @param string
456 * @return string
457 */
Greg Akerd1af1852011-12-25 21:59:30 -0600458 public function set_hash($type = 'sha1')
Derek Allard2067d1a2008-11-13 22:59:24 +0000459 {
Andrey Andreev7c251b32011-12-27 16:37:23 +0200460 $this->_hash_type = ($type !== 'sha1' AND $type !== 'md5') ? 'sha1' : $type;
Derek Allard2067d1a2008-11-13 22:59:24 +0000461 }
462
463 // --------------------------------------------------------------------
464
465 /**
466 * Hash encode a string
467 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000468 * @param string
469 * @return string
Barry Mienydd671972010-10-04 16:33:58 +0200470 */
Greg Akerd1af1852011-12-25 21:59:30 -0600471 public function hash($str)
Derek Allard2067d1a2008-11-13 22:59:24 +0000472 {
Andrey Andreev7c251b32011-12-27 16:37:23 +0200473 return ($this->_hash_type === 'sha1') ? sha1($str) : md5($str);
Derek Allard2067d1a2008-11-13 22:59:24 +0000474 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000475}
476
477// END CI_Encrypt class
478
479/* End of file Encrypt.php */
Andrey Andreev7c251b32011-12-27 16:37:23 +0200480/* Location: ./system/libraries/Encrypt.php */