Changeset View
Changeset View
Standalone View
Standalone View
branches/5.2.x/core/kernel/security/SecurityEncrypter.php
Property | Old Value | New Value |
---|---|---|
svn:eol-style | null | LF |
svn:keywords | null | Id |
<?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); | |||||
} | |||||
} |