Index: branches/5.2.x/composer.json
===================================================================
--- branches/5.2.x/composer.json
+++ branches/5.2.x/composer.json
@@ -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/composer.lock
===================================================================
--- branches/5.2.x/composer.lock
+++ branches/5.2.x/composer.lock
@@ -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/install.php
===================================================================
--- branches/5.2.x/core/install.php
+++ branches/5.2.x/core/install.php
@@ -270,7 +270,7 @@
 				case 'sys_requirements':
 					$required_checks = Array (
 						'php_version', 'composer', 'curl', 'simplexml', 'freetype', 'gd_version',
-						'jpeg', 'mysql', 'json', 'date.timezone', 'output_buffering',
+						'jpeg', 'mysql', 'json', 'openssl', 'date.timezone', 'output_buffering',
 					);
 
 					$check_results = $this->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/install/prerequisites.php
===================================================================
--- branches/5.2.x/core/install/prerequisites.php
+++ branches/5.2.x/core/install/prerequisites.php
@@ -145,6 +145,9 @@
 			$ret['mysql'] = function_exists('mysqli_connect');
 			$ret['json'] = function_exists('json_encode');
 
+			// Unable to properly use "SecurityEncrypter::cipherAvailable" method, because no factory here.
+			$ret['openssl'] = function_exists('openssl_encrypt') && in_array('aes-128-cbc', openssl_get_cipher_methods(), true);
+
 			$output = shell_exec('java -version 2>&1');
 			$ret['java'] = stripos($output, 'java version') !== false;
 
Index: branches/5.2.x/core/install/step_templates/sys_requirements.tpl
===================================================================
--- branches/5.2.x/core/install/step_templates/sys_requirements.tpl
+++ branches/5.2.x/core/install/step_templates/sys_requirements.tpl
@@ -25,6 +25,7 @@
 		'jpeg' => '- JPEG images support<span class="error">*</span>',
 		'mysql' => '- Database connectivity (via MySQL)<span class="error">*</span>',
 		'json' => '- JSON processing support<span class="error">*</span>',
+		'openssl' => '- OpenSSL support<span class="error">*</span>',
 		'sep2' => '<strong>PHP settings:</strong>',
 		'memory_limit' => "- Memory requirements changing on the fly",
 		'display_errors' => "- Prevent script errors in production environment",
Index: branches/5.2.x/core/kernel/application.php
===================================================================
--- branches/5.2.x/core/kernel/application.php
+++ branches/5.2.x/core/kernel/application.php
@@ -756,6 +756,11 @@
 		$this->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/SecurityEncrypter.php
