Crypto-js 本地到 php 服务器端
Crypto-js local side to php server side
我有一个使用 crypto-Js AES 的应用程序。模拟工作代码为:
var ciphertext = CryptoJS.AES.encrypt('My_message', 'My_secret_key');
console.log(ciphertext.toString());
答案是:
U2FsdGVkX1/Dd3uAr/mdw5lVoBvq0UX5LHnNoX24JAM=
当我尝试在服务器端重现它时,我从未得到相同的答案:
$passphrase='My_secret_key';
$value='My_message';
$salt = openssl_random_pseudo_bytes(8);
$salt ='';
$salted = '';
$dx = '';
while (strlen($salted) < 48) {
$dx = md5($dx.$passphrase.$salt, true);
$salted .= $dx;
}
$key = substr($salted, 0, 32);
$iv = substr($salted, 32,16);
$encrypted_data = openssl_encrypt($value, 'aes-256-cbc', $key, true, $iv);
echo base64_encode($encrypted_data);
服务器端回答:
3jSTl1yR55lfTbz7f0o3Yw==
我一定错过了什么,但又不能指出是什么。本地端不能碰。
欢迎所有帮助
我以前遇到过你的确切情况。我们很难在 PHP 和 Java(Android)上获得相同的结果。许多天在 2 个公司的许多开发人员。没有运气。
我们最终从 PHP 调用了 CryptoJS。如果我没记错的话,Crypto JS 中有一些非标准的东西。我可能错了,那是前一段时间。
通过 PHP 使用节点调用 CryptoJS 可能是一个更强大的解决方案。然后您可以使用确保兼容性的相同库。
$result = shell_exec('node yourCryptoJSprogram.js');
我们确实达到了可以通过这种方式作为参数传递的数据量的限制。我建议使用 PHP 写入文件并再次使用 NodeJS 读取。
如果性能出现问题,请考虑 运行 Express 服务器并从 PHP 进行 REST 调用。
如果该答案不能满足您的要求,请考虑使用或复制我编写的这个简单的基于 OpenSSL 的 PHP 库来找出答案:
https://github.com/io-digital/php-crypto
如果 CryptoJS.AES.encrypt
中的第二个参数作为字符串传递,它被解释为密码短语,从中派生出实际密钥和 IV,[1]. This is achieved by using the functionality of the OpenSSL-function EVP_BytesToKey
with an iteration count of 1
and the MD5-digest, [2] [3] (note that CryptoJS doesn't consider the switch of the default digest from MD5 to SHA256 from OpenSSL version 1.1.0c on, [4])。
CryptoJS.AES.encrypt
returns一个CipherParams
-object,封装了密文、密钥、IV和盐,[5]。此外 CipherParams#toString()
returns 中的结果 OpenSSL-format 为 Base64 编码的字符串。 OpenSSL-format由一个16字节的header和后面的密文组成。 header 以 ASCII-encoded 字符串 Salted__
开头,后跟一个 8 字节的盐。 salt 每次随机生成,并与密码一起用于派生密钥/IV。这每次都会创建一个不同的密钥/IV。
PHP-code 在功能上是相同的:Key 和 IV 每次都使用新生成的盐从密码短语中通过模拟逻辑导出(证明见下文)。但是,需要进行一些小改动:
必须删除以下行:$salt ='';
目前的代码只显示Base64编码的密文。对于 OpenSSL-format 中结果的 Base64 编码输出,代码必须改为:
echo base64_encode('Salted__'.$salt.$encrypted_data);
openssl_encrypt
中的第 4 个参数应从 true
更改为 OPENSSL_RAW_DATA
。两者在功能上完全相同,但OPENSSL_RAW_DATA
的使用更加透明。
JavaScript- 和 PHP-code 每次都会生成一个新的盐,因此会生成不同的密钥和 IV,每次都会更改密文。事情本该如此。由于盐与密文一起存储,因此可以随时使用密码来解密密文。
证明两个代码使用相同的逻辑推导密钥和IV:每次生成的新盐/密文防止直接比较两个代码的结果。为了不费力地执行此比较,最好在 PHP-code 中也使用 JavaScript-code 中生成的盐。 JavaScript-code中的盐可以确定为十六进制字符串:
console.log(ciphertext.salt.toString(CryptoJS.enc.Hex));
这个salt是要在PHP-code中使用的,而不是随机生成的salt(当然只针对这一比较):
$salt = hex2bin('<Salt from JavaScript-Code as hexadecimal string>');
两个输出的比较现在证明它们是相等的,表明两个代码在功能上是相同的。
我有一个使用 crypto-Js AES 的应用程序。模拟工作代码为:
var ciphertext = CryptoJS.AES.encrypt('My_message', 'My_secret_key');
console.log(ciphertext.toString());
答案是:
U2FsdGVkX1/Dd3uAr/mdw5lVoBvq0UX5LHnNoX24JAM=
当我尝试在服务器端重现它时,我从未得到相同的答案:
$passphrase='My_secret_key';
$value='My_message';
$salt = openssl_random_pseudo_bytes(8);
$salt ='';
$salted = '';
$dx = '';
while (strlen($salted) < 48) {
$dx = md5($dx.$passphrase.$salt, true);
$salted .= $dx;
}
$key = substr($salted, 0, 32);
$iv = substr($salted, 32,16);
$encrypted_data = openssl_encrypt($value, 'aes-256-cbc', $key, true, $iv);
echo base64_encode($encrypted_data);
服务器端回答:
3jSTl1yR55lfTbz7f0o3Yw==
我一定错过了什么,但又不能指出是什么。本地端不能碰。 欢迎所有帮助
我以前遇到过你的确切情况。我们很难在 PHP 和 Java(Android)上获得相同的结果。许多天在 2 个公司的许多开发人员。没有运气。
我们最终从 PHP 调用了 CryptoJS。如果我没记错的话,Crypto JS 中有一些非标准的东西。我可能错了,那是前一段时间。
通过 PHP 使用节点调用 CryptoJS 可能是一个更强大的解决方案。然后您可以使用确保兼容性的相同库。
$result = shell_exec('node yourCryptoJSprogram.js');
我们确实达到了可以通过这种方式作为参数传递的数据量的限制。我建议使用 PHP 写入文件并再次使用 NodeJS 读取。
如果性能出现问题,请考虑 运行 Express 服务器并从 PHP 进行 REST 调用。
如果该答案不能满足您的要求,请考虑使用或复制我编写的这个简单的基于 OpenSSL 的 PHP 库来找出答案: https://github.com/io-digital/php-crypto
如果 CryptoJS.AES.encrypt
中的第二个参数作为字符串传递,它被解释为密码短语,从中派生出实际密钥和 IV,[1]. This is achieved by using the functionality of the OpenSSL-function EVP_BytesToKey
with an iteration count of 1
and the MD5-digest, [2] [3] (note that CryptoJS doesn't consider the switch of the default digest from MD5 to SHA256 from OpenSSL version 1.1.0c on, [4])。
CryptoJS.AES.encrypt
returns一个CipherParams
-object,封装了密文、密钥、IV和盐,[5]。此外 CipherParams#toString()
returns 中的结果 OpenSSL-format 为 Base64 编码的字符串。 OpenSSL-format由一个16字节的header和后面的密文组成。 header 以 ASCII-encoded 字符串 Salted__
开头,后跟一个 8 字节的盐。 salt 每次随机生成,并与密码一起用于派生密钥/IV。这每次都会创建一个不同的密钥/IV。
PHP-code 在功能上是相同的:Key 和 IV 每次都使用新生成的盐从密码短语中通过模拟逻辑导出(证明见下文)。但是,需要进行一些小改动:
必须删除以下行:
$salt ='';
目前的代码只显示Base64编码的密文。对于 OpenSSL-format 中结果的 Base64 编码输出,代码必须改为:
echo base64_encode('Salted__'.$salt.$encrypted_data);
openssl_encrypt
中的第 4 个参数应从true
更改为OPENSSL_RAW_DATA
。两者在功能上完全相同,但OPENSSL_RAW_DATA
的使用更加透明。
JavaScript- 和 PHP-code 每次都会生成一个新的盐,因此会生成不同的密钥和 IV,每次都会更改密文。事情本该如此。由于盐与密文一起存储,因此可以随时使用密码来解密密文。
证明两个代码使用相同的逻辑推导密钥和IV:每次生成的新盐/密文防止直接比较两个代码的结果。为了不费力地执行此比较,最好在 PHP-code 中也使用 JavaScript-code 中生成的盐。 JavaScript-code中的盐可以确定为十六进制字符串:
console.log(ciphertext.salt.toString(CryptoJS.enc.Hex));
这个salt是要在PHP-code中使用的,而不是随机生成的salt(当然只针对这一比较):
$salt = hex2bin('<Salt from JavaScript-Code as hexadecimal string>');
两个输出的比较现在证明它们是相等的,表明两个代码在功能上是相同的。