Как прочитать двоичный файл с помощью FileReader, чтобы хешировать его с помощью SHA-256 в CryptoJS?

как преобразовать строку UTF-8 в строку в кодировке Latin1 с помощью javascript?

Вот что я пытаюсь сделать:

  1. Я получаю файл, разбиваю его на куски, читая как arraybuffer
  2. затем я анализирую буфер массива как строку
  3. и передать его в cryptoJS для вычисления хэша, используя следующий код:

    cryptosha256 = CryptoJS.algo.SHA256.create();
    cryptosha256.update(text);
    hash = cryptosha256.finalize();
    

Все это хорошо работает для текстового файла. У меня возникают проблемы при использовании кода для хеширования нетекстовых файлов (файлы изображений / .wmv). Я видел в другом блоге, и там автор CryptoJS требует, чтобы байты отправлялись в формате Latin1 вместо UTF-8, и здесь я застрял.

Не уверен, как я могу сгенерировать байты (или строки) с использованием формата Latin1 из буфера массива в javascript?

$('#btnHash').click(function () {
    var fr = new FileReader(), 
        file = document.getElementById("fileName").files[0];
    fr.onload = function (e) {
        calcHash(e.target.result, file);
    };
    fr.readAsArrayBuffer(file);
});
function calcHash(dataArray, file) {
    cryptosha256 = CryptoJS.algo.SHA256.create();
    text = CryptoJS.enc.Latin1.parse(dataArray);
    cryptosha256.update(text);
    hash = cryptosha256.finalize();
}

