replace mcrypt with openssl
This commit is contained in:
@@ -96,15 +96,11 @@ function rewriteSettingsFile($base_urls = null, $theme = null, $array_db = null)
|
||||
$defines['_DB_PASSWD_'] = (($array_db && isset($array_db['_DB_PASSWD_'])) ? $array_db['_DB_PASSWD_'] : _DB_PASSWD_);
|
||||
$defines['_COOKIE_KEY_'] = addslashes(_COOKIE_KEY_);
|
||||
$defines['_COOKIE_IV_'] = addslashes(_COOKIE_IV_);
|
||||
$defines['_NEW_COOKIE_KEY_'] = addslashes(_NEW_COOKIE_KEY_);
|
||||
$defines['_PS_CREATION_DATE_'] = addslashes(_PS_CREATION_DATE_);
|
||||
|
||||
if (defined('_RIJNDAEL_KEY_')) {
|
||||
$defines['_RIJNDAEL_KEY_'] = addslashes(_RIJNDAEL_KEY_);
|
||||
}
|
||||
if (defined('_RIJNDAEL_IV_')) {
|
||||
$defines['_RIJNDAEL_IV_'] = addslashes(_RIJNDAEL_IV_);
|
||||
}
|
||||
$defines['_PS_VERSION_'] = addslashes(_PS_VERSION_);
|
||||
$defines['_QLOAPPS_VERSION_'] = addslashes(_QLOAPPS_VERSION_);
|
||||
$content = "<?php\n\n";
|
||||
foreach ($defines as $k => $value) {
|
||||
if ($k == '_PS_VERSION_') {
|
||||
|
||||
@@ -87,6 +87,7 @@ class ConfigurationTestCore
|
||||
'config_dir' => 'config',
|
||||
'files' => false,
|
||||
'mails_dir' => 'mails',
|
||||
'openssl' => false,
|
||||
'curl' => false,
|
||||
'soap' => false,
|
||||
'simplexml' => false,
|
||||
@@ -112,7 +113,6 @@ class ConfigurationTestCore
|
||||
'new_phpversion' => false,
|
||||
'register_globals' => false,
|
||||
'gz' => false,
|
||||
'mcrypt' => false,
|
||||
'mbstring' => false,
|
||||
'magicquotes' => false,
|
||||
'dom' => false,
|
||||
@@ -145,12 +145,12 @@ class ConfigurationTestCore
|
||||
|
||||
public static function test_phpversion()
|
||||
{
|
||||
return version_compare(substr(phpversion(), 0, 5), '5.4.0', '>=');
|
||||
return version_compare(substr(phpversion(), 0, 5), '5.6.0', '>=');
|
||||
}
|
||||
|
||||
public static function test_new_phpversion()
|
||||
{
|
||||
return version_compare(substr(phpversion(), 0, 5), '5.4.0', '>=');
|
||||
return version_compare(substr(phpversion(), 0, 5), '5.6.0', '>=');
|
||||
}
|
||||
|
||||
public static function test_mysql_support()
|
||||
@@ -394,9 +394,9 @@ class ConfigurationTestCore
|
||||
return function_exists('mb_strtolower');
|
||||
}
|
||||
|
||||
public static function test_mcrypt()
|
||||
public static function test_openssl()
|
||||
{
|
||||
return function_exists('mcrypt_encrypt');
|
||||
return function_exists('openssl_encrypt');
|
||||
}
|
||||
|
||||
public static function test_sessions()
|
||||
|
||||
@@ -76,7 +76,7 @@ class CookieCore
|
||||
$this->_name = 'PrestaShop-'.md5(($this->_standalone ? '' : _PS_VERSION_).$name.$this->_domain);
|
||||
$this->_allow_writing = true;
|
||||
$this->_salt = $this->_standalone ? str_pad('', 8, md5('ps'.__FILE__)) : _COOKIE_IV_;
|
||||
$this->_cipherTool = new Rijndael(_RIJNDAEL_KEY_, _RIJNDAEL_IV_);
|
||||
$this->_cipherTool = new PhpEncryption(_NEW_COOKIE_KEY_);
|
||||
$this->_secure = (bool)$secure;
|
||||
|
||||
$this->update();
|
||||
@@ -324,6 +324,11 @@ class CookieCore
|
||||
*/
|
||||
protected function _setcookie($cookie = null)
|
||||
{
|
||||
$length = (ini_get('mbstring.func_overload') & 2) ? mb_strlen($cookie, ini_get('default_charset')) : strlen($cookie);
|
||||
if ($length >= 1048576) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($cookie) {
|
||||
$content = $this->_cipherTool->encrypt($cookie);
|
||||
$time = $this->_expire;
|
||||
|
||||
122
classes/PhpEncryption.php
Normal file
122
classes/PhpEncryption.php
Normal file
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
/**
|
||||
* 2007-2018 PrestaShop.
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to http://www.prestashop.com for more information.
|
||||
*
|
||||
* @author PrestaShop SA <contact@prestashop.com>
|
||||
* @copyright 2007-2018 PrestaShop SA
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
use Defuse\Crypto\Exception\EnvironmentIsBrokenException;
|
||||
|
||||
/**
|
||||
* Class PhpEncryptionCore for openSSL 1.0.1+.
|
||||
*/
|
||||
class PhpEncryptionCore
|
||||
{
|
||||
const ENGINE = 'PhpEncryptionEngine';
|
||||
const LEGACY_ENGINE = 'PhpEncryptionLegacyEngine';
|
||||
|
||||
private static $engine;
|
||||
|
||||
/**
|
||||
* PhpEncryptionCore constructor.
|
||||
*
|
||||
* @param string $hexString A string that only contains hexadecimal characters
|
||||
* Bother upper and lower case are allowed
|
||||
*/
|
||||
public function __construct($hexString)
|
||||
{
|
||||
$engineClass = self::resolveEngineToUse();
|
||||
self::$engine = new $engineClass($hexString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt the plaintext.
|
||||
*
|
||||
* @param string $plaintext Plaintext
|
||||
*
|
||||
* @return string Cipher text
|
||||
*/
|
||||
public function encrypt($plaintext)
|
||||
{
|
||||
return self::$engine->encrypt($plaintext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt the cipher text.
|
||||
*
|
||||
* @param string $cipherText Cipher text
|
||||
*
|
||||
* @return bool|string Plaintext
|
||||
* `false` if unable to decrypt
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function decrypt($cipherText)
|
||||
{
|
||||
return self::$engine->decrypt($cipherText);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $header
|
||||
* @param $bytes
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws \Defuse\Crypto\Exception\EnvironmentIsBrokenException
|
||||
*/
|
||||
public static function saveBytesToChecksummedAsciiSafeString($header, $bytes)
|
||||
{
|
||||
$engine = self::resolveEngineToUse();
|
||||
|
||||
return $engine::saveBytesToChecksummedAsciiSafeString($header, $bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function createNewRandomKey()
|
||||
{
|
||||
$engine = self::resolveEngineToUse();
|
||||
|
||||
try {
|
||||
$randomKey = $engine::createNewRandomKey();
|
||||
} catch (EnvironmentIsBrokenException $exception) {
|
||||
$buf = $engine::randomCompat();
|
||||
$randomKey = $engine::saveToAsciiSafeString($buf);
|
||||
}
|
||||
|
||||
return $randomKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Choose which engine use regarding the OpenSSL cipher methods available.
|
||||
*/
|
||||
public static function resolveEngineToUse()
|
||||
{
|
||||
if (false === in_array(\Defuse\Crypto\Core::CIPHER_METHOD, openssl_get_cipher_methods())) {
|
||||
return self::LEGACY_ENGINE;
|
||||
}
|
||||
|
||||
return self::ENGINE;
|
||||
}
|
||||
}
|
||||
168
classes/PhpEncryptionEngine.php
Normal file
168
classes/PhpEncryptionEngine.php
Normal file
@@ -0,0 +1,168 @@
|
||||
<?php
|
||||
/**
|
||||
* 2007-2018 PrestaShop.
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to http://www.prestashop.com for more information.
|
||||
*
|
||||
* @author PrestaShop SA <contact@prestashop.com>
|
||||
* @copyright 2007-2018 PrestaShop SA
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
use Defuse\Crypto\Crypto;
|
||||
use Defuse\Crypto\Encoding;
|
||||
use Defuse\Crypto\Key;
|
||||
|
||||
/**
|
||||
* Class PhpEncryption engine for openSSL 1.0.1+.
|
||||
*/
|
||||
class PhpEncryptionEngineCore
|
||||
{
|
||||
protected $key;
|
||||
|
||||
/**
|
||||
* PhpEncryptionCore constructor.
|
||||
*
|
||||
* @param string $hexString A string that only contains hexadecimal characters
|
||||
* Bother upper and lower case are allowed
|
||||
*/
|
||||
public function __construct($hexString)
|
||||
{
|
||||
$this->key = self::loadFromAsciiSafeString($hexString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt the plaintext.
|
||||
*
|
||||
* @param string $plaintext Plaintext
|
||||
*
|
||||
* @return string Cipher text
|
||||
*/
|
||||
public function encrypt($plaintext)
|
||||
{
|
||||
return Crypto::encrypt($plaintext, $this->key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt the cipher text.
|
||||
*
|
||||
* @param string $cipherText Cipher text
|
||||
*
|
||||
* @return bool|string Plaintext
|
||||
* `false` if unable to decrypt
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function decrypt($cipherText)
|
||||
{
|
||||
try {
|
||||
$plaintext = Crypto::decrypt($cipherText, $this->key);
|
||||
} catch (Exception $e) {
|
||||
if ($e instanceof \Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException) {
|
||||
return false;
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return $plaintext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $header
|
||||
* @param $bytes
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws \Defuse\Crypto\Exception\EnvironmentIsBrokenException
|
||||
*/
|
||||
public static function saveBytesToChecksummedAsciiSafeString($header, $bytes)
|
||||
{
|
||||
return Encoding::saveBytesToChecksummedAsciiSafeString($header, $bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function createNewRandomKey()
|
||||
{
|
||||
$key = Key::createNewRandomKey();
|
||||
|
||||
return $key->saveToAsciiSafeString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $hexString
|
||||
*
|
||||
* @return Key
|
||||
*/
|
||||
public static function loadFromAsciiSafeString($hexString)
|
||||
{
|
||||
return Key::loadFromAsciiSafeString($hexString);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*
|
||||
* @throws Exception
|
||||
*
|
||||
* @see https://github.com/paragonie/random_compat/blob/v1.4.1/lib/random_bytes_openssl.php
|
||||
* @see https://github.com/paragonie/random_compat/blob/v1.4.1/lib/random_bytes_mcrypt.php
|
||||
*/
|
||||
public static function randomCompat()
|
||||
{
|
||||
$bytes = Key::KEY_BYTE_SIZE;
|
||||
|
||||
$secure = true;
|
||||
$buf = openssl_random_pseudo_bytes($bytes, $secure);
|
||||
if (
|
||||
$buf !== false
|
||||
&&
|
||||
$secure
|
||||
&&
|
||||
RandomCompat_strlen($buf) === $bytes
|
||||
) {
|
||||
return $buf;
|
||||
}
|
||||
|
||||
$buf = @mcrypt_create_iv($bytes, MCRYPT_DEV_URANDOM);
|
||||
if (
|
||||
$buf !== false
|
||||
&&
|
||||
RandomCompat_strlen($buf) === $bytes
|
||||
) {
|
||||
return $buf;
|
||||
}
|
||||
|
||||
throw new Exception(
|
||||
'Could not gather sufficient random data'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $buf
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function saveToAsciiSafeString($buf)
|
||||
{
|
||||
return Encoding::saveBytesToChecksummedAsciiSafeString(
|
||||
Key::KEY_CURRENT_VERSION,
|
||||
$buf
|
||||
);
|
||||
}
|
||||
}
|
||||
168
classes/PhpEncryptionLegacyEngine.php
Normal file
168
classes/PhpEncryptionLegacyEngine.php
Normal file
@@ -0,0 +1,168 @@
|
||||
<?php
|
||||
/**
|
||||
* 2007-2018 PrestaShop.
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to http://www.prestashop.com for more information.
|
||||
*
|
||||
* @author PrestaShop SA <contact@prestashop.com>
|
||||
* @copyright 2007-2018 PrestaShop SA
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class PhpEncryption engine for openSSL < 0.9.8.
|
||||
*
|
||||
* @doc http://php.net/manual/fr/function.mcrypt-encrypt.php#refsect1-function.mcrypt-encrypt-examples
|
||||
*
|
||||
* This class will be deprecated when web hosting providers will update their version of OpenSSL.
|
||||
*/
|
||||
class PhpEncryptionLegacyEngineCore extends PhpEncryptionEngine
|
||||
{
|
||||
protected $key;
|
||||
protected $hmacIv;
|
||||
protected $iv;
|
||||
protected $ivSize;
|
||||
|
||||
protected $mode = MCRYPT_MODE_CBC;
|
||||
protected $cipher = MCRYPT_RIJNDAEL_128;
|
||||
|
||||
/**
|
||||
* PhpEncryptionCore constructor.
|
||||
*
|
||||
* @param string $hexString A string that only contains hexadecimal characters
|
||||
* Bother upper and lower case are allowed
|
||||
*/
|
||||
public function __construct($hexString)
|
||||
{
|
||||
$this->key = substr($hexString, 0, 32);
|
||||
$this->ivSize = mcrypt_get_iv_size($this->cipher, $this->mode);
|
||||
$this->iv = mcrypt_create_iv($this->ivSize, MCRYPT_RAND);
|
||||
$this->hmacIv = substr(sha1(_COOKIE_KEY_), 0, $this->ivSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt the plaintext.
|
||||
*
|
||||
* @param string $plaintext Plaintext
|
||||
*
|
||||
* @return string Cipher text
|
||||
*/
|
||||
public function encrypt($plaintext)
|
||||
{
|
||||
$blockSize = mcrypt_get_block_size($this->cipher, $this->mode);
|
||||
$pad = $blockSize - (strlen($plaintext) % $blockSize);
|
||||
|
||||
$cipherText = mcrypt_encrypt(
|
||||
$this->cipher,
|
||||
$this->key,
|
||||
$plaintext . str_repeat(chr($pad), $pad),
|
||||
$this->mode,
|
||||
$this->iv
|
||||
);
|
||||
$cipherText = $this->iv . $cipherText;
|
||||
|
||||
return $this->generateHmac($cipherText) . ':' . base64_encode($cipherText);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt the cipher text.
|
||||
*
|
||||
* @param string $cipherText Cipher text
|
||||
*
|
||||
* @return bool|string Plaintext
|
||||
* `false` if unable to decrypt
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function decrypt($cipherText)
|
||||
{
|
||||
$data = explode(':', $cipherText);
|
||||
if (count($data) != 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
list($hmac, $encrypted) = $data;
|
||||
$encrypted = base64_decode($encrypted);
|
||||
$newHmac = $this->generateHmac($encrypted);
|
||||
if ($hmac !== $newHmac) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$ivDec = substr($encrypted, 0, $this->ivSize);
|
||||
$cipherText = substr($encrypted, $this->ivSize);
|
||||
|
||||
$data = mcrypt_decrypt(
|
||||
$this->cipher,
|
||||
$this->key,
|
||||
$cipherText,
|
||||
$this->mode,
|
||||
$ivDec
|
||||
);
|
||||
|
||||
$pad = ord($data[strlen($data) - 1]);
|
||||
|
||||
return substr($data, 0, -$pad);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate Hmac.
|
||||
*
|
||||
* @param string $encrypted
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function generateHmac($encrypted)
|
||||
{
|
||||
$macKey = $this->generateKeygenS2k('sha256', $this->key, $this->hmacIv, 32);
|
||||
|
||||
return hash_hmac(
|
||||
'sha256',
|
||||
$this->hmacIv . $this->cipher . $encrypted,
|
||||
$macKey
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alternative to mhash_keygen_s2k for security reason
|
||||
* and php compatibilities.
|
||||
*
|
||||
* @param string $hash
|
||||
* @param string $password
|
||||
* @param string $salt
|
||||
* @param int $bytes
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function generateKeygenS2k($hash, $password, $salt, $bytes)
|
||||
{
|
||||
$result = '';
|
||||
foreach (range(0, ceil($bytes / strlen(hash($hash, null, true))) - 1) as $i) {
|
||||
$result .= hash(
|
||||
$hash,
|
||||
str_repeat("\0", $i) . str_pad(substr($salt, 0, 8), 8, "\0", STR_PAD_RIGHT) . $password,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
return substr(
|
||||
$result,
|
||||
0,
|
||||
intval($bytes)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* 2007-2018 PrestaShop
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* http://opensource.org/licenses/osl-3.0.php
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to http://www.prestashop.com for more information.
|
||||
*
|
||||
* @author PrestaShop SA <contact@prestashop.com>
|
||||
* @copyright 2007-2018 PrestaShop SA
|
||||
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
|
||||
class RijndaelCore
|
||||
{
|
||||
protected $_key;
|
||||
protected $_iv;
|
||||
|
||||
public function __construct($key, $iv)
|
||||
{
|
||||
$this->_key = $key;
|
||||
$this->_iv = base64_decode($iv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Base64 is not required, but it is be more compact than urlencode
|
||||
*
|
||||
* @param string $plaintext
|
||||
* @return bool|string
|
||||
*/
|
||||
public function encrypt($plaintext)
|
||||
{
|
||||
if (strlen($plaintext) >= 1048576) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$cipherText = null;
|
||||
if (function_exists('openssl_encrypt') && version_compare(phpversion(), '5.3.3', '>=')) {
|
||||
$cipherText = openssl_encrypt($plaintext, 'AES-128-CBC', $this->_key, OPENSSL_RAW_DATA, $this->_iv);
|
||||
} elseif (function_exists('mcrypt_encrypt')) {
|
||||
$ivSize = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
|
||||
$iv = mcrypt_create_iv($ivSize, MCRYPT_RAND);
|
||||
$blockSize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
|
||||
$pad = $blockSize - (strlen($plaintext) % $blockSize);
|
||||
|
||||
$cipherText = mcrypt_encrypt(
|
||||
MCRYPT_RIJNDAEL_128,
|
||||
$this->_key,
|
||||
$plaintext . str_repeat(chr($pad), $pad),
|
||||
MCRYPT_MODE_CBC,
|
||||
$iv
|
||||
);
|
||||
$cipherText = $iv.$cipherText;
|
||||
} else {
|
||||
throw new RuntimeException('Either Mcrypt or OpenSSL extension is required to run Prestashop');
|
||||
}
|
||||
|
||||
return $this->generateHmac($cipherText) . ':' . base64_encode($cipherText);
|
||||
}
|
||||
|
||||
public function decrypt($cipherText)
|
||||
{
|
||||
$data = explode(':', $cipherText);
|
||||
if (count($data) != 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
list($hmac, $encrypted) = $data;
|
||||
|
||||
$encrypted = base64_decode($encrypted);
|
||||
$newHmac = $this->generateHmac($encrypted);
|
||||
if ($hmac !== $newHmac) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$output = null;
|
||||
if (function_exists('openssl_decrypt') && version_compare(phpversion(), '5.3.3', '>=')) {
|
||||
$output = openssl_decrypt($encrypted, 'AES-128-CBC', $this->_key, OPENSSL_RAW_DATA, $this->_iv);
|
||||
} elseif (function_exists('mcrypt_decrypt')) {
|
||||
$ivSize = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
|
||||
$ivDec = substr($encrypted, 0, $ivSize);
|
||||
$encrypted = substr($encrypted, $ivSize);
|
||||
$output = mcrypt_decrypt(
|
||||
MCRYPT_RIJNDAEL_128,
|
||||
$this->_key,
|
||||
$encrypted,
|
||||
MCRYPT_MODE_CBC,
|
||||
$ivDec
|
||||
);
|
||||
$pad = ord($output[strlen($output) - 1]);
|
||||
$output = substr($output, 0, -$pad);
|
||||
} else {
|
||||
throw new RuntimeException('Either Mcrypt or OpenSSL extension is required to run Prestashop');
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate Hmac
|
||||
*
|
||||
* @param string $encrypted
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function generateHmac($encrypted)
|
||||
{
|
||||
$macKey = $this->generateKeygenS2k('sha256', $this->_key, $this->_iv, 32);
|
||||
return hash_hmac(
|
||||
'sha256',
|
||||
$this->_iv . MCRYPT_RIJNDAEL_128 . $encrypted,
|
||||
$macKey
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alternative to mhash_keygen_s2k for security reason
|
||||
* and php compatibilities.
|
||||
*
|
||||
* @param string $hash
|
||||
* @param string $password
|
||||
* @param string $salt
|
||||
* @param integer $bytes
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function generateKeygenS2k($hash, $password, $salt, $bytes)
|
||||
{
|
||||
$result = '';
|
||||
foreach (range(0, ceil($bytes / strlen(hash($hash, null, true))) - 1) as $i) {
|
||||
$result .= hash(
|
||||
$hash,
|
||||
str_repeat("\0", $i) . str_pad(substr($salt, 0, 8), 8, "\0", STR_PAD_RIGHT) . $password,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
return substr(
|
||||
$result,
|
||||
0,
|
||||
intval($bytes)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@
|
||||
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
require_once (_PS_TOOL_DIR_.'defuse/php-encryption/defuse-crypto.phar');
|
||||
|
||||
// Include some alias functions
|
||||
require_once(_PS_CONFIG_DIR_.'alias.php');
|
||||
|
||||
@@ -128,7 +128,8 @@ class AdminInformationControllerCore extends AdminController
|
||||
'register_globals' => $this->l('Set PHP "register_globals" option to "Off".'),
|
||||
'gz' => $this->l('Enable GZIP compression on your server.'),
|
||||
'files' => $this->l('Some PrestaShop files are missing from your server.'),
|
||||
'new_phpversion' => sprintf($this->l('You are using PHP %s version. Soon, the latest PHP version supported by PrestaShop will be PHP 5.4. To make sure you’re ready for the future, we recommend you to upgrade to PHP 5.4 now!'), phpversion())
|
||||
'new_phpversion' => sprintf($this->l('You are using PHP %s version. Soon, the latest PHP version supported by PrestaShop will be PHP 5.4. To make sure you’re ready for the future, we recommend you to upgrade to PHP 5.4 now!'), phpversion()),
|
||||
'openssl' => $this->l('PHP OpenSSL extension is not loaded'),
|
||||
);
|
||||
|
||||
// Functions list to test with 'test_system'
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
|
||||
require_once (_PS_TOOL_DIR_.'defuse/php-encryption/defuse-crypto.phar');
|
||||
|
||||
class InstallModelInstall extends InstallAbstractModel
|
||||
{
|
||||
const SETTINGS_FILE = 'config/settings.inc.php';
|
||||
@@ -69,6 +71,7 @@ class InstallModelInstall extends InstallAbstractModel
|
||||
$this->setError($this->language->l('%s folder is not writable (check permissions)', dirname(self::SETTINGS_FILE)));
|
||||
return false;
|
||||
}
|
||||
$key = \Defuse\Crypto\Key::createNewRandomKey();
|
||||
|
||||
// Generate settings content and write file
|
||||
$settings_constants = array(
|
||||
@@ -82,17 +85,12 @@ class InstallModelInstall extends InstallAbstractModel
|
||||
'_PS_CACHE_ENABLED_' => '0',
|
||||
'_COOKIE_KEY_' => Tools::passwdGen(56),
|
||||
'_COOKIE_IV_' => Tools::passwdGen(8),
|
||||
'_NEW_COOKIE_KEY_' => $key->saveToAsciiSafeString(),
|
||||
'_PS_CREATION_DATE_' => date('Y-m-d'),
|
||||
'_PS_VERSION_' => _PS_INSTALL_VERSION_,
|
||||
'_QLOAPPS_VERSION_' => _QLO_INSTALL_VERSION_,
|
||||
);
|
||||
|
||||
// If mcrypt is activated, add Rijndael 128 configuration
|
||||
if (function_exists('mcrypt_encrypt')) {
|
||||
$settings_constants['_RIJNDAEL_KEY_'] = Tools::passwdGen(mcrypt_get_key_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC));
|
||||
$settings_constants['_RIJNDAEL_IV_'] = base64_encode(mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_RAND));
|
||||
}
|
||||
|
||||
$settings_content = "<?php\n";
|
||||
|
||||
foreach ($settings_constants as $constant => $value) {
|
||||
|
||||
29
tools/defuse/index.php
Normal file
29
tools/defuse/index.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
/**
|
||||
* 2010-2021 Webkul.
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* All right is reserved,
|
||||
* Please go through this link for complete license : https://store.webkul.com/license.html
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade this module to newer
|
||||
* versions in the future. If you wish to customize this module for your
|
||||
* needs please refer to https://store.webkul.com/customisation-guidelines/ for more information.
|
||||
*
|
||||
* @author Webkul IN <support@webkul.com>
|
||||
* @copyright 2010-2021 Webkul IN
|
||||
* @license https://store.webkul.com/license.html
|
||||
*/
|
||||
|
||||
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
|
||||
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
|
||||
|
||||
header('Cache-Control: no-store, no-cache, must-revalidate');
|
||||
header('Cache-Control: post-check=0, pre-check=0', false);
|
||||
header('Pragma: no-cache');
|
||||
|
||||
header('Location: ../');
|
||||
exit;
|
||||
21
tools/defuse/php-encryption/LICENSE
Normal file
21
tools/defuse/php-encryption/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Taylor Hornby <https://defuse.ca> and Paragon Initiative
|
||||
Enterprises <https://paragonie.com>.
|
||||
|
||||
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.
|
||||
87
tools/defuse/php-encryption/README.md
Normal file
87
tools/defuse/php-encryption/README.md
Normal file
@@ -0,0 +1,87 @@
|
||||
php-encryption
|
||||
===============
|
||||
|
||||
[](https://travis-ci.org/defuse/php-encryption)
|
||||
|
||||
This is a library for encrypting data with a key or password in PHP. **It
|
||||
requires PHP 5.4 or newer.** The current version is v2.0.0, which is expected to
|
||||
remain stable and supported by its authors with security and bugfixes until at
|
||||
least January 1st, 2019.
|
||||
|
||||
The library is a joint effort between [Taylor Hornby](https://defuse.ca/) and
|
||||
[Scott Arciszewski](https://paragonie.com/blog/author/scott-arcizewski) as well
|
||||
as numerous open-source contributors.
|
||||
|
||||
What separates this library from other PHP encryption libraries is, firstly,
|
||||
that it is secure. The authors used to encounter insecure PHP encryption code on
|
||||
a daily basis, so they created this library to bring more security to the
|
||||
ecosystem. Secondly, this library is "difficult to misuse." Like
|
||||
[libsodium](https://github.com/jedisct1/libsodium), its API is designed to be
|
||||
easy to use in a secure way and hard to use in an insecure way.
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
This library requres no special dependencies except for PHP 5.4 or newer with
|
||||
the OpenSSL extensions enabled (this is the default). It uses
|
||||
[random\_compat](https://github.com/paragonie/random_compat), which is bundled
|
||||
in with this library so that your users will not need to follow any special
|
||||
installation steps.
|
||||
|
||||
Getting Started
|
||||
----------------
|
||||
|
||||
Start with the [**Tutorial**](docs/Tutorial.md). You can find instructions for
|
||||
obtaining this library's code securely in the [Installing and
|
||||
Verifying](docs/InstallingAndVerifying.md) documentation.
|
||||
|
||||
After you've read the tutorial and got the code, refer to the formal
|
||||
documentation for each of the classes this library provides:
|
||||
|
||||
- [Crypto](docs/classes/Crypto.md)
|
||||
- [File](docs/classes/File.md)
|
||||
- [Key](docs/classes/Key.md)
|
||||
- [KeyProtectedByPassword](docs/classes/KeyProtectedByPassword.md)
|
||||
|
||||
If you encounter difficulties, see the [FAQ](docs/FAQ.md) answers. The fixes to
|
||||
the most commonly-reported problems are explained there.
|
||||
|
||||
If you're a cryptographer and want to understand the nitty-gritty details of how
|
||||
this library works, look at the [Cryptography Details](docs/CryptoDetails.md)
|
||||
documentation.
|
||||
|
||||
If you're interested in contributing to this library, see the [Internal
|
||||
Developer Documentation](docs/InternalDeveloperDocs.md).
|
||||
|
||||
Examples
|
||||
---------
|
||||
|
||||
If the documentation is not enough for you to understand how to use this
|
||||
library, then you can look at an example project that uses this library:
|
||||
|
||||
- [encutil](https://github.com/defuse/encutil)
|
||||
|
||||
Security Audit Status
|
||||
---------------------
|
||||
|
||||
This code has not been subjected to a formal, paid, security audit. However, it
|
||||
has received lots of review from members of the PHP security community, and the
|
||||
authors are experienced with cryptography. In all likelihood, you are safer
|
||||
using this library than almost any other encryption library for PHP.
|
||||
|
||||
If you use this library as a part of your business and would like to help fund
|
||||
a formal audit, please [contact Taylor Hornby](https://defuse.ca/contact.htm).
|
||||
|
||||
Public Keys
|
||||
------------
|
||||
|
||||
The GnuPG public key used to sign releases is available in
|
||||
[dist/signingkey.asc](https://github.com/defuse/php-encryption/raw/master/dist/signingkey.asc). Its fingerprint is:
|
||||
|
||||
```
|
||||
2FA6 1D8D 99B9 2658 6BAC 3D53 385E E055 A129 1538
|
||||
```
|
||||
|
||||
You can verify it against the Taylor Hornby's [contact
|
||||
page](https://defuse.ca/contact.htm) and
|
||||
[twitter](https://twitter.com/DefuseSec/status/723741424253059074).
|
||||
BIN
tools/defuse/php-encryption/defuse-crypto.phar
Normal file
BIN
tools/defuse/php-encryption/defuse-crypto.phar
Normal file
Binary file not shown.
37
tools/defuse/php-encryption/dist/Makefile
vendored
Normal file
37
tools/defuse/php-encryption/dist/Makefile
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
# This builds defuse-crypto.phar. To run this Makefile, `box` and `composer`
|
||||
# must be installed and in your $PATH. Run it from inside the dist/ directory.
|
||||
|
||||
box := $(shell which box)
|
||||
composer := "composer"
|
||||
|
||||
.PHONY: all
|
||||
all: build-phar
|
||||
|
||||
.PHONY: sign-phar
|
||||
sign-phar:
|
||||
gpg -u 7B4B2D98 --armor --output defuse-crypto.phar.sig --detach-sig defuse-crypto.phar
|
||||
|
||||
# ensure we run in clean tree. export git tree and run there.
|
||||
.PHONY: build-phar
|
||||
build-phar:
|
||||
@echo "Creating .phar from revision $(shell git rev-parse HEAD)."
|
||||
rm -rf worktree
|
||||
install -d worktree
|
||||
(cd $(CURDIR)/..; git archive HEAD) | tar -x -C worktree
|
||||
$(MAKE) -f $(CURDIR)/Makefile -C worktree defuse-crypto.phar
|
||||
mv worktree/*.phar .
|
||||
rm -rf worktree
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -vf defuse-crypto.phar defuse-crypto.phar.sig
|
||||
|
||||
# Inside workdir/:
|
||||
|
||||
defuse-crypto.phar: dist/box.json composer.lock
|
||||
cp dist/box.json .
|
||||
php -d phar.readonly=0 $(box) build -c box.json -v
|
||||
|
||||
composer.lock:
|
||||
$(composer) install --no-dev
|
||||
|
||||
25
tools/defuse/php-encryption/dist/box.json
vendored
Normal file
25
tools/defuse/php-encryption/dist/box.json
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"chmod": "0755",
|
||||
"finder": [
|
||||
{
|
||||
"in": "src",
|
||||
"name": "*.php"
|
||||
},
|
||||
{
|
||||
"in": "vendor/composer",
|
||||
"name": "*.php"
|
||||
},
|
||||
{
|
||||
"in": "vendor/paragonie",
|
||||
"name": "*.php",
|
||||
"exclude": "other"
|
||||
}
|
||||
],
|
||||
"compactors": [
|
||||
"Herrera\\Box\\Compactor\\Php"
|
||||
],
|
||||
"main": "vendor/autoload.php",
|
||||
"output": "defuse-crypto.phar",
|
||||
"shebang": false,
|
||||
"stub": true
|
||||
}
|
||||
29
tools/defuse/php-encryption/dist/index.php
vendored
Normal file
29
tools/defuse/php-encryption/dist/index.php
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
/**
|
||||
* 2010-2021 Webkul.
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* All right is reserved,
|
||||
* Please go through this link for complete license : https://store.webkul.com/license.html
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade this module to newer
|
||||
* versions in the future. If you wish to customize this module for your
|
||||
* needs please refer to https://store.webkul.com/customisation-guidelines/ for more information.
|
||||
*
|
||||
* @author Webkul IN <support@webkul.com>
|
||||
* @copyright 2010-2021 Webkul IN
|
||||
* @license https://store.webkul.com/license.html
|
||||
*/
|
||||
|
||||
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
|
||||
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
|
||||
|
||||
header('Cache-Control: no-store, no-cache, must-revalidate');
|
||||
header('Cache-Control: post-check=0, pre-check=0', false);
|
||||
header('Pragma: no-cache');
|
||||
|
||||
header('Location: ../');
|
||||
exit;
|
||||
52
tools/defuse/php-encryption/dist/signingkey.asc
vendored
Normal file
52
tools/defuse/php-encryption/dist/signingkey.asc
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
Version: GnuPG v2
|
||||
|
||||
mQINBFarvO4BEACdQBaLt6SUBx1cB5liUu1qo+YwVLh9bxTregQtmEREMdTVqXYt
|
||||
e5b79uL4pQp2GlKHcEyRURS+6rIIruM0oh9ZYGTJYPAkCDzJxaU2awZeFbfBvpCm
|
||||
iF66/O4ZJI4mlT8dFKmxBJxDhfeOR2UmmhDiEsJK9FxBKUzvo/dWrX2pBzf8Y122
|
||||
iIaVraSo+tymaf7vriaIf/NnSKhDw8dtQYGM4NMrxxsPTfbCF8XiboDgTkoD2A+6
|
||||
NpOJYxA4Veedsf2TP9YLhljH4m5yYlfjjqBzbBCPWuE6Hhy5Xze9mncgDr7LKenm
|
||||
Ctf2NxW6y4O3RCI+9eLlBfFWB+KuGV87/b5daetX7NNLbjID8z2rqEa+d6wu5xA5
|
||||
Ta2uiVkAOEovr3XnkayZ9zth+Za7w7Ai0ln0N/LVMkM+Gu4z/pJv6HjmTGDM2wJb
|
||||
fs+UOM0TFdg+N81Do67XT2M4o0MeHyUqsIiWpYa2Qf1PNmqTQNJnRk8uZZ9I96Nh
|
||||
eCgNuCbhsQiYBMicox+xmuWAlGAfA06y0kCtmqGhiBGArdJlWvUqPqGiZ4Hln9z0
|
||||
FJmXDOh0Q/FIPxcDg8mKRRbx+lOP389PLsPpj4b2B/4PEgfpCCOwuKpLotATZxC1
|
||||
9JwFk0Y/cvUUkq4a+nAJBNtBbtRJkEesuuUnRq6XexmnE3uUucDcV0XCSwARAQAB
|
||||
tCBUYXlsb3IgSG9ybmJ5IDx0YXlsb3JAZGVmdXNlLmNhPokCPQQTAQgAJwUCVqu8
|
||||
7gIbAwUJB4TOAAULCQgHAgYVCAkKCwIEFgIDAQIeAQIXgAAKCRA4XuBVoSkVOJbx
|
||||
EACG0F9blPMAsK05EWyNnnS4mw25zPfbaqqEvYbquAeM0nBpRDm7sRn2MNR0AL4g
|
||||
7XrtxE/4qYkdEl6f2wFCQeRhZgxE3w22llredzLme11Hic8hn4i7ysdIw0r9dMMR
|
||||
kjgR5UcWpv8iU847czyK09PkKW2EaLRbX2qbA7rNU5qCFKeD4Sy4bBTteISeVsHo
|
||||
Vr9o1/bRrMhgZ++ts8hYf0LmujIf5cxp+qcdKwCXSnS/gmmXaKRMCPv/Wdlq9bt6
|
||||
LX9jZB9lXBdGxcBJeFOsTG+QRDiVjg3d6i3o3TAKV87ALBI4v2ADEYtN8lviHo3/
|
||||
SovVKv6zrUsZHxhoGiLTiksNrYsKMmiMxdJCoOazmtUPnZ4UOtT8NdqMPoKvdoRz
|
||||
f4rhZ+f5jSVD9OuX2PDmfyq21Rdiym7Vcgr+uTIFJ3ShRHjWb/ytCwoB2FeGY6+G
|
||||
AKY58bTQvUIqEJvSov/+TAqZ4BfOuSdTLcHglV1OdUu2SFZvU2gmyVp0l5elGv5t
|
||||
FyUlBJUkQT9MtvsdLOR7vQi8QapV+9LWpqwvaj9hyEJz848DQ2sdYTphUytFHv7H
|
||||
k58DAtVhTrVjHyeefjiYtMl6vSAgTjy5LWAUpo5TfhdGrAi0Tdd/GD7amHoWoDy8
|
||||
EKXKq2xPLo3JOdkWYQUi5NErzEskfsSzpCOgyDJmGetWK7kCDQRWq7zuARAAu7/i
|
||||
cm8cjgLhHEX/bgfwOT2hLOLSjjve0O8YFSuJO9XqIHXqmfVOrqWtfG0Mh4bwlfqc
|
||||
MAvBfF5NSSPfAE4ftBAQ1e5jEv8hJeqICpq3IHTFX4etBs49NfNkyveQl/amVTu1
|
||||
+/O5J4CuIcsEf3y0Xuu38n7EB3SfMQCWLcOR1NyZoX3bI+CGRpOVVoFse3ljSWL4
|
||||
LhLVl0WiEMXULsussEoN+c6x9KCyAi/jFOrxrTrFC//sZesKj6KucoqKGfwMWrrv
|
||||
IeRT9Ga8Wn5MJnQu0aWg+zVVYqTedXZLNLODgQIInFnXO0seBXy15yDok1y5bkx2
|
||||
sinKg4+mueYaGUpoUti0hM3J3yaC34i6Cwa8MQoLNw1JIS/oNtKjpMxyV10w8aoc
|
||||
PHRK3n7UYp10mJHx7aM+lldSKvVS1NTQmI4vloNLwMp324H5ANDFAlRUz7mysVnu
|
||||
DEEvigPSPxs5ZYENu/i7pCQC5qHfhrlBrQwTjhegr0pQPcumy2fO5SGC9l/5B7ev
|
||||
bqQSZmDeWWoTvh2w2wl5/RWAsgZKx6rDtkCqYx7sSBY17uorrxP24LP4zhq7NxRV
|
||||
nfdsLogbCFNVQ66u7qvq5zFccdFtg9h1HQWdS7wbnKSBGZoo5gl6js7GGtxfGbb0
|
||||
oQ9kp6eciF4U92r6POhVgbRe4CfPo50nqgZBddkAEQEAAYkCJQQYAQgADwUCVqu8
|
||||
7gIbDAUJB4TOAAAKCRA4XuBVoSkVOFJ8D/9J8IJ4XWUU3FYIaHJ3XeSoxDmTi7d5
|
||||
WmNdf1lmwz82MQjG4uw17oCbvQzmj4/a/CM1Ly4v0WwBhUf9aiNErD0ByHASFnuc
|
||||
tlQBLVJdk0vRyD0fZakGg64qCA76hiySjMhlGHkQFyP2mDORc2GNu/OqFGm79pXT
|
||||
ZUplXxd431E603/agM5xJrweutMMpP1nBFTSEMJvbMNzDVN8I1A1CH4zVmAVxOUk
|
||||
sQ5L5rXW+KeXWyiMF24+l2CMnkQ2CxfHpkcpfPJs1Cbt+TIBSSofIqK8QJXrb/2f
|
||||
Zpl/ftqW7Xe86rJFrB/Y/77LDWx10rqWEvfCqrBxrMj7ONAQfbKQF/IjAwDN17Wf
|
||||
1K74rqKnRu+KHCyNM89s1iDbQC9kzZfzYt4AEOvAH/ZQDMZffzPSbnfkBerExFpa
|
||||
93XMuiR66jiBsf9IXIQeydpJD4Ogl2sSUSxFEJxJ/bBSxPxC5w7/BVMA7Am1y8Zo
|
||||
3hrpqnX2PBzxG7L0FZ6fYkfR3p8JS7vI6nByBf2IDv8W32wn43olPf+u6uobHLvt
|
||||
ttapOjwPAhPDalRuxs9U6WSg06QJkT/0F8TFUPWpsFmKTl+G4Ty7PHWsjeeNHJCL
|
||||
7/5RQboFY3k8Jy3/sIofABO6Un9LJivDuu9PxqA0IgvaS6Mja8JdCCk9Nyk4vHB7
|
||||
IEgAL/CYqrk38w==
|
||||
=lmD7
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
29
tools/defuse/php-encryption/index.php
Normal file
29
tools/defuse/php-encryption/index.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
/**
|
||||
* 2010-2021 Webkul.
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* All right is reserved,
|
||||
* Please go through this link for complete license : https://store.webkul.com/license.html
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade this module to newer
|
||||
* versions in the future. If you wish to customize this module for your
|
||||
* needs please refer to https://store.webkul.com/customisation-guidelines/ for more information.
|
||||
*
|
||||
* @author Webkul IN <support@webkul.com>
|
||||
* @copyright 2010-2021 Webkul IN
|
||||
* @license https://store.webkul.com/license.html
|
||||
*/
|
||||
|
||||
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
|
||||
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
|
||||
|
||||
header('Cache-Control: no-store, no-cache, must-revalidate');
|
||||
header('Cache-Control: post-check=0, pre-check=0', false);
|
||||
header('Pragma: no-cache');
|
||||
|
||||
header('Location: ../');
|
||||
exit;
|
||||
434
tools/defuse/php-encryption/src/Core.php
Normal file
434
tools/defuse/php-encryption/src/Core.php
Normal file
@@ -0,0 +1,434 @@
|
||||
<?php
|
||||
|
||||
namespace Defuse\Crypto;
|
||||
|
||||
use Defuse\Crypto\Exception as Ex;
|
||||
|
||||
final class Core
|
||||
{
|
||||
const HEADER_VERSION_SIZE = 4;
|
||||
const MINIMUM_CIPHERTEXT_SIZE = 84;
|
||||
|
||||
const CURRENT_VERSION = "\xDE\xF5\x02\x00";
|
||||
|
||||
const CIPHER_METHOD = 'aes-256-ctr';
|
||||
const BLOCK_BYTE_SIZE = 16;
|
||||
const KEY_BYTE_SIZE = 32;
|
||||
const SALT_BYTE_SIZE = 32;
|
||||
const MAC_BYTE_SIZE = 32;
|
||||
const HASH_FUNCTION_NAME = 'sha256';
|
||||
const ENCRYPTION_INFO_STRING = 'DefusePHP|V2|KeyForEncryption';
|
||||
const AUTHENTICATION_INFO_STRING = 'DefusePHP|V2|KeyForAuthentication';
|
||||
const BUFFER_BYTE_SIZE = 1048576;
|
||||
|
||||
const LEGACY_CIPHER_METHOD = 'aes-128-cbc';
|
||||
const LEGACY_BLOCK_BYTE_SIZE = 16;
|
||||
const LEGACY_KEY_BYTE_SIZE = 16;
|
||||
const LEGACY_HASH_FUNCTION_NAME = 'sha256';
|
||||
const LEGACY_MAC_BYTE_SIZE = 32;
|
||||
const LEGACY_ENCRYPTION_INFO_STRING = 'DefusePHP|KeyForEncryption';
|
||||
const LEGACY_AUTHENTICATION_INFO_STRING = 'DefusePHP|KeyForAuthentication';
|
||||
|
||||
/*
|
||||
* V2.0 Format: VERSION (4 bytes) || SALT (32 bytes) || IV (16 bytes) ||
|
||||
* CIPHERTEXT (varies) || HMAC (32 bytes)
|
||||
*
|
||||
* V1.0 Format: HMAC (32 bytes) || IV (16 bytes) || CIPHERTEXT (varies).
|
||||
*/
|
||||
|
||||
/**
|
||||
* Adds an integer to a block-sized counter.
|
||||
*
|
||||
* @param string $ctr
|
||||
* @param int $inc
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function incrementCounter($ctr, $inc)
|
||||
{
|
||||
if (Core::ourStrlen($ctr) !== Core::BLOCK_BYTE_SIZE) {
|
||||
throw new Ex\EnvironmentIsBrokenException(
|
||||
'Trying to increment a nonce of the wrong size.'
|
||||
);
|
||||
}
|
||||
|
||||
if (! \is_int($inc)) {
|
||||
throw new Ex\EnvironmentIsBrokenException(
|
||||
'Trying to increment nonce by a non-integer.'
|
||||
);
|
||||
}
|
||||
|
||||
if ($inc < 0) {
|
||||
throw new Ex\EnvironmentIsBrokenException(
|
||||
'Trying to increment nonce by a negative amount.'
|
||||
);
|
||||
}
|
||||
|
||||
if ($inc > PHP_INT_MAX - 255) {
|
||||
throw new Ex\EnvironmentIsBrokenException(
|
||||
'Integer overflow may occur.'
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* We start at the rightmost byte (big-endian)
|
||||
* So, too, does OpenSSL: http://stackoverflow.com/a/3146214/2224584
|
||||
*/
|
||||
for ($i = Core::BLOCK_BYTE_SIZE - 1; $i >= 0; --$i) {
|
||||
$sum = \ord($ctr[$i]) + $inc;
|
||||
|
||||
/* Detect integer overflow and fail. */
|
||||
if (! \is_int($sum)) {
|
||||
throw new Ex\EnvironmentIsBrokenException(
|
||||
'Integer overflow in CTR mode nonce increment.'
|
||||
);
|
||||
}
|
||||
|
||||
$ctr[$i] = \pack('C', $sum & 0xFF);
|
||||
$inc = $sum >> 8;
|
||||
}
|
||||
return $ctr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a random byte string of the specified length.
|
||||
*
|
||||
* @param int $octets
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function secureRandom($octets)
|
||||
{
|
||||
self::ensureFunctionExists('random_bytes');
|
||||
try {
|
||||
return \random_bytes($octets);
|
||||
} catch (\Exception $ex) {
|
||||
throw new Ex\EnvironmentIsBrokenException(
|
||||
'Your system does not have a secure random number generator.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the HKDF key derivation function specified in
|
||||
* http://tools.ietf.org/html/rfc5869.
|
||||
*
|
||||
* @param string $hash Hash Function
|
||||
* @param string $ikm Initial Keying Material
|
||||
* @param int $length How many bytes?
|
||||
* @param string $info What sort of key are we deriving?
|
||||
* @param string $salt
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function HKDF($hash, $ikm, $length, $info = '', $salt = null)
|
||||
{
|
||||
$digest_length = Core::ourStrlen(\hash_hmac($hash, '', '', true));
|
||||
|
||||
// Sanity-check the desired output length.
|
||||
if (empty($length) || ! \is_int($length) ||
|
||||
$length < 0 || $length > 255 * $digest_length) {
|
||||
throw new Ex\EnvironmentIsBrokenException(
|
||||
'Bad output length requested of HKDF.'
|
||||
);
|
||||
}
|
||||
|
||||
// "if [salt] not provided, is set to a string of HashLen zeroes."
|
||||
if (\is_null($salt)) {
|
||||
$salt = \str_repeat("\x00", $digest_length);
|
||||
}
|
||||
|
||||
// HKDF-Extract:
|
||||
// PRK = HMAC-Hash(salt, IKM)
|
||||
// The salt is the HMAC key.
|
||||
$prk = \hash_hmac($hash, $ikm, $salt, true);
|
||||
|
||||
// HKDF-Expand:
|
||||
|
||||
// This check is useless, but it serves as a reminder to the spec.
|
||||
if (Core::ourStrlen($prk) < $digest_length) {
|
||||
throw new Ex\EnvironmentIsBrokenException();
|
||||
}
|
||||
|
||||
// T(0) = ''
|
||||
$t = '';
|
||||
$last_block = '';
|
||||
for ($block_index = 1; Core::ourStrlen($t) < $length; ++$block_index) {
|
||||
// T(i) = HMAC-Hash(PRK, T(i-1) | info | 0x??)
|
||||
$last_block = \hash_hmac(
|
||||
$hash,
|
||||
$last_block . $info . \chr($block_index),
|
||||
$prk,
|
||||
true
|
||||
);
|
||||
// T = T(1) | T(2) | T(3) | ... | T(N)
|
||||
$t .= $last_block;
|
||||
}
|
||||
|
||||
// ORM = first L octets of T
|
||||
$orm = Core::ourSubstr($t, 0, $length);
|
||||
if ($orm === false) {
|
||||
throw new Ex\EnvironmentIsBrokenException();
|
||||
}
|
||||
return $orm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if two equal-length strings are the same without leaking
|
||||
* information through side channels.
|
||||
*
|
||||
* @param string $expected
|
||||
* @param string $given
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function hashEquals($expected, $given)
|
||||
{
|
||||
static $native = null;
|
||||
if ($native === null) {
|
||||
$native = \function_exists('hash_equals');
|
||||
}
|
||||
if ($native) {
|
||||
return \hash_equals($expected, $given);
|
||||
}
|
||||
|
||||
// We can't just compare the strings with '==', since it would make
|
||||
// timing attacks possible. We could use the XOR-OR constant-time
|
||||
// comparison algorithm, but that may not be a reliable defense in an
|
||||
// interpreted language. So we use the approach of HMACing both strings
|
||||
// with a random key and comparing the HMACs.
|
||||
|
||||
// We're not attempting to make variable-length string comparison
|
||||
// secure, as that's very difficult. Make sure the strings are the same
|
||||
// length.
|
||||
if (Core::ourStrlen($expected) !== Core::ourStrlen($given)) {
|
||||
throw new Ex\EnvironmentIsBrokenException();
|
||||
}
|
||||
|
||||
$blind = Core::secureRandom(32);
|
||||
$message_compare = \hash_hmac(Core::HASH_FUNCTION_NAME, $given, $blind);
|
||||
$correct_compare = \hash_hmac(Core::HASH_FUNCTION_NAME, $expected, $blind);
|
||||
return $correct_compare === $message_compare;
|
||||
}
|
||||
/**
|
||||
* Throws an exception if the constant doesn't exist.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
*/
|
||||
public static function ensureConstantExists($name)
|
||||
{
|
||||
if (! \defined($name)) {
|
||||
throw new Ex\EnvironmentIsBrokenException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an exception if the function doesn't exist.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
*/
|
||||
public static function ensureFunctionExists($name)
|
||||
{
|
||||
if (! \function_exists($name)) {
|
||||
throw new Ex\EnvironmentIsBrokenException();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We need these strlen() and substr() functions because when
|
||||
* 'mbstring.func_overload' is set in php.ini, the standard strlen() and
|
||||
* substr() are replaced by mb_strlen() and mb_substr().
|
||||
*/
|
||||
|
||||
/**
|
||||
* Computes the length of a string in bytes.
|
||||
*
|
||||
* @param string $str
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function ourStrlen($str)
|
||||
{
|
||||
static $exists = null;
|
||||
if ($exists === null) {
|
||||
$exists = \function_exists('mb_strlen');
|
||||
}
|
||||
if ($exists) {
|
||||
$length = \mb_strlen($str, '8bit');
|
||||
if ($length === false) {
|
||||
throw new Ex\EnvironmentIsBrokenException();
|
||||
}
|
||||
return $length;
|
||||
} else {
|
||||
return \strlen($str);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Behaves roughly like the function substr() in PHP 7 does.
|
||||
*
|
||||
* @param string $str
|
||||
* @param int $start
|
||||
* @param int $length
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function ourSubstr($str, $start, $length = null)
|
||||
{
|
||||
static $exists = null;
|
||||
if ($exists === null) {
|
||||
$exists = \function_exists('mb_substr');
|
||||
}
|
||||
|
||||
if ($exists) {
|
||||
// mb_substr($str, 0, NULL, '8bit') returns an empty string on PHP
|
||||
// 5.3, so we have to find the length ourselves.
|
||||
if (! isset($length)) {
|
||||
if ($start >= 0) {
|
||||
$length = Core::ourStrlen($str) - $start;
|
||||
} else {
|
||||
$length = -$start;
|
||||
}
|
||||
}
|
||||
|
||||
// This is required to make mb_substr behavior identical to substr.
|
||||
// Without this, mb_substr() would return false, contra to what the
|
||||
// PHP documentation says (it doesn't say it can return false.)
|
||||
if ($start === Core::ourStrlen($str) && $length === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ($start > Core::ourStrlen($str)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$substr = \mb_substr($str, $start, $length, '8bit');
|
||||
if (Core::ourStrlen($substr) !== $length) {
|
||||
throw new Ex\EnvironmentIsBrokenException(
|
||||
'Your version of PHP has bug #66797. Its implementation of
|
||||
mb_substr() is incorrect. See the details here:
|
||||
https://bugs.php.net/bug.php?id=66797'
|
||||
);
|
||||
}
|
||||
return $substr;
|
||||
}
|
||||
|
||||
// Unlike mb_substr(), substr() doesn't accept NULL for length
|
||||
if (isset($length)) {
|
||||
return \substr($str, $start, $length);
|
||||
} else {
|
||||
return \substr($str, $start);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the PBKDF2 password-based key derivation function.
|
||||
*
|
||||
* The PBKDF2 function is defined in RFC 2898. Test vectors can be found in
|
||||
* RFC 6070. This implementation of PBKDF2 was originally created by Taylor
|
||||
* Hornby, with improvements from http://www.variations-of-shadow.com/.
|
||||
*
|
||||
* @param string $algorithm The hash algorithm to use. Recommended: SHA256
|
||||
* @param string $password The password.
|
||||
* @param string $salt A salt that is unique to the password.
|
||||
* @param int $count Iteration count. Higher is better, but slower. Recommended: At least 1000.
|
||||
* @param int $key_length The length of the derived key in bytes.
|
||||
* @param bool $raw_output If true, the key is returned in raw binary format. Hex encoded otherwise.
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
*
|
||||
* @return string A $key_length-byte key derived from the password and salt.
|
||||
*/
|
||||
public static function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false)
|
||||
{
|
||||
// Type checks:
|
||||
if (! \is_string($algorithm)) {
|
||||
throw new \InvalidArgumentException(
|
||||
'pbkdf2(): algorithm must be a string'
|
||||
);
|
||||
}
|
||||
if (! \is_string($password)) {
|
||||
throw new \InvalidArgumentException(
|
||||
'pbkdf2(): password must be a string'
|
||||
);
|
||||
}
|
||||
if (! \is_string($salt)) {
|
||||
throw new \InvalidArgumentException(
|
||||
'pbkdf2(): salt must be a string'
|
||||
);
|
||||
}
|
||||
// Coerce strings to integers with no information loss or overflow
|
||||
$count += 0;
|
||||
$key_length += 0;
|
||||
|
||||
$algorithm = \strtolower($algorithm);
|
||||
if (! \in_array($algorithm, \hash_algos(), true)) {
|
||||
throw new Ex\EnvironmentIsBrokenException(
|
||||
'Invalid or unsupported hash algorithm.'
|
||||
);
|
||||
}
|
||||
|
||||
// Whitelist, or we could end up with people using CRC32.
|
||||
$ok_algorithms = [
|
||||
'sha1', 'sha224', 'sha256', 'sha384', 'sha512',
|
||||
'ripemd160', 'ripemd256', 'ripemd320', 'whirlpool',
|
||||
];
|
||||
if (! \in_array($algorithm, $ok_algorithms, true)) {
|
||||
throw new Ex\EnvironmentIsBrokenException(
|
||||
'Algorithm is not a secure cryptographic hash function.'
|
||||
);
|
||||
}
|
||||
|
||||
if ($count <= 0 || $key_length <= 0) {
|
||||
throw new Ex\EnvironmentIsBrokenException(
|
||||
'Invalid PBKDF2 parameters.'
|
||||
);
|
||||
}
|
||||
|
||||
if (\function_exists('hash_pbkdf2')) {
|
||||
// The output length is in NIBBLES (4-bits) if $raw_output is false!
|
||||
if (! $raw_output) {
|
||||
$key_length = $key_length * 2;
|
||||
}
|
||||
return \hash_pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output);
|
||||
}
|
||||
|
||||
$hash_length = Core::ourStrlen(\hash($algorithm, '', true));
|
||||
$block_count = \ceil($key_length / $hash_length);
|
||||
|
||||
$output = '';
|
||||
for ($i = 1; $i <= $block_count; $i++) {
|
||||
// $i encoded as 4 bytes, big endian.
|
||||
$last = $salt . \pack('N', $i);
|
||||
// first iteration
|
||||
$last = $xorsum = \hash_hmac($algorithm, $last, $password, true);
|
||||
// perform the other $count - 1 iterations
|
||||
for ($j = 1; $j < $count; $j++) {
|
||||
$xorsum ^= ($last = \hash_hmac($algorithm, $last, $password, true));
|
||||
}
|
||||
$output .= $xorsum;
|
||||
}
|
||||
|
||||
if ($raw_output) {
|
||||
return Core::ourSubstr($output, 0, $key_length);
|
||||
} else {
|
||||
return Encoding::binToHex(Core::ourSubstr($output, 0, $key_length));
|
||||
}
|
||||
}
|
||||
}
|
||||
372
tools/defuse/php-encryption/src/Crypto.php
Normal file
372
tools/defuse/php-encryption/src/Crypto.php
Normal file
@@ -0,0 +1,372 @@
|
||||
<?php
|
||||
|
||||
namespace Defuse\Crypto;
|
||||
|
||||
use Defuse\Crypto\Exception as Ex;
|
||||
|
||||
class Crypto
|
||||
{
|
||||
/**
|
||||
* Encrypts a string with a Key.
|
||||
*
|
||||
* @param string $plaintext
|
||||
* @param Key $key
|
||||
* @param bool $raw_binary
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function encrypt($plaintext, Key $key, $raw_binary = false)
|
||||
{
|
||||
return self::encryptInternal(
|
||||
$plaintext,
|
||||
KeyOrPassword::createFromKey($key),
|
||||
$raw_binary
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts a string with a password, using a slow key derivation function
|
||||
* to make password cracking more expensive.
|
||||
*
|
||||
* @param string $plaintext
|
||||
* @param string $password
|
||||
* @param bool $raw_binary
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function encryptWithPassword($plaintext, $password, $raw_binary = false)
|
||||
{
|
||||
return self::encryptInternal(
|
||||
$plaintext,
|
||||
KeyOrPassword::createFromPassword($password),
|
||||
$raw_binary
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts a ciphertext to a string with a Key.
|
||||
*
|
||||
* @param string $ciphertext
|
||||
* @param Key $key
|
||||
* @param bool $raw_binary
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
* @throws Ex\WrongKeyOrModifiedCiphertextException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function decrypt($ciphertext, Key $key, $raw_binary = false)
|
||||
{
|
||||
return self::decryptInternal(
|
||||
$ciphertext,
|
||||
KeyOrPassword::createFromKey($key),
|
||||
$raw_binary
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts a ciphertext to a string with a password, using a slow key
|
||||
* derivation function to make password cracking more expensive.
|
||||
*
|
||||
* @param string $ciphertext
|
||||
* @param string $password
|
||||
* @param bool $raw_binary
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
* @throws Ex\WrongKeyOrModifiedCiphertextException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function decryptWithPassword($ciphertext, $password, $raw_binary = false)
|
||||
{
|
||||
return self::decryptInternal(
|
||||
$ciphertext,
|
||||
KeyOrPassword::createFromPassword($password),
|
||||
$raw_binary
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts a legacy ciphertext produced by version 1 of this library.
|
||||
*
|
||||
* @param string $ciphertext
|
||||
* @param string $key
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
* @throws Ex\WrongKeyOrModifiedCiphertextException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function legacyDecrypt($ciphertext, $key)
|
||||
{
|
||||
RuntimeTests::runtimeTest();
|
||||
|
||||
// Extract the HMAC from the front of the ciphertext.
|
||||
if (Core::ourStrlen($ciphertext) <= Core::LEGACY_MAC_BYTE_SIZE) {
|
||||
throw new Ex\WrongKeyOrModifiedCiphertextException(
|
||||
'Ciphertext is too short.'
|
||||
);
|
||||
}
|
||||
$hmac = Core::ourSubstr($ciphertext, 0, Core::LEGACY_MAC_BYTE_SIZE);
|
||||
if ($hmac === false) {
|
||||
throw new Ex\EnvironmentIsBrokenException();
|
||||
}
|
||||
$ciphertext = Core::ourSubstr($ciphertext, Core::LEGACY_MAC_BYTE_SIZE);
|
||||
if ($ciphertext === false) {
|
||||
throw new Ex\EnvironmentIsBrokenException();
|
||||
}
|
||||
|
||||
// Regenerate the same authentication sub-key.
|
||||
$akey = Core::HKDF(
|
||||
Core::LEGACY_HASH_FUNCTION_NAME,
|
||||
$key,
|
||||
Core::LEGACY_KEY_BYTE_SIZE,
|
||||
Core::LEGACY_AUTHENTICATION_INFO_STRING,
|
||||
null
|
||||
);
|
||||
|
||||
if (self::verifyHMAC($hmac, $ciphertext, $akey)) {
|
||||
// Regenerate the same encryption sub-key.
|
||||
$ekey = Core::HKDF(
|
||||
Core::LEGACY_HASH_FUNCTION_NAME,
|
||||
$key,
|
||||
Core::LEGACY_KEY_BYTE_SIZE,
|
||||
Core::LEGACY_ENCRYPTION_INFO_STRING,
|
||||
null
|
||||
);
|
||||
|
||||
// Extract the IV from the ciphertext.
|
||||
if (Core::ourStrlen($ciphertext) <= Core::LEGACY_BLOCK_BYTE_SIZE) {
|
||||
throw new Ex\WrongKeyOrModifiedCiphertextException(
|
||||
'Ciphertext is too short.'
|
||||
);
|
||||
}
|
||||
$iv = Core::ourSubstr($ciphertext, 0, Core::LEGACY_BLOCK_BYTE_SIZE);
|
||||
if ($iv === false) {
|
||||
throw new Ex\EnvironmentIsBrokenException();
|
||||
}
|
||||
$ciphertext = Core::ourSubstr($ciphertext, Core::LEGACY_BLOCK_BYTE_SIZE);
|
||||
if ($ciphertext === false) {
|
||||
throw new Ex\EnvironmentIsBrokenException();
|
||||
}
|
||||
|
||||
// Do the decryption.
|
||||
$plaintext = self::plainDecrypt($ciphertext, $ekey, $iv, Core::LEGACY_CIPHER_METHOD);
|
||||
return $plaintext;
|
||||
} else {
|
||||
throw new Ex\WrongKeyOrModifiedCiphertextException(
|
||||
'Integrity check failed.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts a string with either a key or a password.
|
||||
*
|
||||
* @param string $plaintext
|
||||
* @param KeyOrPassword $secret
|
||||
* @param bool $raw_binary
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private static function encryptInternal($plaintext, KeyOrPassword $secret, $raw_binary)
|
||||
{
|
||||
RuntimeTests::runtimeTest();
|
||||
|
||||
$salt = Core::secureRandom(Core::SALT_BYTE_SIZE);
|
||||
$keys = $secret->deriveKeys($salt);
|
||||
$ekey = $keys->getEncryptionKey();
|
||||
$akey = $keys->getAuthenticationKey();
|
||||
$iv = Core::secureRandom(Core::BLOCK_BYTE_SIZE);
|
||||
|
||||
$ciphertext = Core::CURRENT_VERSION . $salt . $iv . self::plainEncrypt($plaintext, $ekey, $iv);
|
||||
$auth = \hash_hmac(Core::HASH_FUNCTION_NAME, $ciphertext, $akey, true);
|
||||
$ciphertext = $ciphertext . $auth;
|
||||
|
||||
if ($raw_binary) {
|
||||
return $ciphertext;
|
||||
}
|
||||
return Encoding::binToHex($ciphertext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts a ciphertext to a string with either a key or a password.
|
||||
*
|
||||
* @param string $ciphertext
|
||||
* @param KeyOrPassword $secret
|
||||
* @param bool $raw_binary
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
* @throws Ex\WrongKeyOrModifiedCiphertextException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private static function decryptInternal($ciphertext, KeyOrPassword $secret, $raw_binary)
|
||||
{
|
||||
RuntimeTests::runtimeTest();
|
||||
|
||||
if (! $raw_binary) {
|
||||
try {
|
||||
$ciphertext = Encoding::hexToBin($ciphertext);
|
||||
} catch (Ex\BadFormatException $ex) {
|
||||
throw new Ex\WrongKeyOrModifiedCiphertextException(
|
||||
'Ciphertext has invalid hex encoding.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (Core::ourStrlen($ciphertext) < Core::MINIMUM_CIPHERTEXT_SIZE) {
|
||||
throw new Ex\WrongKeyOrModifiedCiphertextException(
|
||||
'Ciphertext is too short.'
|
||||
);
|
||||
}
|
||||
|
||||
// Get and check the version header.
|
||||
$header = Core::ourSubstr($ciphertext, 0, Core::HEADER_VERSION_SIZE);
|
||||
if ($header !== Core::CURRENT_VERSION) {
|
||||
throw new Ex\WrongKeyOrModifiedCiphertextException(
|
||||
'Bad version header.'
|
||||
);
|
||||
}
|
||||
|
||||
// Get the salt.
|
||||
$salt = Core::ourSubstr(
|
||||
$ciphertext,
|
||||
Core::HEADER_VERSION_SIZE,
|
||||
Core::SALT_BYTE_SIZE
|
||||
);
|
||||
if ($salt === false) {
|
||||
throw new Ex\EnvironmentIsBrokenException();
|
||||
}
|
||||
|
||||
// Get the IV.
|
||||
$iv = Core::ourSubstr(
|
||||
$ciphertext,
|
||||
Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE,
|
||||
Core::BLOCK_BYTE_SIZE
|
||||
);
|
||||
if ($iv === false) {
|
||||
throw new Ex\EnvironmentIsBrokenException();
|
||||
}
|
||||
|
||||
// Get the HMAC.
|
||||
$hmac = Core::ourSubstr(
|
||||
$ciphertext,
|
||||
Core::ourStrlen($ciphertext) - Core::MAC_BYTE_SIZE,
|
||||
Core::MAC_BYTE_SIZE
|
||||
);
|
||||
if ($hmac === false) {
|
||||
throw new Ex\EnvironmentIsBrokenException();
|
||||
}
|
||||
|
||||
// Get the actual encrypted ciphertext.
|
||||
$encrypted = Core::ourSubstr(
|
||||
$ciphertext,
|
||||
Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE +
|
||||
Core::BLOCK_BYTE_SIZE,
|
||||
Core::ourStrlen($ciphertext) - Core::MAC_BYTE_SIZE - Core::SALT_BYTE_SIZE -
|
||||
Core::BLOCK_BYTE_SIZE - Core::HEADER_VERSION_SIZE
|
||||
);
|
||||
if ($encrypted === false) {
|
||||
throw new Ex\EnvironmentIsBrokenException();
|
||||
}
|
||||
|
||||
// Derive the separate encryption and authentication keys from the key
|
||||
// or password, whichever it is.
|
||||
$keys = $secret->deriveKeys($salt);
|
||||
|
||||
if (self::verifyHMAC($hmac, $header . $salt . $iv . $encrypted, $keys->getAuthenticationKey())) {
|
||||
$plaintext = self::plainDecrypt($encrypted, $keys->getEncryptionKey(), $iv, Core::CIPHER_METHOD);
|
||||
return $plaintext;
|
||||
} else {
|
||||
throw new Ex\WrongKeyOrModifiedCiphertextException(
|
||||
'Integrity check failed.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Raw unauthenticated encryption (insecure on its own).
|
||||
*
|
||||
* @param string $plaintext
|
||||
* @param string $key
|
||||
* @param string $iv
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function plainEncrypt($plaintext, $key, $iv)
|
||||
{
|
||||
Core::ensureConstantExists('OPENSSL_RAW_DATA');
|
||||
Core::ensureFunctionExists('openssl_encrypt');
|
||||
$ciphertext = \openssl_encrypt(
|
||||
$plaintext,
|
||||
Core::CIPHER_METHOD,
|
||||
$key,
|
||||
OPENSSL_RAW_DATA,
|
||||
$iv
|
||||
);
|
||||
|
||||
if ($ciphertext === false) {
|
||||
throw new Ex\EnvironmentIsBrokenException(
|
||||
'openssl_encrypt() failed.'
|
||||
);
|
||||
}
|
||||
|
||||
return $ciphertext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Raw unauthenticated decryption (insecure on its own).
|
||||
*
|
||||
* @param string $ciphertext
|
||||
* @param string $key
|
||||
* @param string $iv
|
||||
* @param string $cipherMethod
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function plainDecrypt($ciphertext, $key, $iv, $cipherMethod)
|
||||
{
|
||||
Core::ensureConstantExists('OPENSSL_RAW_DATA');
|
||||
Core::ensureFunctionExists('openssl_decrypt');
|
||||
$plaintext = \openssl_decrypt(
|
||||
$ciphertext,
|
||||
$cipherMethod,
|
||||
$key,
|
||||
OPENSSL_RAW_DATA,
|
||||
$iv
|
||||
);
|
||||
if ($plaintext === false) {
|
||||
throw new Ex\EnvironmentIsBrokenException(
|
||||
'openssl_decrypt() failed.'
|
||||
);
|
||||
}
|
||||
|
||||
return $plaintext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies an HMAC without leaking information through side-channels.
|
||||
*
|
||||
* @param string $correct_hmac
|
||||
* @param string $message
|
||||
* @param string $key
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected static function verifyHMAC($correct_hmac, $message, $key)
|
||||
{
|
||||
$message_hmac = \hash_hmac(Core::HASH_FUNCTION_NAME, $message, $key, true);
|
||||
return Core::hashEquals($correct_hmac, $message_hmac);
|
||||
}
|
||||
}
|
||||
37
tools/defuse/php-encryption/src/DerivedKeys.php
Normal file
37
tools/defuse/php-encryption/src/DerivedKeys.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Defuse\Crypto;
|
||||
|
||||
final class DerivedKeys
|
||||
{
|
||||
private $akey = null;
|
||||
private $ekey = null;
|
||||
|
||||
/**
|
||||
* Returns the authentication key.
|
||||
*/
|
||||
public function getAuthenticationKey()
|
||||
{
|
||||
return $this->akey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the encryption key.
|
||||
*/
|
||||
public function getEncryptionKey()
|
||||
{
|
||||
return $this->ekey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for DerivedKeys.
|
||||
*
|
||||
* @param string $akey
|
||||
* @param string $ekey
|
||||
*/
|
||||
public function __construct($akey, $ekey)
|
||||
{
|
||||
$this->akey = $akey;
|
||||
$this->ekey = $ekey;
|
||||
}
|
||||
}
|
||||
212
tools/defuse/php-encryption/src/Encoding.php
Normal file
212
tools/defuse/php-encryption/src/Encoding.php
Normal file
@@ -0,0 +1,212 @@
|
||||
<?php
|
||||
|
||||
namespace Defuse\Crypto;
|
||||
|
||||
use Defuse\Crypto\Exception as Ex;
|
||||
|
||||
final class Encoding
|
||||
{
|
||||
const CHECKSUM_BYTE_SIZE = 32;
|
||||
const CHECKSUM_HASH_ALGO = 'sha256';
|
||||
const SERIALIZE_HEADER_BYTES = 4;
|
||||
|
||||
/**
|
||||
* Converts a byte string to a hexadecimal string without leaking
|
||||
* information through side channels.
|
||||
*
|
||||
* @param string $byte_string
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function binToHex($byte_string)
|
||||
{
|
||||
$hex = '';
|
||||
$len = Core::ourStrlen($byte_string);
|
||||
for ($i = 0; $i < $len; ++$i) {
|
||||
$c = \ord($byte_string[$i]) & 0xf;
|
||||
$b = \ord($byte_string[$i]) >> 4;
|
||||
$hex .= \pack(
|
||||
'CC',
|
||||
87 + $b + ((($b - 10) >> 8) & ~38),
|
||||
87 + $c + ((($c - 10) >> 8) & ~38)
|
||||
);
|
||||
}
|
||||
return $hex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a hexadecimal string into a byte string without leaking
|
||||
* information through side channels.
|
||||
*
|
||||
* @param string $hex_string
|
||||
*
|
||||
* @throws Ex\BadFormatException
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function hexToBin($hex_string)
|
||||
{
|
||||
$hex_pos = 0;
|
||||
$bin = '';
|
||||
$hex_len = Core::ourStrlen($hex_string);
|
||||
$state = 0;
|
||||
$c_acc = 0;
|
||||
|
||||
while ($hex_pos < $hex_len) {
|
||||
$c = \ord($hex_string[$hex_pos]);
|
||||
$c_num = $c ^ 48;
|
||||
$c_num0 = ($c_num - 10) >> 8;
|
||||
$c_alpha = ($c & ~32) - 55;
|
||||
$c_alpha0 = (($c_alpha - 10) ^ ($c_alpha - 16)) >> 8;
|
||||
if (($c_num0 | $c_alpha0) === 0) {
|
||||
throw new Ex\BadFormatException(
|
||||
'Encoding::hexToBin() input is not a hex string.'
|
||||
);
|
||||
}
|
||||
$c_val = ($c_num0 & $c_num) | ($c_alpha & $c_alpha0);
|
||||
if ($state === 0) {
|
||||
$c_acc = $c_val * 16;
|
||||
} else {
|
||||
$bin .= \pack('C', $c_acc | $c_val);
|
||||
}
|
||||
$state ^= 1;
|
||||
++$hex_pos;
|
||||
}
|
||||
return $bin;
|
||||
}
|
||||
|
||||
/*
|
||||
* SECURITY NOTE ON APPLYING CHECKSUMS TO SECRETS:
|
||||
*
|
||||
* The checksum introduces a potential security weakness. For example,
|
||||
* suppose we apply a checksum to a key, and that an adversary has an
|
||||
* exploit against the process containing the key, such that they can
|
||||
* overwrite an arbitrary byte of memory and then cause the checksum to
|
||||
* be verified and learn the result.
|
||||
*
|
||||
* In this scenario, the adversary can extract the key one byte at
|
||||
* a time by overwriting it with their guess of its value and then
|
||||
* asking if the checksum matches. If it does, their guess was right.
|
||||
* This kind of attack may be more easy to implement and more reliable
|
||||
* than a remote code execution attack.
|
||||
*
|
||||
* This attack also applies to authenticated encryption as a whole, in
|
||||
* the situation where the adversary can overwrite a byte of the key
|
||||
* and then cause a valid ciphertext to be decrypted, and then
|
||||
* determine whether the MAC check passed or failed.
|
||||
*
|
||||
* By using the full SHA256 hash instead of truncating it, I'm ensuring
|
||||
* that both ways of going about the attack are equivalently difficult.
|
||||
* A shorter checksum of say 32 bits might be more useful to the
|
||||
* adversary as an oracle in case their writes are coarser grained.
|
||||
*
|
||||
* Because the scenario assumes a serious vulnerability, we don't try
|
||||
* to prevent attacks of this style.
|
||||
*/
|
||||
|
||||
/**
|
||||
* INTERNAL USE ONLY: Applies a version header, applies a checksum, and
|
||||
* then encodes a byte string into a range of printable ASCII characters.
|
||||
*
|
||||
* @param string $header
|
||||
* @param string $bytes
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function saveBytesToChecksummedAsciiSafeString($header, $bytes)
|
||||
{
|
||||
// Headers must be a constant length to prevent one type's header from
|
||||
// being a prefix of another type's header, leading to ambiguity.
|
||||
if (Core::ourStrlen($header) !== self::SERIALIZE_HEADER_BYTES) {
|
||||
throw new Ex\EnvironmentIsBrokenException(
|
||||
'Header must be ' . self::SERIALIZE_HEADER_BYTES . ' bytes.'
|
||||
);
|
||||
}
|
||||
|
||||
return Encoding::binToHex(
|
||||
$header .
|
||||
$bytes .
|
||||
\hash(
|
||||
self::CHECKSUM_HASH_ALGO,
|
||||
$header . $bytes,
|
||||
true
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL USE ONLY: Decodes, verifies the header and checksum, and returns
|
||||
* the encoded byte string.
|
||||
*
|
||||
* @param string $expected_header
|
||||
* @param string $string
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
* @throws Ex\BadFormatException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function loadBytesFromChecksummedAsciiSafeString($expected_header, $string)
|
||||
{
|
||||
// Headers must be a constant length to prevent one type's header from
|
||||
// being a prefix of another type's header, leading to ambiguity.
|
||||
if (Core::ourStrlen($expected_header) !== self::SERIALIZE_HEADER_BYTES) {
|
||||
throw new Ex\EnvironmentIsBrokenException(
|
||||
'Header must be 4 bytes.'
|
||||
);
|
||||
}
|
||||
|
||||
$bytes = Encoding::hexToBin($string);
|
||||
|
||||
/* Make sure we have enough bytes to get the version header and checksum. */
|
||||
if (Core::ourStrlen($bytes) < self::SERIALIZE_HEADER_BYTES + self::CHECKSUM_BYTE_SIZE) {
|
||||
throw new Ex\BadFormatException(
|
||||
'Encoded data is shorter than expected.'
|
||||
);
|
||||
}
|
||||
|
||||
/* Grab the version header. */
|
||||
$actual_header = Core::ourSubstr($bytes, 0, self::SERIALIZE_HEADER_BYTES);
|
||||
|
||||
if ($actual_header !== $expected_header) {
|
||||
throw new Ex\BadFormatException(
|
||||
'Invalid header.'
|
||||
);
|
||||
}
|
||||
|
||||
/* Grab the bytes that are part of the checksum. */
|
||||
$checked_bytes = Core::ourSubstr(
|
||||
$bytes,
|
||||
0,
|
||||
Core::ourStrlen($bytes) - self::CHECKSUM_BYTE_SIZE
|
||||
);
|
||||
|
||||
/* Grab the included checksum. */
|
||||
$checksum_a = Core::ourSubstr(
|
||||
$bytes,
|
||||
Core::ourStrlen($bytes) - self::CHECKSUM_BYTE_SIZE,
|
||||
self::CHECKSUM_BYTE_SIZE
|
||||
);
|
||||
|
||||
/* Re-compute the checksum. */
|
||||
$checksum_b = \hash(self::CHECKSUM_HASH_ALGO, $checked_bytes, true);
|
||||
|
||||
/* Check if the checksum matches. */
|
||||
if (! Core::hashEquals($checksum_a, $checksum_b)) {
|
||||
throw new Ex\BadFormatException(
|
||||
"Data is corrupted, the checksum doesn't match"
|
||||
);
|
||||
}
|
||||
|
||||
return Core::ourSubstr(
|
||||
$bytes,
|
||||
self::SERIALIZE_HEADER_BYTES,
|
||||
Core::ourStrlen($bytes) - self::SERIALIZE_HEADER_BYTES - self::CHECKSUM_BYTE_SIZE
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Defuse\Crypto\Exception;
|
||||
|
||||
class BadFormatException extends \Defuse\Crypto\Exception\CryptoException
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Defuse\Crypto\Exception;
|
||||
|
||||
class CryptoException extends \Exception
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Defuse\Crypto\Exception;
|
||||
|
||||
class EnvironmentIsBrokenException extends \Defuse\Crypto\Exception\CryptoException
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Defuse\Crypto\Exception;
|
||||
|
||||
class IOException extends \Defuse\Crypto\Exception\CryptoException
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Defuse\Crypto\Exception;
|
||||
|
||||
class WrongKeyOrModifiedCiphertextException extends \Defuse\Crypto\Exception\CryptoException
|
||||
{
|
||||
}
|
||||
29
tools/defuse/php-encryption/src/Exception/index.php
Normal file
29
tools/defuse/php-encryption/src/Exception/index.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
/**
|
||||
* 2010-2021 Webkul.
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* All right is reserved,
|
||||
* Please go through this link for complete license : https://store.webkul.com/license.html
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade this module to newer
|
||||
* versions in the future. If you wish to customize this module for your
|
||||
* needs please refer to https://store.webkul.com/customisation-guidelines/ for more information.
|
||||
*
|
||||
* @author Webkul IN <support@webkul.com>
|
||||
* @copyright 2010-2021 Webkul IN
|
||||
* @license https://store.webkul.com/license.html
|
||||
*/
|
||||
|
||||
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
|
||||
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
|
||||
|
||||
header('Cache-Control: no-store, no-cache, must-revalidate');
|
||||
header('Cache-Control: post-check=0, pre-check=0', false);
|
||||
header('Pragma: no-cache');
|
||||
|
||||
header('Location: ../');
|
||||
exit;
|
||||
755
tools/defuse/php-encryption/src/File.php
Normal file
755
tools/defuse/php-encryption/src/File.php
Normal file
@@ -0,0 +1,755 @@
|
||||
<?php
|
||||
|
||||
namespace Defuse\Crypto;
|
||||
|
||||
use Defuse\Crypto\Exception as Ex;
|
||||
|
||||
final class File
|
||||
{
|
||||
/**
|
||||
* Encrypts the input file, saving the ciphertext to the output file.
|
||||
*
|
||||
* @param string $inputFilename
|
||||
* @param string $outputFilename
|
||||
* @param Key $key
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
* @throws Ex\IOException
|
||||
*/
|
||||
public static function encryptFile($inputFilename, $outputFilename, Key $key)
|
||||
{
|
||||
self::encryptFileInternal(
|
||||
$inputFilename,
|
||||
$outputFilename,
|
||||
KeyOrPassword::createFromKey($key)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts a file with a password, using a slow key derivation function to
|
||||
* make password cracking more expensive.
|
||||
*
|
||||
* @param string $inputFilename
|
||||
* @param string $outputFilename
|
||||
* @param string $password
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
* @throws Ex\IOException
|
||||
*/
|
||||
public static function encryptFileWithPassword($inputFilename, $outputFilename, $password)
|
||||
{
|
||||
self::encryptFileInternal(
|
||||
$inputFilename,
|
||||
$outputFilename,
|
||||
KeyOrPassword::createFromPassword($password)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts the input file, saving the plaintext to the output file.
|
||||
*
|
||||
* @param string $inputFilename
|
||||
* @param string $outputFilename
|
||||
* @param Key $key
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
* @throws Ex\IOException
|
||||
* @throws Ex\WrongKeyOrModifiedCiphertextException
|
||||
*/
|
||||
public static function decryptFile($inputFilename, $outputFilename, Key $key)
|
||||
{
|
||||
self::decryptFileInternal(
|
||||
$inputFilename,
|
||||
$outputFilename,
|
||||
KeyOrPassword::createFromKey($key)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts a file with a password, using a slow key derivation function to
|
||||
* make password cracking more expensive.
|
||||
*
|
||||
* @param string $inputFilename
|
||||
* @param string $outputFilename
|
||||
* @param string $password
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
* @throws Ex\IOException
|
||||
* @throws Ex\WrongKeyOrModifiedCiphertextException
|
||||
*/
|
||||
public static function decryptFileWithPassword($inputFilename, $outputFilename, $password)
|
||||
{
|
||||
self::decryptFileInternal(
|
||||
$inputFilename,
|
||||
$outputFilename,
|
||||
KeyOrPassword::createFromPassword($password)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes two resource handles and encrypts the contents of the first,
|
||||
* writing the ciphertext into the second.
|
||||
*
|
||||
* @param resource $inputHandle
|
||||
* @param resource $outputHandle
|
||||
* @param Key $key
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
* @throws Ex\WrongKeyOrModifiedCiphertextException
|
||||
*/
|
||||
public static function encryptResource($inputHandle, $outputHandle, Key $key)
|
||||
{
|
||||
self::encryptResourceInternal(
|
||||
$inputHandle,
|
||||
$outputHandle,
|
||||
KeyOrPassword::createFromKey($key)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts the contents of one resource handle into another with a
|
||||
* password, using a slow key derivation function to make password cracking
|
||||
* more expensive.
|
||||
*
|
||||
* @param resource $inputHandle
|
||||
* @param resource $outputHandle
|
||||
* @param string $password
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
* @throws Ex\IOException
|
||||
* @throws Ex\WrongKeyOrModifiedCiphertextException
|
||||
*/
|
||||
public static function encryptResourceWithPassword($inputHandle, $outputHandle, $password)
|
||||
{
|
||||
self::encryptResourceInternal(
|
||||
$inputHandle,
|
||||
$outputHandle,
|
||||
KeyOrPassword::createFromPassword($password)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes two resource handles and decrypts the contents of the first,
|
||||
* writing the plaintext into the second.
|
||||
*
|
||||
* @param resource $inputHandle
|
||||
* @param resource $outputHandle
|
||||
* @param Key $key
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
* @throws Ex\IOException
|
||||
* @throws Ex\WrongKeyOrModifiedCiphertextException
|
||||
*/
|
||||
public static function decryptResource($inputHandle, $outputHandle, Key $key)
|
||||
{
|
||||
self::decryptResourceInternal(
|
||||
$inputHandle,
|
||||
$outputHandle,
|
||||
KeyOrPassword::createFromKey($key)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts the contents of one resource into another with a password, using
|
||||
* a slow key derivation function to make password cracking more expensive.
|
||||
*
|
||||
* @param resource $inputHandle
|
||||
* @param resource $outputHandle
|
||||
* @param string $password
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
* @throws Ex\IOException
|
||||
* @throws Ex\WrongKeyOrModifiedCiphertextException
|
||||
*/
|
||||
public static function decryptResourceWithPassword($inputHandle, $outputHandle, $password)
|
||||
{
|
||||
self::decryptResourceInternal(
|
||||
$inputHandle,
|
||||
$outputHandle,
|
||||
KeyOrPassword::createFromPassword($password)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts a file with either a key or a password.
|
||||
*
|
||||
* @param string $inputFilename
|
||||
* @param string $outputFilename
|
||||
* @param KeyOrPassword $secret
|
||||
*
|
||||
* @throws Ex\CryptoException
|
||||
* @throws Ex\IOException
|
||||
*/
|
||||
private static function encryptFileInternal($inputFilename, $outputFilename, KeyOrPassword $secret)
|
||||
{
|
||||
/* Open the input file. */
|
||||
$if = @\fopen($inputFilename, 'rb');
|
||||
if ($if === false) {
|
||||
throw new Ex\IOException(
|
||||
'Cannot open input file for encrypting: ' .
|
||||
self::getLastErrorMessage()
|
||||
);
|
||||
}
|
||||
if (\is_callable('\\stream_set_read_buffer')) {
|
||||
/* This call can fail, but the only consequence is performance. */
|
||||
\stream_set_read_buffer($if, 0);
|
||||
}
|
||||
|
||||
/* Open the output file. */
|
||||
$of = @\fopen($outputFilename, 'wb');
|
||||
if ($of === false) {
|
||||
\fclose($if);
|
||||
throw new Ex\IOException(
|
||||
'Cannot open output file for encrypting: ' .
|
||||
self::getLastErrorMessage()
|
||||
);
|
||||
}
|
||||
if (\is_callable('\\stream_set_write_buffer')) {
|
||||
/* This call can fail, but the only consequence is performance. */
|
||||
\stream_set_write_buffer($of, 0);
|
||||
}
|
||||
|
||||
/* Perform the encryption. */
|
||||
try {
|
||||
self::encryptResourceInternal($if, $of, $secret);
|
||||
} catch (Ex\CryptoException $ex) {
|
||||
\fclose($if);
|
||||
\fclose($of);
|
||||
throw $ex;
|
||||
}
|
||||
|
||||
/* Close the input file. */
|
||||
if (\fclose($if) === false) {
|
||||
\fclose($of);
|
||||
throw new Ex\IOException(
|
||||
'Cannot close input file after encrypting'
|
||||
);
|
||||
}
|
||||
|
||||
/* Close the output file. */
|
||||
if (\fclose($of) === false) {
|
||||
throw new Ex\IOException(
|
||||
'Cannot close output file after encrypting'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts a file with either a key or a password.
|
||||
*
|
||||
* @param string $inputFilename
|
||||
* @param string $outputFilename
|
||||
* @param KeyOrPassword $secret
|
||||
*
|
||||
* @throws Ex\CryptoException
|
||||
* @throws Ex\IOException
|
||||
*/
|
||||
private static function decryptFileInternal($inputFilename, $outputFilename, KeyOrPassword $secret)
|
||||
{
|
||||
/* Open the input file. */
|
||||
$if = @\fopen($inputFilename, 'rb');
|
||||
if ($if === false) {
|
||||
throw new Ex\IOException(
|
||||
'Cannot open input file for decrypting: ' .
|
||||
self::getLastErrorMessage()
|
||||
);
|
||||
}
|
||||
|
||||
if (\is_callable('\\stream_set_read_buffer')) {
|
||||
/* This call can fail, but the only consequence is performance. */
|
||||
\stream_set_read_buffer($if, 0);
|
||||
}
|
||||
|
||||
/* Open the output file. */
|
||||
$of = @\fopen($outputFilename, 'wb');
|
||||
if ($of === false) {
|
||||
\fclose($if);
|
||||
throw new Ex\IOException(
|
||||
'Cannot open output file for decrypting: ' .
|
||||
self::getLastErrorMessage()
|
||||
);
|
||||
}
|
||||
|
||||
if (\is_callable('\\stream_set_write_buffer')) {
|
||||
/* This call can fail, but the only consequence is performance. */
|
||||
\stream_set_write_buffer($of, 0);
|
||||
}
|
||||
|
||||
/* Perform the decryption. */
|
||||
try {
|
||||
self::decryptResourceInternal($if, $of, $secret);
|
||||
} catch (Ex\CryptoException $ex) {
|
||||
\fclose($if);
|
||||
\fclose($of);
|
||||
throw $ex;
|
||||
}
|
||||
|
||||
/* Close the input file. */
|
||||
if (\fclose($if) === false) {
|
||||
\fclose($of);
|
||||
throw new Ex\IOException(
|
||||
'Cannot close input file after decrypting'
|
||||
);
|
||||
}
|
||||
|
||||
/* Close the output file. */
|
||||
if (\fclose($of) === false) {
|
||||
throw new Ex\IOException(
|
||||
'Cannot close output file after decrypting'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts a resource with either a key or a password.
|
||||
*
|
||||
* @param resource $inputHandle
|
||||
* @param resource $outputHandle
|
||||
* @param KeyOrPassword $secret
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
* @throws Ex\IOException
|
||||
*/
|
||||
private static function encryptResourceInternal($inputHandle, $outputHandle, KeyOrPassword $secret)
|
||||
{
|
||||
if (! \is_resource($inputHandle)) {
|
||||
throw new Ex\IOException(
|
||||
'Input handle must be a resource!'
|
||||
);
|
||||
}
|
||||
if (! \is_resource($outputHandle)) {
|
||||
throw new Ex\IOException(
|
||||
'Output handle must be a resource!'
|
||||
);
|
||||
}
|
||||
|
||||
$inputStat = \fstat($inputHandle);
|
||||
$inputSize = $inputStat['size'];
|
||||
|
||||
$file_salt = Core::secureRandom(Core::SALT_BYTE_SIZE);
|
||||
$keys = $secret->deriveKeys($file_salt);
|
||||
$ekey = $keys->getEncryptionKey();
|
||||
$akey = $keys->getAuthenticationKey();
|
||||
|
||||
$ivsize = Core::BLOCK_BYTE_SIZE;
|
||||
$iv = Core::secureRandom($ivsize);
|
||||
|
||||
/* Initialize a streaming HMAC state. */
|
||||
$hmac = \hash_init(Core::HASH_FUNCTION_NAME, HASH_HMAC, $akey);
|
||||
if ($hmac === false) {
|
||||
throw new Ex\EnvironmentIsBrokenException(
|
||||
'Cannot initialize a hash context'
|
||||
);
|
||||
}
|
||||
|
||||
/* Write the header, salt, and IV. */
|
||||
self::writeBytes(
|
||||
$outputHandle,
|
||||
Core::CURRENT_VERSION . $file_salt . $iv,
|
||||
Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE + $ivsize
|
||||
);
|
||||
|
||||
/* Add the header, salt, and IV to the HMAC. */
|
||||
\hash_update($hmac, Core::CURRENT_VERSION);
|
||||
\hash_update($hmac, $file_salt);
|
||||
\hash_update($hmac, $iv);
|
||||
|
||||
/* $thisIv will be incremented after each call to the encryption. */
|
||||
$thisIv = $iv;
|
||||
|
||||
/* How many blocks do we encrypt at a time? We increment by this value. */
|
||||
$inc = Core::BUFFER_BYTE_SIZE / Core::BLOCK_BYTE_SIZE;
|
||||
|
||||
/* Loop until we reach the end of the input file. */
|
||||
$at_file_end = false;
|
||||
while (! (\feof($inputHandle) || $at_file_end)) {
|
||||
/* Find out if we can read a full buffer, or only a partial one. */
|
||||
$pos = \ftell($inputHandle);
|
||||
if ($pos === false) {
|
||||
throw new Ex\IOException(
|
||||
'Could not get current position in input file during encryption'
|
||||
);
|
||||
}
|
||||
if ($pos + Core::BUFFER_BYTE_SIZE >= $inputSize) {
|
||||
/* We're at the end of the file, so we need to break out of the loop. */
|
||||
$at_file_end = true;
|
||||
$read = self::readBytes(
|
||||
$inputHandle,
|
||||
$inputSize - $pos
|
||||
);
|
||||
} else {
|
||||
$read = self::readBytes(
|
||||
$inputHandle,
|
||||
Core::BUFFER_BYTE_SIZE
|
||||
);
|
||||
}
|
||||
|
||||
/* Encrypt this buffer. */
|
||||
$encrypted = \openssl_encrypt(
|
||||
$read,
|
||||
Core::CIPHER_METHOD,
|
||||
$ekey,
|
||||
OPENSSL_RAW_DATA,
|
||||
$thisIv
|
||||
);
|
||||
|
||||
if ($encrypted === false) {
|
||||
throw new Ex\EnvironmentIsBrokenException(
|
||||
'OpenSSL encryption error'
|
||||
);
|
||||
}
|
||||
|
||||
/* Write this buffer's ciphertext. */
|
||||
self::writeBytes($outputHandle, $encrypted, Core::ourStrlen($encrypted));
|
||||
/* Add this buffer's ciphertext to the HMAC. */
|
||||
\hash_update($hmac, $encrypted);
|
||||
|
||||
/* Increment the counter by the number of blocks in a buffer. */
|
||||
$thisIv = Core::incrementCounter($thisIv, $inc);
|
||||
/* WARNING: Usually, unless the file is a multiple of the buffer
|
||||
* size, $thisIv will contain an incorrect value here on the last
|
||||
* iteration of this loop. */
|
||||
}
|
||||
|
||||
/* Get the HMAC and append it to the ciphertext. */
|
||||
$final_mac = \hash_final($hmac, true);
|
||||
self::writeBytes($outputHandle, $final_mac, Core::MAC_BYTE_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts a file-backed resource with either a key or a password.
|
||||
*
|
||||
* @param resource $inputHandle
|
||||
* @param resource $outputHandle
|
||||
* @param KeyOrPassword $secret
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
* @throws Ex\IOException
|
||||
* @throws Ex\WrongKeyOrModifiedCiphertextException
|
||||
*/
|
||||
public static function decryptResourceInternal($inputHandle, $outputHandle, KeyOrPassword $secret)
|
||||
{
|
||||
if (! \is_resource($inputHandle)) {
|
||||
throw new Ex\IOException(
|
||||
'Input handle must be a resource!'
|
||||
);
|
||||
}
|
||||
if (! \is_resource($outputHandle)) {
|
||||
throw new Ex\IOException(
|
||||
'Output handle must be a resource!'
|
||||
);
|
||||
}
|
||||
|
||||
/* Make sure the file is big enough for all the reads we need to do. */
|
||||
$stat = \fstat($inputHandle);
|
||||
if ($stat['size'] < Core::MINIMUM_CIPHERTEXT_SIZE) {
|
||||
throw new Ex\WrongKeyOrModifiedCiphertextException(
|
||||
'Input file is too small to have been created by this library.'
|
||||
);
|
||||
}
|
||||
|
||||
/* Check the version header. */
|
||||
$header = self::readBytes($inputHandle, Core::HEADER_VERSION_SIZE);
|
||||
if ($header !== Core::CURRENT_VERSION) {
|
||||
throw new Ex\WrongKeyOrModifiedCiphertextException(
|
||||
'Bad version header.'
|
||||
);
|
||||
}
|
||||
|
||||
/* Get the salt. */
|
||||
$file_salt = self::readBytes($inputHandle, Core::SALT_BYTE_SIZE);
|
||||
|
||||
/* Get the IV. */
|
||||
$ivsize = Core::BLOCK_BYTE_SIZE;
|
||||
$iv = self::readBytes($inputHandle, $ivsize);
|
||||
|
||||
/* Derive the authentication and encryption keys. */
|
||||
$keys = $secret->deriveKeys($file_salt);
|
||||
$ekey = $keys->getEncryptionKey();
|
||||
$akey = $keys->getAuthenticationKey();
|
||||
|
||||
/* We'll store the MAC of each buffer-sized chunk as we verify the
|
||||
* actual MAC, so that we can check them again when decrypting. */
|
||||
$macs = [];
|
||||
|
||||
/* $thisIv will be incremented after each call to the decryption. */
|
||||
$thisIv = $iv;
|
||||
|
||||
/* How many blocks do we encrypt at a time? We increment by this value. */
|
||||
$inc = Core::BUFFER_BYTE_SIZE / Core::BLOCK_BYTE_SIZE;
|
||||
|
||||
/* Get the HMAC. */
|
||||
if (\fseek($inputHandle, (-1 * Core::MAC_BYTE_SIZE), SEEK_END) === false) {
|
||||
throw new Ex\IOException(
|
||||
'Cannot seek to beginning of MAC within input file'
|
||||
);
|
||||
}
|
||||
|
||||
/* Get the position of the last byte in the actual ciphertext. */
|
||||
$cipher_end = \ftell($inputHandle);
|
||||
if ($cipher_end === false) {
|
||||
throw new Ex\IOException(
|
||||
'Cannot read input file'
|
||||
);
|
||||
}
|
||||
/* We have the position of the first byte of the HMAC. Go back by one. */
|
||||
--$cipher_end;
|
||||
|
||||
/* Read the HMAC. */
|
||||
$stored_mac = self::readBytes($inputHandle, Core::MAC_BYTE_SIZE);
|
||||
|
||||
/* Initialize a streaming HMAC state. */
|
||||
$hmac = \hash_init(Core::HASH_FUNCTION_NAME, HASH_HMAC, $akey);
|
||||
if ($hmac === false) {
|
||||
throw new Ex\EnvironmentIsBrokenException(
|
||||
'Cannot initialize a hash context'
|
||||
);
|
||||
}
|
||||
|
||||
/* Reset file pointer to the beginning of the file after the header */
|
||||
if (\fseek($inputHandle, Core::HEADER_VERSION_SIZE, SEEK_SET) === false) {
|
||||
throw new Ex\IOException(
|
||||
'Cannot read seek within input file'
|
||||
);
|
||||
}
|
||||
|
||||
/* Seek to the start of the actual ciphertext. */
|
||||
if (\fseek($inputHandle, Core::SALT_BYTE_SIZE + $ivsize, SEEK_CUR) === false) {
|
||||
throw new Ex\IOException(
|
||||
'Cannot seek input file to beginning of ciphertext'
|
||||
);
|
||||
}
|
||||
|
||||
/* PASS #1: Calculating the HMAC. */
|
||||
|
||||
\hash_update($hmac, $header);
|
||||
\hash_update($hmac, $file_salt);
|
||||
\hash_update($hmac, $iv);
|
||||
$hmac2 = \hash_copy($hmac);
|
||||
|
||||
$break = false;
|
||||
while (! $break) {
|
||||
$pos = \ftell($inputHandle);
|
||||
if ($pos === false) {
|
||||
throw new Ex\IOException(
|
||||
'Could not get current position in input file during decryption'
|
||||
);
|
||||
}
|
||||
|
||||
/* Read the next buffer-sized chunk (or less). */
|
||||
if ($pos + Core::BUFFER_BYTE_SIZE >= $cipher_end) {
|
||||
$break = true;
|
||||
$read = self::readBytes(
|
||||
$inputHandle,
|
||||
$cipher_end - $pos + 1
|
||||
);
|
||||
} else {
|
||||
$read = self::readBytes(
|
||||
$inputHandle,
|
||||
Core::BUFFER_BYTE_SIZE
|
||||
);
|
||||
}
|
||||
|
||||
/* Update the HMAC. */
|
||||
\hash_update($hmac, $read);
|
||||
|
||||
/* Remember this buffer-sized chunk's HMAC. */
|
||||
$chunk_mac = \hash_copy($hmac);
|
||||
if ($chunk_mac === false) {
|
||||
throw new Ex\EnvironmentIsBrokenException(
|
||||
'Cannot duplicate a hash context'
|
||||
);
|
||||
}
|
||||
$macs []= \hash_final($chunk_mac);
|
||||
}
|
||||
|
||||
/* Get the final HMAC, which should match the stored one. */
|
||||
$final_mac = \hash_final($hmac, true);
|
||||
|
||||
/* Verify the HMAC. */
|
||||
if (! Core::hashEquals($final_mac, $stored_mac)) {
|
||||
throw new Ex\WrongKeyOrModifiedCiphertextException(
|
||||
'Integrity check failed.'
|
||||
);
|
||||
}
|
||||
|
||||
/* PASS #2: Decrypt and write output. */
|
||||
|
||||
/* Rewind to the start of the actual ciphertext. */
|
||||
if (\fseek($inputHandle, Core::SALT_BYTE_SIZE + $ivsize + Core::HEADER_VERSION_SIZE, SEEK_SET) === false) {
|
||||
throw new Ex\IOException(
|
||||
'Could not move the input file pointer during decryption'
|
||||
);
|
||||
}
|
||||
|
||||
$at_file_end = false;
|
||||
while (! $at_file_end) {
|
||||
$pos = \ftell($inputHandle);
|
||||
if ($pos === false) {
|
||||
throw new Ex\IOException(
|
||||
'Could not get current position in input file during decryption'
|
||||
);
|
||||
}
|
||||
|
||||
/* Read the next buffer-sized chunk (or less). */
|
||||
if ($pos + Core::BUFFER_BYTE_SIZE >= $cipher_end) {
|
||||
$at_file_end = true;
|
||||
$read = self::readBytes(
|
||||
$inputHandle,
|
||||
$cipher_end - $pos + 1
|
||||
);
|
||||
} else {
|
||||
$read = self::readBytes(
|
||||
$inputHandle,
|
||||
Core::BUFFER_BYTE_SIZE
|
||||
);
|
||||
}
|
||||
|
||||
/* Recalculate the MAC (so far) and compare it with the one we
|
||||
* remembered from pass #1 to ensure attackers didn't change the
|
||||
* ciphertext after MAC verification. */
|
||||
\hash_update($hmac2, $read);
|
||||
$calc_mac = \hash_copy($hmac2);
|
||||
if ($calc_mac === false) {
|
||||
throw new Ex\EnvironmentIsBrokenException(
|
||||
'Cannot duplicate a hash context'
|
||||
);
|
||||
}
|
||||
$calc = \hash_final($calc_mac);
|
||||
|
||||
if (empty($macs)) {
|
||||
throw new Ex\WrongKeyOrModifiedCiphertextException(
|
||||
'File was modified after MAC verification'
|
||||
);
|
||||
} elseif (! Core::hashEquals(\array_shift($macs), $calc)) {
|
||||
throw new Ex\WrongKeyOrModifiedCiphertextException(
|
||||
'File was modified after MAC verification'
|
||||
);
|
||||
}
|
||||
|
||||
/* Decrypt this buffer-sized chunk. */
|
||||
$decrypted = \openssl_decrypt(
|
||||
$read,
|
||||
Core::CIPHER_METHOD,
|
||||
$ekey,
|
||||
OPENSSL_RAW_DATA,
|
||||
$thisIv
|
||||
);
|
||||
if ($decrypted === false) {
|
||||
throw new Ex\EnvironmentIsBrokenException(
|
||||
'OpenSSL decryption error'
|
||||
);
|
||||
}
|
||||
|
||||
/* Write the plaintext to the output file. */
|
||||
self::writeBytes(
|
||||
$outputHandle,
|
||||
$decrypted,
|
||||
Core::ourStrlen($decrypted)
|
||||
);
|
||||
|
||||
/* Increment the IV by the amount of blocks in a buffer. */
|
||||
$thisIv = Core::incrementCounter($thisIv, $inc);
|
||||
/* WARNING: Usually, unless the file is a multiple of the buffer
|
||||
* size, $thisIv will contain an incorrect value here on the last
|
||||
* iteration of this loop. */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read from a stream; prevent partial reads.
|
||||
*
|
||||
* @param resource $stream
|
||||
* @param int $num_bytes
|
||||
*
|
||||
* @throws Ex\IOException
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function readBytes($stream, $num_bytes)
|
||||
{
|
||||
if ($num_bytes < 0) {
|
||||
throw new Ex\EnvironmentIsBrokenException(
|
||||
'Tried to read less than 0 bytes'
|
||||
);
|
||||
} elseif ($num_bytes === 0) {
|
||||
return '';
|
||||
}
|
||||
$buf = '';
|
||||
$remaining = $num_bytes;
|
||||
while ($remaining > 0 && ! \feof($stream)) {
|
||||
$read = \fread($stream, $remaining);
|
||||
|
||||
if ($read === false) {
|
||||
throw new Ex\IOException(
|
||||
'Could not read from the file'
|
||||
);
|
||||
}
|
||||
$buf .= $read;
|
||||
$remaining -= Core::ourStrlen($read);
|
||||
}
|
||||
if (Core::ourStrlen($buf) !== $num_bytes) {
|
||||
throw new Ex\IOException(
|
||||
'Tried to read past the end of the file'
|
||||
);
|
||||
}
|
||||
return $buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write to a stream; prevents partial writes.
|
||||
*
|
||||
* @param resource $stream
|
||||
* @param string $buf
|
||||
* @param int $num_bytes
|
||||
*
|
||||
* @throws Ex\IOException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function writeBytes($stream, $buf, $num_bytes = null)
|
||||
{
|
||||
$bufSize = Core::ourStrlen($buf);
|
||||
if ($num_bytes === null) {
|
||||
$num_bytes = $bufSize;
|
||||
}
|
||||
if ($num_bytes > $bufSize) {
|
||||
throw new Ex\IOException(
|
||||
'Trying to write more bytes than the buffer contains.'
|
||||
);
|
||||
}
|
||||
if ($num_bytes < 0) {
|
||||
throw new Ex\IOException(
|
||||
'Tried to write less than 0 bytes'
|
||||
);
|
||||
}
|
||||
$remaining = $num_bytes;
|
||||
while ($remaining > 0) {
|
||||
$written = \fwrite($stream, $buf, $remaining);
|
||||
if ($written === false) {
|
||||
throw new Ex\IOException(
|
||||
'Could not write to the file'
|
||||
);
|
||||
}
|
||||
$buf = Core::ourSubstr($buf, $written, null);
|
||||
$remaining -= $written;
|
||||
}
|
||||
return $num_bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last PHP error's or warning's message string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private static function getLastErrorMessage()
|
||||
{
|
||||
$error = error_get_last();
|
||||
if ($error === null) {
|
||||
return '[no PHP error]';
|
||||
} else {
|
||||
return $error['message'];
|
||||
}
|
||||
}
|
||||
}
|
||||
84
tools/defuse/php-encryption/src/Key.php
Normal file
84
tools/defuse/php-encryption/src/Key.php
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace Defuse\Crypto;
|
||||
|
||||
use Defuse\Crypto\Exception as Ex;
|
||||
|
||||
final class Key
|
||||
{
|
||||
const KEY_CURRENT_VERSION = "\xDE\xF0\x00\x00";
|
||||
const KEY_BYTE_SIZE = 32;
|
||||
|
||||
private $key_bytes = null;
|
||||
|
||||
/**
|
||||
* Creates new random key.
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
*
|
||||
* @return Key
|
||||
*/
|
||||
public static function createNewRandomKey()
|
||||
{
|
||||
return new Key(Core::secureRandom(self::KEY_BYTE_SIZE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a Key from its encoded form.
|
||||
*
|
||||
* @param string $saved_key_string
|
||||
*
|
||||
* @throws Ex\BadFormatException
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
*
|
||||
* @return Key
|
||||
*/
|
||||
public static function loadFromAsciiSafeString($saved_key_string)
|
||||
{
|
||||
$key_bytes = Encoding::loadBytesFromChecksummedAsciiSafeString(self::KEY_CURRENT_VERSION, $saved_key_string);
|
||||
return new Key($key_bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the Key into a string of printable ASCII characters.
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function saveToAsciiSafeString()
|
||||
{
|
||||
return Encoding::saveBytesToChecksummedAsciiSafeString(
|
||||
self::KEY_CURRENT_VERSION,
|
||||
$this->key_bytes
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the raw bytes of the key.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRawBytes()
|
||||
{
|
||||
return $this->key_bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new Key object from a string of raw bytes.
|
||||
*
|
||||
* @param string $bytes
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
*/
|
||||
private function __construct($bytes)
|
||||
{
|
||||
if (Core::ourStrlen($bytes) !== self::KEY_BYTE_SIZE) {
|
||||
throw new Ex\EnvironmentIsBrokenException(
|
||||
'Bad key length.'
|
||||
);
|
||||
}
|
||||
$this->key_bytes = $bytes;
|
||||
}
|
||||
|
||||
}
|
||||
119
tools/defuse/php-encryption/src/KeyOrPassword.php
Normal file
119
tools/defuse/php-encryption/src/KeyOrPassword.php
Normal file
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
namespace Defuse\Crypto;
|
||||
|
||||
use Defuse\Crypto\Exception as Ex;
|
||||
|
||||
final class KeyOrPassword
|
||||
{
|
||||
const PBKDF2_ITERATIONS = 100000;
|
||||
const SECRET_TYPE_KEY = 1;
|
||||
const SECRET_TYPE_PASSWORD = 2;
|
||||
|
||||
private $secret_type = null;
|
||||
private $secret = null;
|
||||
|
||||
/**
|
||||
* Initializes an instance of KeyOrPassword from a key.
|
||||
*
|
||||
* @param Key $key
|
||||
*
|
||||
* @return KeyOrPassword
|
||||
*/
|
||||
public static function createFromKey(Key $key)
|
||||
{
|
||||
return new KeyOrPassword(self::SECRET_TYPE_KEY, $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes an instance of KeyOrPassword from a password.
|
||||
*
|
||||
* @param string $password
|
||||
*
|
||||
* @return KeyOrPassword
|
||||
*/
|
||||
public static function createFromPassword($password)
|
||||
{
|
||||
return new KeyOrPassword(self::SECRET_TYPE_PASSWORD, $password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Derives authentication and encryption keys from the secret, using a slow
|
||||
* key derivation function if the secret is a password.
|
||||
*
|
||||
* @param string $salt
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
*
|
||||
* @return DerivedKeys
|
||||
*/
|
||||
public function deriveKeys($salt)
|
||||
{
|
||||
if (Core::ourStrlen($salt) !== Core::SALT_BYTE_SIZE) {
|
||||
throw new Ex\EnvironmentIsBrokenException('Bad salt.');
|
||||
}
|
||||
|
||||
if ($this->secret_type === self::SECRET_TYPE_KEY) {
|
||||
$akey = Core::HKDF(
|
||||
Core::HASH_FUNCTION_NAME,
|
||||
$this->secret->getRawBytes(),
|
||||
Core::KEY_BYTE_SIZE,
|
||||
Core::AUTHENTICATION_INFO_STRING,
|
||||
$salt
|
||||
);
|
||||
$ekey = Core::HKDF(
|
||||
Core::HASH_FUNCTION_NAME,
|
||||
$this->secret->getRawBytes(),
|
||||
Core::KEY_BYTE_SIZE,
|
||||
Core::ENCRYPTION_INFO_STRING,
|
||||
$salt
|
||||
);
|
||||
return new DerivedKeys($akey, $ekey);
|
||||
} elseif ($this->secret_type === self::SECRET_TYPE_PASSWORD) {
|
||||
/* Our PBKDF2 polyfill is vulnerable to a DoS attack documented in
|
||||
* GitHub issue #230. The fix is to pre-hash the password to ensure
|
||||
* it is short. We do the prehashing here instead of in pbkdf2() so
|
||||
* that pbkdf2() still computes the function as defined by the
|
||||
* standard. */
|
||||
$prehash = \hash(Core::HASH_FUNCTION_NAME, $this->secret, true);
|
||||
$prekey = Core::pbkdf2(
|
||||
Core::HASH_FUNCTION_NAME,
|
||||
$prehash,
|
||||
$salt,
|
||||
self::PBKDF2_ITERATIONS,
|
||||
Core::KEY_BYTE_SIZE,
|
||||
true
|
||||
);
|
||||
$akey = Core::HKDF(
|
||||
Core::HASH_FUNCTION_NAME,
|
||||
$prekey,
|
||||
Core::KEY_BYTE_SIZE,
|
||||
Core::AUTHENTICATION_INFO_STRING,
|
||||
$salt
|
||||
);
|
||||
/* Note the cryptographic re-use of $salt here. */
|
||||
$ekey = Core::HKDF(
|
||||
Core::HASH_FUNCTION_NAME,
|
||||
$prekey,
|
||||
Core::KEY_BYTE_SIZE,
|
||||
Core::ENCRYPTION_INFO_STRING,
|
||||
$salt
|
||||
);
|
||||
return new DerivedKeys($akey, $ekey);
|
||||
} else {
|
||||
throw new Ex\EnvironmentIsBrokenException('Bad secret type.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for KeyOrPassword.
|
||||
*
|
||||
* @param int $secret_type
|
||||
* @param mixed $secret (either a Key or a password string)
|
||||
*/
|
||||
private function __construct($secret_type, $secret)
|
||||
{
|
||||
$this->secret_type = $secret_type;
|
||||
$this->secret = $secret;
|
||||
}
|
||||
}
|
||||
112
tools/defuse/php-encryption/src/KeyProtectedByPassword.php
Normal file
112
tools/defuse/php-encryption/src/KeyProtectedByPassword.php
Normal file
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
namespace Defuse\Crypto;
|
||||
|
||||
use Defuse\Crypto\Exception as Ex;
|
||||
|
||||
final class KeyProtectedByPassword
|
||||
{
|
||||
const PASSWORD_KEY_CURRENT_VERSION = "\xDE\xF1\x00\x00";
|
||||
|
||||
private $encrypted_key = null;
|
||||
|
||||
/**
|
||||
* Creates a random key protected by the provided password.
|
||||
*
|
||||
* @param string $password
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
*
|
||||
* @return KeyProtectedByPassword
|
||||
*/
|
||||
public static function createRandomPasswordProtectedKey($password)
|
||||
{
|
||||
$inner_key = Key::createNewRandomKey();
|
||||
/* The password is hashed as a form of poor-man's domain separation
|
||||
* between this use of encryptWithPassword() and other uses of
|
||||
* encryptWithPassword() that the user may also be using as part of the
|
||||
* same protocol. */
|
||||
$encrypted_key = Crypto::encryptWithPassword(
|
||||
$inner_key->saveToAsciiSafeString(),
|
||||
\hash(Core::HASH_FUNCTION_NAME, $password, true),
|
||||
true
|
||||
);
|
||||
|
||||
return new KeyProtectedByPassword($encrypted_key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a KeyProtectedByPassword from its encoded form.
|
||||
*
|
||||
* @param string $saved_key_string
|
||||
*
|
||||
* @throws Ex\BadFormatException
|
||||
*
|
||||
* @return KeyProtectedByPassword
|
||||
*/
|
||||
public static function loadFromAsciiSafeString($saved_key_string)
|
||||
{
|
||||
$encrypted_key = Encoding::loadBytesFromChecksummedAsciiSafeString(
|
||||
self::PASSWORD_KEY_CURRENT_VERSION,
|
||||
$saved_key_string
|
||||
);
|
||||
return new KeyProtectedByPassword($encrypted_key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the KeyProtectedByPassword into a string of printable ASCII
|
||||
* characters.
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function saveToAsciiSafeString()
|
||||
{
|
||||
return Encoding::saveBytesToChecksummedAsciiSafeString(
|
||||
self::PASSWORD_KEY_CURRENT_VERSION,
|
||||
$this->encrypted_key
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts the protected key, returning an unprotected Key object that can
|
||||
* be used for encryption and decryption.
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
* @throws Ex\WrongKeyOrModifiedCiphertextException
|
||||
*
|
||||
* @return Key
|
||||
*/
|
||||
public function unlockKey($password)
|
||||
{
|
||||
try {
|
||||
$inner_key_encoded = Crypto::decryptWithPassword(
|
||||
$this->encrypted_key,
|
||||
\hash(Core::HASH_FUNCTION_NAME, $password, true),
|
||||
true
|
||||
);
|
||||
return Key::loadFromAsciiSafeString($inner_key_encoded);
|
||||
} catch (Ex\BadFormatException $ex) {
|
||||
/* This should never happen unless an attacker replaced the
|
||||
* encrypted key ciphertext with some other ciphertext that was
|
||||
* encrypted with the same password. We transform the exception type
|
||||
* here in order to make the API simpler, avoiding the need to
|
||||
* document that this method might throw an Ex\BadFormatException. */
|
||||
throw new Ex\WrongKeyOrModifiedCiphertextException(
|
||||
"The decrypted key was found to be in an invalid format. " .
|
||||
"This very likely indicates it was modified by an attacker."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for KeyProtectedByPassword.
|
||||
*
|
||||
* @param string $encrypted_key
|
||||
*/
|
||||
private function __construct($encrypted_key)
|
||||
{
|
||||
$this->encrypted_key = $encrypted_key;
|
||||
}
|
||||
}
|
||||
242
tools/defuse/php-encryption/src/RuntimeTests.php
Normal file
242
tools/defuse/php-encryption/src/RuntimeTests.php
Normal file
@@ -0,0 +1,242 @@
|
||||
<?php
|
||||
|
||||
namespace Defuse\Crypto;
|
||||
|
||||
use Defuse\Crypto\Exception as Ex;
|
||||
|
||||
/*
|
||||
* We're using static class inheritance to get access to protected methods
|
||||
* inside Crypto. To make it easy to know where the method we're calling can be
|
||||
* found, within this file, prefix calls with `Crypto::` or `RuntimeTests::`,
|
||||
* and don't use `self::`.
|
||||
*/
|
||||
|
||||
class RuntimeTests extends Crypto
|
||||
{
|
||||
/**
|
||||
* Runs the runtime tests.
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
*/
|
||||
public static function runtimeTest()
|
||||
{
|
||||
// 0: Tests haven't been run yet.
|
||||
// 1: Tests have passed.
|
||||
// 2: Tests are running right now.
|
||||
// 3: Tests have failed.
|
||||
static $test_state = 0;
|
||||
|
||||
if ($test_state === 1 || $test_state === 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($test_state === 3) {
|
||||
/* If an intermittent problem caused a test to fail previously, we
|
||||
* want that to be indicated to the user with every call to this
|
||||
* library. This way, if the user first does something they really
|
||||
* don't care about, and just ignores all exceptions, they won't get
|
||||
* screwed when they then start to use the library for something
|
||||
* they do care about. */
|
||||
throw new Ex\EnvironmentIsBrokenException('Tests failed previously.');
|
||||
}
|
||||
|
||||
try {
|
||||
$test_state = 2;
|
||||
|
||||
Core::ensureFunctionExists('openssl_get_cipher_methods');
|
||||
if (\in_array(Core::CIPHER_METHOD, \openssl_get_cipher_methods()) === false) {
|
||||
throw new Ex\EnvironmentIsBrokenException(
|
||||
'Cipher method not supported. This is normally caused by an outdated ' .
|
||||
'version of OpenSSL (and/or OpenSSL compiled for FIPS compliance). ' .
|
||||
'Please upgrade to a newer version of OpenSSL that supports ' .
|
||||
Core::CIPHER_METHOD . ' to use this library.'
|
||||
);
|
||||
}
|
||||
|
||||
RuntimeTests::AESTestVector();
|
||||
RuntimeTests::HMACTestVector();
|
||||
RuntimeTests::HKDFTestVector();
|
||||
|
||||
RuntimeTests::testEncryptDecrypt();
|
||||
if (Core::ourStrlen(Key::createNewRandomKey()->getRawBytes()) != Core::KEY_BYTE_SIZE) {
|
||||
throw new Ex\EnvironmentIsBrokenException();
|
||||
}
|
||||
|
||||
if (Core::ENCRYPTION_INFO_STRING == Core::AUTHENTICATION_INFO_STRING) {
|
||||
throw new Ex\EnvironmentIsBrokenException();
|
||||
}
|
||||
} catch (Ex\EnvironmentIsBrokenException $ex) {
|
||||
// Do this, otherwise it will stay in the "tests are running" state.
|
||||
$test_state = 3;
|
||||
throw $ex;
|
||||
}
|
||||
|
||||
// Change this to '0' make the tests always re-run (for benchmarking).
|
||||
$test_state = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* High-level tests of Crypto operations.
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
*/
|
||||
private static function testEncryptDecrypt()
|
||||
{
|
||||
$key = Key::createNewRandomKey();
|
||||
$data = "EnCrYpT EvErYThInG\x00\x00";
|
||||
|
||||
// Make sure encrypting then decrypting doesn't change the message.
|
||||
$ciphertext = Crypto::encrypt($data, $key, true);
|
||||
try {
|
||||
$decrypted = Crypto::decrypt($ciphertext, $key, true);
|
||||
} catch (Ex\WrongKeyOrModifiedCiphertextException $ex) {
|
||||
// It's important to catch this and change it into a
|
||||
// Ex\EnvironmentIsBrokenException, otherwise a test failure could trick
|
||||
// the user into thinking it's just an invalid ciphertext!
|
||||
throw new Ex\EnvironmentIsBrokenException();
|
||||
}
|
||||
if ($decrypted !== $data) {
|
||||
throw new Ex\EnvironmentIsBrokenException();
|
||||
}
|
||||
|
||||
// Modifying the ciphertext: Appending a string.
|
||||
try {
|
||||
Crypto::decrypt($ciphertext . 'a', $key, true);
|
||||
throw new Ex\EnvironmentIsBrokenException();
|
||||
} catch (Ex\WrongKeyOrModifiedCiphertextException $e) { /* expected */
|
||||
}
|
||||
|
||||
// Modifying the ciphertext: Changing an HMAC byte.
|
||||
$indices_to_change = [
|
||||
0, // The header.
|
||||
Core::HEADER_VERSION_SIZE + 1, // the salt
|
||||
Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE + 1, // the IV
|
||||
Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE + Core::BLOCK_BYTE_SIZE + 1, // the ciphertext
|
||||
];
|
||||
|
||||
foreach ($indices_to_change as $index) {
|
||||
try {
|
||||
$ciphertext[$index] = \chr((\ord($ciphertext[$index]) + 1) % 256);
|
||||
Crypto::decrypt($ciphertext, $key, true);
|
||||
throw new Ex\EnvironmentIsBrokenException();
|
||||
} catch (Ex\WrongKeyOrModifiedCiphertextException $e) { /* expected */
|
||||
}
|
||||
}
|
||||
|
||||
// Decrypting with the wrong key.
|
||||
$key = Key::createNewRandomKey();
|
||||
$data = 'abcdef';
|
||||
$ciphertext = Crypto::encrypt($data, $key, true);
|
||||
$wrong_key = Key::createNewRandomKey();
|
||||
try {
|
||||
Crypto::decrypt($ciphertext, $wrong_key, true);
|
||||
throw new Ex\EnvironmentIsBrokenException();
|
||||
} catch (Ex\WrongKeyOrModifiedCiphertextException $e) { /* expected */
|
||||
}
|
||||
|
||||
// Ciphertext too small.
|
||||
$key = Key::createNewRandomKey();
|
||||
$ciphertext = \str_repeat('A', Core::MINIMUM_CIPHERTEXT_SIZE - 1);
|
||||
try {
|
||||
Crypto::decrypt($ciphertext, $key, true);
|
||||
throw new Ex\EnvironmentIsBrokenException();
|
||||
} catch (Ex\WrongKeyOrModifiedCiphertextException $e) { /* expected */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test HKDF against test vectors.
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
*/
|
||||
private static function HKDFTestVector()
|
||||
{
|
||||
// HKDF test vectors from RFC 5869
|
||||
|
||||
// Test Case 1
|
||||
$ikm = \str_repeat("\x0b", 22);
|
||||
$salt = Encoding::hexToBin('000102030405060708090a0b0c');
|
||||
$info = Encoding::hexToBin('f0f1f2f3f4f5f6f7f8f9');
|
||||
$length = 42;
|
||||
$okm = Encoding::hexToBin(
|
||||
'3cb25f25faacd57a90434f64d0362f2a' .
|
||||
'2d2d0a90cf1a5a4c5db02d56ecc4c5bf' .
|
||||
'34007208d5b887185865'
|
||||
);
|
||||
$computed_okm = Core::HKDF('sha256', $ikm, $length, $info, $salt);
|
||||
if ($computed_okm !== $okm) {
|
||||
throw new Ex\EnvironmentIsBrokenException();
|
||||
}
|
||||
|
||||
// Test Case 7
|
||||
$ikm = \str_repeat("\x0c", 22);
|
||||
$length = 42;
|
||||
$okm = Encoding::hexToBin(
|
||||
'2c91117204d745f3500d636a62f64f0a' .
|
||||
'b3bae548aa53d423b0d1f27ebba6f5e5' .
|
||||
'673a081d70cce7acfc48'
|
||||
);
|
||||
$computed_okm = Core::HKDF('sha1', $ikm, $length, '', null);
|
||||
if ($computed_okm !== $okm) {
|
||||
throw new Ex\EnvironmentIsBrokenException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test HMAC against test vectors.
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
*/
|
||||
private static function HMACTestVector()
|
||||
{
|
||||
// HMAC test vector From RFC 4231 (Test Case 1)
|
||||
$key = \str_repeat("\x0b", 20);
|
||||
$data = 'Hi There';
|
||||
$correct = 'b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7';
|
||||
if (\hash_hmac(Core::HASH_FUNCTION_NAME, $data, $key) !== $correct) {
|
||||
throw new Ex\EnvironmentIsBrokenException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test AES against test vectors.
|
||||
*
|
||||
* @throws Ex\EnvironmentIsBrokenException
|
||||
*/
|
||||
private static function AESTestVector()
|
||||
{
|
||||
// AES CTR mode test vector from NIST SP 800-38A
|
||||
$key = Encoding::hexToBin(
|
||||
'603deb1015ca71be2b73aef0857d7781' .
|
||||
'1f352c073b6108d72d9810a30914dff4'
|
||||
);
|
||||
$iv = Encoding::hexToBin('f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff');
|
||||
$plaintext = Encoding::hexToBin(
|
||||
'6bc1bee22e409f96e93d7e117393172a' .
|
||||
'ae2d8a571e03ac9c9eb76fac45af8e51' .
|
||||
'30c81c46a35ce411e5fbc1191a0a52ef' .
|
||||
'f69f2445df4f9b17ad2b417be66c3710'
|
||||
);
|
||||
$ciphertext = Encoding::hexToBin(
|
||||
'601ec313775789a5b7a7f504bbf3d228' .
|
||||
'f443e3ca4d62b59aca84e990cacaf5c5' .
|
||||
'2b0930daa23de94ce87017ba2d84988d' .
|
||||
'dfc9c58db67aada613c2dd08457941a6'
|
||||
);
|
||||
|
||||
$computed_ciphertext = Crypto::plainEncrypt($plaintext, $key, $iv);
|
||||
if ($computed_ciphertext !== $ciphertext) {
|
||||
echo \str_repeat("\n", 30);
|
||||
echo \bin2hex($computed_ciphertext);
|
||||
echo "\n---\n";
|
||||
echo \bin2hex($ciphertext);
|
||||
echo \str_repeat("\n", 30);
|
||||
throw new Ex\EnvironmentIsBrokenException();
|
||||
}
|
||||
|
||||
$computed_plaintext = Crypto::plainDecrypt($ciphertext, $key, $iv, Core::CIPHER_METHOD);
|
||||
if ($computed_plaintext !== $plaintext) {
|
||||
throw new Ex\EnvironmentIsBrokenException();
|
||||
}
|
||||
}
|
||||
}
|
||||
29
tools/defuse/php-encryption/src/index.php
Normal file
29
tools/defuse/php-encryption/src/index.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
/**
|
||||
* 2010-2021 Webkul.
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* All right is reserved,
|
||||
* Please go through this link for complete license : https://store.webkul.com/license.html
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade this module to newer
|
||||
* versions in the future. If you wish to customize this module for your
|
||||
* needs please refer to https://store.webkul.com/customisation-guidelines/ for more information.
|
||||
*
|
||||
* @author Webkul IN <support@webkul.com>
|
||||
* @copyright 2010-2021 Webkul IN
|
||||
* @license https://store.webkul.com/license.html
|
||||
*/
|
||||
|
||||
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
|
||||
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
|
||||
|
||||
header('Cache-Control: no-store, no-cache, must-revalidate');
|
||||
header('Cache-Control: post-check=0, pre-check=0', false);
|
||||
header('Pragma: no-cache');
|
||||
|
||||
header('Location: ../');
|
||||
exit;
|
||||
Reference in New Issue
Block a user