JS通过crypto加密的字符串如何在PHP中解密 AES-128-ECB结果不一致
问题根因排查
导致两端加密结果不一致的核心原因有4个:
- 输出格式不匹配:JS侧指定输出
hex编码,PHP侧openssl_encrypt默认返回base64编码,二者编码规则不同直接导致结果看起来完全不同。 - 密钥长度不符合AES规范:AES-128要求密钥必须为16字节,你使用的密钥
aeda94ad8azd仅12字节,Node.js和PHP对长度不足的密钥默认处理逻辑不同,加密核心参数不一致。 - 填充逻辑冲突:你手动给
p2补空格到16字节倍数,但Node.jscrypto和PHPopenssl默认都会自动添加PKCS7填充,相当于额外多了一轮填充,逻辑不统一。 - JS加密逻辑不完整:Node.js的
cipher.update()仅返回当前处理块的加密结果,缺少cipher.final()调用会导致最终结果丢失部分加密内容。
修复方案
方案1:保留原有手动补空格的逻辑,两端统一规则
修正后的JS代码:
const crypto = require('crypto'); const p1 = ['abc', 1, 'def', 'hij'].join('a'); let p2 = crypto.createHash('md5').update(p1, 'ascii').digest('hex') + 'a' + p1 + 'a'; // 原有手动补空格逻辑保留 while (p2.length % 16 > 0) p2 += ' '; // 密钥补到16字节,和PHP统一用\0填充 const key = Buffer.from('aeda94ad8azd'.padEnd(16, '\0')); const cipher = crypto.createCipheriv('aes-128-ecb', key, null); // 关闭默认PKCS7填充,使用手动补的空格 cipher.setAutoPadding(false); // 拼接update和final的结果,输出hex let result = cipher.update(p2, 'ascii', 'hex') + cipher.final('hex'); console.log(result);
对应PHP代码:
$p1 = implode('a', ['abc', 1, 'def', 'hij']); $p2 = hash('md5', $p1, false) . 'a' . $p1 . 'a'; // 原有手动补空格逻辑保留 while (strlen($p2) % 16 > 0) $p2 .= ' '; // 密钥补到16字节,和JS统一用\0填充 $key = str_pad('aeda94ad8azd', 16, "\0"); // 关闭自动填充,返回原始二进制后转hex和JS输出对齐 $result = bin2hex(openssl_encrypt($p2, 'aes-128-ecb', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING)); echo $result;
方案2:删除手动补空格逻辑,使用默认PKCS7填充(更规范)
修正后的JS代码:
const crypto = require('crypto'); const p1 = ['abc', 1, 'def', 'hij'].join('a'); let p2 = crypto.createHash('md5').update(p1, 'ascii').digest('hex') + 'a' + p1 + 'a'; const key = Buffer.from('aeda94ad8azd'.padEnd(16, '\0')); const cipher = crypto.createCipheriv('aes-128-ecb', key, null); let result = cipher.update(p2, 'ascii', 'hex') + cipher.final('hex'); console.log(result);
对应PHP代码:
$p1 = implode('a', ['abc', 1, 'def', 'hij']); $p2 = hash('md5', $p1, false) . 'a' . $p1 . 'a'; $key = str_pad('aeda94ad8azd', 16, "\0"); $result = bin2hex(openssl_encrypt($p2, 'aes-128-ecb', $key, OPENSSL_RAW_DATA)); echo $result;
注意
AES-ECB模式安全性较低,生产环境建议使用CBC、GCM等更安全的加密模式。
内容的提问来源于stack exchange,提问作者Théo Dulieu
相关产品推荐
相关产品推荐

