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

Dragokas

Angry & Scary Developer
Команда форума
Супер-Модератор
Разработчик
Клуб переводчиков
Сообщения
7,813
Реакции
6,592
Достаточно часто, при работе с различными онлайн-сервисами нам приходится сталкиваться с хэшированием. Наиболее часто используемые при этом алгоритмы — MD5 и SHA1 (ну, по крайней мере, мне с этими алгоритмами приходится сталкиваться часто, с остальными — намного реже). Буквально недавно столкнулся в очередной раз с вычислением SHA1. Причем хэш необходимо рассчитывать для содержимого файла и передавать этот хэш в заголовках POST-запроса вместе с самим файлом на сервер. Ну, а так как, теоретически, на сервер можно отправлять файлы до 2 Гб, то возник вполне резонный вопрос: какой самый быстрый способ получить хэш SHA1 для файла есть в Delphi 10? Одно дело, когда необходимо получить хэш для строки в несколько сотен символов, а другое — для файла в несколько гигабайт.

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

Как получить SHA1 в Indy:
Код:
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:
Код:
uses synautil, synacode;
....
Hash:=StrToHex(SHA1(ReadStrFromStream(FS, FS.Size)));
....
Как получить SHA1 в DCPCRYPT (DCP):
Код:
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:
Код:
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:
Код:
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 Гб
DCP |0,0015 |0,0206 |9,455 |28,0592
Synapse |0,0041 |0,0373 |32,3996| Error
Indy |0,0035 |0,0329 |23,7571 |164,1033
LockBox |0,0039 |0,0335 |24,3384 |118,3559
System.Hash |0,0014 |0,0103 |7,0152 |20,3686

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

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

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