Commit 6dc69e68 by ekerazha

Add data padding and key derivation.

parent efef0e52
...@@ -24,20 +24,40 @@ use yii\base\InvalidParamException; ...@@ -24,20 +24,40 @@ 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 ...@@ -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);
$last = ord($end);
$n = StringHelper::strlen($data) - $last;
if (StringHelper::substr($data, $n) == 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