612 lines
15 KiB
Plaintext
612 lines
15 KiB
Plaintext
{*******************************************************}
|
|
{ }
|
|
{ Tocsg.Hash }
|
|
{ }
|
|
{ Copyright (C) 2020 kku }
|
|
{ }
|
|
{*******************************************************}
|
|
|
|
unit Tocsg.Hash;
|
|
|
|
interface
|
|
|
|
uses
|
|
// EM.SHA1, // 11.1 에서 제대로 동작 하지 않음 22_0419 08:29:50 kku
|
|
Windows, SysUtils, System.Classes, EM.MD5, EM.Tocsg.Sha1,
|
|
EM.Tocsg.hash, Tocsg.Obj;
|
|
|
|
type
|
|
THashStreamBase = class(TTgObject)
|
|
protected
|
|
bInit_: Boolean;
|
|
public
|
|
Constructor Create(bInit: Boolean = true);
|
|
procedure WorkInit; virtual; abstract;
|
|
procedure SetBuffer(buf: Pointer; nCount: Integer); virtual; abstract;
|
|
|
|
function WorkFinalToStr: String; virtual; abstract;
|
|
end;
|
|
|
|
TSHA1Hash = class(THashStreamBase)
|
|
private
|
|
ctx_: TTgHashContext; // TSHA1Context;
|
|
public
|
|
procedure WorkInit; override;
|
|
procedure SetBuffer(buf: Pointer; nCount: Integer); override;
|
|
function WorkFinalToStr: String; override;
|
|
function WorkFinalToDigest(var SHA1Digest: TSHA1Digest): Boolean;
|
|
end;
|
|
|
|
TSHA256Hash = class(THashStreamBase)
|
|
private
|
|
ctx_: TTgHashContext; // TSHA1Context;
|
|
public
|
|
procedure WorkInit; override;
|
|
procedure SetBuffer(buf: Pointer; nCount: Integer); override;
|
|
function WorkFinalToStr: String; override;
|
|
function WorkFinalToDigest(var SHA256Digest: TSHA256Digest): Boolean;
|
|
end;
|
|
|
|
TMD5Hash = class(THashStreamBase)
|
|
private
|
|
ctx_: TMD5Context;
|
|
public
|
|
procedure WorkInit; override;
|
|
procedure SetBuffer(buf: Pointer; nCount: Integer); override;
|
|
function WorkFinalToStr: String; override;
|
|
end;
|
|
|
|
TTgHashProgress = reference to function(s: TStream; nPercent: Integer): Boolean;
|
|
|
|
function GetStreamToSha1Str(aStream: TStream; aProgress: TTgHashProgress = nil): String;
|
|
function GetFileToSha1Str(const sPath: String; aProgress: TTgHashProgress = nil): String;
|
|
|
|
function GetStreamToHash(aStream: TStream; var sSHA1, sMD5, sSHA256: AnsiString;
|
|
aProgress: TTgHashProgress = nil; llUntilSize: LONGLONG = 0): Boolean;
|
|
function GetFileToHash(const sPath: String; var sSHA1, sMD5, sSHA256: AnsiString;
|
|
aProgress: TTgHashProgress = nil; llUntilSize: LONGLONG = 0): Boolean; overload;
|
|
|
|
function GetStreamToSha256(aStream: TStream; aProgress: TTgHashProgress = nil; llUntilSize: LONGLONG = 0): AnsiString;
|
|
function GetFileToSha256(const sPath: String; aProgress: TTgHashProgress = nil; llUntilSize: LONGLONG = 0): AnsiString;
|
|
|
|
function ConvStrToSha1A(str: AnsiString): String;
|
|
function ConvStrToSha1A_Bin(str: AnsiString): TBytes;
|
|
function ConvStrToSha1W(str: WideString): String;
|
|
function ConvStrToSha256A_Bin(str: AnsiString): TBytes;
|
|
function ConvStrToSha256A(str: AnsiString): String;
|
|
function ConvStrToSha256W(str: WideString): String;
|
|
function ConvStrToHash(str: String): DWORD;
|
|
|
|
// By .. https://helloacm.com/simple-and-fast-hash-functions-in-delphi/
|
|
type
|
|
HashFunction = function(aData: Pointer; aDataLength: Integer): DWORD;
|
|
|
|
function Hash_djb2(aData: Pointer; aDataLength: Integer): NativeUInt;
|
|
function Hash_djb2a(aData: Pointer; aDataLength: Integer): NativeUInt;
|
|
function Hash_fnv(aData: Pointer; aDataLength: Integer): NativeUInt;
|
|
function Hash_fnv1a(aData: Pointer; aDataLength: Integer): NativeUInt;
|
|
function Hash_sdbm(aData: Pointer; aDataLength: Integer): NativeUInt;
|
|
function Hash_jenkis(aData: Pointer; aDataLength: Integer): NativeUInt;
|
|
|
|
implementation
|
|
|
|
uses
|
|
EM.CRC32, EM.Tocsg.sha256, Tocsg.Binary, Tocsg.Safe, Tocsg.Exception;
|
|
|
|
const
|
|
// BUF_SIZE = 65536; // 이거 쓰면 Range 오류남 25_0911 17:38:13 kku
|
|
BUF_SIZE = 32768;
|
|
|
|
function ConvStrToSha1A(str: AnsiString): String;
|
|
var
|
|
nRead : Integer;
|
|
ctx: TTgHashContext; //TSHA1Context;
|
|
sd: TSHA1Digest;
|
|
begin
|
|
try
|
|
SHA1Init(ctx);
|
|
nRead := Length(str);
|
|
SHA1Update(ctx, @str[1], nRead);
|
|
|
|
SHA1Final(ctx, sd);
|
|
Result := ConvBytesToHexStr(PByte(@sd), SizeOf(sd));
|
|
finally
|
|
|
|
end;
|
|
end;
|
|
|
|
function ConvStrToSha1A_Bin(str: AnsiString): TBytes;
|
|
var
|
|
nRead : Integer;
|
|
ctx: TTgHashContext; //TSHA1Context;
|
|
sd: TSHA1Digest;
|
|
begin
|
|
try
|
|
SHA1Init(ctx);
|
|
nRead := Length(str);
|
|
SHA1Update(ctx, @str[1], nRead);
|
|
|
|
SHA1Final(ctx, sd);
|
|
SetLength(Result, Length(sd));
|
|
CopyMemory(Result, @sd[0], SizeOf(sd));
|
|
finally
|
|
|
|
end;
|
|
end;
|
|
|
|
function ConvStrToSha1W(str: WideString): String;
|
|
var
|
|
nRead: Integer;
|
|
ctx: TTgHashContext; //TSHA1Context;
|
|
sd: TSHA1Digest;
|
|
begin
|
|
try
|
|
if str = '' then
|
|
begin
|
|
Result := '';
|
|
exit;
|
|
end;
|
|
|
|
SHA1Init(ctx);
|
|
nRead := Length(str);
|
|
SHA1Update(ctx, @str[1], nRead*2);
|
|
|
|
SHA1Final(ctx, sd);
|
|
Result := ConvBytesToHexStr(PByte(@sd), SizeOf(sd));
|
|
except
|
|
on E: Exception do
|
|
ETgException.TraceException(E, 'Fail .. ConvStrToSha1W()');
|
|
end;
|
|
end;
|
|
|
|
function ConvStrToSha256A_Bin(str: AnsiString): TBytes;
|
|
var
|
|
nRead : Integer;
|
|
ctx: TTgHashContext;
|
|
sd: TSHA256Digest;
|
|
begin
|
|
try
|
|
SHA256Init(ctx);
|
|
nRead := Length(str);
|
|
SHA256Update(ctx, @str[1], nRead);
|
|
|
|
SHA256Final(ctx, sd);
|
|
SetLength(Result, Length(sd));
|
|
CopyMemory(Result, @sd[0], SizeOf(sd));
|
|
finally
|
|
|
|
end;
|
|
end;
|
|
|
|
function ConvStrToSha256A(str: AnsiString): String;
|
|
var
|
|
nRead: Integer;
|
|
ctx: TTgHashContext;
|
|
sd: TSHA256Digest;
|
|
begin
|
|
Result := '';
|
|
try
|
|
if str = '' then
|
|
exit;
|
|
|
|
SHA256Init(ctx);
|
|
nRead := Length(str);
|
|
SHA256Update(ctx, @str[1], nRead);
|
|
|
|
SHA256Final(ctx, sd);
|
|
Result := ConvBytesToHexStr(PByte(@sd), SizeOf(sd));
|
|
except
|
|
on E: Exception do
|
|
ETgException.TraceException(E, 'Fail .. ConvStrToSha256A()');
|
|
end;
|
|
end;
|
|
|
|
function ConvStrToSha256W(str: WideString): String;
|
|
var
|
|
nRead: Integer;
|
|
ctx: TTgHashContext;
|
|
sd: TSHA256Digest;
|
|
begin
|
|
Result := '';
|
|
try
|
|
if str = '' then
|
|
exit;
|
|
|
|
SHA256Init(ctx);
|
|
nRead := Length(str);
|
|
SHA256Update(ctx, @str[1], nRead*2);
|
|
|
|
SHA256Final(ctx, sd);
|
|
Result := ConvBytesToHexStr(PByte(@sd), SizeOf(sd));
|
|
except
|
|
on E: Exception do
|
|
ETgException.TraceException(E, 'Fail .. ConvStrToSha256W()');
|
|
end;
|
|
end;
|
|
|
|
function GetStreamToSha1Str(aStream: TStream; aProgress: TTgHashProgress = nil): String;
|
|
var
|
|
nRead: Integer;
|
|
pBuf: array [0..BUF_SIZE] of AnsiChar;
|
|
ctx: TTgHashContext; //TSHA1Context;
|
|
sd: TSHA1Digest;
|
|
begin
|
|
Result := '';
|
|
|
|
SHA1Init(ctx);
|
|
Repeat
|
|
nRead := aStream.Read(pBuf, BUF_SIZE);
|
|
SHA1Update(ctx, @pBuf, nRead);
|
|
|
|
if Assigned(aProgress) then
|
|
if not aProgress(aStream, (aStream.Position * 100) div aStream.Size) then
|
|
exit;
|
|
Until nRead <> BUF_SIZE;
|
|
|
|
SHA1Final(ctx, sd);
|
|
Result := ConvBytesToHexStr(PByte(@sd), SizeOf(sd));
|
|
end;
|
|
|
|
function GetFileToSha1Str(const sPath: String; aProgress: TTgHashProgress = nil): String;
|
|
var
|
|
fs: TFileStream;
|
|
begin
|
|
Result := '';
|
|
try
|
|
if FileExists(sPath) then
|
|
begin
|
|
Guard(fs, TFileStream.Create(sPath, fmOpenRead or fmShareDenyNone));
|
|
Result := GetStreamToSha1Str(fs, aProgress);
|
|
end;
|
|
except
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
function GetFileToHash(const sPath: String; var sSHA1, sMD5, sSHA256: AnsiString;
|
|
aProgress: TTgHashProgress = nil; llUntilSize: LONGLONG = 0): Boolean;
|
|
var
|
|
fs: TFileStream;
|
|
begin
|
|
try
|
|
Guard(fs, TFileStream.Create(sPath, fmOpenRead or fmShareDenyNone));
|
|
Result := GetStreamToHash(fs, sSHA1, sMD5, sSHA256, aProgress, llUntilSize);
|
|
except
|
|
Result := false;
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
function GetStreamToHash(aStream: TStream; var sSHA1, sMD5, sSHA256: AnsiString;
|
|
aProgress: TTgHashProgress = nil; llUntilSize: LONGLONG = 0): Boolean;
|
|
var
|
|
nRead: Integer;
|
|
pBuf: array [0..BUF_SIZE-1] of AnsiChar;
|
|
SHA1Ctx: TTgHashContext; //TSHA1Context;
|
|
MD5Ctx: TMD5Context;
|
|
SHA256Ctx: TTgHashContext;
|
|
sd: TSHA1Digest;
|
|
md: EM.MD5.TMD5Digest;
|
|
s256d: TSHA256Digest;
|
|
llTotalRead: LONGLONG;
|
|
begin
|
|
Result := false;
|
|
|
|
if aStream.Size > 0 then
|
|
begin
|
|
llTotalRead := 0;
|
|
sSHA1 := '';
|
|
sMD5 := '';
|
|
sSHA256 := '';
|
|
|
|
MD5Init(MD5Ctx);
|
|
SHA1Init(SHA1Ctx);
|
|
SHA256Init(SHA256Ctx);
|
|
Repeat
|
|
nRead := aStream.Read(pBuf, BUF_SIZE);
|
|
MD5Update(MD5Ctx, @pBuf, nRead);
|
|
SHA1Update(SHA1Ctx, @pBuf, nRead);
|
|
SHA256Update(SHA256Ctx, @pBuf, nRead);
|
|
|
|
if Assigned(aProgress) then
|
|
if not aProgress(aStream, (aStream.Position * 100) div aStream.Size) then
|
|
exit;
|
|
|
|
Inc(llTotalRead, nRead);
|
|
if (llUntilSize > 0) and (llUntilSize <= llTotalRead) then // 추가 15_0921 11:43:31 kku
|
|
break;
|
|
Until (nRead <> BUF_SIZE) or (aStream.Size <= llTotalRead);
|
|
|
|
MD5Final(MD5Ctx, md);
|
|
SHA1Final(SHA1Ctx, sd);
|
|
SHA256Final(SHA256Ctx, s256d);
|
|
|
|
sMD5 := ConvBytesToHexStr(PByte(@md), SizeOf(md));
|
|
sSHA1 := ConvBytesToHexStr(PByte(@sd), SizeOf(sd));
|
|
sSHA256 := ConvBytesToHexStr(PByte(@s256d), SizeOf(s256d));
|
|
|
|
Result := true;
|
|
end;
|
|
end;
|
|
|
|
function GetStreamToSha256(aStream: TStream; aProgress: TTgHashProgress = nil; llUntilSize: LONGLONG = 0): AnsiString;
|
|
//const
|
|
// BUF_SIZE2 = 32768; // BUF_SIZE(65536) 사용하면 Range 오류난다 25_0728 18:20:37 kku
|
|
var
|
|
nRead: Integer;
|
|
pBuf: array [0..BUF_SIZE-1] of AnsiChar;
|
|
SHA256Ctx: TTgHashContext;
|
|
s256d: TSHA256Digest;
|
|
llTotalRead: LONGLONG;
|
|
begin
|
|
Result := '';
|
|
|
|
if aStream.Size > 0 then
|
|
begin
|
|
llTotalRead := 0;
|
|
|
|
SHA256Init(SHA256Ctx);
|
|
Repeat
|
|
nRead := aStream.Read(pBuf, BUF_SIZE);
|
|
SHA256Update(SHA256Ctx, @pBuf, nRead);
|
|
|
|
if Assigned(aProgress) then
|
|
if not aProgress(aStream, (aStream.Position * 100) div aStream.Size) then
|
|
exit;
|
|
|
|
Inc(llTotalRead, nRead);
|
|
if (llUntilSize > 0) and (llUntilSize <= llTotalRead) then // 추가 15_0921 11:43:31 kku
|
|
break;
|
|
Until (nRead <> BUF_SIZE) or (aStream.Size <= llTotalRead);
|
|
|
|
SHA256Final(SHA256Ctx, s256d);
|
|
|
|
Result := ConvBytesToHexStr(PByte(@s256d), SizeOf(s256d));
|
|
end;
|
|
end;
|
|
|
|
function GetFileToSha256(const sPath: String; aProgress: TTgHashProgress = nil; llUntilSize: LONGLONG = 0): AnsiString;
|
|
var
|
|
fs: TFileStream;
|
|
begin
|
|
try
|
|
Guard(fs, TFileStream.Create(sPath, fmOpenRead or fmShareDenyNone));
|
|
Result := GetStreamToSha256(fs, aProgress, llUntilSize);
|
|
except
|
|
Result := '';
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
// IniFiles.pas 에서 TStringHash.HashOf 가져옴 2010-11-04 kku
|
|
function ConvStrToHash(str: String): DWORD;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := 0;
|
|
for i := 1 to Length(str) do
|
|
Result := ((Result shl 2) or
|
|
(Result shr (SizeOf(Result) * 8 - 2))) xor
|
|
Ord(str[i]);
|
|
end;
|
|
|
|
{ THashStreamBase }
|
|
|
|
Constructor THashStreamBase.Create(bInit: Boolean = true);
|
|
begin
|
|
Inherited Create;
|
|
|
|
bInit_ := false;
|
|
|
|
if bInit then
|
|
WorkInit;
|
|
end;
|
|
|
|
{ TSHA1Hash }
|
|
|
|
procedure TSHA1Hash.WorkInit;
|
|
begin
|
|
SHA1Init(ctx_);
|
|
bInit_ := true;
|
|
end;
|
|
|
|
procedure TSHA1Hash.SetBuffer(buf: Pointer; nCount: Integer);
|
|
begin
|
|
if bInit_ then
|
|
SHA1Update(ctx_, buf, nCount);
|
|
end;
|
|
|
|
function TSHA1Hash.WorkFinalToStr: String;
|
|
var
|
|
sd : TSHA1Digest;
|
|
begin
|
|
Result := '';
|
|
if bInit_ then
|
|
begin
|
|
SHA1Final(ctx_, sd);
|
|
Result := ConvBytesToHexStr(PByte(@sd), SizeOf(sd));
|
|
bInit_ := false;
|
|
end;
|
|
end;
|
|
|
|
function TSHA1Hash.WorkFinalToDigest(var SHA1Digest: TSHA1Digest): Boolean;
|
|
begin
|
|
Result := false;
|
|
ZeroMemory(@SHA1Digest, SizeOf(SHA1Digest));
|
|
if bInit_ then
|
|
begin
|
|
SHA1Final(ctx_, SHA1Digest);
|
|
bInit_ := false;
|
|
Result := true;
|
|
end;
|
|
end;
|
|
|
|
{ TSHA256Hash }
|
|
|
|
procedure TSHA256Hash.WorkInit;
|
|
begin
|
|
SHA256Init(ctx_);
|
|
bInit_ := true;
|
|
end;
|
|
|
|
procedure TSHA256Hash.SetBuffer(buf: Pointer; nCount: Integer);
|
|
begin
|
|
if bInit_ then
|
|
SHA256Update(ctx_, buf, nCount);
|
|
end;
|
|
|
|
function TSHA256Hash.WorkFinalToStr: String;
|
|
var
|
|
sd : TSHA256Digest;
|
|
begin
|
|
Result := '';
|
|
if bInit_ then
|
|
begin
|
|
SHA256Final(ctx_, sd);
|
|
Result := ConvBytesToHexStr(PByte(@sd), SizeOf(sd));
|
|
bInit_ := false;
|
|
end;
|
|
end;
|
|
|
|
function TSHA256Hash.WorkFinalToDigest(var SHA256Digest: TSHA256Digest): Boolean;
|
|
begin
|
|
Result := false;
|
|
ZeroMemory(@SHA256Digest, SizeOf(SHA256Digest));
|
|
if bInit_ then
|
|
begin
|
|
SHA256Final(ctx_, SHA256Digest);
|
|
bInit_ := false;
|
|
Result := true;
|
|
end;
|
|
end;
|
|
|
|
{ TMD5Hash }
|
|
|
|
procedure TMD5Hash.SetBuffer(buf: Pointer; nCount: Integer);
|
|
begin
|
|
if bInit_ then
|
|
MD5Update(ctx_, buf, nCount);
|
|
end;
|
|
|
|
function TMD5Hash.WorkFinalToStr: String;
|
|
var
|
|
sd : EM.MD5.TMD5Digest;
|
|
begin
|
|
Result := '';
|
|
if bInit_ then
|
|
begin
|
|
MD5Final(ctx_, sd);
|
|
Result := ConvBytesToHexStr(PByte(@sd), SizeOf(sd));
|
|
bInit_ := false;
|
|
end;
|
|
end;
|
|
|
|
procedure TMD5Hash.WorkInit;
|
|
begin
|
|
MD5Init(ctx_);
|
|
bInit_ := true;
|
|
end;
|
|
|
|
// By .. https://helloacm.com/simple-and-fast-hash-functions-in-delphi/
|
|
|
|
// HASH_DJB2
|
|
function Hash_djb2(aData: Pointer; aDataLength: Integer): NativeUInt;
|
|
var
|
|
i: integer;
|
|
begin
|
|
Result := 5381;
|
|
for i := 1 to aDataLength do
|
|
begin
|
|
Result := ((Result shl 5) + Result) + PByte(aData)^;
|
|
aData := Pointer(NativeUInt(aData) + 1);
|
|
end;
|
|
end;
|
|
|
|
// HASH_DJB2A
|
|
// A Slight variation of Hash_djb2
|
|
function Hash_djb2a(aData: Pointer; aDataLength: Integer): NativeUInt;
|
|
var
|
|
i: integer;
|
|
begin
|
|
Result := 5381;
|
|
for i := 1 to aDataLength do
|
|
begin
|
|
Result := ((Result shl 5) xor Result) xor PByte(aData)^;
|
|
aData := Pointer(NativeUInt(aData) + 1);
|
|
end;
|
|
end;
|
|
|
|
// HASH_FNV
|
|
function Hash_fnv(aData: Pointer; aDataLength: Integer): NativeUInt;
|
|
var
|
|
i: integer;
|
|
begin
|
|
Result := 2166136261;
|
|
for i := 1 to aDataLength do
|
|
begin
|
|
Result := (Result * 16777619) xor PByte(aData)^;
|
|
aData := Pointer(NativeUInt(aData) + 1);
|
|
end;
|
|
end;
|
|
|
|
// HASH_FNV1A
|
|
// Slight variation of Hash_fnv.
|
|
function Hash_fnv1a(aData: Pointer; aDataLength: Integer): NativeUInt;
|
|
var
|
|
i: integer;
|
|
begin
|
|
Result := 2166136261;
|
|
for i := 1 to aDataLength do
|
|
begin
|
|
Result := (Result xor PByte(aData)^) * 16777619;
|
|
aData := Pointer(NativeUInt(aData) + 1);
|
|
end;
|
|
end;
|
|
|
|
// HASH_SDBM
|
|
function Hash_sdbm(aData: Pointer; aDataLength: Integer): NativeUInt;
|
|
var
|
|
i: integer;
|
|
begin
|
|
Result := 0;
|
|
for i := 1 to aDataLength do
|
|
begin
|
|
Result := PByte(aData)^ + (Result shl 6) + (Result shl 16) - Result;
|
|
aData := Pointer(NativeUInt(aData) + 1);
|
|
end;
|
|
end;
|
|
|
|
// HASH_JENKIS
|
|
function Hash_jenkis(aData: Pointer; aDataLength: Integer): NativeUInt;
|
|
var
|
|
i: integer;
|
|
begin
|
|
Result := 0;
|
|
for i := 1 to aDataLength do
|
|
begin
|
|
Inc(Result, PByte(aData)^);
|
|
Inc(Result, Result shl 10);
|
|
Result := Result xor (Result shr 6);
|
|
aData := Pointer(NativeUInt(aData) + 1);
|
|
end;
|
|
Inc(Result, Result shl 3);
|
|
Result := Result xor (Result shr 11);
|
|
Inc(Result, Result shl 15);
|
|
end;
|
|
|
|
function StrToHash_FNV1A(sSrc: String): NativeUInt;
|
|
var
|
|
nLen: Integer;
|
|
begin
|
|
nLen := Length(sSrc);
|
|
if nLen = 0 then
|
|
begin
|
|
Result := 0;
|
|
exit;
|
|
end;
|
|
|
|
Result := Hash_fnv1a(@sSrc[1], nLen);
|
|
end;
|
|
|
|
end.
|