PageRenderTime 45ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/system/libraries/Encryption.php

https://gitlab.com/betanurlaila/UI_onlineshop
PHP | 931 lines | 519 code | 109 blank | 303 comment | 64 complexity | d0ce13d1ba20ba9a8f7f67c1b3f37a42 MD5 | raw file
  1. <?php
  2. /**
  3. * CodeIgniter
  4. *
  5. * An open source application development framework for PHP
  6. *
  7. * This content is released under the MIT License (MIT)
  8. *
  9. * Copyright (c) 2014 - 2016, British Columbia Institute of Technology
  10. *
  11. * Permission is hereby granted, free of charge, to any person obtaining a copy
  12. * of this software and associated documentation files (the "Software"), to deal
  13. * in the Software without restriction, including without limitation the rights
  14. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  15. * copies of the Software, and to permit persons to whom the Software is
  16. * furnished to do so, subject to the following conditions:
  17. *
  18. * The above copyright notice and this permission notice shall be included in
  19. * all copies or substantial portions of the Software.
  20. *
  21. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  24. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  25. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  26. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  27. * THE SOFTWARE.
  28. *
  29. * @package CodeIgniter
  30. * @author EllisLab Dev Team
  31. * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
  32. * @copyright Copyright (c) 2014 - 2016, British Columbia Institute of Technology (http://bcit.ca/)
  33. * @license http://opensource.org/licenses/MIT MIT License
  34. * @link https://codeigniter.com
  35. * @since Version 3.0.0
  36. * @filesource
  37. */
  38. defined('BASEPATH') OR exit('No direct script access allowed');
  39. /**
  40. * CodeIgniter Encryption Class
  41. *
  42. * Provides two-way keyed encryption via PHP's MCrypt and/or OpenSSL extensions.
  43. *
  44. * @package CodeIgniter
  45. * @subpackage Libraries
  46. * @category Libraries
  47. * @author Andrey Andreev
  48. * @link https://codeigniter.com/user_guide/libraries/encryption.html
  49. */
  50. class CI_Encryption {
  51. /**
  52. * Encryption cipher
  53. *
  54. * @var string
  55. */
  56. protected $_cipher = 'aes-128';
  57. /**
  58. * Cipher mode
  59. *
  60. * @var string
  61. */
  62. protected $_mode = 'cbc';
  63. /**
  64. * Cipher handle
  65. *
  66. * @var mixed
  67. */
  68. protected $_handle;
  69. /**
  70. * Encryption key
  71. *
  72. * @var string
  73. */
  74. protected $_key;
  75. /**
  76. * PHP extension to be used
  77. *
  78. * @var string
  79. */
  80. protected $_driver;
  81. /**
  82. * List of usable drivers (PHP extensions)
  83. *
  84. * @var array
  85. */
  86. protected $_drivers = array();
  87. /**
  88. * List of available modes
  89. *
  90. * @var array
  91. */
  92. protected $_modes = array(
  93. 'mcrypt' => array(
  94. 'cbc' => 'cbc',
  95. 'ecb' => 'ecb',
  96. 'ofb' => 'nofb',
  97. 'ofb8' => 'ofb',
  98. 'cfb' => 'ncfb',
  99. 'cfb8' => 'cfb',
  100. 'ctr' => 'ctr',
  101. 'stream' => 'stream'
  102. ),
  103. 'openssl' => array(
  104. 'cbc' => 'cbc',
  105. 'ecb' => 'ecb',
  106. 'ofb' => 'ofb',
  107. 'cfb' => 'cfb',
  108. 'cfb8' => 'cfb8',
  109. 'ctr' => 'ctr',
  110. 'stream' => '',
  111. 'xts' => 'xts'
  112. )
  113. );
  114. /**
  115. * List of supported HMAC algorithms
  116. *
  117. * name => digest size pairs
  118. *
  119. * @var array
  120. */
  121. protected $_digests = array(
  122. 'sha224' => 28,
  123. 'sha256' => 32,
  124. 'sha384' => 48,
  125. 'sha512' => 64
  126. );
  127. /**
  128. * mbstring.func_override flag
  129. *
  130. * @var bool
  131. */
  132. protected static $func_override;
  133. // --------------------------------------------------------------------
  134. /**
  135. * Class constructor
  136. *
  137. * @param array $params Configuration parameters
  138. * @return void
  139. */
  140. public function __construct(array $params = array())
  141. {
  142. $this->_drivers = array(
  143. 'mcrypt' => defined('MCRYPT_DEV_URANDOM'),
  144. // While OpenSSL is available for PHP 5.3.0, an IV parameter
  145. // for the encrypt/decrypt functions is only available since 5.3.3
  146. 'openssl' => (is_php('5.3.3') && extension_loaded('openssl'))
  147. );
  148. if ( ! $this->_drivers['mcrypt'] && ! $this->_drivers['openssl'])
  149. {
  150. show_error('Encryption: Unable to find an available encryption driver.');
  151. }
  152. isset(self::$func_override) OR self::$func_override = (extension_loaded('mbstring') && ini_get('mbstring.func_override'));
  153. $this->initialize($params);
  154. if ( ! isset($this->_key) && self::strlen($key = config_item('encryption_key')) > 0)
  155. {
  156. $this->_key = $key;
  157. }
  158. log_message('info', 'Encryption Class Initialized');
  159. }
  160. // --------------------------------------------------------------------
  161. /**
  162. * Initialize
  163. *
  164. * @param array $params Configuration parameters
  165. * @return CI_Encryption
  166. */
  167. public function initialize(array $params)
  168. {
  169. if ( ! empty($params['driver']))
  170. {
  171. if (isset($this->_drivers[$params['driver']]))
  172. {
  173. if ($this->_drivers[$params['driver']])
  174. {
  175. $this->_driver = $params['driver'];
  176. }
  177. else
  178. {
  179. log_message('error', "Encryption: Driver '".$params['driver']."' is not available.");
  180. }
  181. }
  182. else
  183. {
  184. log_message('error', "Encryption: Unknown driver '".$params['driver']."' cannot be configured.");
  185. }
  186. }
  187. if (empty($this->_driver))
  188. {
  189. $this->_driver = ($this->_drivers['openssl'] === TRUE)
  190. ? 'openssl'
  191. : 'mcrypt';
  192. log_message('debug', "Encryption: Auto-configured driver '".$this->_driver."'.");
  193. }
  194. empty($params['cipher']) && $params['cipher'] = $this->_cipher;
  195. empty($params['key']) OR $this->_key = $params['key'];
  196. $this->{'_'.$this->_driver.'_initialize'}($params);
  197. return $this;
  198. }
  199. // --------------------------------------------------------------------
  200. /**
  201. * Initialize MCrypt
  202. *
  203. * @param array $params Configuration parameters
  204. * @return void
  205. */
  206. protected function _mcrypt_initialize($params)
  207. {
  208. if ( ! empty($params['cipher']))
  209. {
  210. $params['cipher'] = strtolower($params['cipher']);
  211. $this->_cipher_alias($params['cipher']);
  212. if ( ! in_array($params['cipher'], mcrypt_list_algorithms(), TRUE))
  213. {
  214. log_message('error', 'Encryption: MCrypt cipher '.strtoupper($params['cipher']).' is not available.');
  215. }
  216. else
  217. {
  218. $this->_cipher = $params['cipher'];
  219. }
  220. }
  221. if ( ! empty($params['mode']))
  222. {
  223. $params['mode'] = strtolower($params['mode']);
  224. if ( ! isset($this->_modes['mcrypt'][$params['mode']]))
  225. {
  226. log_message('error', 'Encryption: MCrypt mode '.strtoupper($params['mode']).' is not available.');
  227. }
  228. else
  229. {
  230. $this->_mode = $this->_modes['mcrypt'][$params['mode']];
  231. }
  232. }
  233. if (isset($this->_cipher, $this->_mode))
  234. {
  235. if (is_resource($this->_handle)
  236. && (strtolower(mcrypt_enc_get_algorithms_name($this->_handle)) !== $this->_cipher
  237. OR strtolower(mcrypt_enc_get_modes_name($this->_handle)) !== $this->_mode)
  238. )
  239. {
  240. mcrypt_module_close($this->_handle);
  241. }
  242. if ($this->_handle = mcrypt_module_open($this->_cipher, '', $this->_mode, ''))
  243. {
  244. log_message('info', 'Encryption: MCrypt cipher '.strtoupper($this->_cipher).' initialized in '.strtoupper($this->_mode).' mode.');
  245. }
  246. else
  247. {
  248. log_message('error', 'Encryption: Unable to initialize MCrypt with cipher '.strtoupper($this->_cipher).' in '.strtoupper($this->_mode).' mode.');
  249. }
  250. }
  251. }
  252. // --------------------------------------------------------------------
  253. /**
  254. * Initialize OpenSSL
  255. *
  256. * @param array $params Configuration parameters
  257. * @return void
  258. */
  259. protected function _openssl_initialize($params)
  260. {
  261. if ( ! empty($params['cipher']))
  262. {
  263. $params['cipher'] = strtolower($params['cipher']);
  264. $this->_cipher_alias($params['cipher']);
  265. $this->_cipher = $params['cipher'];
  266. }
  267. if ( ! empty($params['mode']))
  268. {
  269. $params['mode'] = strtolower($params['mode']);
  270. if ( ! isset($this->_modes['openssl'][$params['mode']]))
  271. {
  272. log_message('error', 'Encryption: OpenSSL mode '.strtoupper($params['mode']).' is not available.');
  273. }
  274. else
  275. {
  276. $this->_mode = $this->_modes['openssl'][$params['mode']];
  277. }
  278. }
  279. if (isset($this->_cipher, $this->_mode))
  280. {
  281. // This is mostly for the stream mode, which doesn't get suffixed in OpenSSL
  282. $handle = empty($this->_mode)
  283. ? $this->_cipher
  284. : $this->_cipher.'-'.$this->_mode;
  285. if ( ! in_array($handle, openssl_get_cipher_methods(), TRUE))
  286. {
  287. $this->_handle = NULL;
  288. log_message('error', 'Encryption: Unable to initialize OpenSSL with method '.strtoupper($handle).'.');
  289. }
  290. else
  291. {
  292. $this->_handle = $handle;
  293. log_message('info', 'Encryption: OpenSSL initialized with method '.strtoupper($handle).'.');
  294. }
  295. }
  296. }
  297. // --------------------------------------------------------------------
  298. /**
  299. * Create a random key
  300. *
  301. * @param int $length Output length
  302. * @return string
  303. */
  304. public function create_key($length)
  305. {
  306. if (function_exists('random_bytes'))
  307. {
  308. return random_bytes((int) $length);
  309. }
  310. return ($this->_driver === 'mcrypt')
  311. ? mcrypt_create_iv($length, MCRYPT_DEV_URANDOM)
  312. : openssl_random_pseudo_bytes($length);
  313. }
  314. // --------------------------------------------------------------------
  315. /**
  316. * Encrypt
  317. *
  318. * @param string $data Input data
  319. * @param array $params Input parameters
  320. * @return string
  321. */
  322. public function encrypt($data, array $params = NULL)
  323. {
  324. if (($params = $this->_get_params($params)) === FALSE)
  325. {
  326. return FALSE;
  327. }
  328. isset($params['key']) OR $params['key'] = $this->hkdf($this->_key, 'sha512', NULL, self::strlen($this->_key), 'encryption');
  329. if (($data = $this->{'_'.$this->_driver.'_encrypt'}($data, $params)) === FALSE)
  330. {
  331. return FALSE;
  332. }
  333. $params['base64'] && $data = base64_encode($data);
  334. if (isset($params['hmac_digest']))
  335. {
  336. isset($params['hmac_key']) OR $params['hmac_key'] = $this->hkdf($this->_key, 'sha512', NULL, NULL, 'authentication');
  337. return hash_hmac($params['hmac_digest'], $data, $params['hmac_key'], ! $params['base64']).$data;
  338. }
  339. return $data;
  340. }
  341. // --------------------------------------------------------------------
  342. /**
  343. * Encrypt via MCrypt
  344. *
  345. * @param string $data Input data
  346. * @param array $params Input parameters
  347. * @return string
  348. */
  349. protected function _mcrypt_encrypt($data, $params)
  350. {
  351. if ( ! is_resource($params['handle']))
  352. {
  353. return FALSE;
  354. }
  355. // The greater-than-1 comparison is mostly a work-around for a bug,
  356. // where 1 is returned for ARCFour instead of 0.
  357. $iv = (($iv_size = mcrypt_enc_get_iv_size($params['handle'])) > 1)
  358. ? mcrypt_create_iv($iv_size, MCRYPT_DEV_URANDOM)
  359. : NULL;
  360. if (mcrypt_generic_init($params['handle'], $params['key'], $iv) < 0)
  361. {
  362. if ($params['handle'] !== $this->_handle)
  363. {
  364. mcrypt_module_close($params['handle']);
  365. }
  366. return FALSE;
  367. }
  368. // Use PKCS#7 padding in order to ensure compatibility with OpenSSL
  369. // and other implementations outside of PHP.
  370. if (in_array(strtolower(mcrypt_enc_get_modes_name($params['handle'])), array('cbc', 'ecb'), TRUE))
  371. {
  372. $block_size = mcrypt_enc_get_block_size($params['handle']);
  373. $pad = $block_size - (self::strlen($data) % $block_size);
  374. $data .= str_repeat(chr($pad), $pad);
  375. }
  376. // Work-around for yet another strange behavior in MCrypt.
  377. //
  378. // When encrypting in ECB mode, the IV is ignored. Yet
  379. // mcrypt_enc_get_iv_size() returns a value larger than 0
  380. // even if ECB is used AND mcrypt_generic_init() complains
  381. // if you don't pass an IV with length equal to the said
  382. // return value.
  383. //
  384. // This probably would've been fine (even though still wasteful),
  385. // but OpenSSL isn't that dumb and we need to make the process
  386. // portable, so ...
  387. $data = (mcrypt_enc_get_modes_name($params['handle']) !== 'ECB')
  388. ? $iv.mcrypt_generic($params['handle'], $data)
  389. : mcrypt_generic($params['handle'], $data);
  390. mcrypt_generic_deinit($params['handle']);
  391. if ($params['handle'] !== $this->_handle)
  392. {
  393. mcrypt_module_close($params['handle']);
  394. }
  395. return $data;
  396. }
  397. // --------------------------------------------------------------------
  398. /**
  399. * Encrypt via OpenSSL
  400. *
  401. * @param string $data Input data
  402. * @param array $params Input parameters
  403. * @return string
  404. */
  405. protected function _openssl_encrypt($data, $params)
  406. {
  407. if (empty($params['handle']))
  408. {
  409. return FALSE;
  410. }
  411. $iv = ($iv_size = openssl_cipher_iv_length($params['handle']))
  412. ? openssl_random_pseudo_bytes($iv_size)
  413. : NULL;
  414. $data = openssl_encrypt(
  415. $data,
  416. $params['handle'],
  417. $params['key'],
  418. 1, // DO NOT TOUCH!
  419. $iv
  420. );
  421. if ($data === FALSE)
  422. {
  423. return FALSE;
  424. }
  425. return $iv.$data;
  426. }
  427. // --------------------------------------------------------------------
  428. /**
  429. * Decrypt
  430. *
  431. * @param string $data Encrypted data
  432. * @param array $params Input parameters
  433. * @return string
  434. */
  435. public function decrypt($data, array $params = NULL)
  436. {
  437. if (($params = $this->_get_params($params)) === FALSE)
  438. {
  439. return FALSE;
  440. }
  441. if (isset($params['hmac_digest']))
  442. {
  443. // This might look illogical, but it is done during encryption as well ...
  444. // The 'base64' value is effectively an inverted "raw data" parameter
  445. $digest_size = ($params['base64'])
  446. ? $this->_digests[$params['hmac_digest']] * 2
  447. : $this->_digests[$params['hmac_digest']];
  448. if (self::strlen($data) <= $digest_size)
  449. {
  450. return FALSE;
  451. }
  452. $hmac_input = self::substr($data, 0, $digest_size);
  453. $data = self::substr($data, $digest_size);
  454. isset($params['hmac_key']) OR $params['hmac_key'] = $this->hkdf($this->_key, 'sha512', NULL, NULL, 'authentication');
  455. $hmac_check = hash_hmac($params['hmac_digest'], $data, $params['hmac_key'], ! $params['base64']);
  456. // Time-attack-safe comparison
  457. $diff = 0;
  458. for ($i = 0; $i < $digest_size; $i++)
  459. {
  460. $diff |= ord($hmac_input[$i]) ^ ord($hmac_check[$i]);
  461. }
  462. if ($diff !== 0)
  463. {
  464. return FALSE;
  465. }
  466. }
  467. if ($params['base64'])
  468. {
  469. $data = base64_decode($data);
  470. }
  471. isset($params['key']) OR $params['key'] = $this->hkdf($this->_key, 'sha512', NULL, self::strlen($this->_key), 'encryption');
  472. return $this->{'_'.$this->_driver.'_decrypt'}($data, $params);
  473. }
  474. // --------------------------------------------------------------------
  475. /**
  476. * Decrypt via MCrypt
  477. *
  478. * @param string $data Encrypted data
  479. * @param array $params Input parameters
  480. * @return string
  481. */
  482. protected function _mcrypt_decrypt($data, $params)
  483. {
  484. if ( ! is_resource($params['handle']))
  485. {
  486. return FALSE;
  487. }
  488. // The greater-than-1 comparison is mostly a work-around for a bug,
  489. // where 1 is returned for ARCFour instead of 0.
  490. if (($iv_size = mcrypt_enc_get_iv_size($params['handle'])) > 1)
  491. {
  492. if (mcrypt_enc_get_modes_name($params['handle']) !== 'ECB')
  493. {
  494. $iv = self::substr($data, 0, $iv_size);
  495. $data = self::substr($data, $iv_size);
  496. }
  497. else
  498. {
  499. // MCrypt is dumb and this is ignored, only size matters
  500. $iv = str_repeat("\x0", $iv_size);
  501. }
  502. }
  503. else
  504. {
  505. $iv = NULL;
  506. }
  507. if (mcrypt_generic_init($params['handle'], $params['key'], $iv) < 0)
  508. {
  509. if ($params['handle'] !== $this->_handle)
  510. {
  511. mcrypt_module_close($params['handle']);
  512. }
  513. return FALSE;
  514. }
  515. $data = mdecrypt_generic($params['handle'], $data);
  516. // Remove PKCS#7 padding, if necessary
  517. if (in_array(strtolower(mcrypt_enc_get_modes_name($params['handle'])), array('cbc', 'ecb'), TRUE))
  518. {
  519. $data = self::substr($data, 0, -ord($data[self::strlen($data)-1]));
  520. }
  521. mcrypt_generic_deinit($params['handle']);
  522. if ($params['handle'] !== $this->_handle)
  523. {
  524. mcrypt_module_close($params['handle']);
  525. }
  526. return $data;
  527. }
  528. // --------------------------------------------------------------------
  529. /**
  530. * Decrypt via OpenSSL
  531. *
  532. * @param string $data Encrypted data
  533. * @param array $params Input parameters
  534. * @return string
  535. */
  536. protected function _openssl_decrypt($data, $params)
  537. {
  538. if ($iv_size = openssl_cipher_iv_length($params['handle']))
  539. {
  540. $iv = self::substr($data, 0, $iv_size);
  541. $data = self::substr($data, $iv_size);
  542. }
  543. else
  544. {
  545. $iv = NULL;
  546. }
  547. return empty($params['handle'])
  548. ? FALSE
  549. : openssl_decrypt(
  550. $data,
  551. $params['handle'],
  552. $params['key'],
  553. 1, // DO NOT TOUCH!
  554. $iv
  555. );
  556. }
  557. // --------------------------------------------------------------------
  558. /**
  559. * Get params
  560. *
  561. * @param array $params Input parameters
  562. * @return array
  563. */
  564. protected function _get_params($params)
  565. {
  566. if (empty($params))
  567. {
  568. return isset($this->_cipher, $this->_mode, $this->_key, $this->_handle)
  569. ? array(
  570. 'handle' => $this->_handle,
  571. 'cipher' => $this->_cipher,
  572. 'mode' => $this->_mode,
  573. 'key' => NULL,
  574. 'base64' => TRUE,
  575. 'hmac_digest' => 'sha512',
  576. 'hmac_key' => NULL
  577. )
  578. : FALSE;
  579. }
  580. elseif ( ! isset($params['cipher'], $params['mode'], $params['key']))
  581. {
  582. return FALSE;
  583. }
  584. if (isset($params['mode']))
  585. {
  586. $params['mode'] = strtolower($params['mode']);
  587. if ( ! isset($this->_modes[$this->_driver][$params['mode']]))
  588. {
  589. return FALSE;
  590. }
  591. else
  592. {
  593. $params['mode'] = $this->_modes[$this->_driver][$params['mode']];
  594. }
  595. }
  596. if (isset($params['hmac']) && $params['hmac'] === FALSE)
  597. {
  598. $params['hmac_digest'] = $params['hmac_key'] = NULL;
  599. }
  600. else
  601. {
  602. if ( ! isset($params['hmac_key']))
  603. {
  604. return FALSE;
  605. }
  606. elseif (isset($params['hmac_digest']))
  607. {
  608. $params['hmac_digest'] = strtolower($params['hmac_digest']);
  609. if ( ! isset($this->_digests[$params['hmac_digest']]))
  610. {
  611. return FALSE;
  612. }
  613. }
  614. else
  615. {
  616. $params['hmac_digest'] = 'sha512';
  617. }
  618. }
  619. $params = array(
  620. 'handle' => NULL,
  621. 'cipher' => $params['cipher'],
  622. 'mode' => $params['mode'],
  623. 'key' => $params['key'],
  624. 'base64' => isset($params['raw_data']) ? ! $params['raw_data'] : FALSE,
  625. 'hmac_digest' => $params['hmac_digest'],
  626. 'hmac_key' => $params['hmac_key']
  627. );
  628. $this->_cipher_alias($params['cipher']);
  629. $params['handle'] = ($params['cipher'] !== $this->_cipher OR $params['mode'] !== $this->_mode)
  630. ? $this->{'_'.$this->_driver.'_get_handle'}($params['cipher'], $params['mode'])
  631. : $this->_handle;
  632. return $params;
  633. }
  634. // --------------------------------------------------------------------
  635. /**
  636. * Get MCrypt handle
  637. *
  638. * @param string $cipher Cipher name
  639. * @param string $mode Encryption mode
  640. * @return resource
  641. */
  642. protected function _mcrypt_get_handle($cipher, $mode)
  643. {
  644. return mcrypt_module_open($cipher, '', $mode, '');
  645. }
  646. // --------------------------------------------------------------------
  647. /**
  648. * Get OpenSSL handle
  649. *
  650. * @param string $cipher Cipher name
  651. * @param string $mode Encryption mode
  652. * @return string
  653. */
  654. protected function _openssl_get_handle($cipher, $mode)
  655. {
  656. // OpenSSL methods aren't suffixed with '-stream' for this mode
  657. return ($mode === 'stream')
  658. ? $cipher
  659. : $cipher.'-'.$mode;
  660. }
  661. // --------------------------------------------------------------------
  662. /**
  663. * Cipher alias
  664. *
  665. * Tries to translate cipher names between MCrypt and OpenSSL's "dialects".
  666. *
  667. * @param string $cipher Cipher name
  668. * @return void
  669. */
  670. protected function _cipher_alias(&$cipher)
  671. {
  672. static $dictionary;
  673. if (empty($dictionary))
  674. {
  675. $dictionary = array(
  676. 'mcrypt' => array(
  677. 'aes-128' => 'rijndael-128',
  678. 'aes-192' => 'rijndael-128',
  679. 'aes-256' => 'rijndael-128',
  680. 'des3-ede3' => 'tripledes',
  681. 'bf' => 'blowfish',
  682. 'cast5' => 'cast-128',
  683. 'rc4' => 'arcfour',
  684. 'rc4-40' => 'arcfour'
  685. ),
  686. 'openssl' => array(
  687. 'rijndael-128' => 'aes-128',
  688. 'tripledes' => 'des-ede3',
  689. 'blowfish' => 'bf',
  690. 'cast-128' => 'cast5',
  691. 'arcfour' => 'rc4-40',
  692. 'rc4' => 'rc4-40'
  693. )
  694. );
  695. // Notes:
  696. //
  697. // - Rijndael-128 is, at the same time all three of AES-128,
  698. // AES-192 and AES-256. The only difference between them is
  699. // the key size. Rijndael-192, Rijndael-256 on the other hand
  700. // also have different block sizes and are NOT AES-compatible.
  701. //
  702. // - Blowfish is said to be supporting key sizes between
  703. // 4 and 56 bytes, but it appears that between MCrypt and
  704. // OpenSSL, only those of 16 and more bytes are compatible.
  705. // Also, don't know what MCrypt's 'blowfish-compat' is.
  706. //
  707. // - CAST-128/CAST5 produces a longer cipher when encrypted via
  708. // OpenSSL, but (strangely enough) can be decrypted by either
  709. // extension anyway.
  710. // Also, it appears that OpenSSL uses 16 rounds regardless of
  711. // the key size, while RFC2144 says that for key sizes lower
  712. // than 11 bytes, only 12 rounds should be used. This makes
  713. // it portable only with keys of between 11 and 16 bytes.
  714. //
  715. // - RC4 (ARCFour) has a strange implementation under OpenSSL.
  716. // Its 'rc4-40' cipher method seems to work flawlessly, yet
  717. // there's another one, 'rc4' that only works with a 16-byte key.
  718. //
  719. // - DES is compatible, but doesn't need an alias.
  720. //
  721. // Other seemingly matching ciphers between MCrypt, OpenSSL:
  722. //
  723. // - RC2 is NOT compatible and only an obscure forum post
  724. // confirms that it is MCrypt's fault.
  725. }
  726. if (isset($dictionary[$this->_driver][$cipher]))
  727. {
  728. $cipher = $dictionary[$this->_driver][$cipher];
  729. }
  730. }
  731. // --------------------------------------------------------------------
  732. /**
  733. * HKDF
  734. *
  735. * @link https://tools.ietf.org/rfc/rfc5869.txt
  736. * @param $key Input key
  737. * @param $digest A SHA-2 hashing algorithm
  738. * @param $salt Optional salt
  739. * @param $length Output length (defaults to the selected digest size)
  740. * @param $info Optional context/application-specific info
  741. * @return string A pseudo-random key
  742. */
  743. public function hkdf($key, $digest = 'sha512', $salt = NULL, $length = NULL, $info = '')
  744. {
  745. if ( ! isset($this->_digests[$digest]))
  746. {
  747. return FALSE;
  748. }
  749. if (empty($length) OR ! is_int($length))
  750. {
  751. $length = $this->_digests[$digest];
  752. }
  753. elseif ($length > (255 * $this->_digests[$digest]))
  754. {
  755. return FALSE;
  756. }
  757. self::strlen($salt) OR $salt = str_repeat("\0", $this->_digests[$digest]);
  758. $prk = hash_hmac($digest, $key, $salt, TRUE);
  759. $key = '';
  760. for ($key_block = '', $block_index = 1; self::strlen($key) < $length; $block_index++)
  761. {
  762. $key_block = hash_hmac($digest, $key_block.$info.chr($block_index), $prk, TRUE);
  763. $key .= $key_block;
  764. }
  765. return self::substr($key, 0, $length);
  766. }
  767. // --------------------------------------------------------------------
  768. /**
  769. * __get() magic
  770. *
  771. * @param string $key Property name
  772. * @return mixed
  773. */
  774. public function __get($key)
  775. {
  776. // Because aliases
  777. if ($key === 'mode')
  778. {
  779. return array_search($this->_mode, $this->_modes[$this->_driver], TRUE);
  780. }
  781. elseif (in_array($key, array('cipher', 'driver', 'drivers', 'digests'), TRUE))
  782. {
  783. return $this->{'_'.$key};
  784. }
  785. return NULL;
  786. }
  787. // --------------------------------------------------------------------
  788. /**
  789. * Byte-safe strlen()
  790. *
  791. * @param string $str
  792. * @return integer
  793. */
  794. protected static function strlen($str)
  795. {
  796. return (self::$func_override)
  797. ? mb_strlen($str, '8bit')
  798. : strlen($str);
  799. }
  800. // --------------------------------------------------------------------
  801. /**
  802. * Byte-safe substr()
  803. *
  804. * @param string $str
  805. * @param int $start
  806. * @param int $length
  807. * @return string
  808. */
  809. protected static function substr($str, $start, $length = NULL)
  810. {
  811. if (self::$func_override)
  812. {
  813. // mb_substr($str, $start, null, '8bit') returns an empty
  814. // string on PHP 5.3
  815. isset($length) OR $length = ($start >= 0 ? self::strlen($str) - $start : -$start);
  816. return mb_substr($str, $start, $length, '8bit');
  817. }
  818. return isset($length)
  819. ? substr($str, $start, $length)
  820. : substr($str, $start);
  821. }
  822. }