PageRenderTime 47ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/system/libraries/Encrypt.php

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