dreamfly0514 2018-10-05 19:53
浏览 144
已采纳

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

I'm upgrading a legacy application from PHP 7.0 to 7.2 and my decrypt function isn't working when I switch out mcrypt for openssl.

I tried the existing answers like mcrypt is deprecated, what is the alternative?, and Gists like https://gist.github.com/odan/c1dc2798ef9cedb9fedd09cdfe6e8e76, but I'm still not able to make the code work.

Can anyone shed some light what I'm doing wrong?

Old code

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"
    );
}

New code (not working with existing inputs)

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);
}

For context, here's how the old code encrypted the values:

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
        );
}

Also, the raw value in $value is twice as long when output to the error log in the new code than the old code and looks similar but with more characters.

  • 写回答

1条回答 默认 最新

  • doumu4916 2018-10-05 20:46
    关注

    The main issue here is the key size. You're creating the key with SHA256 which returns a 256 bit hash, therefore you're using AES / Rijndael with a 256 bit key.

    The number in Rijndael-128 defines the block size, the key size is determined by the length of the key we use. The number in AES-128 defines the key size (the block size is constant, 128 bits), and if the actual key length is different than this number, then the key is shortened or expanded (with zero bytes) to fit the selected key size.

    This means that your mcrypt code uses Rijndael-128 (AES) with a 256 bit key, in CBC mode. The openssl equivalent is AES-256-CBC, and if we use this algorithm then mcrypt and openssl should produce compatible results.

    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 is not suitable as a key derivation function. If you're deriving your key from a password you can use hash_pbkdf2 with a random salt and a high enough number of iterations. Or you could create a cryptographically secure pseudo-random key with openssl_random_pseudo_bytes.

    I think it's best to stop using mcrypt completely and use only openssl. Mcrypt doesn't support PKCS7 padding, it doesn't provide any authenticated encryption algorithms, and it is not being maintained anymore.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 信号傅里叶变换在matlab上遇到的小问题请求帮助
  • ¥15 保护模式-系统加载-段寄存器
  • ¥15 电脑桌面设定一个区域禁止鼠标操作