Commit ed455371 by Qiang Xue

Merge pull request #919 from ekerazha/master

Add data padding and key derivation.
parents efef0e52 cb7921b8
......@@ -24,20 +24,40 @@ 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);
}
/**
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment