【问题标题】:Run openssl encryption functions faster更快地运行 openssl 加密功能
【发布时间】:2018-07-23 12:15:01
【问题描述】:

这是一个与安全相关的问题,发布在here

我在当前的 PHP 7.0 设置中使用this,它工作正常。但是因为自 7.2 以来 mcrypt 已被 openssl 取代,我正在努力使用发布的 here 更新加密和解密函数,因为它是内置的。

但因为这是在一个包含 25 个项目的网页上,所以执行需要很长时间,这对最终用户来说是不可接受的。

<?php
define("ENCRYPTION_KEY", "!@#$%^&*");

$StartTime = microtime(TRUE);

$e = [];
for ($i = 0; $i < 25; $i++)
{
    $e[] = encrypt($i, ENCRYPTION_KEY);
}

echo number_format(microtime(TRUE) - $StartTime, 3)." seconds\n";

# https://stackoverflow.com/a/50373095/126833
function sign($message, $key) {
    return hash_hmac('sha256', $message, $key) . $message;
}

function verify($bundle, $key) {
    return hash_equals(
      hash_hmac('sha256', mb_substr($bundle, 64, null, '8bit'), $key),
      mb_substr($bundle, 0, 64, '8bit')
    );
}

function getKey($password, $keysize = 16) {
    return hash_pbkdf2('sha256',$password,'some_token',100000,$keysize,true);
}

function encrypt($message, $password) {
    $iv = random_bytes(16);
    $key = getKey($password);
    $result = sign(openssl_encrypt($message,'aes-256-ctr',$key,OPENSSL_RAW_DATA,$iv), $key);
    return bin2hex($iv).bin2hex($result);
}

function decrypt($hash, $password) {
    $iv = hex2bin(substr($hash, 0, 32));
    $data = hex2bin(substr($hash, 32));
    $key = getKey($password);
    if (!verify($data, $key)) {
      return null;
    }
    return openssl_decrypt(mb_substr($data, 64, null, '8bit'),'aes-256-ctr',$key,OPENSSL_RAW_DATA,$iv);
}
?>

.

$ php encrypt-decrypt.php 
6.288 seconds

有什么方法可以真正快速执行吗? (比如 25 次迭代不到一秒)

【问题讨论】:

  • 你告诉 hash_pbkdf2 执行 100k 次迭代,这是花费时间的地方,它通过花费时间来做它应该做的事情。为了加快速度,减少迭代次数以平衡性能。
  • 我可以看到文档中的示例 (php.net/manual/en/function.hash-pbkdf2.php) 使用了 1000 次迭代,这要快得多。我盲目地复制了其他 SO 答案中发布的内容。谢谢。
  • 请记住,更多的迭代意味着您的用户的安全性更高。这就是@AlexK 的原因。用了“平衡”这个词。也许 10k 次迭代是可以接受的性能。
  • @JamesKPolk 你注意到getKey / hash_pbkdf2 的名字了吗?
  • @MaartenBodewes:不,我什至不喜欢阅读 PHP。

标签: php encryption openssl php-7.2


【解决方案1】:

PBKDF2的迭代次数称为工作因子。如果迭代次数很高,那么工作因子(PBKDF2 需要执行的工作量)也很高。请注意,迭代次数与要执行的工作量线性,并且计算机变得更快(接近)指数

请注意,PBKDF2 实现可以在硬件和软件中加速。因此请注意,攻击者将能够更快地执行它们。 100,000 实际上是推荐的数量。


您的实现正确地调用了少量字节的 PBKDF2(小于哈希值的输出。如果您不这样做,那么 PBKDF2 基本上会被调用两次,而攻击者可能只调用一次来验证密码猜测。所以请注意,不要将代码更改为要求两个密钥,这只会减慢服务器速度。

但是,您在 encrypt 函数中调用 $key = getKey($password);。这意味着密钥是为每个调用派生的。这当然不是很聪明:您应该缓存密钥,直到不再需要它,然后直接销毁它。无需导出密钥 25 次。只是降低迭代是一种临时解决方案,可以将很多优势交还给攻击者。

【讨论】:

  • 是的,即使有 100000 次迭代,这也快得多。我把 $key = getKey(ENCRYPTION_KEY);退出循环并在 0.259 秒内执行。谢谢。
猜你喜欢
  • 1970-01-01
  • 2015-02-18
  • 1970-01-01
  • 2016-02-27
  • 2014-10-17
  • 2012-07-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多