CryptoJs - Encrypt/Decrypt by PHP and Javascript - 简单输出加密字符串
CryptoJs - Encrypt/Decrypt by PHP and Javascript - Simple Output Encrypted String
我想加密和解密 Php 和 Javascript 中的一些字符串,在网上看,最好和最安全的方法似乎是 CryptoJs。
这个 post 不是 Encrypt with PHP, Decrypt with Javascript (cryptojs) 的副本,因为它的输出字符串不简单。
这是我的代码,但是Js解密代码不起作用。
怎么了?
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js"></script>
</head>
<body>
<p>--- PHP ------------------</p>
<?php
function myCrypt($value, $passphrase, $iv){
$encrypted_data = openssl_encrypt($value, 'aes-256-cbc', $passphrase, true, $iv);
return base64_encode($encrypted_data);
}
function myDecrypt($value, $passphrase, $iv){
$value = base64_decode($value);
$data = openssl_decrypt($value, 'aes-256-cbc', $passphrase, true, $iv);
return $data;
}
$valTxt="MyText";
$pswd="MyPassword";
$vector="1234567890123412";
$encrypted = myCrypt($valTxt, $pswd, $vector);
$decrypted = myDecrypt($encrypted, $pswd, $vector);
echo "<p>Text to crypt --------> ".$valTxt." </p>";
echo "<p>Password: ".$pswd." </p>";
echo "<p>Vector: ".$vector." </p>";
echo "<p>TextEncrypt: ".$encrypted." </p>";
echo "<p>TextDecrypt: ".$decrypted." </p>";
?>
<br><br><br>
<p>--- Javascript ------------------</p>
<p>JS-DataEncrypt: --------- <span id="DataEncrypt"></span></p>
<p>JS-DataPassword: -------- <span id="DataPassword"></span></p>
<p>JS-DataVector: ---------- <span id="DataVector"></span></p>
<p>JS-TextDecrypted: ------- <span id="result"></span></p>
<script>
var DataEncrypt='<?php echo $encrypted;?>';
var DataPassword='<?php echo $pswd;?>';
var DataVector='<?php echo $vector;?>';
//var key = CryptoJS.enc.Hex.parse(DataPassword);
//var iv = CryptoJS.enc.Hex.parse(DataVector);
//var decrypted = CryptoJS.AES.decrypt(DataEncrypt, key, { iv: iv });
var decrypted = CryptoJS.AES.decrypt(DataEncrypt, DataPassword, { iv: DataVector });
decrypted= CryptoJS.enc.Utf8.stringify(decrypted)
document.getElementById("DataEncrypt").innerHTML = DataEncrypt;
document.getElementById("DataPassword").innerHTML = DataPassword;
document.getElementById("DataVector").innerHTML = DataVector;
document.getElementById("result").innerHTML = decrypted;
</script>
</body>
</html>
PS。如果输出字符串 ($encrypted) 为 16 位数字 A-Za-z0-9 更好...是否可以更改 'aes-256-cbc'?
在 PHP 代码中应考虑以下内容:
$passphrase
不表示密码,而是密钥。对于选项 aes-256-cbc
,此密钥的大小必须为 32 字节。如果太短,则用 0 值填充,如果太长,则截断。这是一个常见的错误来源,因此应使用恰好 32 字节的密钥。如果您想使用密码短语,则必须使用 KDF(如 PBKDF2)。
- 在第四个参数中设置了标志,没有布尔表达式(如
true
)。如果数据应以二进制形式返回,则必须设置 OPENSSL_RAW_DATA
标志。
- 静态IV是不安全的,通常每次加密都会生成一个新的IV,与密文一起发送给接收方。由于IV不是秘密的,因此通常在不加密的情况下将其放在字节级别的密文之前。
以下示例 PHP 代码(基于发布的代码):
function myCrypt($value, $key, $iv){
$encrypted_data = openssl_encrypt($value, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
return base64_encode($encrypted_data);
}
function myDecrypt($value, $key, $iv){
$value = base64_decode($value);
$data = openssl_decrypt($value, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
return $data;
}
$valTxt="MyText";
$key="01234567890123456789012345678901"; // 32 bytes
$vector="1234567890123412"; // 16 bytes
$encrypted = myCrypt($valTxt, $key, $vector);
$decrypted = myDecrypt($encrypted, $key, $vector);
print($encrypted . "\n");
print($decrypted . "\n");
returns 结果如下:
1SF+kez1CE5Rci3H6ff8og==
MyText
解密对应的CryptoJS代码为:
var DataEncrypt = "1SF+kez1CE5Rci3H6ff8og==";
var DataKey = CryptoJS.enc.Utf8.parse("01234567890123456789012345678901");
var DataVector = CryptoJS.enc.Utf8.parse("1234567890123412");
var decrypted = CryptoJS.AES.decrypt(DataEncrypt, DataKey, { iv: DataVector });
var decrypted = CryptoJS.enc.Utf8.stringify(decrypted);
console.log(decrypted);
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
输出MyText
对应原始明文
密钥作为 WordArray
传递很重要,这样它就会被解释为密钥而不是密码。对于转换,CryptoJS 提供了编码器(如 CryptoJS.enc.Utf8
)。
关于你最后的问题:密文是二进制任意序列,可以转换为具有特殊 binary-to-text 编码的字符串(例如本例中的 Base64,或十六进制),通常比原始数据(Base64:75% 效率,十六进制:50% 效率,参见here)。
因此,通常不可能用等于块大小(例如 AES 的 16 字节)的字母数字字符(例如 16 个字符)来表示密文块。
请注意,转换为具有字符集编码(如 UTF8)的字符串也不是解决方案,但会损坏数据。
我想加密和解密 Php 和 Javascript 中的一些字符串,在网上看,最好和最安全的方法似乎是 CryptoJs。
这个 post 不是 Encrypt with PHP, Decrypt with Javascript (cryptojs) 的副本,因为它的输出字符串不简单。
这是我的代码,但是Js解密代码不起作用。 怎么了?
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js"></script>
</head>
<body>
<p>--- PHP ------------------</p>
<?php
function myCrypt($value, $passphrase, $iv){
$encrypted_data = openssl_encrypt($value, 'aes-256-cbc', $passphrase, true, $iv);
return base64_encode($encrypted_data);
}
function myDecrypt($value, $passphrase, $iv){
$value = base64_decode($value);
$data = openssl_decrypt($value, 'aes-256-cbc', $passphrase, true, $iv);
return $data;
}
$valTxt="MyText";
$pswd="MyPassword";
$vector="1234567890123412";
$encrypted = myCrypt($valTxt, $pswd, $vector);
$decrypted = myDecrypt($encrypted, $pswd, $vector);
echo "<p>Text to crypt --------> ".$valTxt." </p>";
echo "<p>Password: ".$pswd." </p>";
echo "<p>Vector: ".$vector." </p>";
echo "<p>TextEncrypt: ".$encrypted." </p>";
echo "<p>TextDecrypt: ".$decrypted." </p>";
?>
<br><br><br>
<p>--- Javascript ------------------</p>
<p>JS-DataEncrypt: --------- <span id="DataEncrypt"></span></p>
<p>JS-DataPassword: -------- <span id="DataPassword"></span></p>
<p>JS-DataVector: ---------- <span id="DataVector"></span></p>
<p>JS-TextDecrypted: ------- <span id="result"></span></p>
<script>
var DataEncrypt='<?php echo $encrypted;?>';
var DataPassword='<?php echo $pswd;?>';
var DataVector='<?php echo $vector;?>';
//var key = CryptoJS.enc.Hex.parse(DataPassword);
//var iv = CryptoJS.enc.Hex.parse(DataVector);
//var decrypted = CryptoJS.AES.decrypt(DataEncrypt, key, { iv: iv });
var decrypted = CryptoJS.AES.decrypt(DataEncrypt, DataPassword, { iv: DataVector });
decrypted= CryptoJS.enc.Utf8.stringify(decrypted)
document.getElementById("DataEncrypt").innerHTML = DataEncrypt;
document.getElementById("DataPassword").innerHTML = DataPassword;
document.getElementById("DataVector").innerHTML = DataVector;
document.getElementById("result").innerHTML = decrypted;
</script>
</body>
</html>
PS。如果输出字符串 ($encrypted) 为 16 位数字 A-Za-z0-9 更好...是否可以更改 'aes-256-cbc'?
在 PHP 代码中应考虑以下内容:
$passphrase
不表示密码,而是密钥。对于选项aes-256-cbc
,此密钥的大小必须为 32 字节。如果太短,则用 0 值填充,如果太长,则截断。这是一个常见的错误来源,因此应使用恰好 32 字节的密钥。如果您想使用密码短语,则必须使用 KDF(如 PBKDF2)。- 在第四个参数中设置了标志,没有布尔表达式(如
true
)。如果数据应以二进制形式返回,则必须设置OPENSSL_RAW_DATA
标志。 - 静态IV是不安全的,通常每次加密都会生成一个新的IV,与密文一起发送给接收方。由于IV不是秘密的,因此通常在不加密的情况下将其放在字节级别的密文之前。
以下示例 PHP 代码(基于发布的代码):
function myCrypt($value, $key, $iv){
$encrypted_data = openssl_encrypt($value, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
return base64_encode($encrypted_data);
}
function myDecrypt($value, $key, $iv){
$value = base64_decode($value);
$data = openssl_decrypt($value, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
return $data;
}
$valTxt="MyText";
$key="01234567890123456789012345678901"; // 32 bytes
$vector="1234567890123412"; // 16 bytes
$encrypted = myCrypt($valTxt, $key, $vector);
$decrypted = myDecrypt($encrypted, $key, $vector);
print($encrypted . "\n");
print($decrypted . "\n");
returns 结果如下:
1SF+kez1CE5Rci3H6ff8og==
MyText
解密对应的CryptoJS代码为:
var DataEncrypt = "1SF+kez1CE5Rci3H6ff8og==";
var DataKey = CryptoJS.enc.Utf8.parse("01234567890123456789012345678901");
var DataVector = CryptoJS.enc.Utf8.parse("1234567890123412");
var decrypted = CryptoJS.AES.decrypt(DataEncrypt, DataKey, { iv: DataVector });
var decrypted = CryptoJS.enc.Utf8.stringify(decrypted);
console.log(decrypted);
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
输出MyText
对应原始明文
密钥作为 WordArray
传递很重要,这样它就会被解释为密钥而不是密码。对于转换,CryptoJS 提供了编码器(如 CryptoJS.enc.Utf8
)。
关于你最后的问题:密文是二进制任意序列,可以转换为具有特殊 binary-to-text 编码的字符串(例如本例中的 Base64,或十六进制),通常比原始数据(Base64:75% 效率,十六进制:50% 效率,参见here)。
因此,通常不可能用等于块大小(例如 AES 的 16 字节)的字母数字字符(例如 16 个字符)来表示密文块。
请注意,转换为具有字符集编码(如 UTF8)的字符串也不是解决方案,但会损坏数据。