【问题标题】:Failing to upgrade mcrypt to openssl decryption in PHP无法在 PHP 中将 mcrypt 升级为 openssl 解密
【发布时间】:2019-03-11 08:48:17
【问题描述】:

我正在将旧版应用程序从 PHP 7.0 升级到 7.2,当我为 openssl 切换 mcrypt 时,我的解密功能不起作用。

我尝试了mcrypt is deprecated, what is the alternative? 之类的现有答案和https://gist.github.com/odan/c1dc2798ef9cedb9fedd09cdfe6e8e76 之类的 Gists,但我仍然无法使代码正常工作。

谁能解释我做错了什么?

旧代码

function decrypt($value, $key) {
    $ivLength = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
    $iv = substr($value, 0, $ivLength);
    return rtrim(
        mcrypt_decrypt(
            MCRYPT_RIJNDAEL_128,
            hash('sha256', $key, true),
            substr($value, $ivLength),
            MCRYPT_MODE_CBC,
            $iv
        ),
        "\0"
    );
}

新代码(不适用于现有输入)

function decrypt($value, $key) {
    $ivLength = openssl_cipher_iv_length('AES-128-CBC');
    $iv = substr($value, 0, $ivLength);
    // Note: $key is hashed because it was hashed in the old encrypt function below
    return openssl_decrypt(substr($value, $ivLength), 'AES-128-CBC', hash('sha256', $key, true), OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
}

就上下文而言,以下是旧代码加密值的方式:

function encrypt($value, $key) {
    $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_DEV_URANDOM);
    return $iv . mcrypt_encrypt(
            MCRYPT_RIJNDAEL_128,
            hash('sha256', $key, true),
            $value,
            MCRYPT_MODE_CBC,
            $iv
        );
}

此外,$value 中的原始值在新代码中输出到错误日志时的长度是旧代码的两倍,并且看起来相似但字符更多。

【问题讨论】:

  • 我很确定旧的加密和新的解密不会相互兼容
  • 为什么要使用不同的方法来获取密钥? additional_key 也没有在任何地方定义
  • @Devon 哎呀,那不应该在那里,它已经被重构了。我从代码中删除了它。
  • 您仍在对旧加密中的密钥进行哈希处理
  • @Devon 很好。我更新了代码,但它仍然不起作用,返回一个空字符串。

标签: php openssl mcrypt


【解决方案1】:

这里的主要问题是密钥大小。您正在使用 SHA256 创建密钥,该密钥返回 256 位哈希,因此您使用 AES / Rijndael 和 256 位密钥。

Rijndael-128 中的数字定义了块大小,密钥大小由我们使用的密钥长度决定。 AES-128 中的数字定义了密钥大小(块大小为常数,128 位),如果实际密钥长度与此数字不同,则缩短或扩展密钥(零字节)以适合所选密钥大小。

这意味着您的 mcrypt 代码在 CBC 模式下使用带有 256 位密钥的 Rijndael-128 (AES)。 openssl 等效于 AES-256-CBC,如果我们使用此算法,那么 mcryptopenssl 应该会产生兼容的结果。

function decrypt_mcrypt_with_openssl($value, $key) {
    $iv = substr($value, 0, 16);
    $ciphertext = substr($value, 16);
    $key = hash('sha256', $key, true);
    $plaintext = openssl_decrypt(
        $ciphertext, 'AES-256-CBC', $key, 
        OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, 
        $iv
    );
    return rtrim($plaintext, "\0");
}

SHA256 不适合作为密钥派生函数。如果您从密码中获取密钥,则可以使用 hash_pbkdf2 与随机盐和足够多的迭代次数。或者,您可以使用 openssl_random_pseudo_bytes 创建一个加密安全的伪随机密钥。

我认为最好完全停止使用mcrypt,而只使用openssl。 Mcrypt 不支持 PKCS7 填充,不提供任何authenticated encryption 算法,并且不再维护。

【讨论】:

  • 你是迄今为止我遇到过的最好的程序员@t.m.adam。是的,结果是正确的。真希望有你做我的老师。谢谢。
猜你喜欢
  • 2020-04-12
  • 2017-09-05
  • 1970-01-01
  • 2014-02-24
  • 2015-10-09
  • 2018-11-10
  • 2018-08-02
  • 2019-07-23
  • 2019-04-13
相关资源
最近更新 更多