123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941 |
- <?php
- /**
- * CodeIgniter
- *
- * An open source application development framework for PHP
- *
- * This content is released under the MIT License (MIT)
- *
- * Copyright (c) 2014 - 2019, British Columbia Institute of Technology
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- * @package CodeIgniter
- * @author EllisLab Dev Team
- * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
- * @copyright Copyright (c) 2014 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
- * @license https://opensource.org/licenses/MIT MIT License
- * @link https://codeigniter.com
- * @since Version 3.0.0
- * @filesource
- */
- defined('BASEPATH') OR exit('No direct script access allowed');
- /**
- * CodeIgniter Encryption Class
- *
- * Provides two-way keyed encryption via PHP's MCrypt and/or OpenSSL extensions.
- *
- * @package CodeIgniter
- * @subpackage Libraries
- * @category Libraries
- * @author Andrey Andreev
- * @link https://codeigniter.com/user_guide/libraries/encryption.html
- */
- class CI_Encryption {
- /**
- * Encryption cipher
- *
- * @var string
- */
- protected $_cipher = 'aes-128';
- /**
- * Cipher mode
- *
- * @var string
- */
- protected $_mode = 'cbc';
- /**
- * Cipher handle
- *
- * @var mixed
- */
- protected $_handle;
- /**
- * Encryption key
- *
- * @var string
- */
- protected $_key;
- /**
- * PHP extension to be used
- *
- * @var string
- */
- protected $_driver;
- /**
- * List of usable drivers (PHP extensions)
- *
- * @var array
- */
- protected $_drivers = array();
- /**
- * List of available modes
- *
- * @var array
- */
- protected $_modes = array(
- 'mcrypt' => array(
- 'cbc' => 'cbc',
- 'ecb' => 'ecb',
- 'ofb' => 'nofb',
- 'ofb8' => 'ofb',
- 'cfb' => 'ncfb',
- 'cfb8' => 'cfb',
- 'ctr' => 'ctr',
- 'stream' => 'stream'
- ),
- 'openssl' => array(
- 'cbc' => 'cbc',
- 'ecb' => 'ecb',
- 'ofb' => 'ofb',
- 'cfb' => 'cfb',
- 'cfb8' => 'cfb8',
- 'ctr' => 'ctr',
- 'stream' => '',
- 'xts' => 'xts'
- )
- );
- /**
- * List of supported HMAC algorithms
- *
- * name => digest size pairs
- *
- * @var array
- */
- protected $_digests = array(
- 'sha224' => 28,
- 'sha256' => 32,
- 'sha384' => 48,
- 'sha512' => 64
- );
- /**
- * mbstring.func_overload flag
- *
- * @var bool
- */
- protected static $func_overload;
- // --------------------------------------------------------------------
- /**
- * Class constructor
- *
- * @param array $params Configuration parameters
- * @return void
- */
- public function __construct(array $params = array())
- {
- $this->_drivers = array(
- 'mcrypt' => defined('MCRYPT_DEV_URANDOM'),
- 'openssl' => extension_loaded('openssl')
- );
- if ( ! $this->_drivers['mcrypt'] && ! $this->_drivers['openssl'])
- {
- show_error('Encryption: Unable to find an available encryption driver.');
- }
- isset(self::$func_overload) OR self::$func_overload = (extension_loaded('mbstring') && ini_get('mbstring.func_overload'));
- $this->initialize($params);
- if ( ! isset($this->_key) && self::strlen($key = config_item('encryption_key')) > 0)
- {
- $this->_key = $key;
- }
- log_message('info', 'Encryption Class Initialized');
- }
- // --------------------------------------------------------------------
- /**
- * Initialize
- *
- * @param array $params Configuration parameters
- * @return CI_Encryption
- */
- public function initialize(array $params)
- {
- if ( ! empty($params['driver']))
- {
- if (isset($this->_drivers[$params['driver']]))
- {
- if ($this->_drivers[$params['driver']])
- {
- $this->_driver = $params['driver'];
- }
- else
- {
- log_message('error', "Encryption: Driver '".$params['driver']."' is not available.");
- }
- }
- else
- {
- log_message('error', "Encryption: Unknown driver '".$params['driver']."' cannot be configured.");
- }
- }
- if (empty($this->_driver))
- {
- $this->_driver = ($this->_drivers['openssl'] === TRUE)
- ? 'openssl'
- : 'mcrypt';
- log_message('debug', "Encryption: Auto-configured driver '".$this->_driver."'.");
- }
- empty($params['cipher']) && $params['cipher'] = $this->_cipher;
- empty($params['key']) OR $this->_key = $params['key'];
- $this->{'_'.$this->_driver.'_initialize'}($params);
- return $this;
- }
- // --------------------------------------------------------------------
- /**
- * Initialize MCrypt
- *
- * @param array $params Configuration parameters
- * @return void
- */
- protected function _mcrypt_initialize($params)
- {
- if ( ! empty($params['cipher']))
- {
- $params['cipher'] = strtolower($params['cipher']);
- $this->_cipher_alias($params['cipher']);
- if ( ! in_array($params['cipher'], mcrypt_list_algorithms(), TRUE))
- {
- log_message('error', 'Encryption: MCrypt cipher '.strtoupper($params['cipher']).' is not available.');
- }
- else
- {
- $this->_cipher = $params['cipher'];
- }
- }
- if ( ! empty($params['mode']))
- {
- $params['mode'] = strtolower($params['mode']);
- if ( ! isset($this->_modes['mcrypt'][$params['mode']]))
- {
- log_message('error', 'Encryption: MCrypt mode '.strtoupper($params['mode']).' is not available.');
- }
- else
- {
- $this->_mode = $this->_modes['mcrypt'][$params['mode']];
- }
- }
- if (isset($this->_cipher, $this->_mode))
- {
- if (is_resource($this->_handle)
- && (strtolower(mcrypt_enc_get_algorithms_name($this->_handle)) !== $this->_cipher
- OR strtolower(mcrypt_enc_get_modes_name($this->_handle)) !== $this->_mode)
- )
- {
- mcrypt_module_close($this->_handle);
- }
- if ($this->_handle = mcrypt_module_open($this->_cipher, '', $this->_mode, ''))
- {
- log_message('info', 'Encryption: MCrypt cipher '.strtoupper($this->_cipher).' initialized in '.strtoupper($this->_mode).' mode.');
- }
- else
- {
- log_message('error', 'Encryption: Unable to initialize MCrypt with cipher '.strtoupper($this->_cipher).' in '.strtoupper($this->_mode).' mode.');
- }
- }
- }
- // --------------------------------------------------------------------
- /**
- * Initialize OpenSSL
- *
- * @param array $params Configuration parameters
- * @return void
- */
- protected function _openssl_initialize($params)
- {
- if ( ! empty($params['cipher']))
- {
- $params['cipher'] = strtolower($params['cipher']);
- $this->_cipher_alias($params['cipher']);
- $this->_cipher = $params['cipher'];
- }
- if ( ! empty($params['mode']))
- {
- $params['mode'] = strtolower($params['mode']);
- if ( ! isset($this->_modes['openssl'][$params['mode']]))
- {
- log_message('error', 'Encryption: OpenSSL mode '.strtoupper($params['mode']).' is not available.');
- }
- else
- {
- $this->_mode = $this->_modes['openssl'][$params['mode']];
- }
- }
- if (isset($this->_cipher, $this->_mode))
- {
- // This is mostly for the stream mode, which doesn't get suffixed in OpenSSL
- $handle = empty($this->_mode)
- ? $this->_cipher
- : $this->_cipher.'-'.$this->_mode;
- if ( ! in_array($handle, openssl_get_cipher_methods(), TRUE))
- {
- $this->_handle = NULL;
- log_message('error', 'Encryption: Unable to initialize OpenSSL with method '.strtoupper($handle).'.');
- }
- else
- {
- $this->_handle = $handle;
- log_message('info', 'Encryption: OpenSSL initialized with method '.strtoupper($handle).'.');
- }
- }
- }
- // --------------------------------------------------------------------
- /**
- * Create a random key
- *
- * @param int $length Output length
- * @return string
- */
- public function create_key($length)
- {
- if (function_exists('random_bytes'))
- {
- try
- {
- return random_bytes((int) $length);
- }
- catch (Exception $e)
- {
- log_message('error', $e->getMessage());
- return FALSE;
- }
- }
- elseif (defined('MCRYPT_DEV_URANDOM'))
- {
- return mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
- }
- $is_secure = NULL;
- $key = openssl_random_pseudo_bytes($length, $is_secure);
- return ($is_secure === TRUE)
- ? $key
- : FALSE;
- }
- // --------------------------------------------------------------------
- /**
- * Encrypt
- *
- * @param string $data Input data
- * @param array $params Input parameters
- * @return string
- */
- public function encrypt($data, array $params = NULL)
- {
- if (($params = $this->_get_params($params)) === FALSE)
- {
- return FALSE;
- }
- isset($params['key']) OR $params['key'] = $this->hkdf($this->_key, 'sha512', NULL, self::strlen($this->_key), 'encryption');
- if (($data = $this->{'_'.$this->_driver.'_encrypt'}($data, $params)) === FALSE)
- {
- return FALSE;
- }
- $params['base64'] && $data = base64_encode($data);
- if (isset($params['hmac_digest']))
- {
- isset($params['hmac_key']) OR $params['hmac_key'] = $this->hkdf($this->_key, 'sha512', NULL, NULL, 'authentication');
- return hash_hmac($params['hmac_digest'], $data, $params['hmac_key'], ! $params['base64']).$data;
- }
- return $data;
- }
- // --------------------------------------------------------------------
- /**
- * Encrypt via MCrypt
- *
- * @param string $data Input data
- * @param array $params Input parameters
- * @return string
- */
- protected function _mcrypt_encrypt($data, $params)
- {
- if ( ! is_resource($params['handle']))
- {
- return FALSE;
- }
- // The greater-than-1 comparison is mostly a work-around for a bug,
- // where 1 is returned for ARCFour instead of 0.
- $iv = (($iv_size = mcrypt_enc_get_iv_size($params['handle'])) > 1)
- ? $this->create_key($iv_size)
- : NULL;
- if (mcrypt_generic_init($params['handle'], $params['key'], $iv) < 0)
- {
- if ($params['handle'] !== $this->_handle)
- {
- mcrypt_module_close($params['handle']);
- }
- return FALSE;
- }
- // Use PKCS#7 padding in order to ensure compatibility with OpenSSL
- // and other implementations outside of PHP.
- if (in_array(strtolower(mcrypt_enc_get_modes_name($params['handle'])), array('cbc', 'ecb'), TRUE))
- {
- $block_size = mcrypt_enc_get_block_size($params['handle']);
- $pad = $block_size - (self::strlen($data) % $block_size);
- $data .= str_repeat(chr($pad), $pad);
- }
- // Work-around for yet another strange behavior in MCrypt.
- //
- // When encrypting in ECB mode, the IV is ignored. Yet
- // mcrypt_enc_get_iv_size() returns a value larger than 0
- // even if ECB is used AND mcrypt_generic_init() complains
- // if you don't pass an IV with length equal to the said
- // return value.
- //
- // This probably would've been fine (even though still wasteful),
- // but OpenSSL isn't that dumb and we need to make the process
- // portable, so ...
- $data = (mcrypt_enc_get_modes_name($params['handle']) !== 'ECB')
- ? $iv.mcrypt_generic($params['handle'], $data)
- : mcrypt_generic($params['handle'], $data);
- mcrypt_generic_deinit($params['handle']);
- if ($params['handle'] !== $this->_handle)
- {
- mcrypt_module_close($params['handle']);
- }
- return $data;
- }
- // --------------------------------------------------------------------
- /**
- * Encrypt via OpenSSL
- *
- * @param string $data Input data
- * @param array $params Input parameters
- * @return string
- */
- protected function _openssl_encrypt($data, $params)
- {
- if (empty($params['handle']))
- {
- return FALSE;
- }
- $iv = ($iv_size = openssl_cipher_iv_length($params['handle']))
- ? $this->create_key($iv_size)
- : NULL;
- $data = openssl_encrypt(
- $data,
- $params['handle'],
- $params['key'],
- 1, // DO NOT TOUCH!
- $iv
- );
- if ($data === FALSE)
- {
- return FALSE;
- }
- return $iv.$data;
- }
- // --------------------------------------------------------------------
- /**
- * Decrypt
- *
- * @param string $data Encrypted data
- * @param array $params Input parameters
- * @return string
- */
- public function decrypt($data, array $params = NULL)
- {
- if (($params = $this->_get_params($params)) === FALSE)
- {
- return FALSE;
- }
- if (isset($params['hmac_digest']))
- {
- // This might look illogical, but it is done during encryption as well ...
- // The 'base64' value is effectively an inverted "raw data" parameter
- $digest_size = ($params['base64'])
- ? $this->_digests[$params['hmac_digest']] * 2
- : $this->_digests[$params['hmac_digest']];
- if (self::strlen($data) <= $digest_size)
- {
- return FALSE;
- }
- $hmac_input = self::substr($data, 0, $digest_size);
- $data = self::substr($data, $digest_size);
- isset($params['hmac_key']) OR $params['hmac_key'] = $this->hkdf($this->_key, 'sha512', NULL, NULL, 'authentication');
- $hmac_check = hash_hmac($params['hmac_digest'], $data, $params['hmac_key'], ! $params['base64']);
- // Time-attack-safe comparison
- $diff = 0;
- for ($i = 0; $i < $digest_size; $i++)
- {
- $diff |= ord($hmac_input[$i]) ^ ord($hmac_check[$i]);
- }
- if ($diff !== 0)
- {
- return FALSE;
- }
- }
- if ($params['base64'])
- {
- $data = base64_decode($data);
- }
- isset($params['key']) OR $params['key'] = $this->hkdf($this->_key, 'sha512', NULL, self::strlen($this->_key), 'encryption');
- return $this->{'_'.$this->_driver.'_decrypt'}($data, $params);
- }
- // --------------------------------------------------------------------
- /**
- * Decrypt via MCrypt
- *
- * @param string $data Encrypted data
- * @param array $params Input parameters
- * @return string
- */
- protected function _mcrypt_decrypt($data, $params)
- {
- if ( ! is_resource($params['handle']))
- {
- return FALSE;
- }
- // The greater-than-1 comparison is mostly a work-around for a bug,
- // where 1 is returned for ARCFour instead of 0.
- if (($iv_size = mcrypt_enc_get_iv_size($params['handle'])) > 1)
- {
- if (mcrypt_enc_get_modes_name($params['handle']) !== 'ECB')
- {
- $iv = self::substr($data, 0, $iv_size);
- $data = self::substr($data, $iv_size);
- }
- else
- {
- // MCrypt is dumb and this is ignored, only size matters
- $iv = str_repeat("\x0", $iv_size);
- }
- }
- else
- {
- $iv = NULL;
- }
- if (mcrypt_generic_init($params['handle'], $params['key'], $iv) < 0)
- {
- if ($params['handle'] !== $this->_handle)
- {
- mcrypt_module_close($params['handle']);
- }
- return FALSE;
- }
- $data = mdecrypt_generic($params['handle'], $data);
- // Remove PKCS#7 padding, if necessary
- if (in_array(strtolower(mcrypt_enc_get_modes_name($params['handle'])), array('cbc', 'ecb'), TRUE))
- {
- $data = self::substr($data, 0, -ord($data[self::strlen($data)-1]));
- }
- mcrypt_generic_deinit($params['handle']);
- if ($params['handle'] !== $this->_handle)
- {
- mcrypt_module_close($params['handle']);
- }
- return $data;
- }
- // --------------------------------------------------------------------
- /**
- * Decrypt via OpenSSL
- *
- * @param string $data Encrypted data
- * @param array $params Input parameters
- * @return string
- */
- protected function _openssl_decrypt($data, $params)
- {
- if ($iv_size = openssl_cipher_iv_length($params['handle']))
- {
- $iv = self::substr($data, 0, $iv_size);
- $data = self::substr($data, $iv_size);
- }
- else
- {
- $iv = NULL;
- }
- return empty($params['handle'])
- ? FALSE
- : openssl_decrypt(
- $data,
- $params['handle'],
- $params['key'],
- 1, // DO NOT TOUCH!
- $iv
- );
- }
- // --------------------------------------------------------------------
- /**
- * Get params
- *
- * @param array $params Input parameters
- * @return array
- */
- protected function _get_params($params)
- {
- if (empty($params))
- {
- return isset($this->_cipher, $this->_mode, $this->_key, $this->_handle)
- ? array(
- 'handle' => $this->_handle,
- 'cipher' => $this->_cipher,
- 'mode' => $this->_mode,
- 'key' => NULL,
- 'base64' => TRUE,
- 'hmac_digest' => 'sha512',
- 'hmac_key' => NULL
- )
- : FALSE;
- }
- elseif ( ! isset($params['cipher'], $params['mode'], $params['key']))
- {
- return FALSE;
- }
- if (isset($params['mode']))
- {
- $params['mode'] = strtolower($params['mode']);
- if ( ! isset($this->_modes[$this->_driver][$params['mode']]))
- {
- return FALSE;
- }
- $params['mode'] = $this->_modes[$this->_driver][$params['mode']];
- }
- if (isset($params['hmac']) && $params['hmac'] === FALSE)
- {
- $params['hmac_digest'] = $params['hmac_key'] = NULL;
- }
- else
- {
- if ( ! isset($params['hmac_key']))
- {
- return FALSE;
- }
- elseif (isset($params['hmac_digest']))
- {
- $params['hmac_digest'] = strtolower($params['hmac_digest']);
- if ( ! isset($this->_digests[$params['hmac_digest']]))
- {
- return FALSE;
- }
- }
- else
- {
- $params['hmac_digest'] = 'sha512';
- }
- }
- $params = array(
- 'handle' => NULL,
- 'cipher' => $params['cipher'],
- 'mode' => $params['mode'],
- 'key' => $params['key'],
- 'base64' => isset($params['raw_data']) ? ! $params['raw_data'] : FALSE,
- 'hmac_digest' => $params['hmac_digest'],
- 'hmac_key' => $params['hmac_key']
- );
- $this->_cipher_alias($params['cipher']);
- $params['handle'] = ($params['cipher'] !== $this->_cipher OR $params['mode'] !== $this->_mode)
- ? $this->{'_'.$this->_driver.'_get_handle'}($params['cipher'], $params['mode'])
- : $this->_handle;
- return $params;
- }
- // --------------------------------------------------------------------
- /**
- * Get MCrypt handle
- *
- * @param string $cipher Cipher name
- * @param string $mode Encryption mode
- * @return resource
- */
- protected function _mcrypt_get_handle($cipher, $mode)
- {
- return mcrypt_module_open($cipher, '', $mode, '');
- }
- // --------------------------------------------------------------------
- /**
- * Get OpenSSL handle
- *
- * @param string $cipher Cipher name
- * @param string $mode Encryption mode
- * @return string
- */
- protected function _openssl_get_handle($cipher, $mode)
- {
- // OpenSSL methods aren't suffixed with '-stream' for this mode
- return ($mode === 'stream')
- ? $cipher
- : $cipher.'-'.$mode;
- }
- // --------------------------------------------------------------------
- /**
- * Cipher alias
- *
- * Tries to translate cipher names between MCrypt and OpenSSL's "dialects".
- *
- * @param string $cipher Cipher name
- * @return void
- */
- protected function _cipher_alias(&$cipher)
- {
- static $dictionary;
- if (empty($dictionary))
- {
- $dictionary = array(
- 'mcrypt' => array(
- 'aes-128' => 'rijndael-128',
- 'aes-192' => 'rijndael-128',
- 'aes-256' => 'rijndael-128',
- 'des3-ede3' => 'tripledes',
- 'bf' => 'blowfish',
- 'cast5' => 'cast-128',
- 'rc4' => 'arcfour',
- 'rc4-40' => 'arcfour'
- ),
- 'openssl' => array(
- 'rijndael-128' => 'aes-128',
- 'tripledes' => 'des-ede3',
- 'blowfish' => 'bf',
- 'cast-128' => 'cast5',
- 'arcfour' => 'rc4-40',
- 'rc4' => 'rc4-40'
- )
- );
- // Notes:
- //
- // - Rijndael-128 is, at the same time all three of AES-128,
- // AES-192 and AES-256. The only difference between them is
- // the key size. Rijndael-192, Rijndael-256 on the other hand
- // also have different block sizes and are NOT AES-compatible.
- //
- // - Blowfish is said to be supporting key sizes between
- // 4 and 56 bytes, but it appears that between MCrypt and
- // OpenSSL, only those of 16 and more bytes are compatible.
- // Also, don't know what MCrypt's 'blowfish-compat' is.
- //
- // - CAST-128/CAST5 produces a longer cipher when encrypted via
- // OpenSSL, but (strangely enough) can be decrypted by either
- // extension anyway.
- // Also, it appears that OpenSSL uses 16 rounds regardless of
- // the key size, while RFC2144 says that for key sizes lower
- // than 11 bytes, only 12 rounds should be used. This makes
- // it portable only with keys of between 11 and 16 bytes.
- //
- // - RC4 (ARCFour) has a strange implementation under OpenSSL.
- // Its 'rc4-40' cipher method seems to work flawlessly, yet
- // there's another one, 'rc4' that only works with a 16-byte key.
- //
- // - DES is compatible, but doesn't need an alias.
- //
- // Other seemingly matching ciphers between MCrypt, OpenSSL:
- //
- // - RC2 is NOT compatible and only an obscure forum post
- // confirms that it is MCrypt's fault.
- }
- if (isset($dictionary[$this->_driver][$cipher]))
- {
- $cipher = $dictionary[$this->_driver][$cipher];
- }
- }
- // --------------------------------------------------------------------
- /**
- * HKDF
- *
- * @link https://tools.ietf.org/rfc/rfc5869.txt
- * @param $key Input key
- * @param $digest A SHA-2 hashing algorithm
- * @param $salt Optional salt
- * @param $length Output length (defaults to the selected digest size)
- * @param $info Optional context/application-specific info
- * @return string A pseudo-random key
- */
- public function hkdf($key, $digest = 'sha512', $salt = NULL, $length = NULL, $info = '')
- {
- if ( ! isset($this->_digests[$digest]))
- {
- return FALSE;
- }
- if (empty($length) OR ! is_int($length))
- {
- $length = $this->_digests[$digest];
- }
- elseif ($length > (255 * $this->_digests[$digest]))
- {
- return FALSE;
- }
- self::strlen($salt) OR $salt = str_repeat("\0", $this->_digests[$digest]);
- $prk = hash_hmac($digest, $key, $salt, TRUE);
- $key = '';
- for ($key_block = '', $block_index = 1; self::strlen($key) < $length; $block_index++)
- {
- $key_block = hash_hmac($digest, $key_block.$info.chr($block_index), $prk, TRUE);
- $key .= $key_block;
- }
- return self::substr($key, 0, $length);
- }
- // --------------------------------------------------------------------
- /**
- * __get() magic
- *
- * @param string $key Property name
- * @return mixed
- */
- public function __get($key)
- {
- // Because aliases
- if ($key === 'mode')
- {
- return array_search($this->_mode, $this->_modes[$this->_driver], TRUE);
- }
- elseif (in_array($key, array('cipher', 'driver', 'drivers', 'digests'), TRUE))
- {
- return $this->{'_'.$key};
- }
- return NULL;
- }
- // --------------------------------------------------------------------
- /**
- * Byte-safe strlen()
- *
- * @param string $str
- * @return int
- */
- protected static function strlen($str)
- {
- return (self::$func_overload)
- ? mb_strlen($str, '8bit')
- : strlen($str);
- }
- // --------------------------------------------------------------------
- /**
- * Byte-safe substr()
- *
- * @param string $str
- * @param int $start
- * @param int $length
- * @return string
- */
- protected static function substr($str, $start, $length = NULL)
- {
- if (self::$func_overload)
- {
- // mb_substr($str, $start, null, '8bit') returns an empty
- // string on PHP 5.3
- isset($length) OR $length = ($start >= 0 ? self::strlen($str) - $start : -$start);
- return mb_substr($str, $start, $length, '8bit');
- }
- return isset($length)
- ? substr($str, $start, $length)
- : substr($str, $start);
- }
- }
|