Implemented the first extension: the Encryption extension.
The Encryption Library provides two-way data encryption. To do so in a cryptographically secure way, it utilizes one of multple PHP extensions.
This commit is contained in:
parent
4e9fe8db4a
commit
2cbc431283
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
|
||||
return array(
|
||||
'encryption_key' => '',
|
||||
);
|
|
@ -8,4 +8,5 @@ return array(
|
|||
'administrator_mail' => '',
|
||||
'default_controller' => 'standard',
|
||||
'default_function' => 'index',
|
||||
'application_library_prefix' => 'MY_'
|
||||
);
|
||||
|
|
|
@ -0,0 +1,973 @@
|
|||
<?php
|
||||
/**
|
||||
* FuzeWorks.
|
||||
*
|
||||
* The FuzeWorks MVC PHP FrameWork
|
||||
*
|
||||
* Copyright (C) 2015 TechFuze
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @author TechFuze
|
||||
* @copyright Copyright (c) 2013 - 2016, Techfuze. (http://techfuze.net)
|
||||
* @copyright Copyright (c) 1996 - 2015, Free Software Foundation, Inc. (http://www.fsf.org/)
|
||||
* @license http://opensource.org/licenses/GPL-3.0 GPLv3 License
|
||||
*
|
||||
* @link http://fuzeworks.techfuze.net
|
||||
* @since Version 0.0.1
|
||||
*
|
||||
* @version Version 0.0.1
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 - 2016, 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 - 2016, British Columbia Institute of Technology (http://bcit.ca/)
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 3.0.0
|
||||
* @filesource
|
||||
*/
|
||||
|
||||
namespace FuzeWorks\Library;
|
||||
use FuzeWorks\Core;
|
||||
use FuzeWorks\Logger;
|
||||
use FuzeWorks\LibraryException;
|
||||
use FuzeWorks\Config;
|
||||
|
||||
/**
|
||||
* CodeIgniter Encryption Class.
|
||||
*
|
||||
* Converted to FuzeWorks.
|
||||
*
|
||||
* 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
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
*/
|
||||
class FW_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_override flag
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected static $func_override;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param array $params Configuration parameters
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(array $params = array())
|
||||
{
|
||||
Logger::newLevel('Initializing Encryption Library');
|
||||
$this->_drivers = array(
|
||||
'mcrypt' => defined('MCRYPT_DEV_URANDOM'),
|
||||
// While OpenSSL is available for PHP 5.3.0, an IV parameter
|
||||
// for the encrypt/decrypt functions is only available since 5.3.3
|
||||
'openssl' => (Core::isPHP('5.3.3') && extension_loaded('openssl'))
|
||||
);
|
||||
|
||||
if ( ! $this->_drivers['mcrypt'] && ! $this->_drivers['openssl'])
|
||||
{
|
||||
throw new LibraryException('Encryption: Unable to find an available encryption driver.', 1);
|
||||
}
|
||||
|
||||
isset(self::$func_override) OR self::$func_override = (extension_loaded('mbstring') && ini_get('mbstring.func_override'));
|
||||
$this->initialize($params);
|
||||
|
||||
if ( ! isset($this->_key) && self::strlen($key = Config::get('encryption')->encryption_key) > 0)
|
||||
{
|
||||
$this->_key = $key;
|
||||
}
|
||||
|
||||
Logger::log('Encryption Class Initialized');
|
||||
Logger::stopLevel();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 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
|
||||
{
|
||||
Logger::logError("Encryption: Driver '".$params['driver']."' is not available.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::logError("Encryption: Unknown driver '".$params['driver']."' cannot be configured.");
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($this->_driver))
|
||||
{
|
||||
$this->_driver = ($this->_drivers['openssl'] === TRUE)
|
||||
? 'openssl'
|
||||
: 'mcrypt';
|
||||
|
||||
Logger::logDebug("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))
|
||||
{
|
||||
Logger::logError('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']]))
|
||||
{
|
||||
Logger::logError('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, ''))
|
||||
{
|
||||
Logger::log('Encryption: MCrypt cipher '.strtoupper($this->_cipher).' initialized in '.strtoupper($this->_mode).' mode.');
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::logError('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']]))
|
||||
{
|
||||
Logger::logError('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;
|
||||
Logger::logError('Encryption: Unable to initialize OpenSSL with method '.strtoupper($handle).'.');
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->_handle = $handle;
|
||||
Logger::log('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'))
|
||||
{
|
||||
return random_bytes((int) $length);
|
||||
}
|
||||
|
||||
return ($this->_driver === 'mcrypt')
|
||||
? mcrypt_create_iv($length, MCRYPT_DEV_URANDOM)
|
||||
: openssl_random_pseudo_bytes($length);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 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)
|
||||
? mcrypt_create_iv($iv_size, MCRYPT_DEV_URANDOM)
|
||||
: 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']))
|
||||
? openssl_random_pseudo_bytes($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;
|
||||
}
|
||||
else
|
||||
{
|
||||
$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 integer
|
||||
*/
|
||||
protected static function strlen($str)
|
||||
{
|
||||
return (self::$func_override)
|
||||
? 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_override)
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
}
|
|
@ -187,4 +187,24 @@ class Core
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the current running version of PHP is equal to the input string.
|
||||
*
|
||||
* @param string
|
||||
* @return bool true if running higher than input string
|
||||
*
|
||||
*/
|
||||
public static function isPHP($version)
|
||||
{
|
||||
static $_is_php;
|
||||
$version = (string) $version;
|
||||
|
||||
if ( ! isset($_is_php[$version]))
|
||||
{
|
||||
$_is_php[$version] = version_compare(PHP_VERSION, $version, '>=');
|
||||
}
|
||||
|
||||
return $_is_php[$version];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ class Libraries
|
|||
|
||||
protected static $libraries = array();
|
||||
|
||||
public static function get($libraryName, $parameters = null, $directory = null)
|
||||
public static function get($libraryName, array $parameters = null, $directory = null)
|
||||
{
|
||||
if (empty($libraryName))
|
||||
{
|
||||
|
@ -246,6 +246,7 @@ class Libraries
|
|||
}
|
||||
|
||||
// Now load the class
|
||||
$parameters = (is_null($parameters) ? array() : $parameters);
|
||||
self::$libraries[$class] = new $class($parameters);
|
||||
Logger::log("Loaded Library: ".$class);
|
||||
return $c = self::$libraries[$class];
|
||||
|
|
Loading…
Reference in New Issue