person learnedOne    schedule 25.11.2015    source источник
comment
«байты» не в Latin1 или каком-либо другом формате. А для двоичных файлов, таких как (большинство) изображений и звуков, кодировка символов на самом деле не применяется. Если вы конвертируете текст из одной кодировки в другую, у вас просто есть текст в другой кодировке (с возможной потерей некоторых символов). Если вы конвертируете двоичный файл в другую кодировку текста, у вас, скорее всего, будет поврежденный файл.   -  person GolezTrol    schedule 25.11.2015
comment
Я почти уверен, что CryptoJS напрямую принимает буфер массива. Не нужно заботиться о кодировках текста.   -  person Bergi    schedule 25.11.2015
comment
спасибо GolezTrol ... вот что пишет автор криптографии: когда вы передаете строку хешеру, она конвертируется в байты с использованием UTF-8. Это необходимо для того, чтобы не обрезать посторонние символы. Поскольку вы работаете с двоичными данными, вам нужно преобразовать строку в байты с помощью Latin1. sha256.update (CryptoJS.enc.Latin1.parse (evt.target.result));   -  person learnedOne    schedule 25.11.2015
comment
ссылка на приведенное выше утверждение: code.google.com/p/crypto-js/issues/   -  person learnedOne    schedule 25.11.2015
comment
когда я пытался использовать криптографический метод sha256.update (CryptoJS.enc.Latin1.parse (evt.target.result)); В качестве хеш-значения он вернул undefined :(   -  person learnedOne    schedule 25.11.2015
comment
Вы уверены, что evt.target.result содержит правильное значение? Обновите свой вопрос, добавив в него весь фрагмент кода.   -  person nwellnhof    schedule 25.11.2015
comment
@Bergi Нет, CryptoJS не работает с ArrayBuffer. Он имеет внутренний двоичный формат, в котором данные хранятся в виде массива слов (32-битные целые числа). Было бы необходимо преобразовать ArrayBuffer в WordArray   -  person Artjom B.    schedule 25.11.2015
comment
@nwellnhof .... обновил подробный код в исходном вопросе.   -  person learnedOne    schedule 25.11.2015
comment
@ArtjomB. для меня это не работает и для небольших изображений (я также пробовал с файлом png размером 200 КБ).   -  person learnedOne    schedule 25.11.2015
comment
@ArtjomB. Я тоже пробовал использовать readAsBinaryString. Это все еще дает мне неопределенное значение `` хеш-код '' ...   -  person learnedOne    schedule 25.11.2015
comment
Пожалуйста, не публикуйте решение вашего вопроса. Я откатил вашу правку. Вы можете добавить дополнительный ответ на свой вопрос.   -  person Artjom B.    schedule 25.11.2015
comment
Просто пришел, чтобы опубликовать, что после нескольких часов отладки этого онлайн-решения решение в комментарии выше, использующее CryptoJS.enc.Latin1.parse(evt.target.result) для получения правильного хэша SHA1, наконец, сработало для меня. Вроде при чтении двоичных данных нужен синтаксический анализ Latin1.   -  person Matt Welke    schedule 08.09.2019


Ответы (1)


CryptoJS не понимает, что такое ArrayBuffer, и если вы используете текстовую кодировку, например Latin1 или UTF-8, вы неизбежно потеряете несколько байтов. Не каждое возможное значение байта имеет допустимую кодировку в одной из этих текстовых кодировок.

Вам нужно будет преобразовать ArrayBuffer во внутренний WordArray CryptoJS, который содержит байты как массив слов (32-битные целые числа). Мы можем рассматривать ArrayBuffer как массив 8-битных целых чисел без знака и складывать их вместе, чтобы построить WordArray (см. arrayBufferToWordArray).

В следующем коде показан полный пример:

function arrayBufferToWordArray(ab) {
  var i8a = new Uint8Array(ab);
  var a = [];
  for (var i = 0; i < i8a.length; i += 4) {
    a.push(i8a[i] << 24 | i8a[i + 1] << 16 | i8a[i + 2] << 8 | i8a[i + 3]);
  }
  return CryptoJS.lib.WordArray.create(a, i8a.length);
}

function handleFileSelect(evt) {
  var files = evt.target.files; // FileList object

  // Loop through the FileList and render image files as thumbnails.
  for (var i = 0, f; f = files[i]; i++) {
    var reader = new FileReader();

    // Closure to capture the file information.
    reader.onloadend = (function(theFile) {
      return function(e) {
        var arrayBuffer = e.target.result;

        var hash = CryptoJS.SHA256(arrayBufferToWordArray(arrayBuffer));
        var elem = document.getElementById("hashValue");
        elem.value = hash;
      };

    })(f);
    reader.onerror = function(e) {
      console.error(e);
    };

    // Read in the image file as a data URL.
    reader.readAsArrayBuffer(f);
  }
}

document.getElementById('upload').addEventListener('change', handleFileSelect, false);
<script src="https://cdn.rawgit.com/CryptoStore/crypto-js/3.1.2/build/rollups/sha256.js"></script>
<form method="post" enctype="multipart/form-data">
  Select image to upload:
  <input type="file" name="upload" id="upload">
  <input type="text" name="hashValue" id="hashValue">
</form>

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

person Artjom B.    schedule 25.11.2015
comment
Благодарность! Ваш ответ дал мне больше, чем я ожидал. просто чтобы вы знали, хэш-значение undefined, которое я получал, было вызвано странной причиной наличия двух других ссылок на <script src="http://crypto-js.googlecode.com/svn/tags/3.0.2/build/rollups/hmac-sha256.js"></script> <script src="http://crypto-js.googlecode.com/svn/tags/3.0.2/build/components/enc-base64-min.js"></script>, я удалил их, и проблема undefined исчезла. Спасибо ребята! - person learnedOne; 25.11.2015
comment
arrayBufferToWordArray сотворил для меня волшебство. Спасибо! - person learnedOne; 25.11.2015
comment
вставьте .toString () в хеш var, чтобы получить фактический вывод хеша строки! - person Micheal C Wallas; 15.08.2019
comment
@MichealCWallas Вы имеете в виду, что строку elem.value = hash; нужно изменить на elem.value = hash.toString();? Это не должно повредить, но в этом также не должно быть необходимости, потому что присвоение объекта WordArray строковому свойству должно приводить к автоматической строковой обработке. Я тестировал это с Firefox и Vivaldi и не обнаружил проблемы. Возможно, это ошибка используемого вами браузера. - person Artjom B.; 16.08.2019
comment
@ArtjomB. извините, я имел в виду в конечном результате var hash = CryptoJS.SHA256(arrayBufferToWordArray(arrayBuffer)).toString(). Я думал, что код не работает, но toString () - это все, что нужно для вывода строкового хэша :) - person Micheal C Wallas; 26.08.2019
comment
Это то же самое значение, что я имел в виду. Вы пробовали напечатать это так console.log(hash)? Если нет, то какой браузер вы использовали? - person Artjom B.; 26.08.2019
comment
Большие файлы этот код вызывает сбой браузера. может ли кто-нибудь помочь в этом? - person Sharad; 03.02.2020
comment
@Sharad Ты дочитал мой ответ до конца? Есть ссылка на ссылку на возможно рабочий код. - person Artjom B.; 05.02.2020