0

我的 PHP 代码有 2 个函数,有使用 openSSL 的加密和解密,实际上在我重构它之前,我将 openSSL 结果编码为 base64,导致它太长我更改为使用 zlib(gzdeflate,gzinflate)压缩然后转换最后结果为十六进制。

这是我的 PHP 代码,它在 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 );
$action = 'e';
$string = "33f6f1d3ebe5b9da5fd0e3a1c7dd71c6e484be914731cf96adac0c00" //decrypted = "test"
if( $action == 'e' ) 
{
    $output = bin2hex(gzdeflate( gzdeflate(openssl_encrypt( $string, $encrypt_method, $key, 0, $iv ), 9),  9) );
}
else if( $action == 'd' )
{
    if (!empty($string))
        $output = openssl_decrypt( gzinflate(gzinflate(pack("H*", $string ) ) ), $encrypt_method, $key, 0, $iv );
}
echo $output; // output : "test", it's working fine on PHP

然后我尝试在 React 上将 JS 转换为 JS 并制作了简单的实用程序,这是我到目前为止的 JS 代码:

     let secret_key = "thisIsK3y";
      let secret_iv = "tHis1s1v";

      var output = false;
      let encrypt_method = "AES-256-CBC";
      let key = String(sha256(secret_key)).toString(Hex).substr(0, 32);
      let iv = String(sha256(secret_iv)).toString(Hex).substr(0, 16);

      if (action == 'd') { // Decryption
        let enc = gzinflate(gzinflate(hex2bin(string)));
        enc = enc.toString(Utf8);
      
        let decrypted = AES.decrypt(enc, Utf8.parse(key), {
          iv: Utf8.parse(iv),
        }).toString(Utf8);
        console.log('sss', hex2bin('33f6f1d3ebe5b9da5fd0e3a1c7dd71c6e484be914731cf96adac0c00'));
        debugger;
        output = decrypted;
      }

将 gzinfalte、gzdeflate、hex2bin、bin2hex方法拆分为另一个名为string.js的 JS 文件并导入一些包CryptoJSPakoJS

string.js 包含一些这样的方法:

export function gzdeflate(str) {
    return pako.deflateRaw(str);
}

export function gzinflate(str) {
    return pako.inflateRaw(str);
}

export function bin2hex(s) {
    let i
    let l
    let o = ''
    let n
    s += ''
    for (i = 0, l = s.length; i < l; i++) {
        n = s.charCodeAt(i)
        .toString(16)
        o += n.length < 2 ? '0' + n : n
    }
    return o
}

export function hex2bin(hex) {
    let bytes = [], str;

    for(var i=0; i< hex.length-1; i+=2){
        bytes.push(parseInt(hex.substr(i, 2), 16));
    }

    str = String.fromCharCode.apply(String, bytes);
    return str;
}

尝试调试时,hex2bin方法没有错误

console.log(hex2bin('33f6f1d3ebe5b9da5fd0e3a1c7dd71c6e484be914731cf96adac0c00'));

但是,当我尝试将二进制文件转换为gzinflate时,它​​会显示错误

console.log(gzinflate(gzinflate(hex2bin(33f6f1d3ebe5b9da5fd0e3a1c7dd71c6e484be914731cf96adac0c00))))

无法读取未定义的属性“密文”

当我尝试更改secret_keyiv时出现错误:

let secret_key = 'ffffffffffffffffffffffff{Curi}ty';
let secret_iv = 'ffffffffffffffffffffffff{Curi}ty';

显示错误

错误:无效的存储块长度

任何人都可以帮助我吗?

4

1 回答 1

0

我不是 PHP 专家,但我有其他人建议 PHP 可能会为您截断一些键。

我建议确保密钥生成函数在两种语言中的行为相同,并确保它们都只有 32 字节长。

我想指出我在您的代码中看到的另一个问题。虽然它会起作用,但您正在降低加密的安全性。

让 key = String(sha256(secret_key)).toString(Hex).substr(0, 32);

任何时候你取一个 32 字节的二进制值,转换为 HEX,然后只取 32 个字符的十六进制输出,你就显着降低了密钥的强度。找到一种保持字节值的方法。

您正在尝试创建一个 256 位密钥(32 个字节,每个字节有 256 个可能的值)。您实际上是在创建一个 32 个字符的字符串,每个字符只有 16 个可能的值 (0-1a-f)。您已将加密密钥的密钥安全性从预期的 256^32 (1.1E77) 更改为 16^32 (3.4E38)。

找到一种使用 SHA256 生成的字节值的方法。

于 2021-01-30T02:54:14.810 回答