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

如何在不修改JS代码的前提下用PHP解密CryptoJS加密字符串

解密失败核心原因

返回null本质是PHP端传入openssl_decrypt的所有参数都和CryptoJS默认加密逻辑不匹配:

  • 算法模式选错:CryptoJS.AES.encrypt传入字符串密钥时,默认走AES-256-CBC模式+PKCS7填充,根本不是你写的aes-128-ctr
  • 密钥派生逻辑错:当你给CryptoJS传字符串作为密钥时,它不会直接把这个字符串当原始加密密钥用,而是走OpenSSL兼容的EVP_BytesToKey派生逻辑:生成8字节随机盐存在密文里,结合口令用MD5做1次迭代哈希,派生出32位AES密钥+16位初始向量IV
  • 密文结构没处理:CryptoJS返回的密文是Base64编码的,解码后结构是8字节固定标识Salted__ + 8字节随机盐 + 真实密文,直接把整个字符串丢给openssl_decrypt肯定解析失败
可直接使用的解密代码

以下代码完全对齐CryptoJS默认加密逻辑,不需要修改任何已有JS加密代码:

function cryptoJsAesDecrypt(string $ciphertext, string $passphrase): string|false
{
    // Base64解码存储的密文
    $cipherRaw = base64_decode($ciphertext);
    // 校验密文合法格式
    if (substr($cipherRaw, 0, 8) !== 'Salted__') {
        return false;
    }
    // 拆分盐和真实密文
    $salt = substr($cipherRaw, 8, 8);
    $realCipherText = substr($cipherRaw, 16);
    // 按EVP_BytesToKey规则派生密钥和IV,和CryptoJS默认逻辑完全一致:MD5摘要、1次迭代
    $derivedKeyIv = '';
    $hashBlock = '';
    while (strlen($derivedKeyIv) < 48) { // 32字节AES256密钥 + 16字节CBC模式IV 共48字节
        $hashBlock = md5($hashBlock . $passphrase . $salt, true);
        $derivedKeyIv .= $hashBlock;
    }
    $key = substr($derivedKeyIv, 0, 32);
    $iv = substr($derivedKeyIv, 32, 16);
    // 解密,OPENSSL_RAW_DATA标识传入的密文是原始二进制格式
    return openssl_decrypt($realCipherText, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
}

// 调用示例:传入数据库中存储的密文、原加密用的密钥即可
$plainText = cryptoJsAesDecrypt("数据库存储的JS加密后密文", "Key");
注意事项
  • 不要手动给openssl_decrypt添加OPENSSL_ZERO_PADDING参数,openssl默认开启的PKCS7填充和CryptoJS默认填充规则完全兼容
  • 如果解密返回false,优先检查从数据库取出的密文是否存在多余空格、转义字符,Base64格式被破坏会直接导致解密失败

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 02:09:25