Расчет SHA1 возвращает неверное значение

Я пытаюсь вычислить значение SHA1 файла с помощью javascript. Файл находится в том же каталоге, что и index.html, и загружается с использованием ajax по имени, заданному в качестве параметра запроса.

например, вызов http://localhost:7070/index.html?file=file.zip должен рассчитать SHA1 для file.zip

Следующий код вычисляет SHA1 , но результат отличается от того, который я получаю, используя этот онлайн-инструмент с SHA1 и загружая файл http://onlinemd5.com/

$(document).ready(function(){
   var file = utils.getUrlVars() && utils.getUrlVars().file;

   if (!file) throw "error - no URL was found. set 'file' in query string.";

   $.ajax({

       url: file,
       success: function(data){
           var sha1= CryptoJS.SHA1(data).toString();
           console.log('sha1 - success', sha1);
       },
       error: function(error){
           console.log('ERROR');
       }

   })
});

В чем разница? Я предполагаю, что онлайн-инструмент вычисляет его правильно (и он также дает мне точный результат, который я получаю при вычислении с использованием кода Java), поэтому что-то в этом коде JS немного отличается.

Проблема определенно не в пакете CryptoJS, поскольку при вычислении строки hello с помощью скрипта генерируется следующий вывод:

sha1 - success aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d

И с помощью онлайн-инструмента вы получите то же самое (в верхнем регистре):

AAF4C61DDCC5E8A2DABEDE0F3B482CD9AEA9434D

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

Когда я использую Java для вычисления SHA1, я получаю тот же результат, вычисляя его в массиве байтов файлов, поэтому это указывает на тот факт, что массив байтов, который я получаю с помощью этого скрипта, каким-то образом отличается / частично.


person Eyal    schedule 22.09.2015    source источник
comment
Какой SHA1SUM вы получаете для своего файла? Это da39a3ee5e6b4b0d3255bfef95601890afd80709? Это будет пустой файл. Попробуйте сравнить вывод javascript с известной хорошей простой строкой. hello должен дать aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d. Если это работает хорошо, ошибка в обработке файла. Возможно, JavaScript не разрешено загружать файлы с диска.   -  person neuhaus    schedule 22.09.2015
comment
Нет, результат меняется, когда я меняю файлы, он вычисляет SHA1 по чему-то, связанному с файлом.   -  person Eyal    schedule 22.09.2015
comment
При отправке содержимого файла вы использовали заголовок Content-Type: application/octet-stream или нет?   -  person Mjh    schedule 22.09.2015
comment
@neuhaus - привет, результат верное значение, поскольку функция CryptoJS.SHA1 делает то, что должна делать, проблема действительно в обработке файла.   -  person Eyal    schedule 22.09.2015
comment
@Mjh - я пытаюсь добавить contentType в скрипт ajax, но результат не изменился, тот же SHA1 создается для тех же файлов   -  person Eyal    schedule 22.09.2015
comment
Я отменил ваше последнее изменение. Пожалуйста, не включайте ответы в вопрос - это делает существующие ответы бесполезными / запутывающими и делает вопрос подвижной целью для других читателей.   -  person AD7six    schedule 22.09.2015
comment
var sha1= CryptoJS.SHA1(data).toString(); Я бы начал с регистрации и демонстрации того, что data и sha1 для известных (коротких) значений данных.   -  person AD7six    schedule 22.09.2015
comment
@ AD7six - когда я записываю данные на консоль, я получаю длинную строку символов, которая показывает мне, что она представляет собой поток байтов.   -  person Eyal    schedule 22.09.2015
comment
Я говорю о файле, вы хотите, чтобы я поместил ссылку на настоящий файл для загрузки?   -  person Eyal    schedule 22.09.2015
comment
@Eyal - использование contentType в $.ajax устанавливает заголовок для запроса. Заголовок, о котором я спрашиваю, - это заголовок ответа. Ваши функции хеширования должны работать с одним и тем же двоичным содержимым, иначе вы получите другой результат хеширования. CryptoJS определенно реализует хеширование правильно, так что это означает, что ошибка находится где-то в отправляющей / принимающей части, а не в самой библиотеке.   -  person Mjh    schedule 22.09.2015
comment
Я не могу найти место, чтобы объявить этот заголовок ответа, я предполагаю, что это может быть проблемой, однако я не имел ни малейшего представления о том, где следует сделать изменение.   -  person Eyal    schedule 22.09.2015
comment
@Eyal Я прошу вас отладить, указав небольшой файл (например, простой значок) и обновить вопрос, показывая, что такое data и sha1. Вы, вероятно, обнаружите, что data делает < i> not соответствует содержимому файла - это будет означать, что проблема не в криптографической библиотеке, а в том, как вы получаете содержимое файла.   -  person AD7six    schedule 22.09.2015
comment
@ AD7six - хорошо, я обновил, что при вычислении значения строки с помощью скрипта предоставляется правильный хеш, поэтому он должен мешать тому, как я обрабатываю файл.   -  person Eyal    schedule 22.09.2015


Ответы (2)


Согласно руководству для .ajax, вам необходимо установить для параметра dataType значение text, в противном случае попробуйте угадать тип, и тогда text никогда не станет вариантом.

person Emil Vikström    schedule 22.09.2015
comment
попытался добавить следующее, но результат тот же: dataType: 'text' - person Eyal; 22.09.2015

В конце концов нам удалось решить эту проблему, решение представляет собой чистый JS без использования Ajax:

$(document).ready(function(){

var url = utils.getUrlVars() && utils.getUrlVars().url;

if (!url) throw "error - no URL was found. set 'url' in query string.";

var oReq = new XMLHttpRequest();
oReq.open("GET", url, true);
oReq.responseType = "blob";

oReq.onreadystatechange = function(e) {

    if (oReq.readyState == 4 && oReq.status == 200) {
        console.log('xhr success');
        success(e);
    } else if (oReq.readyState == 4 && oReq.status != 200){
        console.log('xhr error');
        error(e);
    }
}

var success = function() {
    var blob = oReq.response; 
    var sha1 = CryptoJS.algo.SHA1.create(); 
    var reader = new FileReader();
    reader.readAsArrayBuffer(blob);

    reader.onload = function(e) {
        var arrbuffer = e.target.result.slice(0, e.target.result.byteLength);
        var bytes = CryptoJS.enc.u8array.parse(new Uint8Array(arrbuffer));
        sha1.update(bytes);
        var sha1res = sha1.finalize().toString(CryptoJS.enc.Hex);
        // print results
        console.log('sha1 - success', sha1res);
    }
};

var error = function(){
    IJavaScriptImplementer.onError(JSON.stringify(error));
    IJavaScriptImplementer.log(JSON.stringify(error));
}

oReq.send(null);
});

Как вы видите, файл запрашивается как большой двоичный объект и читается как один фрагмент (вы также можете делать это фрагмент за фрагментом, но в моем случае файлы маленькие), затем байты считываются и вычисляются в значение SHA1.

person Eyal    schedule 06.10.2015