【问题标题】:OpenSSL Encrypt-Decrypt with CryptoJS使用 CryptoJS 的 OpenSSL 加密-解密
【发布时间】:2020-11-11 02:13:45
【问题描述】:

我在 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 转换为 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 中解密。但它显示纯文本似乎是不可打印的 ascii

b"}¦7▀À4█ÍØ█ù6ÒM§Ú¡]ÙW[¸^8"

还有 PHP 通知:

PHP 通知:iconv():在输入字符串中检测到非法字符 /var/www/html/blabla/vendor/symfony/var-dumper/Dumper/AbstractDumper.php 在第 203 行

谁能帮帮我?

【问题讨论】:

    标签: javascript node.js reactjs encryption cryptojs


    【解决方案1】:

    如果 PHP 代码以明文$string = "test"; 执行,则加密部分提供:

    MWNjdVlVL1hBWGN2UFlpMG9yMGZBUT09
    

    关于 PHP 代码需要注意以下几点:

    1. 加密过程 Base64 编码两次。一次显式使用base64_encode,一次默认隐式使用(s.openssl_encrypt, 4th parameter)。这种冗余不是必需的,即应该删除两个 Base64 编码之一。类似于解密。
    2. hash 函数默认返回以小写形式编码的十六进制数据。因此$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 作为密钥派生函数也不是很安全。

    【讨论】:

    • 非常感谢!所以 iv 应该是动态的,是否仍然可以攻击这种加密?
    • 两个代码都应用CBC模式。如果密钥/IV 对只使用一次,则 AES-CBC 被认为是安全的。 here。通常这是通过为每个加密生成一个新的随机 IV 来确保的。此外,不应将 SHA256 用作密钥派生函数,而应将其用作更可靠的算法(例如 PBKDF2)。 CBC 的替代方案是GCM,它不仅提供机密性,还提供真实性和完整性,s。 here.
    猜你喜欢
    • 1970-01-01
    • 2021-12-20
    • 2017-05-04
    • 1970-01-01
    • 1970-01-01
    • 2015-06-13
    • 2015-08-27
    • 2016-10-05
    • 1970-01-01
    相关资源
    最近更新 更多