уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.

Достаточно часто, при работе с различными онлайн-сервисами нам приходится сталкиваться с хэшированием. Наиболее часто используемые при этом алгоритмы — 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 секунд.

Книжная полка

Описание Подробно рассматривается библиотека FM, позволяющая создавать полнофункциональное программное обеспечение для операционных систем Windows и OS X, а также для смартфонов и планшетных компьютеров, работающих под управлением Android и iOS
купить книгу delphi на ЛитРес
Описание: Рассмотрены практические вопросы по разработке клиент-серверных приложений в среде Delphi 7 и Delphi 2005 с использованием СУБД MS SQL Server 2000, InterBase и Firebird. Приведена информация о теории построения реляционных баз данных и языке SQL. Освещены вопросы эксплуатации и администрирования СУБД.
купить книгу delphi на ЛитРес
Описание: Рассмотрены малоосвещенные вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные режимы их работы, особенности для протоколов TCP и UDP и др.
купить книгу delphi на ЛитРес
5 1 голос
Рейтинг статьи
уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
Подписаться
Уведомить о
7 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии
ND
ND
23/01/2016 06:17

Для SHA1 функции из пакета hash FPC работают примерно в 2 раза быстрее, чем из DCP. Проверял для функций на строках (что бы скорость чтения диска не влияла), строка длиной в 1000000, 1000 итераций, DCP ~ 40s, FPC ~ 20s. Удачи :)

Юрий Иванов
29/01/2016 07:36

Очень заинтересовало Как получить SHA1 в System.Hash

Сразу скажу, что с Delphi знаком только неделю, поэтому или не понимаю, или дается с трудом. Можно код для формы, на которой после нажатия кнопки будет считаться SHA1 по уже известному пути?

IL
IL
01/02/2016 17:19

Как же так, реализацию на ассемблере в TForge не попробовать? :)
https://sergworks.wordpress.com/2014/10/25/high-performance-hash-library/

IL
IL
01/02/2016 17:21

Что-то блог ваш «колбасит», то практически пуст за исключением статьи за 2010 год, как его взломали через темы вордпресса, то все на месте…

Alexey Pikurov
29/08/2018 20:23

Влад, реализация рассчёта SHA-1, которую мы используем в нашем мессенджере MyChat. Delphi XE3, файл 4,1 гигабайта, процессор Core i7, SSD, время 18,53.

Alexey Pikurov
30/08/2018 01:04

P.S. С мелкими оптимизациями вышли на 14 секунд. Пишите, если будет интересно, вышлю исходник для Delphi XE3.