Реализация шифрования и дешифрования OpenSSL и zlib в ReactJS

#javascript #reactjs #encryption #cryptojs #pako

#javascript #reactjs #шифрование #cryptojs #пако

Вопрос:

У меня есть 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
 

затем я попытался перевести язык на JS в React и сделал простые утилиты, вот мой 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 на другой JS-файл с именем string.js и импортируйте некоторые пакеты CryptoJS и PakoJS

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))))
 

Не удается прочитать свойство ‘ciphertext’ неопределенного

и когда я пытаюсь изменить secret_key и iv, появляется ошибка :

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

покажите мне ошибку

Ошибка: недопустимые сохраненные длины блоков

Кто-нибудь может мне помочь?

Ответ №1:

Я не эксперт по PHP, но у меня есть другие предположения, что PHP может усекать некоторые ключи для вас.

Я предлагаю убедиться, что функции генерации ключей ведут себя одинаково для вас на обоих языках, и убедитесь, что они имеют длину всего 32 байта.

Я хочу указать на еще одну проблему, которую я вижу в вашем коде. Хотя это будет работать, вы снижаете безопасность своего шифрования.

пусть ключ = строка(sha256(secret_key)).toString(Hex).substr(0, 32);

Каждый раз, когда вы берете 32-байтовое двоичное значение, преобразуете в шестнадцатеричное, а затем принимаете только 32 символа шестнадцатеричного вывода, вы значительно снижаете надежность своего ключа. Найдите способ сохранить значение в виде байта.

Вы пытаетесь создать 256-битный ключ (32 байта с 256 возможными значениями для каждого байта). На самом деле вы создаете строку из 32 символов, и каждый символ имеет только 16 возможных значений (0-1a-f). Вы изменили безопасность вашего ключа шифрования с предполагаемых 256 ^ 32 (1.1E77) на 16 ^ 32 (3.4E38).

Найдите способ использовать значения байтов, созданные SHA256.