将 PHP openssl_encrypt 与 JavaScript 中的空白 IV 匹配
Match PHPs openssl_encrypt with blank IV in JavaScript
当 PHP 中没有声明 IV 并且使用了不合规的密钥长度时,如何在 JavaScript 中匹配 openssl_encrypt
的输出?
PHP
php -r '$value = openssl_encrypt("test", "AES-128-CBC", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); echo $value;'
/u+5lB/VwbMX9U1YY4cnCQ==
JavaScript
iv = CryptoJS.enc.Utf8.parse("");
var encrypted = CryptoJS.AES.encrypt("test", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaa", {iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7});
console.log(encrypted.toString());
U2FsdGVkX19Cn1f6x8C/rJdfwzsZk5m5WWCUrR4z3U4=
console.log(CryptoJS.enc.Base64.stringify(encrypted.ciphertext));
l1/DOxmTmblZYJStHjPdTg==
我只能修改 Javascript 代码,我需要一种方法来加密字符串,以便它可以被 PHP 的 openssl_decrypt
解密。如果字符串是从 PHP.
加密的,它显然工作正常
我知道不声明 IV 会降低代码的安全性,但在我的特定情况下这不是什么大问题。
我在其他主题中读到 PHP 默认填充为 Pkcs7,这就是我将其添加到 JS 方法的原因。
我目前的理论是 PHP 的默认 IV 是问题所在,或者 JS 函数的输出需要进一步处理。如您所见,我尝试了 Base64.stringify
方法,但结果仍然不同。
我在这里使用的示例密钥与实际密钥的长度相同。
我正在使用https://github.com/sytelus/CryptoJS/blob/master/rollups/aes.js(无论我在JS中使用什么,它都需要像独立文件一样易于分发,占用空间相对较小)
您的代码存在一些问题:
- 如果您想使用现有密钥,则需要向
CryptoJS.<cipher>.encrypt
提供一个 WordArray
对象。这意味着必须以某种方式对其进行解析。如果您简单地提供一个字符串作为 "key",那么 CryptoJS 将假定它是一个密码,生成一个随机盐并使用 EVP_BytesToKey 从密码和盐中导出密钥和 IV。
- 您的 "key" 长度为 29 个字符。 AES 仅支持三种密钥大小:16、24 和 32 字节。由于您在 PHP 中使用了 AES-128,因此您需要在 CryptoJS 中提供一个 16 字节的密钥,以便自动选择 AES-128。请记住:密钥应该是随机选择的,并且与随机噪声无法区分,因此它具有某种安全性。如果必须以某种方式打印密钥,请使用 Hex 或 Base64 编码。
完整示例:
var iv = CryptoJS.enc.Utf8.parse("");
var key = CryptoJS.enc.Utf8.parse("aaaaaaaaaaaaaaaa");
var encrypted = CryptoJS.AES.encrypt("test", key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
console.log(CryptoJS.enc.Base64.stringify(encrypted.ciphertext));
<script src="https://cdn.rawgit.com/CryptoStore/crypto-js/3.1.2/build/rollups/aes.js"></script>
当 PHP 中没有声明 IV 并且使用了不合规的密钥长度时,如何在 JavaScript 中匹配 openssl_encrypt
的输出?
PHP
php -r '$value = openssl_encrypt("test", "AES-128-CBC", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); echo $value;'
/u+5lB/VwbMX9U1YY4cnCQ==
JavaScript
iv = CryptoJS.enc.Utf8.parse("");
var encrypted = CryptoJS.AES.encrypt("test", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaa", {iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7});
console.log(encrypted.toString());
U2FsdGVkX19Cn1f6x8C/rJdfwzsZk5m5WWCUrR4z3U4=
console.log(CryptoJS.enc.Base64.stringify(encrypted.ciphertext));
l1/DOxmTmblZYJStHjPdTg==
我只能修改 Javascript 代码,我需要一种方法来加密字符串,以便它可以被 PHP 的 openssl_decrypt
解密。如果字符串是从 PHP.
我知道不声明 IV 会降低代码的安全性,但在我的特定情况下这不是什么大问题。
我在其他主题中读到 PHP 默认填充为 Pkcs7,这就是我将其添加到 JS 方法的原因。
我目前的理论是 PHP 的默认 IV 是问题所在,或者 JS 函数的输出需要进一步处理。如您所见,我尝试了 Base64.stringify
方法,但结果仍然不同。
我在这里使用的示例密钥与实际密钥的长度相同。
我正在使用https://github.com/sytelus/CryptoJS/blob/master/rollups/aes.js(无论我在JS中使用什么,它都需要像独立文件一样易于分发,占用空间相对较小)
您的代码存在一些问题:
- 如果您想使用现有密钥,则需要向
CryptoJS.<cipher>.encrypt
提供一个WordArray
对象。这意味着必须以某种方式对其进行解析。如果您简单地提供一个字符串作为 "key",那么 CryptoJS 将假定它是一个密码,生成一个随机盐并使用 EVP_BytesToKey 从密码和盐中导出密钥和 IV。 - 您的 "key" 长度为 29 个字符。 AES 仅支持三种密钥大小:16、24 和 32 字节。由于您在 PHP 中使用了 AES-128,因此您需要在 CryptoJS 中提供一个 16 字节的密钥,以便自动选择 AES-128。请记住:密钥应该是随机选择的,并且与随机噪声无法区分,因此它具有某种安全性。如果必须以某种方式打印密钥,请使用 Hex 或 Base64 编码。
完整示例:
var iv = CryptoJS.enc.Utf8.parse("");
var key = CryptoJS.enc.Utf8.parse("aaaaaaaaaaaaaaaa");
var encrypted = CryptoJS.AES.encrypt("test", key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
console.log(CryptoJS.enc.Base64.stringify(encrypted.ciphertext));
<script src="https://cdn.rawgit.com/CryptoStore/crypto-js/3.1.2/build/rollups/aes.js"></script>