blob: 8cb4b1b190641c371a3f9d5b03346695ca1ca711 [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
Greg Akera9263282010-11-10 15:26:43 -060049 public function __construct()
Derek Allard2067d1a2008-11-13 22:59:24 +000050 {
Derek Allard2067d1a2008-11-13 22:59:24 +000051 $this->_mcrypt_exists = ( ! function_exists('mcrypt_encrypt')) ? FALSE : TRUE;
Andrey Andreevcc6dbda2012-01-08 06:35:17 +020052 log_message('debug', 'Encrypt Class Initialized');
Derek Allard2067d1a2008-11-13 22:59:24 +000053 }
54
55 // --------------------------------------------------------------------
56
57 /**
58 * Fetch the encryption key
59 *
60 * Returns it as MD5 in order to have an exact-length 128 bit key.
61 * Mcrypt is sensitive to keys that are not the correct length
62 *
Derek Allard2067d1a2008-11-13 22:59:24 +000063 * @param string
64 * @return string
65 */
Greg Akerd1af1852011-12-25 21:59:30 -060066 public function get_key($key = '')
Derek Allard2067d1a2008-11-13 22:59:24 +000067 {
68 if ($key == '')
69 {
70 if ($this->encryption_key != '')
71 {
72 return $this->encryption_key;
73 }
74
75 $CI =& get_instance();
76 $key = $CI->config->item('encryption_key');
77
Greg Akerd1af1852011-12-25 21:59:30 -060078 if ($key === FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +000079 {
80 show_error('In order to use the encryption class requires that you set an encryption key in your config file.');
81 }
82 }
83
84 return md5($key);
85 }
86
87 // --------------------------------------------------------------------
88
89 /**
90 * Set the encryption key
91 *
Derek Allard2067d1a2008-11-13 22:59:24 +000092 * @param string
Andrey Andreevcc6dbda2012-01-08 06:35:17 +020093 * @return object
Derek Allard2067d1a2008-11-13 22:59:24 +000094 */
Greg Akerd1af1852011-12-25 21:59:30 -060095 public function set_key($key = '')
Derek Allard2067d1a2008-11-13 22:59:24 +000096 {
97 $this->encryption_key = $key;
Greg Akerd1af1852011-12-25 21:59:30 -060098 return $this;
Derek Allard2067d1a2008-11-13 22:59:24 +000099 }
100
101 // --------------------------------------------------------------------
102
103 /**
104 * Encode
105 *
106 * Encodes the message string using bitwise XOR encoding.
107 * The key is combined with a random hash, and then it
108 * too gets converted using XOR. The whole thing is then run
109 * through mcrypt (if supported) using the randomized key.
110 * The end result is a double-encrypted message string
111 * that is randomized with each call to this function,
112 * even if the supplied message and key are the same.
113 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000114 * @param string the string to encode
115 * @param string the key
116 * @return string
117 */
Greg Akerd1af1852011-12-25 21:59:30 -0600118 public function encode($string, $key = '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000119 {
Andrey Andreev7c251b32011-12-27 16:37:23 +0200120 $method = ($this->_mcrypt_exists === TRUE) ? 'mcrypt_encode' : '_xor_encode';
121 return base64_encode($this->$method($string, $this->get_key($key)));
Derek Allard2067d1a2008-11-13 22:59:24 +0000122 }
123
124 // --------------------------------------------------------------------
125
126 /**
127 * Decode
128 *
129 * Reverses the above process
130 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000131 * @param string
132 * @param string
133 * @return string
134 */
Greg Akerd1af1852011-12-25 21:59:30 -0600135 public function decode($string, $key = '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000136 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000137 if (preg_match('/[^a-zA-Z0-9\/\+=]/', $string))
138 {
139 return FALSE;
140 }
141
Andrey Andreev7c251b32011-12-27 16:37:23 +0200142 $method = ($this->_mcrypt_exists === TRUE) ? 'mcrypt_decode' : '_xor_decode';
143 return $this->$method(base64_decode($string), $this->get_key($key));
Derek Allard2067d1a2008-11-13 22:59:24 +0000144 }
145
146 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200147
Derek Jones09c77932010-08-31 13:17:10 -0500148 /**
149 * Encode from Legacy
150 *
151 * Takes an encoded string from the original Encryption class algorithms and
152 * returns a newly encoded string using the improved method added in 2.0.0
153 * This allows for backwards compatibility and a method to transition to the
154 * new encryption algorithms.
Barry Mienydd671972010-10-04 16:33:58 +0200155 *
Derek Jones09c77932010-08-31 13:17:10 -0500156 * For more details, see http://codeigniter.com/user_guide/installation/upgrade_200.html#encryption
157 *
Derek Jones09c77932010-08-31 13:17:10 -0500158 * @param string
159 * @param int (mcrypt mode constant)
160 * @param string
161 * @return string
162 */
Greg Akerd1af1852011-12-25 21:59:30 -0600163 public function encode_from_legacy($string, $legacy_mode = MCRYPT_MODE_ECB, $key = '')
Derek Jones09c77932010-08-31 13:17:10 -0500164 {
165 if ($this->_mcrypt_exists === FALSE)
166 {
167 log_message('error', 'Encoding from legacy is available only when Mcrypt is in use.');
168 return FALSE;
169 }
Andrey Andreev7c251b32011-12-27 16:37:23 +0200170 elseif (preg_match('/[^a-zA-Z0-9\/\+=]/', $string))
171 {
172 return FALSE;
173 }
Barry Mienydd671972010-10-04 16:33:58 +0200174
Derek Jones09c77932010-08-31 13:17:10 -0500175 // decode it first
176 // set mode temporarily to what it was when string was encoded with the legacy
Barry Mienydd671972010-10-04 16:33:58 +0200177 // algorithm - typically MCRYPT_MODE_ECB
Derek Jones09c77932010-08-31 13:17:10 -0500178 $current_mode = $this->_get_mode();
179 $this->set_mode($legacy_mode);
Barry Mienydd671972010-10-04 16:33:58 +0200180
Derek Jones09c77932010-08-31 13:17:10 -0500181 $key = $this->get_key($key);
Derek Jones09c77932010-08-31 13:17:10 -0500182 $dec = base64_decode($string);
Derek Jones09c77932010-08-31 13:17:10 -0500183 if (($dec = $this->mcrypt_decode($dec, $key)) === FALSE)
184 {
185 return FALSE;
186 }
187
188 $dec = $this->_xor_decode($dec, $key);
189
190 // set the mcrypt mode back to what it should be, typically MCRYPT_MODE_CBC
Derek Jones092103e2010-09-02 11:11:58 -0500191 $this->set_mode($current_mode);
Derek Jones09c77932010-08-31 13:17:10 -0500192
193 // and re-encode
194 return base64_encode($this->mcrypt_encode($dec, $key));
195 }
196
197 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200198
Derek Allard2067d1a2008-11-13 22:59:24 +0000199 /**
200 * XOR Encode
201 *
202 * Takes a plain-text string and key as input and generates an
203 * encoded bit-string using XOR
204 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000205 * @param string
206 * @param string
207 * @return string
208 */
Greg Akerd1af1852011-12-25 21:59:30 -0600209 protected function _xor_encode($string, $key)
Derek Allard2067d1a2008-11-13 22:59:24 +0000210 {
211 $rand = '';
Andrey Andreev7c251b32011-12-27 16:37:23 +0200212 do
Derek Allard2067d1a2008-11-13 22:59:24 +0000213 {
214 $rand .= mt_rand(0, mt_getrandmax());
215 }
Andrey Andreev7c251b32011-12-27 16:37:23 +0200216 while (strlen($rand) < 32);
Derek Allard2067d1a2008-11-13 22:59:24 +0000217
218 $rand = $this->hash($rand);
219
220 $enc = '';
Andrey Andreev7c251b32011-12-27 16:37:23 +0200221 for ($i = 0, $ls = strlen($string), $lr = strlen($rand); $i < $ls; $i++)
Barry Mienydd671972010-10-04 16:33:58 +0200222 {
Andrey Andreev7c251b32011-12-27 16:37:23 +0200223 $enc .= $rand[($i % $lr)].($rand[($i % $lr)] ^ $string[$i]);
Derek Allard2067d1a2008-11-13 22:59:24 +0000224 }
225
226 return $this->_xor_merge($enc, $key);
227 }
228
229 // --------------------------------------------------------------------
230
231 /**
232 * XOR Decode
233 *
234 * Takes an encoded string and key as input and generates the
235 * plain-text original message
236 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000237 * @param string
238 * @param string
239 * @return string
240 */
Greg Akerd1af1852011-12-25 21:59:30 -0600241 protected function _xor_decode($string, $key)
Derek Allard2067d1a2008-11-13 22:59:24 +0000242 {
243 $string = $this->_xor_merge($string, $key);
244
245 $dec = '';
Andrey Andreev7c251b32011-12-27 16:37:23 +0200246 for ($i = 0, $l = strlen($string); $i < $l; $i++)
Derek Allard2067d1a2008-11-13 22:59:24 +0000247 {
Andrey Andreev7c251b32011-12-27 16:37:23 +0200248 $dec .= ($string[$i++] ^ $string[$i]);
Derek Allard2067d1a2008-11-13 22:59:24 +0000249 }
250
251 return $dec;
252 }
253
254 // --------------------------------------------------------------------
255
256 /**
257 * XOR key + string Combiner
258 *
259 * Takes a string and key as input and computes the difference using XOR
260 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000261 * @param string
262 * @param string
263 * @return string
264 */
Greg Akerd1af1852011-12-25 21:59:30 -0600265 protected function _xor_merge($string, $key)
Derek Allard2067d1a2008-11-13 22:59:24 +0000266 {
267 $hash = $this->hash($key);
268 $str = '';
Andrey Andreev7c251b32011-12-27 16:37:23 +0200269 for ($i = 0, $ls = strlen($string), $lh = strlen($hash); $i < $ls; $i++)
Derek Allard2067d1a2008-11-13 22:59:24 +0000270 {
Andrey Andreev7c251b32011-12-27 16:37:23 +0200271 $str .= $string[$i] ^ $hash[($i % $lh)];
Derek Allard2067d1a2008-11-13 22:59:24 +0000272 }
273
274 return $str;
275 }
276
277 // --------------------------------------------------------------------
278
279 /**
280 * Encrypt using Mcrypt
281 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000282 * @param string
283 * @param string
284 * @return string
285 */
Greg Akerd1af1852011-12-25 21:59:30 -0600286 public function mcrypt_encode($data, $key)
Derek Allard2067d1a2008-11-13 22:59:24 +0000287 {
288 $init_size = mcrypt_get_iv_size($this->_get_cipher(), $this->_get_mode());
289 $init_vect = mcrypt_create_iv($init_size, MCRYPT_RAND);
290 return $this->_add_cipher_noise($init_vect.mcrypt_encrypt($this->_get_cipher(), $key, $data, $this->_get_mode(), $init_vect), $key);
291 }
292
293 // --------------------------------------------------------------------
294
295 /**
296 * Decrypt using Mcrypt
297 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000298 * @param string
299 * @param string
300 * @return string
301 */
Greg Akerd1af1852011-12-25 21:59:30 -0600302 public function mcrypt_decode($data, $key)
Derek Allard2067d1a2008-11-13 22:59:24 +0000303 {
304 $data = $this->_remove_cipher_noise($data, $key);
305 $init_size = mcrypt_get_iv_size($this->_get_cipher(), $this->_get_mode());
306
307 if ($init_size > strlen($data))
308 {
309 return FALSE;
310 }
311
312 $init_vect = substr($data, 0, $init_size);
313 $data = substr($data, $init_size);
314 return rtrim(mcrypt_decrypt($this->_get_cipher(), $key, $data, $this->_get_mode(), $init_vect), "\0");
315 }
316
317 // --------------------------------------------------------------------
318
319 /**
320 * Adds permuted noise to the IV + encrypted data to protect
321 * against Man-in-the-middle attacks on CBC mode ciphers
322 * http://www.ciphersbyritter.com/GLOSSARY.HTM#IV
323 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000324 * @param string
325 * @param string
326 * @return string
327 */
Greg Akerd1af1852011-12-25 21:59:30 -0600328 protected function _add_cipher_noise($data, $key)
Derek Allard2067d1a2008-11-13 22:59:24 +0000329 {
Andrey Andreev7c251b32011-12-27 16:37:23 +0200330 $key = $this->hash($key);
Derek Allard2067d1a2008-11-13 22:59:24 +0000331 $str = '';
332
Andrey Andreev7c251b32011-12-27 16:37:23 +0200333 for ($i = 0, $j = 0, $ld = strlen($data), $lk = strlen($key); $i < $ld; ++$i, ++$j)
Derek Allard2067d1a2008-11-13 22:59:24 +0000334 {
Andrey Andreev7c251b32011-12-27 16:37:23 +0200335 if ($j >= $lk)
Derek Allard2067d1a2008-11-13 22:59:24 +0000336 {
337 $j = 0;
338 }
339
Andrey Andreev7c251b32011-12-27 16:37:23 +0200340 $str .= chr((ord($data[$i]) + ord($key[$j])) % 256);
Derek Allard2067d1a2008-11-13 22:59:24 +0000341 }
342
343 return $str;
344 }
345
346 // --------------------------------------------------------------------
347
348 /**
349 * Removes permuted noise from the IV + encrypted data, reversing
350 * _add_cipher_noise()
351 *
352 * Function description
353 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000354 * @param type
355 * @return type
356 */
Greg Akerd1af1852011-12-25 21:59:30 -0600357 protected function _remove_cipher_noise($data, $key)
Derek Allard2067d1a2008-11-13 22:59:24 +0000358 {
Andrey Andreev7c251b32011-12-27 16:37:23 +0200359 $key = $this->hash($key);
Derek Allard2067d1a2008-11-13 22:59:24 +0000360 $str = '';
361
Andrey Andreev7c251b32011-12-27 16:37:23 +0200362 for ($i = 0, $j = 0, $ld = strlen($data), $lk = strlen($key); $i < $ld; ++$i, ++$j)
Derek Allard2067d1a2008-11-13 22:59:24 +0000363 {
Andrey Andreev7c251b32011-12-27 16:37:23 +0200364 if ($j >= $lk)
Derek Allard2067d1a2008-11-13 22:59:24 +0000365 {
366 $j = 0;
367 }
368
Andrey Andreev7c251b32011-12-27 16:37:23 +0200369 $temp = ord($data[$i]) - ord($key[$j]);
Derek Allard2067d1a2008-11-13 22:59:24 +0000370
371 if ($temp < 0)
372 {
Andrey Andreev7c251b32011-12-27 16:37:23 +0200373 $temp += 256;
Derek Allard2067d1a2008-11-13 22:59:24 +0000374 }
Barry Mienydd671972010-10-04 16:33:58 +0200375
Derek Allard2067d1a2008-11-13 22:59:24 +0000376 $str .= chr($temp);
377 }
378
379 return $str;
380 }
381
382 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200383
Derek Allard2067d1a2008-11-13 22:59:24 +0000384 /**
385 * Set the Mcrypt Cipher
386 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000387 * @param constant
388 * @return string
389 */
Greg Akerd1af1852011-12-25 21:59:30 -0600390 public function set_cipher($cipher)
Derek Allard2067d1a2008-11-13 22:59:24 +0000391 {
392 $this->_mcrypt_cipher = $cipher;
Greg Akerd1af1852011-12-25 21:59:30 -0600393 return $this;
Derek Allard2067d1a2008-11-13 22:59:24 +0000394 }
395
396 // --------------------------------------------------------------------
397
398 /**
399 * Set the Mcrypt Mode
400 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000401 * @param constant
402 * @return string
403 */
Andrey Andreev7c251b32011-12-27 16:37:23 +0200404 public function set_mode($mode)
Derek Allard2067d1a2008-11-13 22:59:24 +0000405 {
406 $this->_mcrypt_mode = $mode;
Greg Akerd1af1852011-12-25 21:59:30 -0600407 return $this;
Derek Allard2067d1a2008-11-13 22:59:24 +0000408 }
409
410 // --------------------------------------------------------------------
411
412 /**
413 * Get Mcrypt cipher Value
414 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000415 * @return string
416 */
Greg Akerd1af1852011-12-25 21:59:30 -0600417 protected function _get_cipher()
Derek Allard2067d1a2008-11-13 22:59:24 +0000418 {
419 if ($this->_mcrypt_cipher == '')
420 {
Andrey Andreevd655a992012-01-10 22:31:29 +0200421 return $this->_mcrypt_cipher = MCRYPT_RIJNDAEL_256;
Derek Allard2067d1a2008-11-13 22:59:24 +0000422 }
423
424 return $this->_mcrypt_cipher;
425 }
426
427 // --------------------------------------------------------------------
428
429 /**
430 * Get Mcrypt Mode Value
431 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000432 * @return string
433 */
Greg Akerd1af1852011-12-25 21:59:30 -0600434 protected function _get_mode()
Derek Allard2067d1a2008-11-13 22:59:24 +0000435 {
436 if ($this->_mcrypt_mode == '')
437 {
Andrey Andreevd655a992012-01-10 22:31:29 +0200438 return $this->_mcrypt_mode = MCRYPT_MODE_CBC;
Derek Allard2067d1a2008-11-13 22:59:24 +0000439 }
Barry Mienydd671972010-10-04 16:33:58 +0200440
Derek Allard2067d1a2008-11-13 22:59:24 +0000441 return $this->_mcrypt_mode;
442 }
443
444 // --------------------------------------------------------------------
445
446 /**
447 * Set the Hash type
448 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000449 * @param string
450 * @return string
451 */
Greg Akerd1af1852011-12-25 21:59:30 -0600452 public function set_hash($type = 'sha1')
Derek Allard2067d1a2008-11-13 22:59:24 +0000453 {
Andrey Andreevcc6dbda2012-01-08 06:35:17 +0200454 $this->_hash_type = ($type !== 'sha1' && $type !== 'md5') ? 'sha1' : $type;
Derek Allard2067d1a2008-11-13 22:59:24 +0000455 }
456
457 // --------------------------------------------------------------------
458
459 /**
460 * Hash encode a string
461 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000462 * @param string
463 * @return string
Barry Mienydd671972010-10-04 16:33:58 +0200464 */
Greg Akerd1af1852011-12-25 21:59:30 -0600465 public function hash($str)
Derek Allard2067d1a2008-11-13 22:59:24 +0000466 {
Andrey Andreev7c251b32011-12-27 16:37:23 +0200467 return ($this->_hash_type === 'sha1') ? sha1($str) : md5($str);
Derek Allard2067d1a2008-11-13 22:59:24 +0000468 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000469}
470
Derek Allard2067d1a2008-11-13 22:59:24 +0000471/* End of file Encrypt.php */
Andrey Andreev7c251b32011-12-27 16:37:23 +0200472/* Location: ./system/libraries/Encrypt.php */