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

将PHP的API密钥AES加密逻辑迁移至JavaScript遇结果不一致问题

问题:PHP与JavaScript AES-256-CBC加密结果不一致

我有一段在PHP中加密API密钥的逻辑,希望在JavaScript中实现完全相同的逻辑以得到一致结果。

PHP代码

$api_key = '7#4VBg7ZN3vGZPL4&r3Ow^k4#s2$Q9&NP!ofWJXPP*Tgg05Y05' . date('Ymd');
$encrypt_method = 'AES-256-CBC';
$salt_key = '0Ao10GYe^4EfBYMp';
$salt_iv = 'uV6h%Vl^$u1$vo4^';
base64_encode(openssl_encrypt($api_key, $encrypt_method, $salt_key, 0, $salt_iv));

尝试的JavaScript代码(结果不一致)

const CryptoJS = require('crypto-js');

const api_key = '7#4VBg7ZN3vGZPL4&r3Ow^k4#s2$Q9&NP!ofWJXPP*Tgg05Y05' + new Date().toISOString().slice(0, 10).replace(/-/g, '');
const salt_key = '0Ao10GYe^4EfBYMp';
const salt_iv = 'uV6h%Vl^$u1$vo4^';

const encrypted = CryptoJS.AES.encrypt(api_key, salt_key, {
  iv: CryptoJS.enc.Utf8.parse(salt_iv),
  mode: CryptoJS.mode.CBC,
  padding: CryptoJS.pad.Pkcs7
});

const base64Encrypted = encrypted.toString();

问题原因与解决方法

核心差异

  1. 密钥处理逻辑不同:PHP的openssl_encrypt直接使用原始密钥字节,若密钥长度不足AES-256要求的32字节,会自动用\x00填充;而CryptoJS默认会对传入的密钥字符串执行PBKDF2密钥推导,而非直接使用原始字节。
  2. 密钥长度适配:你的$salt_key是16字节字符串,PHP会自动补0到32字节以适配AES-256,CryptoJS需要手动模拟此行为。

修正后的JavaScript代码

const CryptoJS = require('crypto-js');

// 构造待加密的API密钥(和PHP逻辑完全一致)
const apiKeyBase = '7#4VBg7ZN3vGZPL4&r3Ow^k4#s2$Q9&NP!ofWJXPP*Tgg05Y05';
const dateStr = new Date().toISOString().slice(0, 10).replace(/-/g, '');
const apiKey = apiKeyBase + dateStr;

const saltKey = '0Ao10GYe^4EfBYMp';
const saltIv = 'uV6h%Vl^$u1$vo4^';

// 处理密钥:转换为UTF8字节,补\x00到32字节(匹配PHP自动填充行为)
const keyUtf8 = CryptoJS.enc.Utf8.parse(saltKey);
const key = CryptoJS.lib.WordArray.create(keyUtf8.words, 32); // 强制长度为32字节

// IV直接转换为UTF8字节(已满足AES要求的16字节长度)
const iv = CryptoJS.enc.Utf8.parse(saltIv);

// 执行加密:禁用CryptoJS默认的密钥推导,直接使用原始密钥和IV
const encrypted = CryptoJS.AES.encrypt(apiKey, key, {
  iv: iv,
  mode: CryptoJS.mode.CBC,
  padding: CryptoJS.pad.Pkcs7,
  format: CryptoJS.format.OpenSSL // 对齐PHP的输出格式
});

// 输出base64编码结果,与PHP返回值一致
const base64Encrypted = encrypted.toString(CryptoJS.format.OpenSSL);
console.log(base64Encrypted);

验证注意事项

  • 确保日期字符串生成逻辑一致:PHP的date('Ymd')和JS的new Date().toISOString().slice(0,10).replace(/-/g,'')在同一时间点必须生成完全相同的字符串。
  • 密钥填充逻辑:通过CryptoJS.lib.WordArray.create强制密钥长度为32字节,完全模拟PHP自动补0的行为。
  • 禁用密钥推导:直接传入处理后的密钥WordArray,避免CryptoJS执行额外的密钥推导步骤。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 19:50:10