使用 CryptoJS 在 JavaScript 中使用 PHP openssl_encrypt

问题描述 投票:0回答:2

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

我决定使用来自其他SO答案的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”参数。

javascript encryption encoding cryptojs
2个回答
9
投票

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

"FbcCY2yCFBwVCUE9R+6kJ4fAL4BJxxjd"

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

这也是为什么你可以将 CryptoJS 中的 key 和 IV 视为字符串:

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

但是正确的方法是从 Base64 解码密钥并生成正确的 IV,其长度是编码为十六进制时的两倍。使用前应将其从十六进制解码。

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


0
投票

如果有人像我一样使用 0,而不是字符串,这里是解决方案。

对于密码,我们需要编写以下行代码。

var key =  CryptoJS.enc.Latin1.parse("0".padEnd(32, "\0"));

完整的 HTML 和 PHP 代码:

<!DOCTYPE html>
<html>
<body>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
    <?php 
        echo base64_encode(openssl_encrypt("188","AES-256-CBC","0",true, str_repeat(chr(0), 16))); //EdoxHD0CGtks241nGMEM9Q==
    ?>
    <script>
        var key =  CryptoJS.enc.Latin1.parse("0".padEnd(32, "\0"));
        var iv = String.fromCharCode(0).repeat(16);
        var encrypted = CryptoJS.AES.encrypt("188", key, 
            { iv: CryptoJS.enc.Utf8.parse(iv) }
        );
        var r1 = encrypted.ciphertext.toString();
        var r2 = CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
        console.log("r2 =>", r2); //r2 => EdoxHD0CGtks241nGMEM9Q==
    </script>
</body>
</html>
© www.soinside.com 2019 - 2024. All rights reserved.