使用 CryptoJS 的 OpenSSL 加密解密
OpenSSL Encrypt-Decrypt with CryptoJS
我在 JS 中生成加密时遇到问题,
我在 PHP 中有这样的加密生成器:
$secret_key = 'thisIsK3y';
$secret_iv = 'tHis1s1v';
$output = false;
$encrypt_method = "AES-256-CBC";
$key = hash( 'sha256', $secret_key );
$iv = substr( hash( 'sha256', $secret_iv ), 0, 16 );
if( $action == 'e' )
{
$output = base64_encode( openssl_encrypt( $string, $encrypt_method, $key, 0, $iv ) );
}
else if( $action == 'd')
{
$output = openssl_decrypt( base64_decode( $string ), $encrypt_method, $key, 0, $iv );
}
return $output;
然后我尝试使用 CryptoJS 在 React 上翻译成 JS :
import sha256 from "crypto-js/sha256";
import Base64 from "crypto-js/enc-base64";
import AES from "crypto-js/aes";
let secret_key = "thisIsK3y";
let secret_iv = "tHis1s1v";
let output = false;
let encrypt_method = "AES-256-CBC";
let key = sha256(secret_key);
let iv = String(sha256(secret_iv)).substr(0, 16);
if (action == "e") { // encrypt action
output = AES.encrypt("test", Utf8.parse(key), {
iv: Utf8.parse(iv),
}).toString();
alert(Base64.parse(output));
}
然后警报向我显示此加密:fd0337c029ad25c240316a1d61db9144,然后我尝试在我的 php.but 中解密它显示纯文本似乎不可打印的 ascii
b"}¦7▀À4█ÍØ█ù6ÒM§Ú¡]ÙW[¸^8"
并且有PHP通知:
PHP Notice: iconv(): Detected an illegal character in input string in
/var/www/html/blabla/vendor/symfony/var-dumper/Dumper/AbstractDumper.php
on line 203
谁能帮帮我?
如果PHP代码以明文$string = "test";
执行,则加密部分提供:
MWNjdVlVL1hBWGN2UFlpMG9yMGZBUT09
关于PHP代码,需要注意以下几点:
- 加密过程Base64编码两次。一次显式使用
base64_encode
,一次默认隐式使用 (s. openssl_encrypt
, 4th parameter)。这种冗余是不必要的,即应该删除两个 Base64 编码之一。类似于解密。
hash
函数returns默认情况下数据以小写十六进制编码。因此 $key
的大小为 64 字节。对于 AES-256,OpenSSL 仅隐式使用前 32 个字节。
您发布的 CryptoJS 代码可以修改如下以实现此功能 (JavaScript):
var Sha256 = CryptoJS.SHA256;
var Hex = CryptoJS.enc.Hex;
var Utf8 = CryptoJS.enc.Utf8;
var Base64 = CryptoJS.enc.Base64;
var AES = CryptoJS.AES;
var secret_key = 'thisIsK3y';
var secret_iv = 'tHis1s1v';
var key = Sha256(secret_key).toString(Hex).substr(0,32); // Use the first 32 bytes (see 2.)
var iv = Sha256(secret_iv).toString(Hex).substr(0,16);
// Encryption
var output = AES.encrypt("test", Utf8.parse(key), {
iv: Utf8.parse(iv),
}).toString(); // First Base64 encoding, by default (see 1.)
var output2ndB64 = Utf8.parse(output).toString(Base64); // Second Base64 encoding (see 1.)
console.log(output2ndB64); // MWNjdVlVL1hBWGN2UFlpMG9yMGZBUT09
// Decryption
var decrypted = AES.decrypt(output, Utf8.parse(key), {
iv: Utf8.parse(iv),
}).toString(Utf8);
console.log(decrypted); // test
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
针对PHP代码考虑到上面提到的两点。与PHP代码中的hash
函数一样,toString(Hex)
也是使用小写字母(所以这方面不需要转换)。
请注意,出于安全原因,实际上必须不使用静态 IV。相反,应该为每次加密重新生成 IV,并将其与密文一起发送给收件人(IV 不是秘密的)。此外,使用 SHA256 作为密钥派生函数也不是很安全。
我在 JS 中生成加密时遇到问题, 我在 PHP 中有这样的加密生成器:
$secret_key = 'thisIsK3y';
$secret_iv = 'tHis1s1v';
$output = false;
$encrypt_method = "AES-256-CBC";
$key = hash( 'sha256', $secret_key );
$iv = substr( hash( 'sha256', $secret_iv ), 0, 16 );
if( $action == 'e' )
{
$output = base64_encode( openssl_encrypt( $string, $encrypt_method, $key, 0, $iv ) );
}
else if( $action == 'd')
{
$output = openssl_decrypt( base64_decode( $string ), $encrypt_method, $key, 0, $iv );
}
return $output;
然后我尝试使用 CryptoJS 在 React 上翻译成 JS :
import sha256 from "crypto-js/sha256";
import Base64 from "crypto-js/enc-base64";
import AES from "crypto-js/aes";
let secret_key = "thisIsK3y";
let secret_iv = "tHis1s1v";
let output = false;
let encrypt_method = "AES-256-CBC";
let key = sha256(secret_key);
let iv = String(sha256(secret_iv)).substr(0, 16);
if (action == "e") { // encrypt action
output = AES.encrypt("test", Utf8.parse(key), {
iv: Utf8.parse(iv),
}).toString();
alert(Base64.parse(output));
}
然后警报向我显示此加密:fd0337c029ad25c240316a1d61db9144,然后我尝试在我的 php.but 中解密它显示纯文本似乎不可打印的 ascii
b"}¦7▀À4█ÍØ█ù6ÒM§Ú¡]ÙW[¸^8"
并且有PHP通知:
PHP Notice: iconv(): Detected an illegal character in input string in /var/www/html/blabla/vendor/symfony/var-dumper/Dumper/AbstractDumper.php on line 203
谁能帮帮我?
如果PHP代码以明文$string = "test";
执行,则加密部分提供:
MWNjdVlVL1hBWGN2UFlpMG9yMGZBUT09
关于PHP代码,需要注意以下几点:
- 加密过程Base64编码两次。一次显式使用
base64_encode
,一次默认隐式使用 (s.openssl_encrypt
, 4th parameter)。这种冗余是不必要的,即应该删除两个 Base64 编码之一。类似于解密。 hash
函数returns默认情况下数据以小写十六进制编码。因此$key
的大小为 64 字节。对于 AES-256,OpenSSL 仅隐式使用前 32 个字节。
您发布的 CryptoJS 代码可以修改如下以实现此功能 (JavaScript):
var Sha256 = CryptoJS.SHA256;
var Hex = CryptoJS.enc.Hex;
var Utf8 = CryptoJS.enc.Utf8;
var Base64 = CryptoJS.enc.Base64;
var AES = CryptoJS.AES;
var secret_key = 'thisIsK3y';
var secret_iv = 'tHis1s1v';
var key = Sha256(secret_key).toString(Hex).substr(0,32); // Use the first 32 bytes (see 2.)
var iv = Sha256(secret_iv).toString(Hex).substr(0,16);
// Encryption
var output = AES.encrypt("test", Utf8.parse(key), {
iv: Utf8.parse(iv),
}).toString(); // First Base64 encoding, by default (see 1.)
var output2ndB64 = Utf8.parse(output).toString(Base64); // Second Base64 encoding (see 1.)
console.log(output2ndB64); // MWNjdVlVL1hBWGN2UFlpMG9yMGZBUT09
// Decryption
var decrypted = AES.decrypt(output, Utf8.parse(key), {
iv: Utf8.parse(iv),
}).toString(Utf8);
console.log(decrypted); // test
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
针对PHP代码考虑到上面提到的两点。与PHP代码中的hash
函数一样,toString(Hex)
也是使用小写字母(所以这方面不需要转换)。
请注意,出于安全原因,实际上必须不使用静态 IV。相反,应该为每次加密重新生成 IV,并将其与密文一起发送给收件人(IV 不是秘密的)。此外,使用 SHA256 作为密钥派生函数也不是很安全。