Index: branches/5.2.x/composer.json =================================================================== diff -u -N -r16637 -r16691 --- branches/5.2.x/composer.json (.../composer.json) (revision 16637) +++ branches/5.2.x/composer.json (.../composer.json) (revision 16691) @@ -1,5 +1,11 @@ { "name": "In-Portal", + "require": { + "php": ">=5.3.7", + "paragonie/random_compat": "^2.0", + "symfony/polyfill-php55": "^1.19", + "symfony/polyfill-php56": "^1.19" + }, "require-dev": { "aik099/phpunit-mink": "^2.2", "qa-tools/qa-tools": "^1.2", Index: branches/5.2.x/core/install/prerequisites.php =================================================================== diff -u -N -r16432 -r16691 --- branches/5.2.x/core/install/prerequisites.php (.../prerequisites.php) (revision 16432) +++ branches/5.2.x/core/install/prerequisites.php (.../prerequisites.php) (revision 16691) @@ -1,6 +1,6 @@ &1'); $ret['java'] = stripos($output, 'java version') !== false; Index: branches/5.2.x/composer.lock =================================================================== diff -u -N -r16637 -r16691 --- branches/5.2.x/composer.lock (.../composer.lock) (revision 16637) +++ branches/5.2.x/composer.lock (.../composer.lock) (revision 16691) @@ -4,8 +4,318 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "bdf85cd4a4719d9255c1eb5022f63706", - "packages": [], + "content-hash": "ef20f3d542075e2d792fba4a7d3379c2", + "packages": [ + { + "name": "ircmaxell/password-compat", + "version": "v1.0.4", + "source": { + "type": "git", + "url": "https://github.com/ircmaxell/password_compat.git", + "reference": "5c5cde8822a69545767f7c7f3058cb15ff84614c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ircmaxell/password_compat/zipball/5c5cde8822a69545767f7c7f3058cb15ff84614c", + "reference": "5c5cde8822a69545767f7c7f3058cb15ff84614c", + "shasum": "" + }, + "require-dev": { + "phpunit/phpunit": "4.*" + }, + "type": "library", + "autoload": { + "files": [ + "lib/password.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Anthony Ferrara", + "email": "ircmaxell@php.net", + "homepage": "http://blog.ircmaxell.com" + } + ], + "description": "A compatibility library for the proposed simplified password hashing algorithm: https://wiki.php.net/rfc/password_hash", + "homepage": "https://github.com/ircmaxell/password_compat", + "keywords": [ + "hashing", + "password" + ], + "time": "2014-11-20T16:49:30+00:00" + }, + { + "name": "paragonie/random_compat", + "version": "v2.0.19", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "446fc9faa5c2a9ddf65eb7121c0af7e857295241" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/446fc9faa5c2a9ddf65eb7121c0af7e857295241", + "reference": "446fc9faa5c2a9ddf65eb7121c0af7e857295241", + "shasum": "" + }, + "require": { + "php": ">=5.2.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "type": "library", + "autoload": { + "files": [ + "lib/random.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "polyfill", + "pseudorandom", + "random" + ], + "time": "2020-10-15T10:06:57+00:00" + }, + { + "name": "symfony/polyfill-php55", + "version": "v1.19.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php55.git", + "reference": "248a5c9877b126493abb661e4fb47792e418035b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php55/zipball/248a5c9877b126493abb661e4fb47792e418035b", + "reference": "248a5c9877b126493abb661e4fb47792e418035b", + "shasum": "" + }, + "require": { + "ircmaxell/password-compat": "~1.0", + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.19-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php55\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 5.5+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-10-23T09:01:57+00:00" + }, + { + "name": "symfony/polyfill-php56", + "version": "v1.19.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php56.git", + "reference": "ea19621731cbd973a6702cfedef3419768bf3372" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/ea19621731cbd973a6702cfedef3419768bf3372", + "reference": "ea19621731cbd973a6702cfedef3419768bf3372", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "symfony/polyfill-util": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.19-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php56\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 5.6+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-10-23T09:01:57+00:00" + }, + { + "name": "symfony/polyfill-util", + "version": "v1.19.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-util.git", + "reference": "8df0c3e6a4b85df9a5c6f3f2f46fba5c5c47058a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-util/zipball/8df0c3e6a4b85df9a5c6f3f2f46fba5c5c47058a", + "reference": "8df0c3e6a4b85df9a5c6f3f2f46fba5c5c47058a", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.19-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Util\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony utilities for portability of PHP codes", + "homepage": "https://symfony.com", + "keywords": [ + "compat", + "compatibility", + "polyfill", + "shim" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-10-21T09:57:48+00:00" + } + ], "packages-dev": [ { "name": "aik099/coding-standard", @@ -747,6 +1057,7 @@ "keywords": [ "tokenizer" ], + "abandoned": true, "time": "2017-12-04T08:55:13+00:00" }, { @@ -875,6 +1186,7 @@ "mock", "xunit" ], + "abandoned": true, "time": "2015-10-02T06:51:40+00:00" }, { @@ -1593,9 +1905,12 @@ }, "prefer-stable": false, "prefer-lowest": false, - "platform": [], + "platform": { + "php": ">=5.3.7" + }, "platform-dev": [], "platform-overrides": { "php": "5.3.7" - } + }, + "plugin-api-version": "1.1.0" } Index: branches/5.2.x/core/kernel/security/SecurityGenerator.php =================================================================== diff -u -N --- branches/5.2.x/core/kernel/security/SecurityGenerator.php (revision 0) +++ branches/5.2.x/core/kernel/security/SecurityGenerator.php (revision 16691) @@ -0,0 +1,193 @@ + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', + self::CHAR_LOWER => 'abcdefghijklmnopqrstuvwxyz', + self::CHAR_DIGITS => '0123456789', + self::CHAR_UPPER_HEX => 'ABCDEF', + self::CHAR_LOWER_HEX => 'abcdef', + self::CHAR_BASE64 => '+/', + self::CHAR_SYMBOLS => '!"#$%&\'()* +,-./:;<=>?@[\]^_`{|}~', + self::CHAR_BRACKETS => '()[]{}<>', + self::CHAR_PUNCT => ',.;:', + ); + + /** + * Generate a random string of specified length using supplied character list. + * + * @param integer $length The length of the generated string. + * @param mixed $characters List of characters to use or character flags. + * + * @return SecurityGeneratorPromise + */ + public static function generateString($length, $characters) + { + // Combine character sets. + if ( is_int($characters) ) { + $characters = self::expandCharacterSets($characters); + } + + return new SecurityGeneratorPromise( + SecurityGeneratorPromise::TYPE_STRING, + array($length, $characters) + ); + } + + /** + * Expand a character set bitwise spec into a string character set. + * This will also replace EASY_TO_READ characters if the flag is set. + * + * @param integer $spec The spec to expand (bitwise combination of flags). + * + * @return string The expanded string + */ + protected static function expandCharacterSets($spec) + { + $combined = ''; + + if ( $spec == self::EASY_TO_READ ) { + $spec |= self::CHAR_ALNUM; + } + + foreach ( self::$charArrays as $flag => $chars ) { + // Handle this later. + if ( $flag == self::EASY_TO_READ ) { + continue; + } + + if ( ($spec & $flag) === $flag ) { + $combined .= $chars; + } + } + + // Remove ambiguous characters. + if ( $spec & self::EASY_TO_READ ) { + $combined = str_replace(str_split(self::AMBIGUOUS_CHARS), '', $combined); + } + + return count_chars($combined, 3); + } + + /** + * Generates a random number. + * + * @param integer $min Smallest value. + * @param integer $max Largest value. + * + * @return SecurityGeneratorPromise + */ + public static function generateNumber($min, $max) + { + return new SecurityGeneratorPromise( + SecurityGeneratorPromise::TYPE_NUMBER, + array($min, $max) + ); + } + + /** + * Generates random bytes. + * + * @param integer $length Raw result length. + * @param boolean $raw_output Return raw result. + * + * @return SecurityGeneratorPromise + */ + public static function generateBytes($length = 16, $raw_output = false) + { + return new SecurityGeneratorPromise( + SecurityGeneratorPromise::TYPE_BYTES, + array($length, $raw_output) + ); + } + +} Index: branches/5.2.x/core/kernel/security/SecurityEncrypter.php =================================================================== diff -u -N --- branches/5.2.x/core/kernel/security/SecurityEncrypter.php (revision 0) +++ branches/5.2.x/core/kernel/security/SecurityEncrypter.php (revision 16691) @@ -0,0 +1,228 @@ +getData(); + + // In the config data is encoded stored to avoid corruption. + $this->hmacKey = base64_decode($vars['SecurityHmacKey']); + + // Equivalent of "hex2bin" for PHP < 5.4. + $this->encryptionKey = pack('H*', $vars['SecurityEncryptionKey']); + } + + /** + * Creates signature. + * + * @param string $string String. + * @param boolean $raw_output Return raw signature version. + * @param string|null $key_override Override key. + * + * @return string + */ + public function createSignature($string, $raw_output = false, $key_override = null) + { + return hash_hmac(self::HASHING_ALGORITHM, $string, $this->_getHmacKey($key_override), $raw_output); + } + + /** + * Returns HMAC key. + * + * @param string|null $key_override Key override. + * + * @return string + * @throws InvalidArgumentException When HMAC key is empty. + */ + private function _getHmacKey($key_override = null) + { + $key = $this->doGetHmacKey($key_override); + + if ( empty($key) ) { + throw new InvalidArgumentException('The HMAC key is empty.'); + } + + if ( mb_strlen($key, '8bit') === self::HASHING_KEY_LENGTH ) { + return $key; + } + + return $this->deriveKey($key, self::HASHING_KEY_LENGTH); + } + + /** + * Returns HMAC key. + * + * @param string|null $key_override Key override. + * + * @return string + */ + protected function doGetHmacKey($key_override = null) + { + return isset($key_override) ? $key_override : $this->hmacKey; + } + + /** + * Returns encryption key. + * + * @param string|null $key_override Key override. + * + * @return string + * @throws InvalidArgumentException When encryption key is empty. + */ + private function _getEncryptionKey($key_override = null) + { + $key = $this->doGetEncryptionKey($key_override); + + if ( empty($key) ) { + throw new InvalidArgumentException('The encryption key is empty.'); + } + + if ( mb_strlen($key, '8bit') === self::ENCRYPTION_KEY_LENGTH ) { + return $key; + } + + return $this->deriveKey($key, self::ENCRYPTION_KEY_LENGTH); + } + + /** + * Returns encryption key. + * + * @param string|null $key_override Key override. + * + * @return string + */ + protected function doGetEncryptionKey($key_override = null) + { + return isset($key_override) ? $key_override : $this->encryptionKey; + } + + /** + * Derives given key. + * + * @param string $key Key. + * @param integer $length Length. + * + * @return string + */ + final public function deriveKey($key, $length) + { + $salt = SecurityGenerator::generateBytes(16, true); + + return hash_pbkdf2(self::HASHING_ALGORITHM, $key, $salt, 80000, $length, true); + } + + /** + * Encrypts a plain text. + * + * @param string $plaintext Plain text. + * @param string|null $key_override Key override. + * + * @return string + */ + final public function encrypt($plaintext, $key_override = null) + { + $iv_size = openssl_cipher_iv_length(self::ENCRYPTION_METHOD); + $iv = openssl_random_pseudo_bytes($iv_size); + + $ciphertext = openssl_encrypt( + $plaintext, + self::ENCRYPTION_METHOD, + $this->_getEncryptionKey($key_override), + OPENSSL_RAW_DATA, + $iv + ); + + // Note: We cover the IV in our HMAC. + $hmac = $this->createSignature($iv . $ciphertext, true); + + return base64_encode($hmac . $iv . $ciphertext); + } + + /** + * Decrypts a cipher text. + * + * @param string $ciphertext Cipher text. + * @param string|null $key_override Key override. + * + * @return string|false + * @throws LogicException When signature verification has failed. + */ + final public function decrypt($ciphertext, $key_override = null) + { + $iv_size = openssl_cipher_iv_length(self::ENCRYPTION_METHOD); + + $decoded = base64_decode($ciphertext); + $hmac = mb_substr($decoded, 0, self::HASHING_KEY_LENGTH, '8bit'); + $iv = mb_substr($decoded, self::HASHING_KEY_LENGTH, $iv_size, '8bit'); + $ciphertext = mb_substr($decoded, self::HASHING_KEY_LENGTH + $iv_size, null, '8bit'); + + $calculated = $this->createSignature($iv . $ciphertext, true); + + if ( !hash_equals($hmac, $calculated) ) { + throw new LogicException('Signature verification of ciphertext failed.'); + } + + return openssl_decrypt( + $ciphertext, + self::ENCRYPTION_METHOD, + $this->_getEncryptionKey($key_override), + OPENSSL_RAW_DATA, + $iv + ); + } + + /** + * Determines if used cipher is available. + * + * @return boolean + */ + final public function cipherAvailable() + { + return in_array(self::ENCRYPTION_METHOD, openssl_get_cipher_methods(), true); + } + +} Index: branches/5.2.x/core/kernel/application.php =================================================================== diff -u -N -r16662 -r16691 --- branches/5.2.x/core/kernel/application.php (.../application.php) (revision 16662) +++ branches/5.2.x/core/kernel/application.php (.../application.php) (revision 16691) @@ -1,6 +1,6 @@ registerClass('kCache', KERNEL_PATH . '/utility/cache.php', 'kCache', 'Params'); $this->registerClass('kHTTPQuery', KERNEL_PATH . '/utility/http_query.php', 'HTTPQuery'); + // security + $this->registerClass('SecurityGenerator', KERNEL_PATH . '/security/SecurityGenerator.php'); + $this->registerClass('SecurityGeneratorPromise', KERNEL_PATH . '/security/SecurityGeneratorPromise.php'); + $this->registerClass('SecurityEncrypter', KERNEL_PATH . '/security/SecurityEncrypter.php'); + // session $this->registerClass('Session', KERNEL_PATH . '/session/session.php'); $this->registerClass('SessionStorage', KERNEL_PATH . '/session/session_storage.php'); Index: branches/5.2.x/core/kernel/security/SecurityGeneratorPromise.php =================================================================== diff -u -N --- branches/5.2.x/core/kernel/security/SecurityGeneratorPromise.php (revision 0) +++ branches/5.2.x/core/kernel/security/SecurityGeneratorPromise.php (revision 16691) @@ -0,0 +1,274 @@ + 'generateNumber', + self::TYPE_STRING => 'generateString', + self::TYPE_BYTES => 'generateBytes', + ); + + if ( !isset($mapping[$type]) ) { + throw new InvalidArgumentException('The "' . $type . '" promise type is not supported.'); + } + + $this->method = $mapping[$type]; + $this->arguments = $arguments; + } + + /** + * Makes sure, that resolved value isn't already used in the given database table's column. + * + * @param string $prefix_or_table Unit config prefix or table name. + * @param string $column Column in specified table. + * + * @return mixed + * @throws LogicException When after 10 retries still unable to generate unique value for database. + */ + public function resolveForPersisting($prefix_or_table, $column) + { + $application =& kApplication::Instance(); + + if ( $application->prefixRegistred($prefix_or_table) ) { + $table = $application->getUnitOption($prefix_or_table, 'TableName'); + } + else { + $table = $prefix_or_table; + } + + $retries = 0; + + do { + $resolved_value = $this->resolve(); + + $sql = 'SELECT ' . $column . ' + FROM ' . $table . ' + WHERE ' . $column . ' = ' . $application->Conn->qstr($resolved_value); + $found = $application->Conn->GetOne($sql) !== false; + + if ( $found ) { + $this->resolvedValue = null; + $retries++; + } + } while ( $found && $retries < 10 ); + + if ( $found ) { + throw new LogicException(sprintf( + 'Unable to generate unique value for "%s" column with current generator configuration.', + $table . '.' . $column + )); + } + + return $resolved_value; + } + + /** + * Resolves a promise. + * + * @return mixed + */ + public function resolve() + { + if ( !$this->isResolved() ) { + $this->resolvedValue = call_user_func_array(array($this, $this->method), $this->arguments); + } + + if ( !$this->asSignature ) { + return $this->resolvedValue; + } + + $application =& kApplication::Instance(); + + /** @var SecurityEncrypter $encrypter */ + $encrypter = $application->recallObject('SecurityEncrypter'); + + return $encrypter->createSignature( + $this->resolvedValue, + $this->signatureRawOutput, + $this->signatureKeyOverride + ); + } + + /** + * Configures promise to return signature of a resolved value. + * + * @param boolean $raw_output Return raw signature value during resolving. + * @param string|null $key_override Alternative key used for creating signature of resolved value. + * + * @return self + */ + public function asSignature($raw_output = false, $key_override = null) + { + $this->asSignature = true; + $this->signatureRawOutput = $raw_output; + $this->signatureKeyOverride = $key_override; + + return $this; + } + + /** + * Configures promise to return resolved value as-is. + * + * @return self + */ + public function asValue() + { + $this->asSignature = false; + $this->signatureRawOutput = false; + $this->signatureKeyOverride = null; + + return $this; + } + + /** + * Generate a random string of specified length using supplied character list. + * + * @param integer $length The length of the generated string. + * @param mixed $characters List of characters to use. + * + * @return string + */ + protected function generateString($length, $characters) + { + $ret = ''; + $max_index = mb_strlen($characters) - 1; + + for ( $i = 0; $i < $length; $i++ ) { + $ret .= mb_substr($characters, $this->generateNumber(0, $max_index), 1); + } + + return $ret; + } + + /** + * Generates a random number. + * + * @param integer $min Smallest value. + * @param integer $max Largest value. + * + * @return integer + */ + protected function generateNumber($min, $max) + { + return random_int($min, $max); + } + + /** + * Generates random bytes. + * + * @param integer $length Raw result length. + * @param boolean $raw_output Return raw result. + * + * @return string + */ + protected function generateBytes($length = 16, $raw_output = false) + { + $ret = random_bytes($length); + + return $raw_output ? $ret : bin2hex($ret); + } + + /** + * Determines if promise was already resolved. + * + * @return boolean + */ + protected function isResolved() + { + return $this->resolvedValue !== null; + } + + /** + * Returns promise resolved value casted to string. + * + * @return string + */ + public function __toString() + { + return (string)$this->resolve(); + } + +} Index: branches/5.2.x/core/install/step_templates/sys_requirements.tpl =================================================================== diff -u -N -r16117 -r16691 --- branches/5.2.x/core/install/step_templates/sys_requirements.tpl (.../sys_requirements.tpl) (revision 16117) +++ branches/5.2.x/core/install/step_templates/sys_requirements.tpl (.../sys_requirements.tpl) (revision 16691) @@ -25,6 +25,7 @@ 'jpeg' => '- JPEG images support*', 'mysql' => '- Database connectivity (via MySQL)*', 'json' => '- JSON processing support*', + 'openssl' => '- OpenSSL support*', 'sep2' => 'PHP settings:', 'memory_limit' => "- Memory requirements changing on the fly", 'display_errors' => "- Prevent script errors in production environment", Index: branches/5.2.x/core/install.php =================================================================== diff -u -N -r16689 -r16691 --- branches/5.2.x/core/install.php (.../install.php) (revision 16689) +++ branches/5.2.x/core/install.php (.../install.php) (revision 16691) @@ -1,6 +1,6 @@ toolkit->CallPrerequisitesMethod('core/', 'CheckSystemRequirements'); @@ -841,6 +841,24 @@ } } + if ( !$this->toolkit->systemConfig->get('SecurityHmacKey', 'Misc') + || !$this->toolkit->systemConfig->get('SecurityEncryptionKey', 'Misc') + ) { + $this->toolkit->systemConfig->set( + 'SecurityHmacKey', + 'Misc', + base64_encode(SecurityGenerator::generateString( + SecurityEncrypter::HASHING_KEY_LENGTH, + SecurityGenerator::CHAR_ALNUM | SecurityGenerator::CHAR_SYMBOLS + )) + ); + $this->toolkit->systemConfig->set( + 'SecurityEncryptionKey', + 'Misc', + SecurityGenerator::generateBytes(SecurityEncrypter::ENCRYPTION_KEY_LENGTH) + ); + } + $this->toolkit->systemConfig->save(); break; Index: branches/5.2.x/core/kernel/utility/system_config.php =================================================================== diff -u -N -r16439 -r16691 --- branches/5.2.x/core/kernel/utility/system_config.php (.../system_config.php) (revision 16439) +++ branches/5.2.x/core/kernel/utility/system_config.php (.../system_config.php) (revision 16691) @@ -84,6 +84,8 @@ 'WebsiteCharset' => 'utf-8', 'WebsitePath' => rtrim(preg_replace('/'.preg_quote(rtrim(defined('REL_PATH') ? REL_PATH : '', '/'), '/').'$/', '', str_replace('\\', '/', dirname($_SERVER['PHP_SELF']))), '/'), 'WriteablePath' => DIRECTORY_SEPARATOR . 'system', + 'SecurityHmacKey' => '', + 'SecurityEncryptionKey' => '', ); return $this->parseSections ? array('Misc' => $ret) : $ret;