From 3b2470809848b923569aaea313c121372b7174ed Mon Sep 17 00:00:00 2001 From: shreesh arora Date: Wed, 28 Apr 2021 13:36:42 +0530 Subject: [PATCH 1/2] replace mcrypt with openssl --- admin/functions.php | 8 +- classes/ConfigurationTest.php | 10 +- classes/Cookie.php | 7 +- classes/PhpEncryption.php | 122 +++ classes/PhpEncryptionEngine.php | 168 ++++ classes/PhpEncryptionLegacyEngine.php | 168 ++++ classes/Rijndael.php | 157 ---- config/autoload.php | 1 + .../admin/AdminInformationController.php | 3 +- install/models/install.php | 10 +- tools/defuse/index.php | 29 + tools/defuse/php-encryption/LICENSE | 21 + tools/defuse/php-encryption/README.md | 87 ++ .../defuse/php-encryption/defuse-crypto.phar | Bin 0 -> 50825 bytes tools/defuse/php-encryption/dist/Makefile | 37 + tools/defuse/php-encryption/dist/box.json | 25 + tools/defuse/php-encryption/dist/index.php | 29 + .../defuse/php-encryption/dist/signingkey.asc | 52 ++ tools/defuse/php-encryption/index.php | 29 + tools/defuse/php-encryption/src/Core.php | 434 ++++++++++ tools/defuse/php-encryption/src/Crypto.php | 372 +++++++++ .../defuse/php-encryption/src/DerivedKeys.php | 37 + tools/defuse/php-encryption/src/Encoding.php | 212 +++++ .../src/Exception/BadFormatException.php | 7 + .../src/Exception/CryptoException.php | 7 + .../EnvironmentIsBrokenException.php | 7 + .../src/Exception/IOException.php | 7 + .../WrongKeyOrModifiedCiphertextException.php | 7 + .../php-encryption/src/Exception/index.php | 29 + tools/defuse/php-encryption/src/File.php | 755 ++++++++++++++++++ tools/defuse/php-encryption/src/Key.php | 84 ++ .../php-encryption/src/KeyOrPassword.php | 119 +++ .../src/KeyProtectedByPassword.php | 112 +++ .../php-encryption/src/RuntimeTests.php | 242 ++++++ tools/defuse/php-encryption/src/index.php | 29 + 35 files changed, 3247 insertions(+), 176 deletions(-) create mode 100644 classes/PhpEncryption.php create mode 100644 classes/PhpEncryptionEngine.php create mode 100644 classes/PhpEncryptionLegacyEngine.php delete mode 100644 classes/Rijndael.php create mode 100644 tools/defuse/index.php create mode 100644 tools/defuse/php-encryption/LICENSE create mode 100644 tools/defuse/php-encryption/README.md create mode 100644 tools/defuse/php-encryption/defuse-crypto.phar create mode 100644 tools/defuse/php-encryption/dist/Makefile create mode 100644 tools/defuse/php-encryption/dist/box.json create mode 100644 tools/defuse/php-encryption/dist/index.php create mode 100644 tools/defuse/php-encryption/dist/signingkey.asc create mode 100644 tools/defuse/php-encryption/index.php create mode 100644 tools/defuse/php-encryption/src/Core.php create mode 100644 tools/defuse/php-encryption/src/Crypto.php create mode 100644 tools/defuse/php-encryption/src/DerivedKeys.php create mode 100644 tools/defuse/php-encryption/src/Encoding.php create mode 100644 tools/defuse/php-encryption/src/Exception/BadFormatException.php create mode 100644 tools/defuse/php-encryption/src/Exception/CryptoException.php create mode 100644 tools/defuse/php-encryption/src/Exception/EnvironmentIsBrokenException.php create mode 100644 tools/defuse/php-encryption/src/Exception/IOException.php create mode 100644 tools/defuse/php-encryption/src/Exception/WrongKeyOrModifiedCiphertextException.php create mode 100644 tools/defuse/php-encryption/src/Exception/index.php create mode 100644 tools/defuse/php-encryption/src/File.php create mode 100644 tools/defuse/php-encryption/src/Key.php create mode 100644 tools/defuse/php-encryption/src/KeyOrPassword.php create mode 100644 tools/defuse/php-encryption/src/KeyProtectedByPassword.php create mode 100644 tools/defuse/php-encryption/src/RuntimeTests.php create mode 100644 tools/defuse/php-encryption/src/index.php diff --git a/admin/functions.php b/admin/functions.php index 15c397049..ac1bf8175 100644 --- a/admin/functions.php +++ b/admin/functions.php @@ -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 = " $value) { if ($k == '_PS_VERSION_') { diff --git a/classes/ConfigurationTest.php b/classes/ConfigurationTest.php index 6981c6c76..fe01c59eb 100644 --- a/classes/ConfigurationTest.php +++ b/classes/ConfigurationTest.php @@ -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() diff --git a/classes/Cookie.php b/classes/Cookie.php index 6747b0c24..4c9b65110 100644 --- a/classes/Cookie.php +++ b/classes/Cookie.php @@ -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; diff --git a/classes/PhpEncryption.php b/classes/PhpEncryption.php new file mode 100644 index 000000000..13d4fa7a1 --- /dev/null +++ b/classes/PhpEncryption.php @@ -0,0 +1,122 @@ + + * @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; + } +} diff --git a/classes/PhpEncryptionEngine.php b/classes/PhpEncryptionEngine.php new file mode 100644 index 000000000..3f496f4a2 --- /dev/null +++ b/classes/PhpEncryptionEngine.php @@ -0,0 +1,168 @@ + + * @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 + ); + } +} diff --git a/classes/PhpEncryptionLegacyEngine.php b/classes/PhpEncryptionLegacyEngine.php new file mode 100644 index 000000000..3033024ca --- /dev/null +++ b/classes/PhpEncryptionLegacyEngine.php @@ -0,0 +1,168 @@ + + * @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) + ); + } +} diff --git a/classes/Rijndael.php b/classes/Rijndael.php deleted file mode 100644 index 16edb83bb..000000000 --- a/classes/Rijndael.php +++ /dev/null @@ -1,157 +0,0 @@ - -* @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) - ); - } -} diff --git a/config/autoload.php b/config/autoload.php index 20a6c05fa..0cfc7a14c 100644 --- a/config/autoload.php +++ b/config/autoload.php @@ -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'); diff --git a/controllers/admin/AdminInformationController.php b/controllers/admin/AdminInformationController.php index e740a895f..0225dba02 100644 --- a/controllers/admin/AdminInformationController.php +++ b/controllers/admin/AdminInformationController.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' diff --git a/install/models/install.php b/install/models/install.php index adf157ea3..5325f4a80 100644 --- a/install/models/install.php +++ b/install/models/install.php @@ -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 = " $value) { diff --git a/tools/defuse/index.php b/tools/defuse/index.php new file mode 100644 index 000000000..d9925ba54 --- /dev/null +++ b/tools/defuse/index.php @@ -0,0 +1,29 @@ + +* @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; diff --git a/tools/defuse/php-encryption/LICENSE b/tools/defuse/php-encryption/LICENSE new file mode 100644 index 000000000..f3e7c8e60 --- /dev/null +++ b/tools/defuse/php-encryption/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Taylor Hornby and Paragon Initiative +Enterprises . + +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. diff --git a/tools/defuse/php-encryption/README.md b/tools/defuse/php-encryption/README.md new file mode 100644 index 000000000..cd101a2cd --- /dev/null +++ b/tools/defuse/php-encryption/README.md @@ -0,0 +1,87 @@ +php-encryption +=============== + +[![Build Status](https://travis-ci.org/defuse/php-encryption.svg?branch=master)](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). diff --git a/tools/defuse/php-encryption/defuse-crypto.phar b/tools/defuse/php-encryption/defuse-crypto.phar new file mode 100644 index 0000000000000000000000000000000000000000..74c1b849242c28201ac5378e3bf796d29fe18520 GIT binary patch literal 50825 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 literal 0 HcmV?d00001 diff --git a/tools/defuse/php-encryption/dist/Makefile b/tools/defuse/php-encryption/dist/Makefile new file mode 100644 index 000000000..4b65c9ec4 --- /dev/null +++ b/tools/defuse/php-encryption/dist/Makefile @@ -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 + diff --git a/tools/defuse/php-encryption/dist/box.json b/tools/defuse/php-encryption/dist/box.json new file mode 100644 index 000000000..f225f781e --- /dev/null +++ b/tools/defuse/php-encryption/dist/box.json @@ -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 +} diff --git a/tools/defuse/php-encryption/dist/index.php b/tools/defuse/php-encryption/dist/index.php new file mode 100644 index 000000000..d9925ba54 --- /dev/null +++ b/tools/defuse/php-encryption/dist/index.php @@ -0,0 +1,29 @@ + +* @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; diff --git a/tools/defuse/php-encryption/dist/signingkey.asc b/tools/defuse/php-encryption/dist/signingkey.asc new file mode 100644 index 000000000..63b6aa3dd --- /dev/null +++ b/tools/defuse/php-encryption/dist/signingkey.asc @@ -0,0 +1,52 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v2 + +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 +IEgAL/CYqrk38w== +=lmD7 +-----END PGP PUBLIC KEY BLOCK----- diff --git a/tools/defuse/php-encryption/index.php b/tools/defuse/php-encryption/index.php new file mode 100644 index 000000000..d9925ba54 --- /dev/null +++ b/tools/defuse/php-encryption/index.php @@ -0,0 +1,29 @@ + +* @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; diff --git a/tools/defuse/php-encryption/src/Core.php b/tools/defuse/php-encryption/src/Core.php new file mode 100644 index 000000000..c489f3903 --- /dev/null +++ b/tools/defuse/php-encryption/src/Core.php @@ -0,0 +1,434 @@ + 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)); + } + } +} diff --git a/tools/defuse/php-encryption/src/Crypto.php b/tools/defuse/php-encryption/src/Crypto.php new file mode 100644 index 000000000..3acd6112a --- /dev/null +++ b/tools/defuse/php-encryption/src/Crypto.php @@ -0,0 +1,372 @@ +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); + } +} diff --git a/tools/defuse/php-encryption/src/DerivedKeys.php b/tools/defuse/php-encryption/src/DerivedKeys.php new file mode 100644 index 000000000..fcfc04307 --- /dev/null +++ b/tools/defuse/php-encryption/src/DerivedKeys.php @@ -0,0 +1,37 @@ +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; + } +} diff --git a/tools/defuse/php-encryption/src/Encoding.php b/tools/defuse/php-encryption/src/Encoding.php new file mode 100644 index 000000000..6e022d779 --- /dev/null +++ b/tools/defuse/php-encryption/src/Encoding.php @@ -0,0 +1,212 @@ +> 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 + ); + } +} diff --git a/tools/defuse/php-encryption/src/Exception/BadFormatException.php b/tools/defuse/php-encryption/src/Exception/BadFormatException.php new file mode 100644 index 000000000..804d9c17e --- /dev/null +++ b/tools/defuse/php-encryption/src/Exception/BadFormatException.php @@ -0,0 +1,7 @@ + +* @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; diff --git a/tools/defuse/php-encryption/src/File.php b/tools/defuse/php-encryption/src/File.php new file mode 100644 index 000000000..d73907775 --- /dev/null +++ b/tools/defuse/php-encryption/src/File.php @@ -0,0 +1,755 @@ +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']; + } + } +} diff --git a/tools/defuse/php-encryption/src/Key.php b/tools/defuse/php-encryption/src/Key.php new file mode 100644 index 000000000..ca7b9b2ee --- /dev/null +++ b/tools/defuse/php-encryption/src/Key.php @@ -0,0 +1,84 @@ +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; + } + +} diff --git a/tools/defuse/php-encryption/src/KeyOrPassword.php b/tools/defuse/php-encryption/src/KeyOrPassword.php new file mode 100644 index 000000000..2a46b711a --- /dev/null +++ b/tools/defuse/php-encryption/src/KeyOrPassword.php @@ -0,0 +1,119 @@ +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; + } +} diff --git a/tools/defuse/php-encryption/src/KeyProtectedByPassword.php b/tools/defuse/php-encryption/src/KeyProtectedByPassword.php new file mode 100644 index 000000000..b9a40f157 --- /dev/null +++ b/tools/defuse/php-encryption/src/KeyProtectedByPassword.php @@ -0,0 +1,112 @@ +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; + } +} diff --git a/tools/defuse/php-encryption/src/RuntimeTests.php b/tools/defuse/php-encryption/src/RuntimeTests.php new file mode 100644 index 000000000..9c0ba339d --- /dev/null +++ b/tools/defuse/php-encryption/src/RuntimeTests.php @@ -0,0 +1,242 @@ +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(); + } + } +} diff --git a/tools/defuse/php-encryption/src/index.php b/tools/defuse/php-encryption/src/index.php new file mode 100644 index 000000000..d9925ba54 --- /dev/null +++ b/tools/defuse/php-encryption/src/index.php @@ -0,0 +1,29 @@ + +* @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; From 6d665618659f8ca94a8758dc191349e669c9471d Mon Sep 17 00:00:00 2001 From: shreesh arora Date: Sun, 2 May 2021 17:31:17 +0530 Subject: [PATCH 2/2] remove cypher configuration from performance controller --- .../admin/AdminPerformanceController.php | 89 ------------------- 1 file changed, 89 deletions(-) diff --git a/controllers/admin/AdminPerformanceController.php b/controllers/admin/AdminPerformanceController.php index 5f2e4f9b7..3bd340a1b 100644 --- a/controllers/admin/AdminPerformanceController.php +++ b/controllers/admin/AdminPerformanceController.php @@ -460,49 +460,6 @@ class AdminPerformanceControllerCore extends AdminController $this->fields_value['_MEDIA_SERVER_3_'] = Configuration::get('PS_MEDIA_SERVER_3'); } - public function initFieldsetCiphering() - { - $phpdoc_langs = array('en', 'zh', 'fr', 'de', 'ja', 'pl', 'ro', 'ru', 'fa', 'es', 'tr'); - $php_lang = in_array($this->context->language->iso_code, $phpdoc_langs) ? $this->context->language->iso_code : 'en'; - - $warning_mcrypt = ' '.$this->l('(you must install the [a]Mcrypt extension[/a])'); - $warning_mcrypt = str_replace('[a]', '', $warning_mcrypt); - $warning_mcrypt = str_replace('[/a]', '', $warning_mcrypt); - - if (defined('_RIJNDAEL_KEY_') && defined('_RIJNDAEL_IV_')) { - $this->fields_form[5]['form'] = array( - - 'legend' => array( - 'title' => $this->l('Ciphering'), - 'icon' => 'icon-desktop' - ), - 'input' => array( - array( - 'type' => 'hidden', - 'name' => 'ciphering_up' - ), - array( - 'type' => 'radio', - 'label' => $this->l('Algorithm'), - 'name' => 'PS_CIPHER_ALGORITHM', - 'values' => array( - array( - 'id' => 'PS_CIPHER_ALGORITHM_1', - 'value' => 1, - 'label' => $this->l('Use Rijndael with mcrypt lib.').(function_exists('mcrypt_encrypt') ? '' : $warning_mcrypt) - ), - ) - ) - ), - 'submit' => array( - 'title' => $this->l('Save') - ) - ); - } - - $this->fields_value['PS_CIPHER_ALGORITHM'] = Configuration::get('PS_CIPHER_ALGORITHM'); - } - public function initFieldsetCaching() { $phpdoc_langs = array('en', 'zh', 'fr', 'de', 'ja', 'pl', 'ro', 'ru', 'fa', 'es', 'tr'); @@ -618,7 +575,6 @@ class AdminPerformanceControllerCore extends AdminController if (!defined('_PS_HOST_MODE_')) { $this->initFieldsetMediaServer(); - $this->initFieldsetCiphering(); $this->initFieldsetCaching(); } @@ -840,51 +796,6 @@ class AdminPerformanceControllerCore extends AdminController $this->errors[] = Tools::displayError('You do not have permission to edit this.'); } } - if ((bool)Tools::getValue('ciphering_up') && Configuration::get('PS_CIPHER_ALGORITHM') != (int)Tools::getValue('PS_CIPHER_ALGORITHM')) { - if ($this->tabAccess['edit'] === '1') { - $algo = (int)Tools::getValue('PS_CIPHER_ALGORITHM'); - $prev_settings = file_get_contents(_PS_ROOT_DIR_.'/config/settings.inc.php'); - $new_settings = $prev_settings; - if ($algo) { - if (!function_exists('mcrypt_encrypt')) { - $this->errors[] = Tools::displayError('The "Mcrypt" PHP extension is not activated on this server.'); - } else { - if (!strstr($new_settings, '_RIJNDAEL_KEY_')) { - $key_size = mcrypt_get_key_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC); - $key = Tools::passwdGen($key_size); - $new_settings = preg_replace( - '/define\(\'_COOKIE_KEY_\', \'([a-z0-9=\/+-_]+)\'\);/i', - 'define(\'_COOKIE_KEY_\', \'\1\');'."\n".'define(\'_RIJNDAEL_KEY_\', \''.$key.'\');', - $new_settings - ); - } - if (!strstr($new_settings, '_RIJNDAEL_IV_')) { - $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC); - $iv = base64_encode(mcrypt_create_iv($iv_size, MCRYPT_RAND)); - $new_settings = preg_replace( - '/define\(\'_COOKIE_IV_\', \'([a-z0-9=\/+-_]+)\'\);/i', - 'define(\'_COOKIE_IV_\', \'\1\');'."\n".'define(\'_RIJNDAEL_IV_\', \''.$iv.'\');', - $new_settings - ); - } - } - } - if (!count($this->errors)) { - // If there is not settings file modification or if the backup and replacement of the settings file worked - if ($new_settings == $prev_settings || ( - copy(_PS_ROOT_DIR_.'/config/settings.inc.php', _PS_ROOT_DIR_.'/config/settings.old.php') - && (bool)file_put_contents(_PS_ROOT_DIR_.'/config/settings.inc.php', $new_settings) - )) { - Configuration::updateValue('PS_CIPHER_ALGORITHM', $algo); - $redirectAdmin = true; - } else { - $this->errors[] = Tools::displayError('The settings file cannot be overwritten.'); - } - } - } else { - $this->errors[] = Tools::displayError('You do not have permission to edit this.'); - } - } if ((bool)Tools::getValue('cache_up')) { if ($this->tabAccess['edit'] === '1') {