无法在PHP中将mcrypt升级为openssl解密

无法在PHP中将mcrypt升级为openssl解密,php,openssl,mcrypt,Php,Openssl,Mcrypt,我正在将一个旧式应用程序从PHP7.0升级到7.2,当我将mcrypt切换到openssl时,我的解密功能不起作用 我尝试了现有的答案,如,和GIST,但我仍然无法使代码工作 谁能解释一下我做错了什么 旧代码 function decrypt($value, $key) { $ivLength = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC); $iv = substr($value, 0, $ivLength)

我正在将一个旧式应用程序从PHP7.0升级到7.2,当我将mcrypt切换到openssl时,我的解密功能不起作用

我尝试了现有的答案,如,和GIST,但我仍然无法使代码工作

谁能解释一下我做错了什么

旧代码

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 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
中的原始值在新代码中输出到错误日志时的长度是旧代码的两倍,并且看起来类似,但包含更多字符。

这里的主要问题是密钥大小。您使用返回256位哈希的SHA256创建密钥,因此您将AES/Rijndael与256位密钥一起使用

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

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

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不适合作为密钥派生函数。如果您是从密码派生密钥,则可以使用随机salt和足够高的迭代次数。或者您可以使用创建一个加密安全的伪随机密钥


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

这里的主要问题是密钥大小。您使用返回256位哈希的SHA256创建密钥,因此您将AES/Rijndael与256位密钥一起使用

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

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

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不适合作为密钥派生函数。如果您是从密码派生密钥,则可以使用随机salt和足够高的迭代次数。或者您可以使用创建一个加密安全的伪随机密钥


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

我很确定旧的加密和新的解密将不兼容。为什么要对密钥使用不同的方法<代码>附加_键也未定义anywhere@Devon哎呀,那不应该在那里,它已经被重构了。我把它从代码中删除了。你还在旧代码中散列密钥encrypt@Devon抢手货我更新了代码,但仍然不起作用,返回一个空字符串。我很确定旧的加密和新的解密将彼此不兼容。为什么对密钥使用不同的方法<代码>附加_键也未定义anywhere@Devon哎呀,那不应该在那里,它已经被重构了。我把它从代码中删除了。你还在旧代码中散列密钥encrypt@Devon抢手货我更新了代码,但仍然不起作用,返回一个空字符串。你是迄今为止我遇到的最好的程序员@t.m.adam。是的,结果是对的。但愿我有你做我的老师。谢谢。你是迄今为止我遇到的最好的程序员@t.m.adam。是的,结果是对的。但愿我有你做我的老师。谢谢