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

求助:将Mcrypt加密算法转换为OpenSSL的实现方案(PHP7.2+兼容)

把Mcrypt加密的字符串用OpenSSL解密的实现方案

我来帮你搞定这个转换!先得拆解下你原来的Mcrypt加密代码的核心细节,这样才能精准用OpenSSL实现对应的解密逻辑:

原Mcrypt加密的关键特性

  • 算法:RIJNDAEL-256(注意:这不是AES-256,AES的块大小固定为128位,而RIJNDAEL-256的块大小是256位)
  • 模式:ECB(这个模式下IV是无效的,原代码里生成了IV但实际没用到)
  • 填充方式:Mcrypt默认用零字节填充(当明文长度不是256位块的整数倍时,补0x00)
  • Base64编码:自定义的URL安全Base64,把+换成-,/换成_,去掉了=填充符

对应的OpenSSL解密代码

下面是完全匹配原加密逻辑的OpenSSL解密实现,每一步都加了注释说明对应原代码的逻辑:

class CryptoHandler {
    /**
     * 解密用原Mcrypt加密的字符串
     * @param string $encryptedValue 加密后的URL安全Base64字符串
     * @param string $key 加密时用的密钥
     * @return string|false 解密后的明文,失败返回false
     */
    static function decode($encryptedValue = NULL, $key = NULL) {
        if (!$encryptedValue || !$key) {
            return false;
        }

        // 还原自定义的URL安全Base64为标准Base64格式
        $encoded = str_replace(array('-', '_'), array('+', '/'), $encryptedValue);
        // 补回可能被去掉的=填充符,确保Base64解码正常
        $padding = strlen($encoded) % 4;
        if ($padding) {
            $encoded .= str_repeat('=', 4 - $padding);
        }

        // Base64解码得到加密后的二进制数据
        $crypttext = base64_decode($encoded);
        if ($crypttext === false) {
            return false;
        }

        // 用OpenSSL解密,严格匹配原算法和模式
        // OPENSSL_RAW_DATA:返回原始二进制数据,不自动处理Base64
        // OPENSSL_NO_PADDING:禁用OpenSSL默认的PKCS#7填充,改用原Mcrypt的零填充逻辑
        $decrypted = openssl_decrypt(
            $crypttext,
            'rijndael-256', // 对应原MCRYPT_RIJNDAEL_256
            $key,
            OPENSSL_RAW_DATA | OPENSSL_NO_PADDING,
            '' // ECB模式不需要IV,传空字符串即可
        );

        if ($decrypted === false) {
            return false;
        }

        // 移除零字节填充(原Mcrypt加密时自动补的0x00)
        // 注意:如果你的明文本身结尾有0x00字符,这一步会误删,这种场景需要调整去填充逻辑
        $decrypted = rtrim($decrypted, "\x00");

        return $decrypted;
    }

    // 如果你需要用OpenSSL实现和原Mcrypt完全一致的加密逻辑,也可以用这个方法
    static function encode($value = NULL, $key = NULL) {
        if (!$value || !$key) {
            return false;
        }

        // 手动给明文加零字节填充,凑到RIJNDAEL-256的块大小(32字节)的整数倍
        $blockSize = 32;
        $paddingLength = $blockSize - (strlen($value) % $blockSize);
        $paddedValue = $value . str_repeat("\x00", $paddingLength);

        // OpenSSL加密
        $crypttext = openssl_encrypt(
            $paddedValue,
            'rijndael-256',
            $key,
            OPENSSL_RAW_DATA | OPENSSL_NO_PADDING,
            ''
        );

        if ($crypttext === false) {
            return false;
        }

        // 用和原代码一致的自定义URL安全Base64编码
        return self::safe_b64encode($crypttext);
    }

    private static function safe_b64encode($string = NULL) {
        $data = base64_encode($string);
        $data = str_replace(array('+','/','='),array('-','_',''),$data);
        return $data;
    }
}

额外注意事项

  1. RIJNDAEL-256和AES的区别:别搞混这两个!AES是Rijndael的标准化实现,固定块大小128位,而RIJNDAEL-256的块大小是256位,所以OpenSSL里必须指定rijndael-256,不能用aes-256-ecb,这是解密成功的关键。
  2. 填充逻辑的特殊情况:如果你的明文本身结尾有0x00字符,那rtrim($decrypted, "\x00")会把这些合法字符删掉,这种场景你需要重新评估填充方式,但因为你只需要解密旧数据,只能按原Mcrypt的零填充逻辑处理。
  3. ECB模式的安全性:顺便提一句,ECB模式是不安全的加密模式,如果后续有新的加密需求,建议改用CBC或GCM模式,搭配随机生成的IV使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:38:54