blob: 7c8720fd644b5830d968b0f4130800c8ec1002e4 [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
Andrey Andreevf4cb94e2012-01-19 15:16:55 +020012 * bundled with this package in the files license.txt / license.rst. It is
Derek Jonesf4a4bd82011-10-20 12:18:42 -050013 * 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
Derek Allard2067d1a2008-11-13 22:59:24 +000028/**
29 * CodeIgniter Encryption Class
30 *
31 * Provides two-way keyed encoding using XOR Hashing and Mcrypt
32 *
33 * @package CodeIgniter
34 * @subpackage Libraries
35 * @category Libraries
Derek Jonesf4a4bd82011-10-20 12:18:42 -050036 * @author EllisLab Dev Team
Derek Allard2067d1a2008-11-13 22:59:24 +000037 * @link http://codeigniter.com/user_guide/libraries/encryption.html
38 */
39class CI_Encrypt {
40
Greg Akerd1af1852011-12-25 21:59:30 -060041 public $encryption_key = '';
42 protected $_hash_type = 'sha1';
43 protected $_mcrypt_exists = FALSE;
44 protected $_mcrypt_cipher;
45 protected $_mcrypt_mode;
Derek Allard2067d1a2008-11-13 22:59:24 +000046
Greg Akera9263282010-11-10 15:26:43 -060047 public function __construct()
Derek Allard2067d1a2008-11-13 22:59:24 +000048 {
Derek Allard2067d1a2008-11-13 22:59:24 +000049 $this->_mcrypt_exists = ( ! function_exists('mcrypt_encrypt')) ? FALSE : TRUE;
Andrey Andreevcc6dbda2012-01-08 06:35:17 +020050 log_message('debug', 'Encrypt Class Initialized');
Derek Allard2067d1a2008-11-13 22:59:24 +000051 }
52
53 // --------------------------------------------------------------------
54
55 /**
56 * Fetch the encryption key
57 *
58 * Returns it as MD5 in order to have an exact-length 128 bit key.
59 * Mcrypt is sensitive to keys that are not the correct length
60 *
Derek Allard2067d1a2008-11-13 22:59:24 +000061 * @param string
62 * @return string
63 */
Greg Akerd1af1852011-12-25 21:59:30 -060064 public function get_key($key = '')
Derek Allard2067d1a2008-11-13 22:59:24 +000065 {
66 if ($key == '')
67 {
68 if ($this->encryption_key != '')
69 {
70 return $this->encryption_key;
71 }
72
73 $CI =& get_instance();
74 $key = $CI->config->item('encryption_key');
75
Greg Akerd1af1852011-12-25 21:59:30 -060076 if ($key === FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +000077 {
78 show_error('In order to use the encryption class requires that you set an encryption key in your config file.');
79 }
80 }
81
82 return md5($key);
83 }
84
85 // --------------------------------------------------------------------
86
87 /**
88 * Set the encryption key
89 *
Derek Allard2067d1a2008-11-13 22:59:24 +000090 * @param string
Andrey Andreevcc6dbda2012-01-08 06:35:17 +020091 * @return object
Derek Allard2067d1a2008-11-13 22:59:24 +000092 */
Greg Akerd1af1852011-12-25 21:59:30 -060093 public function set_key($key = '')
Derek Allard2067d1a2008-11-13 22:59:24 +000094 {
95 $this->encryption_key = $key;
Greg Akerd1af1852011-12-25 21:59:30 -060096 return $this;
Derek Allard2067d1a2008-11-13 22:59:24 +000097 }
98
99 // --------------------------------------------------------------------
100
101 /**
102 * Encode
103 *
104 * Encodes the message string using bitwise XOR encoding.
105 * The key is combined with a random hash, and then it
106 * too gets converted using XOR. The whole thing is then run
107 * through mcrypt (if supported) using the randomized key.
108 * The end result is a double-encrypted message string
109 * that is randomized with each call to this function,
110 * even if the supplied message and key are the same.
111 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000112 * @param string the string to encode
113 * @param string the key
114 * @return string
115 */
Greg Akerd1af1852011-12-25 21:59:30 -0600116 public function encode($string, $key = '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000117 {
Andrey Andreev7c251b32011-12-27 16:37:23 +0200118 $method = ($this->_mcrypt_exists === TRUE) ? 'mcrypt_encode' : '_xor_encode';
119 return base64_encode($this->$method($string, $this->get_key($key)));
Derek Allard2067d1a2008-11-13 22:59:24 +0000120 }
121
122 // --------------------------------------------------------------------
123
124 /**
125 * Decode
126 *
127 * Reverses the above process
128 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000129 * @param string
130 * @param string
131 * @return string
132 */
Greg Akerd1af1852011-12-25 21:59:30 -0600133 public function decode($string, $key = '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000134 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000135 if (preg_match('/[^a-zA-Z0-9\/\+=]/', $string))
136 {
137 return FALSE;
138 }
139
Andrey Andreev7c251b32011-12-27 16:37:23 +0200140 $method = ($this->_mcrypt_exists === TRUE) ? 'mcrypt_decode' : '_xor_decode';
141 return $this->$method(base64_decode($string), $this->get_key($key));
Derek Allard2067d1a2008-11-13 22:59:24 +0000142 }
143
144 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200145
Derek Jones09c77932010-08-31 13:17:10 -0500146 /**
147 * Encode from Legacy
148 *
149 * Takes an encoded string from the original Encryption class algorithms and
150 * returns a newly encoded string using the improved method added in 2.0.0
151 * This allows for backwards compatibility and a method to transition to the
152 * new encryption algorithms.
Barry Mienydd671972010-10-04 16:33:58 +0200153 *
Derek Jones09c77932010-08-31 13:17:10 -0500154 * For more details, see http://codeigniter.com/user_guide/installation/upgrade_200.html#encryption
155 *
Derek Jones09c77932010-08-31 13:17:10 -0500156 * @param string
157 * @param int (mcrypt mode constant)
158 * @param string
159 * @return string
160 */
Greg Akerd1af1852011-12-25 21:59:30 -0600161 public function encode_from_legacy($string, $legacy_mode = MCRYPT_MODE_ECB, $key = '')
Derek Jones09c77932010-08-31 13:17:10 -0500162 {
163 if ($this->_mcrypt_exists === FALSE)
164 {
165 log_message('error', 'Encoding from legacy is available only when Mcrypt is in use.');
166 return FALSE;
167 }
Andrey Andreev7c251b32011-12-27 16:37:23 +0200168 elseif (preg_match('/[^a-zA-Z0-9\/\+=]/', $string))
169 {
170 return FALSE;
171 }
Barry Mienydd671972010-10-04 16:33:58 +0200172
Derek Jones09c77932010-08-31 13:17:10 -0500173 // decode it first
174 // set mode temporarily to what it was when string was encoded with the legacy
Barry Mienydd671972010-10-04 16:33:58 +0200175 // algorithm - typically MCRYPT_MODE_ECB
Derek Jones09c77932010-08-31 13:17:10 -0500176 $current_mode = $this->_get_mode();
177 $this->set_mode($legacy_mode);
Barry Mienydd671972010-10-04 16:33:58 +0200178
Derek Jones09c77932010-08-31 13:17:10 -0500179 $key = $this->get_key($key);
Derek Jones09c77932010-08-31 13:17:10 -0500180 $dec = base64_decode($string);
Derek Jones09c77932010-08-31 13:17:10 -0500181 if (($dec = $this->mcrypt_decode($dec, $key)) === FALSE)
182 {
183 return FALSE;
184 }
185
186 $dec = $this->_xor_decode($dec, $key);
187
188 // set the mcrypt mode back to what it should be, typically MCRYPT_MODE_CBC
Derek Jones092103e2010-09-02 11:11:58 -0500189 $this->set_mode($current_mode);
Derek Jones09c77932010-08-31 13:17:10 -0500190
191 // and re-encode
192 return base64_encode($this->mcrypt_encode($dec, $key));
193 }
194
195 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200196
Derek Allard2067d1a2008-11-13 22:59:24 +0000197 /**
198 * XOR Encode
199 *
200 * Takes a plain-text string and key as input and generates an
201 * encoded bit-string using XOR
202 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000203 * @param string
204 * @param string
205 * @return string
206 */
Greg Akerd1af1852011-12-25 21:59:30 -0600207 protected function _xor_encode($string, $key)
Derek Allard2067d1a2008-11-13 22:59:24 +0000208 {
209 $rand = '';
Andrey Andreev7c251b32011-12-27 16:37:23 +0200210 do
Derek Allard2067d1a2008-11-13 22:59:24 +0000211 {
212 $rand .= mt_rand(0, mt_getrandmax());
213 }
Andrey Andreev7c251b32011-12-27 16:37:23 +0200214 while (strlen($rand) < 32);
Derek Allard2067d1a2008-11-13 22:59:24 +0000215
216 $rand = $this->hash($rand);
217
218 $enc = '';
Andrey Andreev7c251b32011-12-27 16:37:23 +0200219 for ($i = 0, $ls = strlen($string), $lr = strlen($rand); $i < $ls; $i++)
Barry Mienydd671972010-10-04 16:33:58 +0200220 {
Andrey Andreev7c251b32011-12-27 16:37:23 +0200221 $enc .= $rand[($i % $lr)].($rand[($i % $lr)] ^ $string[$i]);
Derek Allard2067d1a2008-11-13 22:59:24 +0000222 }
223
224 return $this->_xor_merge($enc, $key);
225 }
226
227 // --------------------------------------------------------------------
228
229 /**
230 * XOR Decode
231 *
232 * Takes an encoded string and key as input and generates the
233 * plain-text original message
234 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000235 * @param string
236 * @param string
237 * @return string
238 */
Greg Akerd1af1852011-12-25 21:59:30 -0600239 protected function _xor_decode($string, $key)
Derek Allard2067d1a2008-11-13 22:59:24 +0000240 {
241 $string = $this->_xor_merge($string, $key);
242
243 $dec = '';
Andrey Andreev7c251b32011-12-27 16:37:23 +0200244 for ($i = 0, $l = strlen($string); $i < $l; $i++)
Derek Allard2067d1a2008-11-13 22:59:24 +0000245 {
Andrey Andreev7c251b32011-12-27 16:37:23 +0200246 $dec .= ($string[$i++] ^ $string[$i]);
Derek Allard2067d1a2008-11-13 22:59:24 +0000247 }
248
249 return $dec;
250 }
251
252 // --------------------------------------------------------------------
253
254 /**
255 * XOR key + string Combiner
256 *
257 * Takes a string and key as input and computes the difference using XOR
258 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000259 * @param string
260 * @param string
261 * @return string
262 */
Greg Akerd1af1852011-12-25 21:59:30 -0600263 protected function _xor_merge($string, $key)
Derek Allard2067d1a2008-11-13 22:59:24 +0000264 {
265 $hash = $this->hash($key);
266 $str = '';
Andrey Andreev7c251b32011-12-27 16:37:23 +0200267 for ($i = 0, $ls = strlen($string), $lh = strlen($hash); $i < $ls; $i++)
Derek Allard2067d1a2008-11-13 22:59:24 +0000268 {
Andrey Andreev7c251b32011-12-27 16:37:23 +0200269 $str .= $string[$i] ^ $hash[($i % $lh)];
Derek Allard2067d1a2008-11-13 22:59:24 +0000270 }
271
272 return $str;
273 }
274
275 // --------------------------------------------------------------------
276
277 /**
278 * Encrypt using Mcrypt
279 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000280 * @param string
281 * @param string
282 * @return string
283 */
Greg Akerd1af1852011-12-25 21:59:30 -0600284 public function mcrypt_encode($data, $key)
Derek Allard2067d1a2008-11-13 22:59:24 +0000285 {
286 $init_size = mcrypt_get_iv_size($this->_get_cipher(), $this->_get_mode());
287 $init_vect = mcrypt_create_iv($init_size, MCRYPT_RAND);
288 return $this->_add_cipher_noise($init_vect.mcrypt_encrypt($this->_get_cipher(), $key, $data, $this->_get_mode(), $init_vect), $key);
289 }
290
291 // --------------------------------------------------------------------
292
293 /**
294 * Decrypt using Mcrypt
295 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000296 * @param string
297 * @param string
298 * @return string
299 */
Greg Akerd1af1852011-12-25 21:59:30 -0600300 public function mcrypt_decode($data, $key)
Derek Allard2067d1a2008-11-13 22:59:24 +0000301 {
302 $data = $this->_remove_cipher_noise($data, $key);
303 $init_size = mcrypt_get_iv_size($this->_get_cipher(), $this->_get_mode());
304
305 if ($init_size > strlen($data))
306 {
307 return FALSE;
308 }
309
310 $init_vect = substr($data, 0, $init_size);
311 $data = substr($data, $init_size);
312 return rtrim(mcrypt_decrypt($this->_get_cipher(), $key, $data, $this->_get_mode(), $init_vect), "\0");
313 }
314
315 // --------------------------------------------------------------------
316
317 /**
318 * Adds permuted noise to the IV + encrypted data to protect
319 * against Man-in-the-middle attacks on CBC mode ciphers
320 * http://www.ciphersbyritter.com/GLOSSARY.HTM#IV
321 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000322 * @param string
323 * @param string
324 * @return string
325 */
Greg Akerd1af1852011-12-25 21:59:30 -0600326 protected function _add_cipher_noise($data, $key)
Derek Allard2067d1a2008-11-13 22:59:24 +0000327 {
Andrey Andreev7c251b32011-12-27 16:37:23 +0200328 $key = $this->hash($key);
Derek Allard2067d1a2008-11-13 22:59:24 +0000329 $str = '';
330
Andrey Andreev7c251b32011-12-27 16:37:23 +0200331 for ($i = 0, $j = 0, $ld = strlen($data), $lk = strlen($key); $i < $ld; ++$i, ++$j)
Derek Allard2067d1a2008-11-13 22:59:24 +0000332 {
Andrey Andreev7c251b32011-12-27 16:37:23 +0200333 if ($j >= $lk)
Derek Allard2067d1a2008-11-13 22:59:24 +0000334 {
335 $j = 0;
336 }
337
Andrey Andreev7c251b32011-12-27 16:37:23 +0200338 $str .= chr((ord($data[$i]) + ord($key[$j])) % 256);
Derek Allard2067d1a2008-11-13 22:59:24 +0000339 }
340
341 return $str;
342 }
343
344 // --------------------------------------------------------------------
345
346 /**
347 * Removes permuted noise from the IV + encrypted data, reversing
348 * _add_cipher_noise()
349 *
350 * Function description
351 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000352 * @param type
353 * @return type
354 */
Greg Akerd1af1852011-12-25 21:59:30 -0600355 protected function _remove_cipher_noise($data, $key)
Derek Allard2067d1a2008-11-13 22:59:24 +0000356 {
Andrey Andreev7c251b32011-12-27 16:37:23 +0200357 $key = $this->hash($key);
Derek Allard2067d1a2008-11-13 22:59:24 +0000358 $str = '';
359
Andrey Andreev7c251b32011-12-27 16:37:23 +0200360 for ($i = 0, $j = 0, $ld = strlen($data), $lk = strlen($key); $i < $ld; ++$i, ++$j)
Derek Allard2067d1a2008-11-13 22:59:24 +0000361 {
Andrey Andreev7c251b32011-12-27 16:37:23 +0200362 if ($j >= $lk)
Derek Allard2067d1a2008-11-13 22:59:24 +0000363 {
364 $j = 0;
365 }
366
Andrey Andreev7c251b32011-12-27 16:37:23 +0200367 $temp = ord($data[$i]) - ord($key[$j]);
Derek Allard2067d1a2008-11-13 22:59:24 +0000368
369 if ($temp < 0)
370 {
Andrey Andreev7c251b32011-12-27 16:37:23 +0200371 $temp += 256;
Derek Allard2067d1a2008-11-13 22:59:24 +0000372 }
Barry Mienydd671972010-10-04 16:33:58 +0200373
Derek Allard2067d1a2008-11-13 22:59:24 +0000374 $str .= chr($temp);
375 }
376
377 return $str;
378 }
379
380 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200381
Derek Allard2067d1a2008-11-13 22:59:24 +0000382 /**
383 * Set the Mcrypt Cipher
384 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000385 * @param constant
386 * @return string
387 */
Greg Akerd1af1852011-12-25 21:59:30 -0600388 public function set_cipher($cipher)
Derek Allard2067d1a2008-11-13 22:59:24 +0000389 {
390 $this->_mcrypt_cipher = $cipher;
Greg Akerd1af1852011-12-25 21:59:30 -0600391 return $this;
Derek Allard2067d1a2008-11-13 22:59:24 +0000392 }
393
394 // --------------------------------------------------------------------
395
396 /**
397 * Set the Mcrypt Mode
398 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000399 * @param constant
400 * @return string
401 */
Andrey Andreev7c251b32011-12-27 16:37:23 +0200402 public function set_mode($mode)
Derek Allard2067d1a2008-11-13 22:59:24 +0000403 {
404 $this->_mcrypt_mode = $mode;
Greg Akerd1af1852011-12-25 21:59:30 -0600405 return $this;
Derek Allard2067d1a2008-11-13 22:59:24 +0000406 }
407
408 // --------------------------------------------------------------------
409
410 /**
411 * Get Mcrypt cipher Value
412 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000413 * @return string
414 */
Greg Akerd1af1852011-12-25 21:59:30 -0600415 protected function _get_cipher()
Derek Allard2067d1a2008-11-13 22:59:24 +0000416 {
417 if ($this->_mcrypt_cipher == '')
418 {
Andrey Andreevd655a992012-01-10 22:31:29 +0200419 return $this->_mcrypt_cipher = MCRYPT_RIJNDAEL_256;
Derek Allard2067d1a2008-11-13 22:59:24 +0000420 }
421
422 return $this->_mcrypt_cipher;
423 }
424
425 // --------------------------------------------------------------------
426
427 /**
428 * Get Mcrypt Mode Value
429 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000430 * @return string
431 */
Greg Akerd1af1852011-12-25 21:59:30 -0600432 protected function _get_mode()
Derek Allard2067d1a2008-11-13 22:59:24 +0000433 {
434 if ($this->_mcrypt_mode == '')
435 {
Andrey Andreevd655a992012-01-10 22:31:29 +0200436 return $this->_mcrypt_mode = MCRYPT_MODE_CBC;
Derek Allard2067d1a2008-11-13 22:59:24 +0000437 }
Barry Mienydd671972010-10-04 16:33:58 +0200438
Derek Allard2067d1a2008-11-13 22:59:24 +0000439 return $this->_mcrypt_mode;
440 }
441
442 // --------------------------------------------------------------------
443
444 /**
445 * Set the Hash type
446 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000447 * @param string
Andrey Andreevf4cb94e2012-01-19 15:16:55 +0200448 * @return void
Derek Allard2067d1a2008-11-13 22:59:24 +0000449 */
Greg Akerd1af1852011-12-25 21:59:30 -0600450 public function set_hash($type = 'sha1')
Derek Allard2067d1a2008-11-13 22:59:24 +0000451 {
Andrey Andreevcc6dbda2012-01-08 06:35:17 +0200452 $this->_hash_type = ($type !== 'sha1' && $type !== 'md5') ? 'sha1' : $type;
Derek Allard2067d1a2008-11-13 22:59:24 +0000453 }
454
455 // --------------------------------------------------------------------
456
457 /**
458 * Hash encode a string
459 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000460 * @param string
461 * @return string
Barry Mienydd671972010-10-04 16:33:58 +0200462 */
Greg Akerd1af1852011-12-25 21:59:30 -0600463 public function hash($str)
Derek Allard2067d1a2008-11-13 22:59:24 +0000464 {
Andrey Andreev7c251b32011-12-27 16:37:23 +0200465 return ($this->_hash_type === 'sha1') ? sha1($str) : md5($str);
Derek Allard2067d1a2008-11-13 22:59:24 +0000466 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000467}
468
Derek Allard2067d1a2008-11-13 22:59:24 +0000469/* End of file Encrypt.php */
Andrey Andreev7c251b32011-12-27 16:37:23 +0200470/* Location: ./system/libraries/Encrypt.php */