除了填充不匹配之外,您的代码看起来不错。 CryptoJS 默认使用 PKCS#5/PKCS#7 填充,而 MCrypt 仅支持 ZeroPadding。
如果您只发送文本明文,那么您可以安全地使用
CryptoJS.AES.encrypt("Message", key, { iv: iv, padding: CryptoJS.pad.ZeroPadding });
如果没有,那么你应该使用PHP 中正确的 pkcs7unpad:
$plaintext = pkcs7unpad( mcrypt_decrypt( MCRYPT_RIJNDAEL_128, $key, $encrypted, MCRYPT_MODE_CBC, $iv ), 16 );
您的代码的其他问题是您直接使用CryptoJS.AES.encrypt(...).toString()
。这将创建一个 OpenSSL 格式的字符串,它不是纯粹的密文。你需要使用
CryptoJS.AES.encrypt(...).ciphertext.toString(CryptoJS.enc.Base64);
还要确定编码。
现在,这只是混淆,因为您将密钥与密文一起发送。我怀疑您也想在 PHP 中导出密钥。如果是,那么您只需要在服务器知道密码的情况下发送随机盐和密文。
PHP 提供了一个PBKDF2 实施从5.5版本开始。
不涉及 PBKDF2 的完整 JavaScript 部分:
var message = 'My string - Could also be an JS array/object';
var iv = 'a1a2a3a4a5a6a7a8b1b2b3b4b5b6b7b8';
var key = 'c1c2c3c4c5c6c7c8d1d2d3d4d5d6d7d8c1c2c3c4c5c6c7c8d1d2d3d4d5d6d7d8'; // 256-bit hex encoded
var keyBytes = CryptoJS.enc.Hex.parse(key);
var ivBytes = CryptoJS.enc.Hex.parse(iv);
var encrypt = CryptoJS.AES.encrypt(message, keyBytes, {
iv: ivBytes,
padding: CryptoJS.pad.ZeroPadding
}).ciphertext.toString(CryptoJS.enc.Base64);
产生:
j86KHBVRsDGKUnOiYdkEotsFL/lY/1tzz/h3Ay+vlEX11fC055m7vaF6q7w13eUj
不涉及 PBKDF2 的完整 PHP 部分:
<?php
$iv = 'a1a2a3a4a5a6a7a8b1b2b3b4b5b6b7b8';
$key = 'c1c2c3c4c5c6c7c8d1d2d3d4d5d6d7d8c1c2c3c4c5c6c7c8d1d2d3d4d5d6d7d8';
$ct = 'j86KHBVRsDGKUnOiYdkEotsFL/lY/1tzz/h3Ay+vlEX11fC055m7vaF6q7w13eUj';
$ivBytes = hex2bin($iv);
$keyBytes = hex2bin($key);
$ctBytes = base64_decode($ct);
$decrypt = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $keyBytes, $ctBytes, MCRYPT_MODE_CBC, $ivBytes));
echo $decrypt;
产生:
我的字符串 - 也可能是 JS 数组/对象
使用 OpenSSL 扩展也可以实现同样的效果:
<?php
$iv = 'a1a2a3a4a5a6a7a8b1b2b3b4b5b6b7b8';
$key = 'c1c2c3c4c5c6c7c8d1d2d3d4d5d6d7d8c1c2c3c4c5c6c7c8d1d2d3d4d5d6d7d8';
$ct = 'j86KHBVRsDGKUnOiYdkEotsFL/lY/1tzz/h3Ay+vlEX11fC055m7vaF6q7w13eUj';
$ivBytes = hex2bin($iv);
$keyBytes = hex2bin($key);
$ctBytes = base64_decode($ct);
$decrypt = openssl_decrypt($ctBytes, "aes-256-cbc", $keyBytes, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $ivBytes);
echo($decrypt);