Статья Самый быстрый способ получить хэш SHA1 для файла в Delphi 10

Тема в разделе "Другие языки программирования", создана пользователем Dragokas, 12 май 2016.

  1. Dragokas
    Оффлайн

    Dragokas Very kind Developer Команда форума Супер-Модератор Разработчик Клуб переводчиков

    Сообщения:
    4.493
    Симпатии:
    4.310
    Достаточно часто, при работе с различными онлайн-сервисами нам приходится сталкиваться с хэшированием. Наиболее часто используемые при этом алгоритмы — MD5 и SHA1 (ну, по крайней мере, мне с этими алгоритмами приходится сталкиваться часто, с остальными — намного реже). Буквально недавно столкнулся в очередной раз с вычислением SHA1. Причем хэш необходимо рассчитывать для содержимого файла и передавать этот хэш в заголовках POST-запроса вместе с самим файлом на сервер. Ну, а так как, теоретически, на сервер можно отправлять файлы до 2 Гб, то возник вполне резонный вопрос: какой самый быстрый способ получить хэш SHA1 для файла есть в Delphi 10? Одно дело, когда необходимо получить хэш для строки в несколько сотен символов, а другое — для файла в несколько гигабайт.

    Сразу, навскидку, вспомнились:
    • Indy и её класс TIdHashSHA1
    • Synapse и её функция SHA1
    Порывшись по Сети скачал:
    Покопавшись в исходниках к Delphi 10 нашел модуль:
    • System.Hash
    Решил проверить кто из всего этого зоопарка будет быстрее получать хэш из потока TFileStream.

    Как получить SHA1 в Indy:
    Код (Delphi):

    uses IdHashSHA;
    ...
    var Hash: string;
        IdHashSHA1: TIdHashSHA1;
        FS: TFileStream;
    begin
      FS:=TFile.OpenRead('PATH_TO_FILE');
      IdHashSHA1:=TIdHashSHA1.Create;
      try
        S2:=IdHashSHA1.HashStreamAsHex(FS);
      finally
        IdHashSHA1.Free;
      end;
    end;
     
    Как получить SHA1 в Synapse:
    Код (Delphi):

    uses synautil, synacode;
    ....
    Hash:=StrToHex(SHA1(ReadStrFromStream(FS, FS.Size)));
    ....
     
    Как получить SHA1 в DCPCRYPT (DCP):
    Код (Delphi):

    var DCP_sha11: TDCP_sha1;
    HashDigest: array of byte;
    Hash: string;
    begin
      DCP_sha11:=TDCP_sha1.Create(nil);
      try
        DCP_sha11.Init;
        DCP_sha11.UpdateStream(FS,FS.Size);
        SetLength(HashDigest,DCP_sha11.HashSize div 8);
        DCP_sha11.Final(HashDigest[0]);
        for i:= 0 to High(HashDigest) do
          Hash:= Hash + IntToHex(HashDigest[i],2);
      finally
        DCP_sha11.Free
      end;
    end;
     
    Как получить SHA1 в TurboPower LockBox:
    Код (Delphi):

    var
    SHA1Hash: THash;
    CryptoLib: TCryptographicLibrary;
    Hash: string;
    aByte: byte;
    begin
    SHA1Hash:=THash.Create(nil);
    try
       CryptoLib:=TCryptographicLibrary.Create(nil);
       try
         SHA1Hash.CryptoLibrary:=CryptoLib;
         SHA1Hash.Hash:='SHA-1';
         SHA1Hash.HashStream(FS);
         while SHA1Hash.HashOutputValue.Read(aByte, 1) = 1 do
          Hash:= Hash+Format('%.2x', [aByte]);
       finally
         CryptographicLibrary1.Free;
       end;
    finally
       SHA1Hash.Free
    end;
    end;
     
    Как получить SHA1 в System.Hash:
    Код (Delphi):

    var HashSHA1:THashSHA1;
        Hash: string;
        read: integer;
        buffer: array[0..16383] of byte;
    begin
      HashSHA1:=THashSHA1.Create;
      repeat
        read := FS.Read(buffer,Sizeof(buffer));
        HashSHA1.Update(buffer,read);
      until read <> Sizeof(buffer);
      Hash:=HashSHA1.HashAsString;
    end;
     
    Для теста я взял несколько файлов следующих размеров: 116 Кб, 1,1 Мб, 791 Мб и 2,1 Гб. Результаты теста, секунды:
    Пакет 116 Кб 1,1 Мб 791 Мб 2,1 Гб
    1 DCP 0,0015 0,0206 9,455 28,0592
    2 Synapse 0,0041 0,0373 32,3996 Error
    3 Indy 0,0035 0,0329 23,7571 164,1033
    4 LockBox 0,0039 0,0335 24,3384 118,3559
    5 System.Hash 0,0014 0,0103 7,0152 20,3686

    Вот так, товарищи, самым быстрым оказался родной модуль Delphi. А Synapse — единственной библиотекой, которой для получения хэша в обязательном порядке требуется отдавать строку. Отсюда и вылет в Out of Memory на большом файле. Неплохие результаты также показала библиотека DCPCrypt, но какой смысл тащить в проект стороннюю библиотеку, если надо получать только SHA1 и родной модуль Delphi справляется с этим на ура?

    Само собой, что я рассмотрел далеко не все имеющиеся возможности и способы того как рассчитать SHA1 в Delphi, а лишь привел результаты экспериментов с теми библиотеками, которыми сам пользовался долгое время или нашел в Сети самыми первыми. Может быть кто-то знает ещё более быстрый способ расчёта SHA1 для больших файлов? Буду очень признателен за представленный пример, который на файле выше 2 Гб покажет время менее 20 сеукунд.

    Автор: Vlad. Источник.[/B]
     
    Последнее редактирование модератором: 12 май 2016
    akok нравится это.
  2. Dragokas
    Оффлайн

    Dragokas Very kind Developer Команда форума Супер-Модератор Разработчик Клуб переводчиков

    Сообщения:
    4.493
    Симпатии:
    4.310
    Также рекомендуют попробовать функции SHA1 из пакета hash FPC, который по идее работает примерно в 2 раза быстрее, чем из DCP.
    И эту реализацию на ассемблере: High Performance Hash Library, которая также умеет рассчитывать:
    • SHA224
    • SHA384
    • SHA512
     
    Последнее редактирование: 12 май 2016
    akok нравится это.

Поделиться этой страницей