PHP openssl_encrypt 在 JavaScript 中使用 CryptoJS

PHP openssl_encrypt in JavaScript with CryptoJS

我在 JavaScript 中生成第三方 PHP 服务器提供的相同密文时遇到问题。服务器端使用简单的单行代码生成密钥,但我找不到在我的 JavaScript 客户端中执行相同操作的方法。

我决定使用来自 other SO answers 的 CryptoJS 库,我确实生成了一个密文,但它与来自 PHP 服务器的密文不同。

PHP加密:

echo openssl_encrypt("5905","AES-256-CBC","FbcCY2yCFBwVCUE9R+6kJ4fAL4BJxxjdRcqy5rHVLwU=",NULL,"e16ce913a20dadb8");
// phgygAJB3GA0sa4D9k/d8A==

我尝试了 Stack Overflow 中的几种解决方案,但未能创建相同的密文。

此外,PHP 单行中的参数 "AES-256-CBC" 困扰着我:我知道 AES 是什么,但我不知道那些 256 或 CBC 部分是什么,我不知道不知道在 CryptoJS 端设置它们的位置。

我目前的尝试:

var key = 'FbcCY2yCFBwVCUE9R+6kJ4fAL4BJxxjdRcqy5rHVLwU=';
var iv = 'e16ce913a20dadb8';
var encrypted = CryptoJS.AES.encrypt("5905", CryptoJS.enc.Hex.parse(key), { iv: CryptoJS.enc.Hex.parse(iv) });
var r1 = encrypted.ciphertext.toString(); // def44f8822cfb3f317a3c5b67182b437
var r2 = CryptoJS.enc.Base64.stringify(encrypted.ciphertext) // 3vRPiCLPs/MXo8W2cYK0Nw==

我的猜测是我在 JavaScript.

的某处缺少“256”和 "CBC" 参数

您的 "key" 有 44 个字符长,这也等于 PHP 中的 44 个字节。这不是有效的密钥大小。 AES 仅支持 16、24 和 32 字节密钥。无论如何,这个 "key" 将被截断为 32 字节。所以你在 PHP 中的实际密钥是:

"FbcCY2yCFBwVCUE9R+6kJ4fAL4BJxxjd"

您的 IV 长度为 16 个字符(和字节),因此它具有正确的长度并按原样使用。

这也是您可以将 CryptoJS 中的密钥和 IV 视为字符串的原因:

CryptoJS.AES.encrypt("5905", CryptoJS.enc.Utf8.parse(key), { iv: CryptoJS.enc.Utf8.parse(iv) });

但是正确的方法是从 Base64 解码密钥并生成一个适当的 IV,当编码为 Hex 时,它的长度是原来的两倍。使用前应从十六进制解码。

IV 必须是不可预测的(读作:随机)。不要使用静态 IV,因为这会使密码具有确定性,因此在语义上不安全。观察密文的攻击者可以确定之前发送相同消息前缀的时间。 IV 不是秘密的,因此您可以将它与密文一起发送。通常,它只是简单地添加到密文之前,并在解密之前被切掉。