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

时间:2018-10-05 19:53:01

标签: php openssl mcrypt

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

我尝试了诸如mcrypt is deprecated, what is the alternative?之类的现有答案,而尝试了https://gist.github.com/odan/c1dc2798ef9cedb9fedd09cdfe6e8e76之类的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 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中的原始值是旧代码的两倍,并且看起来相似,但字符更多。

1 个答案:

答案 0 :(得分:3)

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

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算法,并且不再进行维护。