===================================================================
--- branches/5.2.x/core/kernel/security/SecurityEncrypter.php
+++ branches/5.2.x/core/kernel/security/SecurityEncrypter.php
@@ -0,0 +1,228 @@
+<?php
+/**
+* @version	$Id$
+* @package	In-Portal
+* @copyright	Copyright (C) 1997 - 2018 Intechnic. All rights reserved.
+* @license      GNU/GPL
+* In-Portal is Open Source software.
+* This means that this software may have been modified pursuant
+* the GNU General Public License, and as distributed it includes
+* or is derivative of works licensed under the GNU General Public License
+* or other free or open source software licenses.
+* See http://www.in-portal.org/license for copyright notices and details.
+*/
+
+defined('FULL_PATH') or die('restricted access!');
+
+
+class SecurityEncrypter extends kBase
+{
+
+	const HASHING_ALGORITHM = 'sha256';
+
+	const HASHING_KEY_LENGTH = 32;
+
+	const ENCRYPTION_METHOD = 'aes-128-cbc'; // Or 'aes-256-cbc'.
+
+	const ENCRYPTION_KEY_LENGTH = 16; // Or 32.
+
+	/**
+	 * The HMAC key.
+	 *
+	 * @var string
+	 */
+	protected $hmacKey;
+
+	/**
+	 * The encryption key.
+	 *
+	 * @var string
+	 */
+	protected $encryptionKey;
+
+	/**
+	 * SecurityEncrypter constructor.
+	 */
+	public function __construct()
+	{
+		parent::__construct();
+
+		$vars = kUtil::getSystemConfig()->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/security/SecurityGenerator.php
===================================================================
--- branches/5.2.x/core/kernel/security/SecurityGenerator.php
+++ branches/5.2.x/core/kernel/security/SecurityGenerator.php
@@ -0,0 +1,193 @@
+<?php
+/**
+* @version	$Id$
+* @package	In-Portal
+* @copyright	Copyright (C) 1997 - 2018 Intechnic. All rights reserved.
+* @license      GNU/GPL
+* In-Portal is Open Source software.
+* This means that this software may have been modified pursuant
+* the GNU General Public License, and as distributed it includes
+* or is derivative of works licensed under the GNU General Public License
+* or other free or open source software licenses.
+* See http://www.in-portal.org/license for copyright notices and details.
+*/
+
+defined('FULL_PATH') or die('restricted access!');
+
+
+final class SecurityGenerator
+{
+
+	/**
+	 * Flag for uppercase letters.
+	 */
+	const CHAR_UPPER = 1;
+
+	/**
+	 * Flag for lowercase letters.
+	 */
+	const CHAR_LOWER = 2;
+
+	/**
+	 * Flag for alpha characters (CHAR_UPPER | CHAR_LOWER).
+	 */
+	const CHAR_ALPHA = 3;
+
+	/**
+	 * Flag for digits.
+	 */
+	const CHAR_DIGITS = 4;
+
+	/**
+	 * Flag for alpha numeric characters (CHAR_ALPHA | CHAR_DIGITS).
+	 */
+	const CHAR_ALNUM = 7;
+
+	/**
+	 * Flag for uppercase hexadecimal symbols (8 | CHAR_DIGITS).
+	 */
+	const CHAR_UPPER_HEX = 12;
+
+	/**
+	 * Flag for lowercase hexidecimal symbols (16 | CHAR_DIGITS).
+	 */
+	const CHAR_LOWER_HEX = 20;
+
+	/**
+	 * Flag for base64 symbols (32 | CHAR_ALNUM).
+	 */
+	const CHAR_BASE64 = 39;
+
+	/**
+	 * Flag for additional symbols accessible via the keyboard.
+	 */
+	const CHAR_SYMBOLS = 64;
+
+	/**
+	 * Flag for brackets.
+	 */
+	const CHAR_BRACKETS = 128;
+
+	/**
+	 * Flag for punctuation marks.
+	 */
+	const CHAR_PUNCT = 256;
+
+	/**
+	 * Flag for upper/lower-case and digits but without "B8G6I1l|0OQDS5Z2".
+	 */
+	const EASY_TO_READ = 512;
+
+	/**
+	 * Ambiguous characters for "Easy To Read" sets.
+	 *
+	 * @internal
+	 */
+	const AMBIGUOUS_CHARS = 'B8G6I1l|0OQDS5Z2()[]{}:;,.';
+
+	/**
+	 * The different characters, by Flag.
+	 *
+	 * @var array
+	 */
+	static protected $charArrays = array(
+		self::CHAR_UPPER => '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/SecurityGeneratorPromise.php
===================================================================
--- branches/5.2.x/core/kernel/security/SecurityGeneratorPromise.php
+++ branches/5.2.x/core/kernel/security/SecurityGeneratorPromise.php
@@ -0,0 +1,274 @@
+<?php
+/**
+* @version	$Id$
+* @package	In-Portal
+* @copyright	Copyright (C) 1997 - 2018 Intechnic. All rights reserved.
+* @license      GNU/GPL
+* In-Portal is Open Source software.
+* This means that this software may have been modified pursuant
+* the GNU General Public License, and as distributed it includes
+* or is derivative of works licensed under the GNU General Public License
+* or other free or open source software licenses.
+* See http://www.in-portal.org/license for copyright notices and details.
+*/
+
+defined('FULL_PATH') or die('restricted access!');
+
+
+final class SecurityGeneratorPromise
+{
+
+	/**
+	 * Promise, that returns random integer number.
+	 */
+	const TYPE_NUMBER = 1;
+
+	/**
+	 * Promise, that returns random string.
+	 */
+	const TYPE_STRING = 2;
+
+	/**
+	 * Promise, that returns random bytes.
+	 */
+	const TYPE_BYTES = 3;
+
+	/**
+	 * Generator method.
+	 *
+	 * @var string
+	 */
+	protected $method;
+
+	/**
+	 * Generator method arguments.
+	 *
+	 * @var array
+	 */
+	protected $arguments = array();
+
+	/**
+	 * Resolved value (only, when was resolved).
+	 *
+	 * @var string
+	 */
+	protected $resolvedValue;
+
+	/**
+	 * Return signature of resolved value.
+	 *
+	 * @var boolean
+	 */
+	protected $asSignature = false;
+
+	/**
+	 * Return raw resolved value's signature representation.
+	 *
+	 * @var boolean
+	 */
+	protected $signatureRawOutput = false;
+
+	/**
+	 * Alternative key used for creating signature of resolved value.
+	 *
+	 * @var string
+	 */
+	protected $signatureKeyOverride;
+
+	/**
+	 * SecurityGeneratorPromise constructor.
+	 *
+	 * @param integer $type      Promise type.
+	 * @param array   $arguments Generator method arguments.
+	 *
+	 * @throws InvalidArgumentException When unsupported promise type is given.
+	 */
+	public function __construct($type, array $arguments = array())
+	{
+		$mapping = array(
+			self::TYPE_NUMBER => '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/kernel/utility/system_config.php
===================================================================
--- branches/5.2.x/core/kernel/utility/system_config.php
+++ branches/5.2.x/core/kernel/utility/system_config.php
@@ -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;