mirror of
https://github.com/yiisoft/yii2.git
synced 2025-11-12 11:40:19 +08:00
Merge pull request #919 from ekerazha/master
Add data padding and key derivation.
This commit is contained in:
@@ -23,21 +23,41 @@ use yii\base\InvalidParamException;
|
|||||||
*/
|
*/
|
||||||
class BaseSecurity
|
class BaseSecurity
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Uses AES, block size is 128-bit (16 bytes).
|
||||||
|
*/
|
||||||
|
const CRYPT_BLOCK_SIZE = 16;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uses AES-192, key size is 192-bit (24 bytes).
|
||||||
|
*/
|
||||||
|
const CRYPT_KEY_SIZE = 24;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uses SHA-256.
|
||||||
|
*/
|
||||||
|
const DERIVATION_HASH = 'sha256';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uses 1000 iterations.
|
||||||
|
*/
|
||||||
|
const DERIVATION_ITERATIONS = 1000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encrypts data.
|
* Encrypts data.
|
||||||
* @param string $data data to be encrypted.
|
* @param string $data data to be encrypted.
|
||||||
* @param string $key the encryption secret key
|
* @param string $password the encryption password
|
||||||
* @return string the encrypted data
|
* @return string the encrypted data
|
||||||
* @throws Exception if PHP Mcrypt extension is not loaded or failed to be initialized
|
* @throws Exception if PHP Mcrypt extension is not loaded or failed to be initialized
|
||||||
* @see decrypt()
|
* @see decrypt()
|
||||||
*/
|
*/
|
||||||
public static function encrypt($data, $key)
|
public static function encrypt($data, $password)
|
||||||
{
|
{
|
||||||
$module = static::openCryptModule();
|
$module = static::openCryptModule();
|
||||||
// 192-bit (24 bytes) key size
|
$data = static::addPadding($data);
|
||||||
$key = StringHelper::substr($key, 0, 24);
|
|
||||||
srand();
|
srand();
|
||||||
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($module), MCRYPT_RAND);
|
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($module), MCRYPT_RAND);
|
||||||
|
$key = static::deriveKey($password, $iv);
|
||||||
mcrypt_generic_init($module, $key, $iv);
|
mcrypt_generic_init($module, $key, $iv);
|
||||||
$encrypted = $iv . mcrypt_generic($module, $data);
|
$encrypted = $iv . mcrypt_generic($module, $data);
|
||||||
mcrypt_generic_deinit($module);
|
mcrypt_generic_deinit($module);
|
||||||
@@ -48,23 +68,70 @@ class BaseSecurity
|
|||||||
/**
|
/**
|
||||||
* Decrypts data
|
* Decrypts data
|
||||||
* @param string $data data to be decrypted.
|
* @param string $data data to be decrypted.
|
||||||
* @param string $key the decryption secret key
|
* @param string $password the decryption password
|
||||||
* @return string the decrypted data
|
* @return string the decrypted data
|
||||||
* @throws Exception if PHP Mcrypt extension is not loaded or failed to be initialized
|
* @throws Exception if PHP Mcrypt extension is not loaded or failed to be initialized
|
||||||
* @see encrypt()
|
* @see encrypt()
|
||||||
*/
|
*/
|
||||||
public static function decrypt($data, $key)
|
public static function decrypt($data, $password)
|
||||||
{
|
{
|
||||||
$module = static::openCryptModule();
|
$module = static::openCryptModule();
|
||||||
// 192-bit (24 bytes) key size
|
|
||||||
$key = StringHelper::substr($key, 0, 24);
|
|
||||||
$ivSize = mcrypt_enc_get_iv_size($module);
|
$ivSize = mcrypt_enc_get_iv_size($module);
|
||||||
$iv = StringHelper::substr($data, 0, $ivSize);
|
$iv = StringHelper::substr($data, 0, $ivSize);
|
||||||
|
$key = static::deriveKey($password, $iv);
|
||||||
mcrypt_generic_init($module, $key, $iv);
|
mcrypt_generic_init($module, $key, $iv);
|
||||||
$decrypted = mdecrypt_generic($module, StringHelper::substr($data, $ivSize, StringHelper::strlen($data)));
|
$decrypted = mdecrypt_generic($module, StringHelper::substr($data, $ivSize, StringHelper::strlen($data)));
|
||||||
mcrypt_generic_deinit($module);
|
mcrypt_generic_deinit($module);
|
||||||
mcrypt_module_close($module);
|
mcrypt_module_close($module);
|
||||||
return rtrim($decrypted, "\0");
|
return static::stripPadding($decrypted);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a padding to the given data (PKCS #7).
|
||||||
|
* @param string $data the data to pad
|
||||||
|
* @return string the padded data
|
||||||
|
*/
|
||||||
|
protected static function addPadding($data)
|
||||||
|
{
|
||||||
|
$pad = self::CRYPT_BLOCK_SIZE - (StringHelper::strlen($data) % self::CRYPT_BLOCK_SIZE);
|
||||||
|
return $data . str_repeat(chr($pad), $pad);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Strips the padding from the given data.
|
||||||
|
* @param string $data the data to trim
|
||||||
|
* @return string the trimmed data
|
||||||
|
*/
|
||||||
|
protected static function stripPadding($data)
|
||||||
|
{
|
||||||
|
$end = StringHelper::substr($data, -1, NULL);
|
||||||
|
$last = ord($end);
|
||||||
|
$n = StringHelper::strlen($data) - $last;
|
||||||
|
if (StringHelper::substr($data, $n, NULL) == str_repeat($end, $last)) {
|
||||||
|
return StringHelper::substr($data, 0, $n);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derives a key from the given password (PBKDF2).
|
||||||
|
* @param string $password the source password
|
||||||
|
* @param string $salt the random salt
|
||||||
|
* @param int $iterations the number of iterations
|
||||||
|
* @return string the derived key
|
||||||
|
*/
|
||||||
|
protected static function deriveKey($password, $salt)
|
||||||
|
{
|
||||||
|
if (function_exists('hash_pbkdf2')) {
|
||||||
|
return hash_pbkdf2(self::DERIVATION_HASH, $password, $salt, self::DERIVATION_ITERATIONS, self::CRYPT_KEY_SIZE, true);
|
||||||
|
}
|
||||||
|
$hmac = hash_hmac(self::DERIVATION_HASH, $salt . pack('N', 1), $password, true);
|
||||||
|
$xorsum = $hmac;
|
||||||
|
for ($i = 1; $i < self::DERIVATION_ITERATIONS; $i++) {
|
||||||
|
$hmac = hash_hmac(self::DERIVATION_HASH, $hmac, $password, true);
|
||||||
|
$xorsum ^= $hmac;
|
||||||
|
}
|
||||||
|
return substr($xorsum, 0, self::CRYPT_KEY_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user