You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将mcrypt_encrypt转换为openssl_encrypt?解决加密结果不一致问题

问题:替换mcrypt为OpenSSL后加密结果不一致的解决方法

我要优化一个用了废弃mcrypt库的WordPress插件,改用OpenSSL加密提交的数据,但遇到了问题:openssl_encrypt的返回结果和mcrypt_encrypt不一致,导致对接的系统无法返回正确数据,而且对方没法提供上传日志。我全网搜过没找到解决方案,怀疑是填充问题,求帮忙。

原代码示例(已修正语法错误)

class EncryptDebug{
    private $algo = 'sha1';
    private $password = 'ab4232goodcf423484422c90c3e4aa7c';
    private $salt = 'ascastas54490a31';
    private $iv = '8947da32awl55kwj';
    private $length = 16;
    private function generate_key(){
        return hash_pbkdf2( $this->algo , $this->password , $this->salt, 100, $this->length, true );
    }
    public function encryptSSL($plaintext){
        $key = $this->generate_key();
        $ciphertext = base64_encode(openssl_encrypt($plaintext, 'AES-128-CBC', $key,  OPENSSL_ZERO_PADDING, $this->iv));
        
        return str_replace('+', '%2B', $ciphertext);

    }
    public function encryptMCRYPT($plaintext){
        $key = $this->generate_key();
        $ciphertext = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $plaintext, MCRYPT_MODE_CBC, $this->iv));
        
        return str_replace('+', '%2B', $ciphertext);

    }
}

补充说明

用OPENSSL_ZERO_PADDING会报错,用OPENSSL_RAW_DATA得到的结果和mcrypt_encrypt相似,但结尾不同,示例如下:

  • OpenSSL加密结果:rPzVvF7gaPMA4ADAjHUW8Wy1ThTJG%2BVPdcz5iKAkAwrDTTFTcOpWgWOCh9l9JFZ8WcNzMJ868026TkUxcYJMrQ==
  • mcrypt加密结果:rPzVvF7gaPMA4ADAjHUW8Wy1ThTJG%2BVPdcz5iKAkAwrDTTFTcOpWgWOCh9l9JFZ8UGVfF091Q9bY61mTRg%2BBSg==

问题根源

mcrypt_encrypt在CBC模式下默认自动用零填充把明文补到块大小的整数倍;而OpenSSL的OPENSSL_ZERO_PADDING选项不会自动填充,必须手动处理,这就是结果不一致的核心原因。

修复方案

1. 修正代码语法错误

  • 把变量名$lenght改为$length,避免拼写错误
  • 在$iv = '8947da32awl55kwj'行末尾添加分号

2. 手动实现零填充

添加一个方法,把明文填充到AES-128的块大小(16字节)的整数倍,和mcrypt的自动填充行为对齐:

private function zero_pad($data, $block_size){
    $pad_length = $block_size - (strlen($data) % $block_size);
    return $data . str_repeat("\0", $pad_length);
}

3. 调整OpenSSL加密参数

使用OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING组合参数,确保输出原始二进制数据且不自动添加PKCS7填充。

修正后的完整代码

class EncryptDebug{
    private $algo = 'sha1';
    private $password = 'ab4232goodcf423484422c90c3e4aa7c';
    private $salt = 'ascastas54490a31';
    private $iv = '8947da32awl55kwj';
    private $length = 16;

    private function generate_key(){
        return hash_pbkdf2($this->algo, $this->password, $this->salt, 100, $this->length, true);
    }

    // 手动零填充,对齐mcrypt行为
    private function zero_pad($data, $block_size){
        $pad_length = $block_size - (strlen($data) % $block_size);
        return $data . str_repeat("\0", $pad_length);
    }

    public function encryptSSL($plaintext){
        $key = $this->generate_key();
        $block_size = openssl_cipher_iv_length('AES-128-CBC');
        $padded_text = $this->zero_pad($plaintext, $block_size);
        // 组合参数确保原始输出+不自动填充
        $ciphertext_raw = openssl_encrypt($padded_text, 'AES-128-CBC', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->iv);
        $ciphertext = base64_encode($ciphertext_raw);
        
        return str_replace('+', '%2B', $ciphertext);
    }

    public function encryptMCRYPT($plaintext){
        $key = $this->generate_key();
        $ciphertext = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $plaintext, MCRYPT_MODE_CBC, $this->iv));
        
        return str_replace('+', '%2B', $ciphertext);
    }
}

验证说明

  • 零填充逻辑和mcrypt完全一致:计算明文长度与16字节块的差值,补对应数量的空字符\0
  • 参数组合OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING让OpenSSL输出和mcrypt相同格式的二进制加密数据,再经过base64编码和字符替换后,结果就能完全匹配。

内容的提问来源于stack exchange,提问作者Astronneu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 03:25:02