PageRenderTime 46ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/system/libraries/Encrypt.php

https://bitbucket.org/kurniawanchan83/codeigniter
PHP | 507 lines | 194 code | 72 blank | 241 comment | 18 complexity | f980a82244daf32c82ba68bb075b2f48 MD5 | raw file
  1. <?php
  2. /**
  3. * CodeIgniter
  4. *
  5. * An open source application development framework for PHP 5.2.4 or newer
  6. *
  7. * 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. *
  19. * @package CodeIgniter
  20. * @author EllisLab Dev Team
  21. * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/)
  22. * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
  23. * @link http://codeigniter.com
  24. * @since Version 1.0
  25. * @filesource
  26. */
  27. defined('BASEPATH') OR exit('No direct script access allowed');
  28. /**
  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
  36. * @author EllisLab Dev Team
  37. * @link http://codeigniter.com/user_guide/libraries/encryption.html
  38. */
  39. class CI_Encrypt {
  40. /**
  41. * Reference to the user's encryption key
  42. *
  43. * @var string
  44. */
  45. public $encryption_key = '';
  46. /**
  47. * Type of hash operation
  48. *
  49. * @var string
  50. */
  51. protected $_hash_type = 'sha1';
  52. /**
  53. * Flag for the existance of mcrypt
  54. *
  55. * @var bool
  56. */
  57. protected $_mcrypt_exists = FALSE;
  58. /**
  59. * Current cipher to be used with mcrypt
  60. *
  61. * @var string
  62. */
  63. protected $_mcrypt_cipher;
  64. /**
  65. * Method for encrypting/decrypting data
  66. *
  67. * @var int
  68. */
  69. protected $_mcrypt_mode;
  70. /**
  71. * Initialize Encryption class
  72. *
  73. * @return void
  74. */
  75. public function __construct()
  76. {
  77. $this->_mcrypt_exists = function_exists('mcrypt_encrypt');
  78. log_message('debug', 'Encrypt Class Initialized');
  79. }
  80. // --------------------------------------------------------------------
  81. /**
  82. * Fetch the encryption key
  83. *
  84. * Returns it as MD5 in order to have an exact-length 128 bit key.
  85. * Mcrypt is sensitive to keys that are not the correct length
  86. *
  87. * @param string
  88. * @return string
  89. */
  90. public function get_key($key = '')
  91. {
  92. if ($key === '')
  93. {
  94. if ($this->encryption_key !== '')
  95. {
  96. return $this->encryption_key;
  97. }
  98. $key = config_item('encryption_key');
  99. if ($key === FALSE)
  100. {
  101. show_error('In order to use the encryption class requires that you set an encryption key in your config file.');
  102. }
  103. }
  104. return md5($key);
  105. }
  106. // --------------------------------------------------------------------
  107. /**
  108. * Set the encryption key
  109. *
  110. * @param string
  111. * @return CI_Encrypt
  112. */
  113. public function set_key($key = '')
  114. {
  115. $this->encryption_key = $key;
  116. return $this;
  117. }
  118. // --------------------------------------------------------------------
  119. /**
  120. * Encode
  121. *
  122. * Encodes the message string using bitwise XOR encoding.
  123. * The key is combined with a random hash, and then it
  124. * too gets converted using XOR. The whole thing is then run
  125. * through mcrypt (if supported) using the randomized key.
  126. * The end result is a double-encrypted message string
  127. * that is randomized with each call to this function,
  128. * even if the supplied message and key are the same.
  129. *
  130. * @param string the string to encode
  131. * @param string the key
  132. * @return string
  133. */
  134. public function encode($string, $key = '')
  135. {
  136. $method = ($this->_mcrypt_exists === TRUE) ? 'mcrypt_encode' : '_xor_encode';
  137. return base64_encode($this->$method($string, $this->get_key($key)));
  138. }
  139. // --------------------------------------------------------------------
  140. /**
  141. * Decode
  142. *
  143. * Reverses the above process
  144. *
  145. * @param string
  146. * @param string
  147. * @return string
  148. */
  149. public function decode($string, $key = '')
  150. {
  151. if (preg_match('/[^a-zA-Z0-9\/\+=]/', $string) OR base64_encode(base64_decode($string)) !== $string)
  152. {
  153. return FALSE;
  154. }
  155. $method = ($this->_mcrypt_exists === TRUE) ? 'mcrypt_decode' : '_xor_decode';
  156. return $this->$method(base64_decode($string), $this->get_key($key));
  157. }
  158. // --------------------------------------------------------------------
  159. /**
  160. * Encode from Legacy
  161. *
  162. * Takes an encoded string from the original Encryption class algorithms and
  163. * returns a newly encoded string using the improved method added in 2.0.0
  164. * This allows for backwards compatibility and a method to transition to the
  165. * new encryption algorithms.
  166. *
  167. * For more details, see http://codeigniter.com/user_guide/installation/upgrade_200.html#encryption
  168. *
  169. * @param string
  170. * @param int (mcrypt mode constant)
  171. * @param string
  172. * @return string
  173. */
  174. public function encode_from_legacy($string, $legacy_mode = MCRYPT_MODE_ECB, $key = '')
  175. {
  176. if ($this->_mcrypt_exists === FALSE)
  177. {
  178. log_message('error', 'Encoding from legacy is available only when Mcrypt is in use.');
  179. return FALSE;
  180. }
  181. elseif (preg_match('/[^a-zA-Z0-9\/\+=]/', $string))
  182. {
  183. return FALSE;
  184. }
  185. // decode it first
  186. // set mode temporarily to what it was when string was encoded with the legacy
  187. // algorithm - typically MCRYPT_MODE_ECB
  188. $current_mode = $this->_get_mode();
  189. $this->set_mode($legacy_mode);
  190. $key = $this->get_key($key);
  191. $dec = base64_decode($string);
  192. if (($dec = $this->mcrypt_decode($dec, $key)) === FALSE)
  193. {
  194. $this->set_mode($current_mode);
  195. return FALSE;
  196. }
  197. $dec = $this->_xor_decode($dec, $key);
  198. // set the mcrypt mode back to what it should be, typically MCRYPT_MODE_CBC
  199. $this->set_mode($current_mode);
  200. // and re-encode
  201. return base64_encode($this->mcrypt_encode($dec, $key));
  202. }
  203. // --------------------------------------------------------------------
  204. /**
  205. * XOR Encode
  206. *
  207. * Takes a plain-text string and key as input and generates an
  208. * encoded bit-string using XOR
  209. *
  210. * @param string
  211. * @param string
  212. * @return string
  213. */
  214. protected function _xor_encode($string, $key)
  215. {
  216. $rand = '';
  217. do
  218. {
  219. $rand .= mt_rand(0, mt_getrandmax());
  220. }
  221. while (strlen($rand) < 32);
  222. $rand = $this->hash($rand);
  223. $enc = '';
  224. for ($i = 0, $ls = strlen($string), $lr = strlen($rand); $i < $ls; $i++)
  225. {
  226. $enc .= $rand[($i % $lr)].($rand[($i % $lr)] ^ $string[$i]);
  227. }
  228. return $this->_xor_merge($enc, $key);
  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. *
  237. * @param string
  238. * @param string
  239. * @return string
  240. */
  241. protected function _xor_decode($string, $key)
  242. {
  243. $string = $this->_xor_merge($string, $key);
  244. $dec = '';
  245. for ($i = 0, $l = strlen($string); $i < $l; $i++)
  246. {
  247. $dec .= ($string[$i++] ^ $string[$i]);
  248. }
  249. return $dec;
  250. }
  251. // --------------------------------------------------------------------
  252. /**
  253. * XOR key + string Combiner
  254. *
  255. * Takes a string and key as input and computes the difference using XOR
  256. *
  257. * @param string
  258. * @param string
  259. * @return string
  260. */
  261. protected function _xor_merge($string, $key)
  262. {
  263. $hash = $this->hash($key);
  264. $str = '';
  265. for ($i = 0, $ls = strlen($string), $lh = strlen($hash); $i < $ls; $i++)
  266. {
  267. $str .= $string[$i] ^ $hash[($i % $lh)];
  268. }
  269. return $str;
  270. }
  271. // --------------------------------------------------------------------
  272. /**
  273. * Encrypt using Mcrypt
  274. *
  275. * @param string
  276. * @param string
  277. * @return string
  278. */
  279. public function mcrypt_encode($data, $key)
  280. {
  281. $init_size = mcrypt_get_iv_size($this->_get_cipher(), $this->_get_mode());
  282. $init_vect = mcrypt_create_iv($init_size, MCRYPT_RAND);
  283. return $this->_add_cipher_noise($init_vect.mcrypt_encrypt($this->_get_cipher(), $key, $data, $this->_get_mode(), $init_vect), $key);
  284. }
  285. // --------------------------------------------------------------------
  286. /**
  287. * Decrypt using Mcrypt
  288. *
  289. * @param string
  290. * @param string
  291. * @return string
  292. */
  293. public function mcrypt_decode($data, $key)
  294. {
  295. $data = $this->_remove_cipher_noise($data, $key);
  296. $init_size = mcrypt_get_iv_size($this->_get_cipher(), $this->_get_mode());
  297. if ($init_size > strlen($data))
  298. {
  299. return FALSE;
  300. }
  301. $init_vect = substr($data, 0, $init_size);
  302. $data = substr($data, $init_size);
  303. return rtrim(mcrypt_decrypt($this->_get_cipher(), $key, $data, $this->_get_mode(), $init_vect), "\0");
  304. }
  305. // --------------------------------------------------------------------
  306. /**
  307. * Adds permuted noise to the IV + encrypted data to protect
  308. * against Man-in-the-middle attacks on CBC mode ciphers
  309. * http://www.ciphersbyritter.com/GLOSSARY.HTM#IV
  310. *
  311. * @param string
  312. * @param string
  313. * @return string
  314. */
  315. protected function _add_cipher_noise($data, $key)
  316. {
  317. $key = $this->hash($key);
  318. $str = '';
  319. for ($i = 0, $j = 0, $ld = strlen($data), $lk = strlen($key); $i < $ld; ++$i, ++$j)
  320. {
  321. if ($j >= $lk)
  322. {
  323. $j = 0;
  324. }
  325. $str .= chr((ord($data[$i]) + ord($key[$j])) % 256);
  326. }
  327. return $str;
  328. }
  329. // --------------------------------------------------------------------
  330. /**
  331. * Removes permuted noise from the IV + encrypted data, reversing
  332. * _add_cipher_noise()
  333. *
  334. * Function description
  335. *
  336. * @param string $data
  337. * @param string $key
  338. * @return string
  339. */
  340. protected function _remove_cipher_noise($data, $key)
  341. {
  342. $key = $this->hash($key);
  343. $str = '';
  344. for ($i = 0, $j = 0, $ld = strlen($data), $lk = strlen($key); $i < $ld; ++$i, ++$j)
  345. {
  346. if ($j >= $lk)
  347. {
  348. $j = 0;
  349. }
  350. $temp = ord($data[$i]) - ord($key[$j]);
  351. if ($temp < 0)
  352. {
  353. $temp += 256;
  354. }
  355. $str .= chr($temp);
  356. }
  357. return $str;
  358. }
  359. // --------------------------------------------------------------------
  360. /**
  361. * Set the Mcrypt Cipher
  362. *
  363. * @param int
  364. * @return CI_Encrypt
  365. */
  366. public function set_cipher($cipher)
  367. {
  368. $this->_mcrypt_cipher = $cipher;
  369. return $this;
  370. }
  371. // --------------------------------------------------------------------
  372. /**
  373. * Set the Mcrypt Mode
  374. *
  375. * @param int
  376. * @return CI_Encrypt
  377. */
  378. public function set_mode($mode)
  379. {
  380. $this->_mcrypt_mode = $mode;
  381. return $this;
  382. }
  383. // --------------------------------------------------------------------
  384. /**
  385. * Get Mcrypt cipher Value
  386. *
  387. * @return int
  388. */
  389. protected function _get_cipher()
  390. {
  391. if ($this->_mcrypt_cipher === NULL)
  392. {
  393. return $this->_mcrypt_cipher = MCRYPT_RIJNDAEL_256;
  394. }
  395. return $this->_mcrypt_cipher;
  396. }
  397. // --------------------------------------------------------------------
  398. /**
  399. * Get Mcrypt Mode Value
  400. *
  401. * @return int
  402. */
  403. protected function _get_mode()
  404. {
  405. if ($this->_mcrypt_mode === NULL)
  406. {
  407. return $this->_mcrypt_mode = MCRYPT_MODE_CBC;
  408. }
  409. return $this->_mcrypt_mode;
  410. }
  411. // --------------------------------------------------------------------
  412. /**
  413. * Set the Hash type
  414. *
  415. * @param string
  416. * @return void
  417. */
  418. public function set_hash($type = 'sha1')
  419. {
  420. $this->_hash_type = in_array($type, hash_algos()) ? $type : 'sha1';
  421. }
  422. // --------------------------------------------------------------------
  423. /**
  424. * Hash encode a string
  425. *
  426. * @param string
  427. * @return string
  428. */
  429. public function hash($str)
  430. {
  431. return hash($this->_hash_type, $str);
  432. }
  433. }
  434. /* End of file Encrypt.php */
  435. /* Location: ./system/libraries/Encrypt.php */