Достаточно часто, при работе с различными онлайн-сервисами нам приходится сталкиваться с хэшированием. Наиболее часто используемые при этом алгоритмы — 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 7 и Delphi 2005 с использованием СУБД MS SQL Server 2000, InterBase и Firebird. Приведена информация о теории построения реляционных баз данных и языке SQL. Освещены вопросы эксплуатации и администрирования СУБД.
|
||
Название: О чем не пишут в книгах по Delphi
Описание: Рассмотрены малоосвещенные вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные режимы их работы, особенности для протоколов TCP и UDP и др.
|
Для SHA1 функции из пакета hash FPC работают примерно в 2 раза быстрее, чем из DCP. Проверял для функций на строках (что бы скорость чтения диска не влияла), строка длиной в 1000000, 1000 итераций, DCP ~ 40s, FPC ~ 20s. Удачи :)
Очень заинтересовало Как получить SHA1 в System.Hash
Сразу скажу, что с Delphi знаком только неделю, поэтому или не понимаю, или дается с трудом. Можно код для формы, на которой после нажатия кнопки будет считаться SHA1 по уже известному пути?
Бросаете на форму кнопку. Дважды по ней кликаете мышкой. Создастся обработчик события OnClick. В этот обработчик копируете код:
var HashSHA1: THashSHA1;
buffer: array[0..16383] of byte;
read:integer;
FFileBuffer: TFileBuffer;
begin
FFileBuffer := TFileStream.Create('СЮДА_ВСТАВЛЯЕМ_ПУТЬ_К_ФАЙЛУ', fmOpenRead);
try
HashSHA1:=THashSHA1.Create;
repeat
read := FFileBuffer.Read(buffer,Sizeof(buffer));
HashSHA1.Update(buffer,read);
until read <> Sizeof(buffer);
ShowMessage(HashSHA1.HashAsString);
finally
FreeAndNil(FFileBuffer);
end;
end;
В Uses не забываете подключить модуль System.Hash.
Как же так, реализацию на ассемблере в TForge не попробовать? :)
https://sergworks.wordpress.com/2014/10/25/high-performance-hash-library/
Что-то блог ваш «колбасит», то практически пуст за исключением статьи за 2010 год, как его взломали через темы вордпресса, то все на месте…
Влад, реализация рассчёта SHA-1, которую мы используем в нашем мессенджере MyChat. Delphi XE3, файл 4,1 гигабайта, процессор Core i7, SSD, время 18,53.
P.S. С мелкими оптимизациями вышли на 14 секунд. Пишите, если будет интересно, вышлю исходник для Delphi XE3.