mirror of
https://github.com/yiisoft/yii2.git
synced 2025-11-12 20:21: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
|
||||
{
|
||||
/**
|
||||
* 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.
|
||||
* @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
|
||||
* @throws Exception if PHP Mcrypt extension is not loaded or failed to be initialized
|
||||
* @see decrypt()
|
||||
*/
|
||||
public static function encrypt($data, $key)
|
||||
public static function encrypt($data, $password)
|
||||
{
|
||||
$module = static::openCryptModule();
|
||||
// 192-bit (24 bytes) key size
|
||||
$key = StringHelper::substr($key, 0, 24);
|
||||
$data = static::addPadding($data);
|
||||
srand();
|
||||
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($module), MCRYPT_RAND);
|
||||
$key = static::deriveKey($password, $iv);
|
||||
mcrypt_generic_init($module, $key, $iv);
|
||||
$encrypted = $iv . mcrypt_generic($module, $data);
|
||||
mcrypt_generic_deinit($module);
|
||||
@@ -48,23 +68,70 @@ class BaseSecurity
|
||||
/**
|
||||
* Decrypts data
|
||||
* @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
|
||||
* @throws Exception if PHP Mcrypt extension is not loaded or failed to be initialized
|
||||
* @see encrypt()
|
||||
*/
|
||||
public static function decrypt($data, $key)
|
||||
public static function decrypt($data, $password)
|
||||
{
|
||||
$module = static::openCryptModule();
|
||||
// 192-bit (24 bytes) key size
|
||||
$key = StringHelper::substr($key, 0, 24);
|
||||
$ivSize = mcrypt_enc_get_iv_size($module);
|
||||
$iv = StringHelper::substr($data, 0, $ivSize);
|
||||
$key = static::deriveKey($password, $iv);
|
||||
mcrypt_generic_init($module, $key, $iv);
|
||||
$decrypted = mdecrypt_generic($module, StringHelper::substr($data, $ivSize, StringHelper::strlen($data)));
|
||||
mcrypt_generic_deinit($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