You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4677 lines
166 KiB
Plaintext
4677 lines
166 KiB
Plaintext
{******************************************************************************}
|
|
{ }
|
|
{ Library: Fundamentals 4.00 }
|
|
{ File name: cHash.pas }
|
|
{ File version: 4.18 }
|
|
{ Description: Hashing functions }
|
|
{ }
|
|
{ Copyright: Copyright (c) 1999-2013, David J Butler }
|
|
{ All rights reserved. }
|
|
{ Redistribution and use in source and binary forms, with }
|
|
{ or without modification, are permitted provided that }
|
|
{ the following conditions are met: }
|
|
{ Redistributions of source code must retain the above }
|
|
{ copyright notice, this list of conditions and the }
|
|
{ following disclaimer. }
|
|
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
|
|
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
|
|
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
|
|
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
|
|
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
|
|
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
|
|
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
|
|
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
|
|
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
|
|
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
|
|
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
|
|
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
|
|
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
|
|
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
|
|
{ POSSIBILITY OF SUCH DAMAGE. }
|
|
{ }
|
|
{ Github: https://github.com/fundamentalslib }
|
|
{ E-mail: fundamentalslib at gmail.com }
|
|
{ }
|
|
{ Revision history: }
|
|
{ }
|
|
{ 2002/04/02 0.01 Initial version from cUtils unit. }
|
|
{ Hash: Checksum, XOR, CRC, MD5, SHA1, SHA256, SNS }
|
|
{ Keyed hash: HMAC-MD5, HMAC-SHA1 }
|
|
{ 2002/04/03 0.02 Securely clear passwords from memory after use. }
|
|
{ 2002/04/05 0.03 Added SNS hashing. }
|
|
{ 2002/04/19 0.04 Added ISBN checksum. }
|
|
{ 2003/07/26 0.05 Added ELF hashing. }
|
|
{ 2003/09/08 3.06 Revised for Fundamentals 3. }
|
|
{ 2005/07/22 4.07 Compilable with FreePascal 2.0 Win32 i386. }
|
|
{ 2005/08/27 4.08 Revised for Fundamentals 4. }
|
|
{ 2008/04/28 4.09 Added Adler hashing. }
|
|
{ 2008/12/30 4.10 Revision. }
|
|
{ 2010/06/27 4.11 Compilable with FreePascal 2.4.0 OSX x86-64 }
|
|
{ 2010/11/14 4.12 Added SHA256. }
|
|
{ 2010/11/15 4.13 Added HMAC-SHA256. }
|
|
{ 2010/11/16 4.14 Added SHA512. }
|
|
{ 2010/11/17 4.15 Added HMAC-SHA512, SHA224, SHA384. }
|
|
{ 2011/04/02 4.16 Compilable with Delphi 5. }
|
|
{ 2011/10/14 4.17 Compilable with Delphi XE. }
|
|
{ 2013/01/27 4.18 Added RipeMD160 sponsored and donated by Stefan Westner. }
|
|
{ }
|
|
{ Supported compilers: }
|
|
{ }
|
|
{ Borland Delphi 5-XE Win32 i386 }
|
|
{ FreePascal 2 Win32 i386 }
|
|
{ FreePascal 2 Linux i386 }
|
|
{ }
|
|
{ Definitions: }
|
|
{ }
|
|
{ Hashes are algorithms for computing condensed representations of }
|
|
{ messages. }
|
|
{ The message is the data being condensed. }
|
|
{ The condensed representation is called the message digest. }
|
|
{ }
|
|
{ Hashes are called secure if it is computationally infeasible to }
|
|
{ find a message that produce a given digest. }
|
|
{ }
|
|
{ Keyed hashes use a key (password) in the hashing process. }
|
|
{ }
|
|
{ Hash algorithms: }
|
|
{ }
|
|
{ Algorithm Digest size (bits) Uses }
|
|
{ ------------ ------------------ ------------------------------ }
|
|
{ Checksum 32 General }
|
|
{ XOR8 8 General }
|
|
{ XOR16 16 General }
|
|
{ XOR32 32 General }
|
|
{ CRC16 16 General / Error detection }
|
|
{ CRC32 32 General / Error detection }
|
|
{ Adler32 32 General }
|
|
{ ELF 32 General }
|
|
{ Knuth 32 General }
|
|
{ MD5 128 Secure hash }
|
|
{ SHA1 160 Secure hash }
|
|
{ SHA256 256 Secure hash }
|
|
{ SHA512 512 Secure hash }
|
|
{ RipeMD160 160 Secure hash }
|
|
{ HMAC/MD5 128 Secure keyed hash }
|
|
{ HMAC/SHA1 160 Secure keyed hash }
|
|
{ HMAC/SHA256 256 Secure keyed hash }
|
|
{ HMAC/SHA512 512 Secure keyed hash }
|
|
{ }
|
|
{ Other: }
|
|
{ }
|
|
{ Algorithm Type }
|
|
{ ------------ -------------------------------------------------- }
|
|
{ ISBN Check-digit for International Standard Book Number }
|
|
{ LUHN Check-digit for credit card numbers }
|
|
{ }
|
|
{******************************************************************************}
|
|
|
|
unit cHash;
|
|
{$I forRnQConfig.inc}
|
|
{$I NoRTTI.inc}
|
|
|
|
{$IFDEF FREEPASCAL}
|
|
{$WARNINGS OFF}{$HINTS OFF}
|
|
{$Q-,R-} // bug in fpc 2.4.0rc1
|
|
{$ENDIF}
|
|
|
|
{$IFDEF DEBUG}
|
|
{$IFDEF SELFTEST}
|
|
{$DEFINE HASH_SELFTEST}
|
|
{$ENDIF}
|
|
{$ENDIF}
|
|
|
|
interface
|
|
|
|
uses
|
|
{ System }
|
|
SysUtils;
|
|
|
|
{ }
|
|
{ Hash digests }
|
|
{ }
|
|
type
|
|
PByte = ^Byte;
|
|
PWord = ^Word;
|
|
PLongWord = ^LongWord;
|
|
Word64 = packed record
|
|
case Integer of
|
|
0 : (Bytes : array[0..7] of Byte);
|
|
1 : (Words : array[0..3] of Word);
|
|
2 : (LongWords : array[0..1] of LongWord);
|
|
end;
|
|
PWord64 = ^Word64;
|
|
T128BitDigest = record
|
|
case integer of
|
|
0 : (Int64s : array[0..1] of Int64);
|
|
1 : (Longs : array[0..3] of LongWord);
|
|
2 : (Words : array[0..7] of Word);
|
|
3 : (Bytes : array[0..15] of Byte);
|
|
end;
|
|
P128BitDigest = ^T128BitDigest;
|
|
T160BitDigest = record
|
|
case integer of
|
|
0 : (Longs : array[0..4] of LongWord);
|
|
1 : (Words : array[0..9] of Word);
|
|
2 : (Bytes : array[0..19] of Byte);
|
|
end;
|
|
P160BitDigest = ^T160BitDigest;
|
|
T224BitDigest = record
|
|
case integer of
|
|
0 : (Longs : array[0..6] of LongWord);
|
|
1 : (Words : array[0..13] of Word);
|
|
2 : (Bytes : array[0..27] of Byte);
|
|
end;
|
|
P224BitDigest = ^T224BitDigest;
|
|
T256BitDigest = record
|
|
case integer of
|
|
0 : (Longs : array[0..7] of LongWord);
|
|
1 : (Words : array[0..15] of Word);
|
|
2 : (Bytes : array[0..31] of Byte);
|
|
end;
|
|
P256BitDigest = ^T256BitDigest;
|
|
T384BitDigest = record
|
|
case integer of
|
|
0 : (Word64s : array[0..5] of Word64);
|
|
1 : (Longs : array[0..11] of LongWord);
|
|
2 : (Words : array[0..23] of Word);
|
|
3 : (Bytes : array[0..47] of Byte);
|
|
end;
|
|
P384BitDigest = ^T384BitDigest;
|
|
T512BitDigest = record
|
|
case integer of
|
|
0 : (Word64s : array[0..7] of Word64);
|
|
1 : (Longs : array[0..15] of LongWord);
|
|
2 : (Words : array[0..31] of Word);
|
|
3 : (Bytes : array[0..63] of Byte);
|
|
end;
|
|
P512BitDigest = ^T512BitDigest;
|
|
T512BitBuf = array[0..63] of Byte;
|
|
T1024BitBuf = array[0..127] of Byte;
|
|
|
|
const
|
|
MaxHashDigestSize = Sizeof(T160BitDigest);
|
|
|
|
procedure DigestToHexBufA(const Digest; const Size: Integer; const Buf);
|
|
procedure DigestToHexBufW(const Digest; const Size: Integer; const Buf);
|
|
function DigestToHexA(const Digest; const Size: Integer): RawByteString;
|
|
function DigestToHexW(const Digest; const Size: Integer): WideString;
|
|
function Digest128Equal(const Digest1, Digest2: T128BitDigest): Boolean;
|
|
function Digest160Equal(const Digest1, Digest2: T160BitDigest): Boolean;
|
|
function Digest224Equal(const Digest1, Digest2: T224BitDigest): Boolean;
|
|
function Digest256Equal(const Digest1, Digest2: T256BitDigest): Boolean;
|
|
function Digest384Equal(const Digest1, Digest2: T384BitDigest): Boolean;
|
|
function Digest512Equal(const Digest1, Digest2: T512BitDigest): Boolean;
|
|
|
|
procedure Digest512XOR8(var Digest: T512BitDigest; const A: Byte);
|
|
procedure Digest512XOR32(var Digest: T512BitDigest; const A: LongWord);
|
|
|
|
|
|
|
|
{ }
|
|
{ Hash errors }
|
|
{ }
|
|
const
|
|
hashNoError = 0;
|
|
hashInternalError = 1;
|
|
hashInvalidHashType = 2;
|
|
hashInvalidBuffer = 3;
|
|
hashInvalidBufferSize = 4;
|
|
hashInvalidDigest = 5;
|
|
hashInvalidKey = 6;
|
|
hashInvalidFileName = 7;
|
|
hashFileOpenError = 8;
|
|
hashFileSeekError = 9;
|
|
hashFileReadError = 10;
|
|
hashNotKeyedHashType = 11;
|
|
hashTooManyOpenHandles = 12;
|
|
hashInvalidHandle = 13;
|
|
hashMAX_ERROR = 13;
|
|
|
|
function GetHashErrorMessage(const ErrorCode: LongWord): PChar;
|
|
|
|
type
|
|
EHashError = class(Exception)
|
|
protected
|
|
FErrorCode : LongWord;
|
|
|
|
public
|
|
constructor Create(const ErrorCode: LongWord; const Msg: String = '');
|
|
property ErrorCode: LongWord read FErrorCode;
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ Secure memory clear }
|
|
{ Used to clear keys and other sensitive data from memory }
|
|
{ }
|
|
procedure SecureClear(var Buf; const BufSize: Integer);
|
|
procedure SecureClear512(var Buf: T512BitBuf);
|
|
procedure SecureClear1024(var Buf: T1024BitBuf);
|
|
procedure SecureClearStr(var S: String);
|
|
procedure SecureClearStrA(var S: RawByteString);
|
|
procedure SecureClearStrW(var S: WideString);
|
|
|
|
|
|
|
|
{ }
|
|
{ Checksum hashing }
|
|
{ }
|
|
function CalcChecksum32(const Buf; const BufSize: Integer): LongWord; overload;
|
|
function CalcChecksum32(const Buf: RawByteString): LongWord; overload;
|
|
|
|
|
|
|
|
{ }
|
|
{ XOR hashing }
|
|
{ }
|
|
function CalcXOR8(const Buf; const BufSize: Integer): Byte; overload;
|
|
function CalcXOR8(const Buf: RawByteString): Byte; overload;
|
|
|
|
function CalcXOR16(const Buf; const BufSize: Integer): Word; overload;
|
|
function CalcXOR16(const Buf: RawByteString): Word; overload;
|
|
|
|
function CalcXOR32(const Buf; const BufSize: Integer): LongWord; overload;
|
|
function CalcXOR32(const Buf: RawByteString): LongWord; overload;
|
|
|
|
|
|
|
|
{ }
|
|
{ CRC 16 hashing }
|
|
{ }
|
|
{ The theory behind CCITT V.41 CRCs: }
|
|
{ }
|
|
{ 1. Select the magnitude of the CRC to be used (typically 16 or 32 }
|
|
{ bits) and choose the polynomial to use. In the case of 16 bit }
|
|
{ CRCs, the CCITT polynomial is recommended and is }
|
|
{ }
|
|
{ 16 12 5 }
|
|
{ G(x) = x + x + x + 1 }
|
|
{ }
|
|
{ This polynomial traps 100% of 1 bit, 2 bit, odd numbers of bit }
|
|
{ errors, 100% of <= 16 bit burst errors and over 99% of all }
|
|
{ other errors. }
|
|
{ }
|
|
{ 2. The CRC is calculated as }
|
|
{ r }
|
|
{ D(x) = (M(x) * 2 ) mod G(x) }
|
|
{ }
|
|
{ This may be better described as : Add r bits (0 content) to }
|
|
{ the end of M(x). Divide this by G(x) and the remainder is the }
|
|
{ CRC. }
|
|
{ }
|
|
{ 3. Tag the CRC onto the end of M(x). }
|
|
{ }
|
|
{ 4. To check it, calculate the CRC of the new message D(x), using }
|
|
{ the same process as in 2. above. The newly calculated CRC }
|
|
{ should be zero. }
|
|
{ }
|
|
{ This effectively means that using CRCs, it is possible to calculate a }
|
|
{ series of bits to tag onto the data which makes the data an exact }
|
|
{ multiple of the polynomial. }
|
|
{ }
|
|
procedure CRC16Init(var CRC16: Word);
|
|
function CRC16Byte(const CRC16: Word; const Octet: Byte): Word;
|
|
function CRC16Buf(const CRC16: Word; const Buf; const BufSize: Integer): Word;
|
|
|
|
function CalcCRC16(const Buf; const BufSize: Integer): Word; overload;
|
|
function CalcCRC16(const Buf: RawByteString): Word; overload;
|
|
|
|
|
|
|
|
{ }
|
|
{ CRC 32 hashing }
|
|
{ }
|
|
procedure SetCRC32Poly(const Poly: LongWord);
|
|
|
|
procedure CRC32Init(var CRC32: LongWord);
|
|
function CRC32Byte(const CRC32: LongWord; const Octet: Byte): LongWord;
|
|
function CRC32Buf(const CRC32: LongWord; const Buf; const BufSize: Integer): LongWord;
|
|
function CRC32BufNoCase(const CRC32: LongWord; const Buf; const BufSize: Integer): LongWord;
|
|
|
|
function CalcCRC32(const Buf; const BufSize: Integer): LongWord; overload;
|
|
function CalcCRC32(const Buf: RawByteString): LongWord; overload;
|
|
|
|
|
|
|
|
{ }
|
|
{ Adler 32 hashing }
|
|
{ }
|
|
procedure Adler32Init(var Adler32: LongWord);
|
|
function Adler32Byte(const Adler32: LongWord; const Octet: Byte): LongWord;
|
|
function Adler32Buf(const Adler32: LongWord; const Buf; const BufSize: Integer): LongWord;
|
|
|
|
function CalcAdler32(const Buf; const BufSize: Integer): LongWord; overload;
|
|
function CalcAdler32(const Buf: RawByteString): LongWord; overload;
|
|
|
|
|
|
|
|
{ }
|
|
{ ELF hashing }
|
|
{ }
|
|
procedure ELFInit(var Digest: LongWord);
|
|
function ELFBuf(const Digest: LongWord; const Buf; const BufSize: Integer): LongWord;
|
|
|
|
function CalcELF(const Buf; const BufSize: Integer): LongWord; overload;
|
|
function CalcELF(const Buf: RawByteString): LongWord; overload;
|
|
|
|
|
|
|
|
{ }
|
|
{ ISBN checksum }
|
|
{ }
|
|
function IsValidISBN(const S: RawByteString): Boolean;
|
|
|
|
|
|
|
|
{ }
|
|
{ LUHN checksum }
|
|
{ }
|
|
{ The LUHN forumula (also known as mod-10) is used in major credit card }
|
|
{ account numbers for validity checking. }
|
|
{ }
|
|
function IsValidLUHN(const S: RawByteString): Boolean;
|
|
|
|
|
|
|
|
{ }
|
|
{ Knuth hash }
|
|
{ General purpose string hashing function proposed by Donald E Knuth in }
|
|
{ 'The Art of Computer Programming Vol 3'. }
|
|
{ }
|
|
function KnuthHashA(const S: RawByteString): LongWord;
|
|
function KnuthHashW(const S: WideString): LongWord;
|
|
|
|
|
|
|
|
{ }
|
|
{ MD5 hash }
|
|
{ }
|
|
{ MD5 is an Internet standard secure hashing function, that was }
|
|
{ developed by Professor Ronald L. Rivest in 1991. Subsequently it has }
|
|
{ been placed in the public domain. }
|
|
{ MD5 was developed to be more secure after MD4 was 'broken'. }
|
|
{ Den Boer and Bosselaers estimate that if a custom machine were to be }
|
|
{ built specifically to find collisions for MD5 (costing $10m in 1994) it }
|
|
{ would on average take 24 days to find a collision. }
|
|
{ }
|
|
procedure MD5InitDigest(var Digest: T128BitDigest);
|
|
procedure MD5Buf(var Digest: T128BitDigest; const Buf; const BufSize: Integer);
|
|
procedure MD5FinalBuf(var Digest: T128BitDigest; const Buf; const BufSize: Integer;
|
|
const TotalSize: Int64);
|
|
|
|
function CalcMD5(const Buf; const BufSize: Integer): T128BitDigest; overload;
|
|
function CalcMD5(const Buf: RawByteString): T128BitDigest; overload;
|
|
|
|
function MD5DigestToStrA(const Digest: T128BitDigest): RawByteString;
|
|
function MD5DigestToHexA(const Digest: T128BitDigest): RawByteString;
|
|
function MD5DigestToHexW(const Digest: T128BitDigest): WideString;
|
|
|
|
|
|
|
|
{ }
|
|
{ SHA1 Hashing }
|
|
{ }
|
|
{ Specification at http://www.itl.nist.gov/fipspubs/fip180-1.htm }
|
|
{ Also see RFC 3174. }
|
|
{ SHA1 was developed by NIST and is specified in the Secure Hash Standard }
|
|
{ (SHS, FIPS 180) and corrects an unpublished flaw the original SHA }
|
|
{ algorithm. }
|
|
{ SHA1 produces a 160-bit digest and is considered more secure than MD5. }
|
|
{ SHA1 has a similar design to the MD4-family of hash functions. }
|
|
{ }
|
|
procedure SHA1InitDigest(var Digest: T160BitDigest);
|
|
procedure SHA1Buf(var Digest: T160BitDigest; const Buf; const BufSize: Integer);
|
|
procedure SHA1FinalBuf(var Digest: T160BitDigest; const Buf; const BufSize: Integer;
|
|
const TotalSize: Int64);
|
|
|
|
function CalcSHA1(const Buf; const BufSize: Integer): T160BitDigest; overload;
|
|
function CalcSHA1(const Buf: RawByteString): T160BitDigest; overload;
|
|
|
|
function SHA1DigestToStrA(const Digest: T160BitDigest): RawByteString;
|
|
function SHA1DigestToHexA(const Digest: T160BitDigest): RawByteString;
|
|
function SHA1DigestToHexW(const Digest: T160BitDigest): WideString;
|
|
|
|
|
|
|
|
{ }
|
|
{ SHA224 Hashing }
|
|
{ }
|
|
{ 224 bit SHA-2 hash }
|
|
{ http://en.wikipedia.org/wiki/SHA-2 }
|
|
{ SHA-224 is based on SHA-256 }
|
|
{ }
|
|
procedure SHA224InitDigest(var Digest: T256BitDigest);
|
|
procedure SHA224Buf(var Digest: T256BitDigest; const Buf; const BufSize: Integer);
|
|
procedure SHA224FinalBuf(var Digest: T256BitDigest; const Buf; const BufSize: Integer; const TotalSize: Int64;
|
|
var OutDigest: T224BitDigest);
|
|
|
|
function CalcSHA224(const Buf; const BufSize: Integer): T224BitDigest; overload;
|
|
function CalcSHA224(const Buf: RawByteString): T224BitDigest; overload;
|
|
|
|
function SHA224DigestToStrA(const Digest: T224BitDigest): RawByteString;
|
|
function SHA224DigestToHexA(const Digest: T224BitDigest): RawByteString;
|
|
function SHA224DigestToHexW(const Digest: T224BitDigest): WideString;
|
|
|
|
|
|
|
|
{ }
|
|
{ SHA256 Hashing }
|
|
{ 256 bit SHA-2 hash }
|
|
{ }
|
|
procedure SHA256InitDigest(var Digest: T256BitDigest);
|
|
procedure SHA256Buf(var Digest: T256BitDigest; const Buf; const BufSize: Integer);
|
|
procedure SHA256FinalBuf(var Digest: T256BitDigest; const Buf; const BufSize: Integer; const TotalSize: Int64);
|
|
|
|
function CalcSHA256(const Buf; const BufSize: Integer): T256BitDigest; overload;
|
|
function CalcSHA256(const Buf: RawByteString): T256BitDigest; overload;
|
|
|
|
function SHA256DigestToStrA(const Digest: T256BitDigest): RawByteString;
|
|
function SHA256DigestToHexA(const Digest: T256BitDigest): RawByteString;
|
|
function SHA256DigestToHexW(const Digest: T256BitDigest): WideString;
|
|
|
|
|
|
|
|
{ }
|
|
{ SHA384 Hashing }
|
|
{ 384 bit SHA-2 hash }
|
|
{ SHA-384 is based on SHA-512 }
|
|
{ }
|
|
procedure SHA384InitDigest(var Digest: T512BitDigest);
|
|
procedure SHA384Buf(var Digest: T512BitDigest; const Buf; const BufSize: Integer);
|
|
procedure SHA384FinalBuf(var Digest: T512BitDigest; const Buf; const BufSize: Integer; const TotalSize: Int64; var OutDigest: T384BitDigest);
|
|
|
|
function CalcSHA384(const Buf; const BufSize: Integer): T384BitDigest; overload;
|
|
function CalcSHA384(const Buf: RawByteString): T384BitDigest; overload;
|
|
|
|
function SHA384DigestToStrA(const Digest: T384BitDigest): RawByteString;
|
|
function SHA384DigestToHexA(const Digest: T384BitDigest): RawByteString;
|
|
function SHA384DigestToHexW(const Digest: T384BitDigest): WideString;
|
|
|
|
|
|
|
|
{ }
|
|
{ SHA512 Hashing }
|
|
{ 512 bit SHA-2 hash }
|
|
{ }
|
|
procedure SHA512InitDigest(var Digest: T512BitDigest);
|
|
procedure SHA512Buf(var Digest: T512BitDigest; const Buf; const BufSize: Integer);
|
|
procedure SHA512FinalBuf(var Digest: T512BitDigest; const Buf; const BufSize: Integer; const TotalSize: Int64);
|
|
|
|
function CalcSHA512(const Buf; const BufSize: Integer): T512BitDigest; overload;
|
|
function CalcSHA512(const Buf: RawByteString): T512BitDigest; overload;
|
|
|
|
function SHA512DigestToStrA(const Digest: T512BitDigest): RawByteString;
|
|
function SHA512DigestToHexA(const Digest: T512BitDigest): RawByteString;
|
|
function SHA512DigestToHexW(const Digest: T512BitDigest): WideString;
|
|
|
|
|
|
|
|
{ }
|
|
{ RIPEMD160 }
|
|
{ }
|
|
{ RIPEMD-160 is a 160-bit cryptographic hash function, designed by }
|
|
{ Hans Dobbertin, Antoon Bosselaers, and Bart Preneel. It is intended to }
|
|
{ be used as a secure replacement for the 128-bit hash functions MD4, MD5, }
|
|
{ and RIPEMD. }
|
|
{ The authors of RIPEMD-160 and RIPEMD-128 do not hold any patents on the }
|
|
{ algorithms (nor on the optional extensions), and are also not aware of }
|
|
{ any patents on these algorithms. }
|
|
{ }
|
|
procedure RipeMD160InitDigest(var Digest: T160BitDigest);
|
|
procedure RipeMD160Buf(var Digest: T160BitDigest; const Buf; const BufSize: Integer);
|
|
procedure RipeMD160FinalBuf(var Digest: T160BitDigest; const Buf; const BufSize: Integer; const TotalSize: Int64);
|
|
|
|
function CalcRipeMD160(const Buf; const BufSize: Integer): T160BitDigest; overload;
|
|
function CalcRipeMD160(const Buf: RawByteString): T160BitDigest; overload;
|
|
|
|
function RipeMD160DigestToStrA(const Digest: T160BitDigest): RawByteString;
|
|
function RipeMD160DigestToHexA(const Digest: T160BitDigest): RawByteString;
|
|
function RipeMD160DigestToHexW(const Digest: T160BitDigest): WideString;
|
|
|
|
|
|
|
|
{ }
|
|
{ HMAC-MD5 keyed hashing }
|
|
{ }
|
|
{ HMAC allows secure keyed hashing (hashing with a password). }
|
|
{ HMAC was designed to meet the requirements of the IPSEC working group in }
|
|
{ the IETF, and is now a standard. }
|
|
{ HMAC, are proven to be secure as long as the underlying hash function }
|
|
{ has some reasonable cryptographic strengths. }
|
|
{ See RFC 2104 for details on HMAC. }
|
|
{ }
|
|
procedure HMAC_MD5Init(const Key: Pointer; const KeySize: Integer;
|
|
var Digest: T128BitDigest; var K: T512BitBuf);
|
|
procedure HMAC_MD5Buf(var Digest: T128BitDigest; const Buf; const BufSize: Integer);
|
|
procedure HMAC_MD5FinalBuf(const K: T512BitBuf; var Digest: T128BitDigest;
|
|
const Buf; const BufSize: Integer; const TotalSize: Int64);
|
|
|
|
function CalcHMAC_MD5(const Key: Pointer; const KeySize: Integer;
|
|
const Buf; const BufSize: Integer): T128BitDigest; overload;
|
|
function CalcHMAC_MD5(const Key: RawByteString; const Buf; const BufSize: Integer): T128BitDigest; overload;
|
|
function CalcHMAC_MD5(const Key, Buf: RawByteString): T128BitDigest; overload;
|
|
|
|
|
|
|
|
{ }
|
|
{ HMAC-SHA1 keyed hashing }
|
|
{ }
|
|
procedure HMAC_SHA1Init(const Key: Pointer; const KeySize: Integer;
|
|
var Digest: T160BitDigest; var K: T512BitBuf);
|
|
procedure HMAC_SHA1Buf(var Digest: T160BitDigest; const Buf; const BufSize: Integer);
|
|
procedure HMAC_SHA1FinalBuf(const K: T512BitBuf; var Digest: T160BitDigest;
|
|
const Buf; const BufSize: Integer; const TotalSize: Int64);
|
|
|
|
function CalcHMAC_SHA1(const Key: Pointer; const KeySize: Integer;
|
|
const Buf; const BufSize: Integer): T160BitDigest; overload;
|
|
function CalcHMAC_SHA1(const Key: RawByteString; const Buf; const BufSize: Integer): T160BitDigest; overload;
|
|
function CalcHMAC_SHA1(const Key, Buf: RawByteString): T160BitDigest; overload;
|
|
|
|
|
|
|
|
{ }
|
|
{ HMAC-SHA256 keyed hashing }
|
|
{ }
|
|
procedure HMAC_SHA256Init(const Key: Pointer; const KeySize: Integer;
|
|
var Digest: T256BitDigest; var K: T512BitBuf);
|
|
procedure HMAC_SHA256Buf(var Digest: T256BitDigest; const Buf; const BufSize: Integer);
|
|
procedure HMAC_SHA256FinalBuf(const K: T512BitBuf; var Digest: T256BitDigest;
|
|
const Buf; const BufSize: Integer; const TotalSize: Int64);
|
|
|
|
function CalcHMAC_SHA256(const Key: Pointer; const KeySize: Integer;
|
|
const Buf; const BufSize: Integer): T256BitDigest; overload;
|
|
function CalcHMAC_SHA256(const Key: RawByteString; const Buf; const BufSize: Integer): T256BitDigest; overload;
|
|
function CalcHMAC_SHA256(const Key, Buf: RawByteString): T256BitDigest; overload;
|
|
|
|
|
|
|
|
{ }
|
|
{ HMAC-SHA512 keyed hashing }
|
|
{ }
|
|
procedure HMAC_SHA512Init(const Key: Pointer; const KeySize: Integer; var Digest: T512BitDigest; var K: T1024BitBuf);
|
|
procedure HMAC_SHA512Buf(var Digest: T512BitDigest; const Buf; const BufSize: Integer);
|
|
procedure HMAC_SHA512FinalBuf(const K: T1024BitBuf; var Digest: T512BitDigest; const Buf; const BufSize: Integer; const TotalSize: Int64);
|
|
|
|
function CalcHMAC_SHA512(const Key: Pointer; const KeySize: Integer;
|
|
const Buf; const BufSize: Integer): T512BitDigest; overload;
|
|
function CalcHMAC_SHA512(const Key: RawByteString; const Buf; const BufSize: Integer): T512BitDigest; overload;
|
|
function CalcHMAC_SHA512(const Key, Buf: RawByteString): T512BitDigest; overload;
|
|
|
|
|
|
|
|
{ }
|
|
{ Hash class wrappers }
|
|
{ }
|
|
type
|
|
{ AHash }
|
|
{ Base class for hash classes. }
|
|
AHash = class
|
|
protected
|
|
FDigest : Pointer;
|
|
FTotalSize : Int64;
|
|
|
|
procedure InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer); virtual; abstract;
|
|
procedure ProcessBuf(const Buf; const BufSize: Integer); virtual; abstract;
|
|
procedure ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64); virtual;
|
|
|
|
public
|
|
class function DigestSize: Integer; virtual; abstract;
|
|
class function BlockSize: Integer; virtual;
|
|
|
|
procedure Init(const Digest: Pointer; const Key: Pointer = nil;
|
|
const KeySize: Integer = 0); overload;
|
|
procedure Init(const Digest: Pointer; const Key: RawByteString = ''); overload;
|
|
|
|
procedure HashBuf(const Buf; const BufSize: Integer; const FinalBuf: Boolean);
|
|
procedure HashFile(const FileName: String; const Offset: Int64 = 0;
|
|
const MaxCount: Int64 = -1);
|
|
end;
|
|
THashClass = class of AHash;
|
|
|
|
{ TChecksum32Hash }
|
|
TChecksum32Hash = class(AHash)
|
|
protected
|
|
procedure InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer); override;
|
|
procedure ProcessBuf(const Buf; const BufSize: Integer); override;
|
|
|
|
public
|
|
class function DigestSize: Integer; override;
|
|
end;
|
|
|
|
{ TXOR8Hash }
|
|
TXOR8Hash = class(AHash)
|
|
protected
|
|
procedure InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer); override;
|
|
procedure ProcessBuf(const Buf; const BufSize: Integer); override;
|
|
|
|
public
|
|
class function DigestSize: Integer; override;
|
|
end;
|
|
|
|
{ TXOR16Hash }
|
|
TXOR16Hash = class(AHash)
|
|
protected
|
|
procedure InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer); override;
|
|
procedure ProcessBuf(const Buf; const BufSize: Integer); override;
|
|
|
|
public
|
|
class function DigestSize: Integer; override;
|
|
end;
|
|
|
|
{ TXOR32Hash }
|
|
TXOR32Hash = class(AHash)
|
|
protected
|
|
procedure InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer); override;
|
|
procedure ProcessBuf(const Buf; const BufSize: Integer); override;
|
|
|
|
public
|
|
class function DigestSize: Integer; override;
|
|
end;
|
|
|
|
{ TCRC16Hash }
|
|
TCRC16Hash = class(AHash)
|
|
protected
|
|
procedure InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer); override;
|
|
procedure ProcessBuf(const Buf; const BufSize: Integer); override;
|
|
|
|
public
|
|
class function DigestSize: Integer; override;
|
|
end;
|
|
|
|
{ TCRC32Hash }
|
|
TCRC32Hash = class(AHash)
|
|
protected
|
|
procedure InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer); override;
|
|
procedure ProcessBuf(const Buf; const BufSize: Integer); override;
|
|
|
|
public
|
|
class function DigestSize: Integer; override;
|
|
end;
|
|
|
|
{ TAdler32Hash }
|
|
TAdler32Hash = class(AHash)
|
|
protected
|
|
procedure InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer); override;
|
|
procedure ProcessBuf(const Buf; const BufSize: Integer); override;
|
|
|
|
public
|
|
class function DigestSize: Integer; override;
|
|
end;
|
|
|
|
{ TELFHash }
|
|
TELFHash = class(AHash)
|
|
protected
|
|
procedure InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer); override;
|
|
procedure ProcessBuf(const Buf; const BufSize: Integer); override;
|
|
|
|
public
|
|
class function DigestSize: Integer; override;
|
|
end;
|
|
|
|
{ TMD5Hash }
|
|
TMD5Hash = class(AHash)
|
|
protected
|
|
procedure InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer); override;
|
|
procedure ProcessBuf(const Buf; const BufSize: Integer); override;
|
|
procedure ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64); override;
|
|
|
|
public
|
|
class function DigestSize: Integer; override;
|
|
class function BlockSize: Integer; override;
|
|
end;
|
|
|
|
{ TSHA1Hash }
|
|
TSHA1Hash = class(AHash)
|
|
protected
|
|
procedure InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer); override;
|
|
procedure ProcessBuf(const Buf; const BufSize: Integer); override;
|
|
procedure ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64); override;
|
|
|
|
public
|
|
class function DigestSize: Integer; override;
|
|
class function BlockSize: Integer; override;
|
|
end;
|
|
|
|
{ TSHA256Hash }
|
|
TSHA256Hash = class(AHash)
|
|
protected
|
|
procedure InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer); override;
|
|
procedure ProcessBuf(const Buf; const BufSize: Integer); override;
|
|
procedure ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64); override;
|
|
|
|
public
|
|
class function DigestSize: Integer; override;
|
|
class function BlockSize: Integer; override;
|
|
end;
|
|
|
|
{ TSHA512Hash }
|
|
TSHA512Hash = class(AHash)
|
|
protected
|
|
procedure InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer); override;
|
|
procedure ProcessBuf(const Buf; const BufSize: Integer); override;
|
|
procedure ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64); override;
|
|
|
|
public
|
|
class function DigestSize: Integer; override;
|
|
class function BlockSize: Integer; override;
|
|
end;
|
|
|
|
{ TRipeMD160Hash }
|
|
TRipeMD160Hash = class(AHash)
|
|
protected
|
|
procedure InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer); override;
|
|
procedure ProcessBuf(const Buf; const BufSize: Integer); override;
|
|
procedure ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64); override;
|
|
|
|
public
|
|
class function DigestSize: Integer; override;
|
|
class function BlockSize: Integer; override;
|
|
end;
|
|
|
|
{ THMAC_MD5Hash }
|
|
THMAC_MD5Hash = class(AHash)
|
|
protected
|
|
FKey : T512BitBuf;
|
|
|
|
procedure InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer); override;
|
|
procedure ProcessBuf(const Buf; const BufSize: Integer); override;
|
|
procedure ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64); override;
|
|
|
|
public
|
|
class function DigestSize: Integer; override;
|
|
class function BlockSize: Integer; override;
|
|
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
{ THMAC_SHA1Hash }
|
|
THMAC_SHA1Hash = class(AHash)
|
|
protected
|
|
FKey : T512BitBuf;
|
|
|
|
procedure InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer); override;
|
|
procedure ProcessBuf(const Buf; const BufSize: Integer); override;
|
|
procedure ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64); override;
|
|
|
|
public
|
|
class function DigestSize: Integer; override;
|
|
class function BlockSize: Integer; override;
|
|
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
{ THMAC_SHA256Hash }
|
|
THMAC_SHA256Hash = class(AHash)
|
|
protected
|
|
FKey : T512BitBuf;
|
|
|
|
procedure InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer); override;
|
|
procedure ProcessBuf(const Buf; const BufSize: Integer); override;
|
|
procedure ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64); override;
|
|
|
|
public
|
|
class function DigestSize: Integer; override;
|
|
class function BlockSize: Integer; override;
|
|
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
{ THMAC_SHA512Hash }
|
|
THMAC_SHA512Hash = class(AHash)
|
|
protected
|
|
FKey : T1024BitBuf;
|
|
|
|
procedure InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer); override;
|
|
procedure ProcessBuf(const Buf; const BufSize: Integer); override;
|
|
procedure ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64); override;
|
|
|
|
public
|
|
class function DigestSize: Integer; override;
|
|
class function BlockSize: Integer; override;
|
|
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ THashType }
|
|
{ }
|
|
type
|
|
THashType = (
|
|
hashChecksum32, hashXOR8, hashXOR16, hashXOR32,
|
|
hashCRC16, hashCRC32,
|
|
hashAdler32,
|
|
hashELF,
|
|
hashMD5, hashSHA1, hashSHA256, hashSHA512, hashRipeMD160,
|
|
hashHMAC_MD5, hashHMAC_SHA1, hashHMAC_SHA256, hashHMAC_SHA512);
|
|
|
|
|
|
|
|
{ }
|
|
{ GetHashClassByType }
|
|
{ }
|
|
function GetHashClassByType(const HashType: THashType): THashClass;
|
|
function GetDigestSize(const HashType: THashType): Integer;
|
|
|
|
|
|
|
|
{ }
|
|
{ CalculateHash }
|
|
{ }
|
|
procedure CalculateHash(const HashType: THashType;
|
|
const Buf; const BufSize: Integer; const Digest: Pointer;
|
|
const Key: Pointer = nil; const KeySize: Integer = 0); overload;
|
|
procedure CalculateHash(const HashType: THashType;
|
|
const Buf; const BufSize: Integer;
|
|
const Digest: Pointer; const Key: RawByteString = ''); overload;
|
|
procedure CalculateHash(const HashType: THashType;
|
|
const Buf: RawByteString; const Digest: Pointer;
|
|
const Key: RawByteString = ''); overload;
|
|
|
|
|
|
|
|
{ }
|
|
{ HashString }
|
|
{ }
|
|
{ HashString is a fast general purpose ASCII string hashing function. }
|
|
{ It returns a 32 bit value in the range 0 to Slots - 1. If Slots = 0 then }
|
|
{ the full 32 bit value is returned. }
|
|
{ If CaseSensitive = False then HashString will return the same hash value }
|
|
{ regardless of the case of the characters in the string. }
|
|
{ }
|
|
{ The implementation is based on CRC32. It uses up to 48 characters from }
|
|
{ the string (first 16 characters, last 16 characters and 16 characters }
|
|
{ uniformly sampled from the remaining characters) to calculate the hash }
|
|
{ value. }
|
|
{ }
|
|
function HashString(const StrBuf: Pointer; const StrLength: Integer;
|
|
const Slots: LongWord = 0; const CaseSensitive: Boolean = True): LongWord; overload;
|
|
function HashString(const S: RawByteString; const Slots: LongWord = 0;
|
|
const CaseSensitive: Boolean = True): LongWord; overload;
|
|
|
|
|
|
|
|
{ }
|
|
{ Self testing code }
|
|
{ }
|
|
{$IFDEF HASH_SELFTEST}
|
|
procedure SelfTest;
|
|
{$ENDIF}
|
|
|
|
|
|
|
|
implementation
|
|
|
|
uses
|
|
Windows
|
|
{$IFDEF UNIX}
|
|
{$IFDEF FREEPASCAL}
|
|
BaseUnix,
|
|
Unix
|
|
{$ELSE}
|
|
libc,
|
|
BaseUnix
|
|
{$ENDIF}
|
|
{$ENDIF};
|
|
{ }
|
|
{ Hash errors }
|
|
{ }
|
|
const
|
|
hashErrorMessages : array[0..hashMAX_ERROR] of String = (
|
|
'',
|
|
'Internal error',
|
|
'Invalid hash type',
|
|
'Invalid buffer',
|
|
'Invalid buffer size',
|
|
'Invalid digest',
|
|
'Invalid key',
|
|
'Invalid file name',
|
|
'File open error',
|
|
'File seek error',
|
|
'File read error',
|
|
'Not a keyed hash type',
|
|
'Too many open handles',
|
|
'Invalid handle');
|
|
|
|
function GetHashErrorMessage(const ErrorCode: LongWord): PChar;
|
|
begin
|
|
if (ErrorCode = hashNoError) or (ErrorCode > hashMAX_ERROR) then
|
|
Result := nil
|
|
else
|
|
Result := PChar(hashErrorMessages[ErrorCode]);
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ EHashError }
|
|
{ }
|
|
constructor EHashError.Create(const ErrorCode: LongWord; const Msg: String);
|
|
begin
|
|
FErrorCode := ErrorCode;
|
|
if (Msg = '') and (ErrorCode <= hashMAX_ERROR) then
|
|
inherited Create(hashErrorMessages[ErrorCode])
|
|
else
|
|
inherited Create(Msg);
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ Secure memory clear }
|
|
{ }
|
|
procedure SecureClear(var Buf; const BufSize: Integer);
|
|
begin
|
|
if BufSize <= 0 then
|
|
exit;
|
|
FillChar(Buf, BufSize, #$00);
|
|
end;
|
|
|
|
procedure SecureClear512(var Buf: T512BitBuf);
|
|
begin
|
|
SecureClear(Buf, SizeOf(Buf));
|
|
end;
|
|
|
|
procedure SecureClear1024(var Buf: T1024BitBuf);
|
|
begin
|
|
SecureClear(Buf, SizeOf(Buf));
|
|
end;
|
|
|
|
procedure SecureClearStr(var S: String);
|
|
var L : Integer;
|
|
begin
|
|
L := Length(S);
|
|
if L = 0 then
|
|
exit;
|
|
SecureClear(S[1], L * SizeOf(Char));
|
|
S := '';
|
|
end;
|
|
|
|
procedure SecureClearStrA(var S: RawByteString);
|
|
var L : Integer;
|
|
begin
|
|
L := Length(S);
|
|
if L = 0 then
|
|
exit;
|
|
SecureClear(S[1], L);
|
|
S := '';
|
|
end;
|
|
|
|
procedure SecureClearStrW(var S: WideString);
|
|
var L : Integer;
|
|
begin
|
|
L := Length(S);
|
|
if L = 0 then
|
|
exit;
|
|
SecureClear(S[1], L * SizeOf(WideChar));
|
|
S := '';
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ Checksum hashing }
|
|
{ }
|
|
{$IFDEF ASM386_DELPHI}
|
|
function CalcChecksum32(const Buf; const BufSize: Integer): LongWord;
|
|
asm
|
|
or eax, eax // eax = Buf
|
|
jz @fin
|
|
or edx, edx // edx = BufSize
|
|
jbe @finz
|
|
push esi
|
|
mov esi, eax
|
|
add esi, edx
|
|
xor eax, eax
|
|
xor ecx, ecx
|
|
@l1:
|
|
dec esi
|
|
mov cl, [esi]
|
|
add eax, ecx
|
|
dec edx
|
|
jnz @l1
|
|
pop esi
|
|
@fin:
|
|
ret
|
|
@finz:
|
|
xor eax, eax
|
|
end;
|
|
{$ELSE}
|
|
function CalcChecksum32(const Buf; const BufSize: Integer): LongWord;
|
|
var I : Integer;
|
|
P : PByte;
|
|
begin
|
|
Result := 0;
|
|
P := @Buf;
|
|
for I := 1 to BufSize do
|
|
begin
|
|
Inc(Result, P^);
|
|
Inc(P);
|
|
end;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
function CalcChecksum32(const Buf: RawByteString): LongWord;
|
|
begin
|
|
Result := CalcChecksum32(Pointer(Buf)^, Length(Buf));
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ XOR hashing }
|
|
{ }
|
|
{$IFDEF ASM386_DELPHI}
|
|
function XOR32Buf(const Buf; const BufSize: Integer): LongWord;
|
|
Asm
|
|
or eax, eax
|
|
jz @fin
|
|
or edx, edx
|
|
jz @finz
|
|
|
|
push esi
|
|
mov esi, eax
|
|
xor eax, eax
|
|
|
|
mov ecx, edx
|
|
shr ecx, 2
|
|
jz @rest
|
|
|
|
@l1:
|
|
xor eax, [esi]
|
|
add esi, 4
|
|
dec ecx
|
|
jnz @l1
|
|
|
|
@rest:
|
|
and edx, 3
|
|
jz @finp
|
|
xor al, [esi]
|
|
dec edx
|
|
jz @finp
|
|
inc esi
|
|
xor ah, [esi]
|
|
dec edx
|
|
jz @finp
|
|
inc esi
|
|
mov dl, [esi]
|
|
shl edx, 16
|
|
xor eax, edx
|
|
|
|
@finp:
|
|
pop esi
|
|
ret
|
|
@finz:
|
|
xor eax, eax
|
|
@fin:
|
|
ret
|
|
end;
|
|
{$ELSE}
|
|
function XOR32Buf(const Buf; const BufSize: Integer): LongWord;
|
|
var I : Integer;
|
|
L : Byte;
|
|
P : PAnsiChar;
|
|
begin
|
|
Result := 0;
|
|
L := 0;
|
|
P := @Buf;
|
|
for I := 1 to BufSize do
|
|
begin
|
|
Result := Result xor (Byte(P^) shl L);
|
|
Inc(L, 8);
|
|
if L = 32 then
|
|
L := 0;
|
|
Inc(P);
|
|
end;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
function CalcXOR8(const Buf; const BufSize: Integer): Byte;
|
|
var L : LongWord;
|
|
begin
|
|
L := XOR32Buf(Buf, BufSize);
|
|
Result := Byte(L) xor
|
|
Byte(L shr 8) xor
|
|
Byte(L shr 16) xor
|
|
Byte(L shr 24);
|
|
end;
|
|
|
|
function CalcXOR8(const Buf: RawByteString): Byte;
|
|
begin
|
|
Result := CalcXOR8(Pointer(Buf)^, Length(Buf));
|
|
end;
|
|
|
|
function CalcXOR16(const Buf; const BufSize: Integer): Word;
|
|
var L : LongWord;
|
|
begin
|
|
L := XOR32Buf(Buf, BufSize);
|
|
Result := Word(L) xor
|
|
Word(L shr 16);
|
|
end;
|
|
|
|
function CalcXOR16(const Buf: RawByteString): Word;
|
|
begin
|
|
Result := CalcXOR16(Pointer(Buf)^, Length(Buf));
|
|
end;
|
|
|
|
function CalcXOR32(const Buf; const BufSize: Integer): LongWord;
|
|
begin
|
|
Result := XOR32Buf(Buf, BufSize);
|
|
end;
|
|
|
|
function CalcXOR32(const Buf: RawByteString): LongWord;
|
|
begin
|
|
Result := XOR32Buf(Pointer(Buf)^, Length(Buf));
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ CRC 16 hashing }
|
|
{ }
|
|
const
|
|
CRC16Table : array[Byte] of Word = (
|
|
$0000, $1021, $2042, $3063, $4084, $50a5, $60c6, $70e7,
|
|
$8108, $9129, $a14a, $b16b, $c18c, $d1ad, $e1ce, $f1ef,
|
|
$1231, $0210, $3273, $2252, $52b5, $4294, $72f7, $62d6,
|
|
$9339, $8318, $b37b, $a35a, $d3bd, $c39c, $f3ff, $e3de,
|
|
$2462, $3443, $0420, $1401, $64e6, $74c7, $44a4, $5485,
|
|
$a56a, $b54b, $8528, $9509, $e5ee, $f5cf, $c5ac, $d58d,
|
|
$3653, $2672, $1611, $0630, $76d7, $66f6, $5695, $46b4,
|
|
$b75b, $a77a, $9719, $8738, $f7df, $e7fe, $d79d, $c7bc,
|
|
$48c4, $58e5, $6886, $78a7, $0840, $1861, $2802, $3823,
|
|
$c9cc, $d9ed, $e98e, $f9af, $8948, $9969, $a90a, $b92b,
|
|
$5af5, $4ad4, $7ab7, $6a96, $1a71, $0a50, $3a33, $2a12,
|
|
$dbfd, $cbdc, $fbbf, $eb9e, $9b79, $8b58, $bb3b, $ab1a,
|
|
$6ca6, $7c87, $4ce4, $5cc5, $2c22, $3c03, $0c60, $1c41,
|
|
$edae, $fd8f, $cdec, $ddcd, $ad2a, $bd0b, $8d68, $9d49,
|
|
$7e97, $6eb6, $5ed5, $4ef4, $3e13, $2e32, $1e51, $0e70,
|
|
$ff9f, $efbe, $dfdd, $cffc, $bf1b, $af3a, $9f59, $8f78,
|
|
$9188, $81a9, $b1ca, $a1eb, $d10c, $c12d, $f14e, $e16f,
|
|
$1080, $00a1, $30c2, $20e3, $5004, $4025, $7046, $6067,
|
|
$83b9, $9398, $a3fb, $b3da, $c33d, $d31c, $e37f, $f35e,
|
|
$02b1, $1290, $22f3, $32d2, $4235, $5214, $6277, $7256,
|
|
$b5ea, $a5cb, $95a8, $8589, $f56e, $e54f, $d52c, $c50d,
|
|
$34e2, $24c3, $14a0, $0481, $7466, $6447, $5424, $4405,
|
|
$a7db, $b7fa, $8799, $97b8, $e75f, $f77e, $c71d, $d73c,
|
|
$26d3, $36f2, $0691, $16b0, $6657, $7676, $4615, $5634,
|
|
$d94c, $c96d, $f90e, $e92f, $99c8, $89e9, $b98a, $a9ab,
|
|
$5844, $4865, $7806, $6827, $18c0, $08e1, $3882, $28a3,
|
|
$cb7d, $db5c, $eb3f, $fb1e, $8bf9, $9bd8, $abbb, $bb9a,
|
|
$4a75, $5a54, $6a37, $7a16, $0af1, $1ad0, $2ab3, $3a92,
|
|
$fd2e, $ed0f, $dd6c, $cd4d, $bdaa, $ad8b, $9de8, $8dc9,
|
|
$7c26, $6c07, $5c64, $4c45, $3ca2, $2c83, $1ce0, $0cc1,
|
|
$ef1f, $ff3e, $cf5d, $df7c, $af9b, $bfba, $8fd9, $9ff8,
|
|
$6e17, $7e36, $4e55, $5e74, $2e93, $3eb2, $0ed1, $1ef0);
|
|
|
|
function CRC16Byte(const CRC16: Word; const Octet: Byte): Word;
|
|
begin
|
|
Result := CRC16Table[Byte(Hi(CRC16) xor Octet)] xor Word(CRC16 shl 8);
|
|
end;
|
|
|
|
function CRC16Buf(const CRC16: Word; const Buf; const BufSize: Integer): Word;
|
|
var I : Integer;
|
|
P : PByte;
|
|
begin
|
|
Result := CRC16;
|
|
P := @Buf;
|
|
for I := 1 to BufSize do
|
|
begin
|
|
Result := CRC16Byte(Result, P^);
|
|
Inc(P);
|
|
end;
|
|
end;
|
|
|
|
procedure CRC16Init(var CRC16: Word);
|
|
begin
|
|
CRC16 := $FFFF;
|
|
end;
|
|
|
|
function CalcCRC16(const Buf; const BufSize: Integer): Word;
|
|
begin
|
|
CRC16Init(Result);
|
|
Result := CRC16Buf(Result, Buf, BufSize);
|
|
end;
|
|
|
|
function CalcCRC16(const Buf: RawByteString): Word;
|
|
begin
|
|
Result := CalcCRC16(Pointer(Buf)^, Length(Buf));
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ CRC 32 hashing }
|
|
{ }
|
|
var
|
|
CRC32TableInit : Boolean = False;
|
|
CRC32Table : array[Byte] of LongWord;
|
|
CRC32Poly : LongWord = $EDB88320;
|
|
|
|
procedure InitCRC32Table;
|
|
var I, J : Byte;
|
|
R : LongWord;
|
|
begin
|
|
for I := $00 to $FF do
|
|
begin
|
|
R := I;
|
|
for J := 8 downto 1 do
|
|
if R and 1 <> 0 then
|
|
R := (R shr 1) xor CRC32Poly else
|
|
R := R shr 1;
|
|
CRC32Table[I] := R;
|
|
end;
|
|
CRC32TableInit := True;
|
|
end;
|
|
|
|
procedure SetCRC32Poly(const Poly: LongWord);
|
|
begin
|
|
CRC32Poly := Poly;
|
|
CRC32TableInit := False;
|
|
end;
|
|
|
|
function CalcCRC32Byte(const CRC32: LongWord; const Octet: Byte): LongWord; {$IFDEF UseInline}inline;{$ENDIF}
|
|
begin
|
|
Result := CRC32Table[Byte(CRC32) xor Octet] xor ((CRC32 shr 8) and $00FFFFFF);
|
|
end;
|
|
|
|
function CRC32Byte(const CRC32: LongWord; const Octet: Byte): LongWord;
|
|
begin
|
|
if not CRC32TableInit then
|
|
InitCRC32Table;
|
|
Result := CalcCRC32Byte(CRC32, Octet);
|
|
end;
|
|
|
|
function CRC32Buf(const CRC32: LongWord; const Buf; const BufSize: Integer): LongWord;
|
|
var P : PByte;
|
|
I : Integer;
|
|
begin
|
|
if not CRC32TableInit then
|
|
InitCRC32Table;
|
|
P := @Buf;
|
|
Result := CRC32;
|
|
for I := 1 to BufSize do
|
|
begin
|
|
Result := CalcCRC32Byte(Result, P^);
|
|
Inc(P);
|
|
end;
|
|
end;
|
|
|
|
function CRC32BufNoCase(const CRC32: LongWord; const Buf; const BufSize: Integer): LongWord;
|
|
var P : PByte;
|
|
I : Integer;
|
|
C : Byte;
|
|
begin
|
|
if not CRC32TableInit then
|
|
InitCRC32Table;
|
|
P := @Buf;
|
|
Result := CRC32;
|
|
for I := 1 to BufSize do
|
|
begin
|
|
C := P^;
|
|
if AnsiChar(C) in ['A'..'Z'] then
|
|
C := C or 32;
|
|
Result := CalcCRC32Byte(Result, C);
|
|
Inc(P);
|
|
end;
|
|
end;
|
|
|
|
procedure CRC32Init(var CRC32: LongWord);
|
|
begin
|
|
CRC32 := $FFFFFFFF;
|
|
end;
|
|
|
|
function CalcCRC32(const Buf; const BufSize: Integer): LongWord;
|
|
begin
|
|
CRC32Init(Result);
|
|
Result := not CRC32Buf(Result, Buf, BufSize);
|
|
end;
|
|
|
|
function CalcCRC32(const Buf: RawByteString): LongWord;
|
|
begin
|
|
Result := CalcCRC32(Pointer(Buf)^, Length(Buf));
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ Adler 32 hashing }
|
|
{ }
|
|
procedure Adler32Init(var Adler32: LongWord);
|
|
begin
|
|
Adler32 := $00000001;
|
|
end;
|
|
|
|
const
|
|
Adler32Mod = 65521; // largest prime smaller than 65536
|
|
|
|
function Adler32Byte(const Adler32: LongWord; const Octet: Byte): LongWord;
|
|
var A, B : LongWord;
|
|
begin
|
|
A := Adler32 and $0000FFFF;
|
|
B := Adler32 shr 16;
|
|
Inc(A, Octet);
|
|
Inc(B, A);
|
|
if A >= Adler32Mod then
|
|
Dec(A, Adler32Mod);
|
|
if B >= Adler32Mod then
|
|
Dec(B, Adler32Mod);
|
|
Result := A or (B shl 16);
|
|
end;
|
|
|
|
function Adler32Buf(const Adler32: LongWord; const Buf; const BufSize: Integer): LongWord;
|
|
var A, B : LongWord;
|
|
P : PByte;
|
|
I : Integer;
|
|
begin
|
|
A := Adler32 and $0000FFFF;
|
|
B := Adler32 shr 16;
|
|
P := @Buf;
|
|
for I := 1 to BufSize do
|
|
begin
|
|
Inc(A, P^);
|
|
Inc(B, A);
|
|
if A >= Adler32Mod then
|
|
Dec(A, Adler32Mod);
|
|
if B >= Adler32Mod then
|
|
Dec(B, Adler32Mod);
|
|
Inc(P);
|
|
end;
|
|
Result := A or (B shl 16);
|
|
end;
|
|
|
|
function CalcAdler32(const Buf; const BufSize: Integer): LongWord;
|
|
begin
|
|
Adler32Init(Result);
|
|
Result := Adler32Buf(Result, Buf, BufSize);
|
|
end;
|
|
|
|
function CalcAdler32(const Buf: RawByteString): LongWord;
|
|
begin
|
|
Result := CalcAdler32(Pointer(Buf)^, Length(Buf));
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ ELF hashing }
|
|
{ }
|
|
procedure ELFInit(var Digest: LongWord);
|
|
begin
|
|
Digest := 0;
|
|
end;
|
|
|
|
function ELFBuf(const Digest: LongWord; const Buf; const BufSize: Integer): LongWord;
|
|
var I : Integer;
|
|
P : PByte;
|
|
X : LongWord;
|
|
begin
|
|
Result := Digest;
|
|
P := @Buf;
|
|
for I := 1 to BufSize do
|
|
begin
|
|
Result := (Result shl 4) + P^;
|
|
Inc(P);
|
|
X := Result and $F0000000;
|
|
if X <> 0 then
|
|
Result := Result xor (X shr 24);
|
|
Result := Result and (not X);
|
|
end;
|
|
end;
|
|
|
|
function CalcELF(const Buf; const BufSize: Integer): LongWord;
|
|
begin
|
|
Result := ELFBuf(0, Buf, BufSize);
|
|
end;
|
|
|
|
function CalcELF(const Buf: RawByteString): LongWord;
|
|
begin
|
|
Result := CalcELF(Pointer(Buf)^, Length(Buf));
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ ISBN checksum }
|
|
{ }
|
|
function IsValidISBN(const S: RawByteString): Boolean;
|
|
var I, L, M, D, C : Integer;
|
|
P : PAnsiChar;
|
|
begin
|
|
L := Length(S);
|
|
if L < 10 then // too few digits
|
|
begin
|
|
Result := False;
|
|
exit;
|
|
end;
|
|
M := 10;
|
|
C := 0;
|
|
P := Pointer(S);
|
|
for I := 1 to L do
|
|
begin
|
|
if (P^ in ['0'..'9']) or ((M = 1) and (P^ in ['x', 'X'])) then
|
|
begin
|
|
if M = 0 then // too many digits
|
|
begin
|
|
Result := False;
|
|
exit;
|
|
end;
|
|
if P^ in ['x', 'X'] then
|
|
D := 10 else
|
|
D := Ord(P^) - Ord('0');
|
|
Inc(C, M * D);
|
|
Dec(M);
|
|
end;
|
|
Inc(P);
|
|
end;
|
|
if M > 0 then // too few digits
|
|
begin
|
|
Result := False;
|
|
exit;
|
|
end;
|
|
Result := C mod 11 = 0;
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ LUHN checksum }
|
|
{ }
|
|
function IsValidLUHN(const S: RawByteString): Boolean;
|
|
var P : PAnsiChar;
|
|
I, L, M, C, D : Integer;
|
|
R : Boolean;
|
|
begin
|
|
L := Length(S);
|
|
if L = 0 then
|
|
begin
|
|
Result := False;
|
|
exit;
|
|
end;
|
|
P := Pointer(S);
|
|
Inc(P, L - 1);
|
|
C := 0;
|
|
M := 0;
|
|
R := False;
|
|
for I := 1 to L do
|
|
begin
|
|
if P^ in ['0'..'9'] then
|
|
begin
|
|
D := Ord(P^) - Ord('0');
|
|
if R then
|
|
begin
|
|
D := D * 2;
|
|
D := (D div 10) + (D mod 10);
|
|
end;
|
|
Inc(C, D);
|
|
Inc(M);
|
|
R := not R;
|
|
end;
|
|
Dec(P);
|
|
end;
|
|
Result := (M >= 1) and (C mod 10 = 0);
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ Knuth Hash }
|
|
{ }
|
|
function KnuthHashA(const S: RawByteString): LongWord;
|
|
var
|
|
I, L : Integer;
|
|
H : LongWord;
|
|
begin
|
|
L := Length(S);
|
|
H := L;
|
|
for I := 1 to L do
|
|
H := ((H shr 5) xor (H shl 27)) xor Ord(S[I]);
|
|
Result := H;
|
|
end;
|
|
|
|
function KnuthHashW(const S: WideString): LongWord;
|
|
var
|
|
I, L : Integer;
|
|
H : LongWord;
|
|
begin
|
|
L := Length(S);
|
|
H := L;
|
|
for I := 1 to L do
|
|
H := ((H shr 5) xor (H shl 27)) xor Ord(S[I]);
|
|
Result := H;
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ Digests }
|
|
{ }
|
|
const
|
|
s_HexDigitsLower : String[16] = '0123456789abcdef';
|
|
|
|
procedure DigestToHexBufA(const Digest; const Size: Integer; const Buf);
|
|
var I : Integer;
|
|
P : PAnsiChar;
|
|
Q : PByte;
|
|
begin
|
|
P := @Buf;;
|
|
Assert(Assigned(P));
|
|
Q := @Digest;
|
|
Assert(Assigned(Q));
|
|
for I := 0 to Size - 1 do
|
|
begin
|
|
P^ := s_HexDigitsLower[Q^ shr 4 + 1];
|
|
Inc(P);
|
|
P^ := s_HexDigitsLower[Q^ and 15 + 1];
|
|
Inc(P);
|
|
Inc(Q);
|
|
end;
|
|
end;
|
|
|
|
procedure DigestToHexBufW(const Digest; const Size: Integer; const Buf);
|
|
var I : Integer;
|
|
P : PWideChar;
|
|
Q : PByte;
|
|
begin
|
|
P := @Buf;;
|
|
Assert(Assigned(P));
|
|
Q := @Digest;
|
|
Assert(Assigned(Q));
|
|
for I := 0 to Size - 1 do
|
|
begin
|
|
P^ := WideChar(s_HexDigitsLower[Q^ shr 4 + 1]);
|
|
Inc(P);
|
|
P^ := WideChar(s_HexDigitsLower[Q^ and 15 + 1]);
|
|
Inc(P);
|
|
Inc(Q);
|
|
end;
|
|
end;
|
|
|
|
function DigestToHexA(const Digest; const Size: Integer): RawByteString;
|
|
begin
|
|
SetLength(Result, Size * 2);
|
|
DigestToHexBufA(Digest, Size, Pointer(Result)^);
|
|
end;
|
|
|
|
function DigestToHexW(const Digest; const Size: Integer): WideString;
|
|
begin
|
|
SetLength(Result, Size * 2);
|
|
DigestToHexBufW(Digest, Size, Pointer(Result)^);
|
|
end;
|
|
|
|
function Digest128Equal(const Digest1, Digest2: T128BitDigest): Boolean;
|
|
var I : Integer;
|
|
begin
|
|
for I := 0 to 3 do
|
|
if Digest1.Longs[I] <> Digest2.Longs[I] then
|
|
begin
|
|
Result := False;
|
|
exit;
|
|
end;
|
|
Result := True;
|
|
end;
|
|
|
|
function Digest160Equal(const Digest1, Digest2: T160BitDigest): Boolean;
|
|
var I : Integer;
|
|
begin
|
|
for I := 0 to 4 do
|
|
if Digest1.Longs[I] <> Digest2.Longs[I] then
|
|
begin
|
|
Result := False;
|
|
exit;
|
|
end;
|
|
Result := True;
|
|
end;
|
|
|
|
function Digest224Equal(const Digest1, Digest2: T224BitDigest): Boolean;
|
|
var I : Integer;
|
|
begin
|
|
for I := 0 to 6 do
|
|
if Digest1.Longs[I] <> Digest2.Longs[I] then
|
|
begin
|
|
Result := False;
|
|
exit;
|
|
end;
|
|
Result := True;
|
|
end;
|
|
|
|
function Digest256Equal(const Digest1, Digest2: T256BitDigest): Boolean;
|
|
var I : Integer;
|
|
begin
|
|
for I := 0 to 7 do
|
|
if Digest1.Longs[I] <> Digest2.Longs[I] then
|
|
begin
|
|
Result := False;
|
|
exit;
|
|
end;
|
|
Result := True;
|
|
end;
|
|
|
|
function Digest384Equal(const Digest1, Digest2: T384BitDigest): Boolean;
|
|
var I : Integer;
|
|
begin
|
|
for I := 0 to 11 do
|
|
if Digest1.Longs[I] <> Digest2.Longs[I] then
|
|
begin
|
|
Result := False;
|
|
exit;
|
|
end;
|
|
Result := True;
|
|
end;
|
|
|
|
function Digest512Equal(const Digest1, Digest2: T512BitDigest): Boolean;
|
|
var I : Integer;
|
|
begin
|
|
for I := 0 to 15 do
|
|
if Digest1.Longs[I] <> Digest2.Longs[I] then
|
|
begin
|
|
Result := False;
|
|
exit;
|
|
end;
|
|
Result := True;
|
|
end;
|
|
|
|
procedure Digest512XOR8(var Digest: T512BitDigest; const A: Byte);
|
|
var I : Integer;
|
|
begin
|
|
for I := 0 to 63 do
|
|
Digest.Bytes[I] := Digest.Bytes[I] xor A;
|
|
end;
|
|
|
|
procedure Digest512XOR32(var Digest: T512BitDigest; const A: LongWord);
|
|
var I : Integer;
|
|
begin
|
|
for I := 0 to 15 do
|
|
Digest.Longs[I] := Digest.Longs[I] xor A;
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ ReverseMem }
|
|
{ Utility function to reverse order of data in buffer. }
|
|
{ }
|
|
procedure ReverseMem(var Buf; const BufSize: Integer);
|
|
var I : Integer;
|
|
P : PByte;
|
|
Q : PByte;
|
|
T : Byte;
|
|
begin
|
|
P := @Buf;
|
|
Q := P;
|
|
Inc(Q, BufSize - 1);
|
|
for I := 1 to BufSize div 2 do
|
|
begin
|
|
T := P^;
|
|
P^ := Q^;
|
|
Q^ := T;
|
|
Inc(P);
|
|
Dec(Q);
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ StdFinalBuf }
|
|
{ Utility function to prepare final buffer(s). }
|
|
{ Fills Buf1 and potentially Buf2 from Buf (FinalBufCount = 1 or 2). }
|
|
{ Used by MD5, SHA1, SHA256, SHA512. }
|
|
{ }
|
|
procedure StdFinalBuf512(
|
|
const Buf; const BufSize: Integer; const TotalSize: Int64;
|
|
var Buf1, Buf2: T512BitBuf;
|
|
var FinalBufs: Integer;
|
|
const SwapEndian: Boolean);
|
|
var P, Q : PByte;
|
|
I : Integer;
|
|
L : Int64;
|
|
begin
|
|
Assert(BufSize < 64, 'Final BufSize must be less than 64 bytes');
|
|
Assert(TotalSize >= BufSize, 'TotalSize >= BufSize');
|
|
|
|
P := @Buf;
|
|
Q := @Buf1[0];
|
|
if BufSize > 0 then
|
|
begin
|
|
Move(P^, Q^, BufSize);
|
|
Inc(Q, BufSize);
|
|
end;
|
|
Q^ := $80;
|
|
Inc(Q);
|
|
|
|
{$IFDEF DELPHI5}
|
|
// Delphi 5 sometimes reports fatal error (internal error C1093) when compiling:
|
|
// L := TotalSize * 8
|
|
L := TotalSize;
|
|
L := L * 8;
|
|
{$ELSE}
|
|
L := TotalSize * 8;
|
|
{$ENDIF}
|
|
if SwapEndian then
|
|
ReverseMem(L, 8);
|
|
if BufSize + 1 > 64 - Sizeof(Int64) then
|
|
begin
|
|
FillChar(Q^, 64 - BufSize - 1, #0);
|
|
Q := @Buf2[0];
|
|
FillChar(Q^, 64 - Sizeof(Int64), #0);
|
|
Inc(Q, 64 - Sizeof(Int64));
|
|
PInt64(Q)^ := L;
|
|
FinalBufs := 2;
|
|
end
|
|
else
|
|
begin
|
|
I := 64 - Sizeof(Int64) - BufSize - 1;
|
|
FillChar(Q^, I, #0);
|
|
Inc(Q, I);
|
|
PInt64(Q)^ := L;
|
|
FinalBufs := 1;
|
|
end;
|
|
end;
|
|
|
|
procedure StdFinalBuf1024(
|
|
const Buf; const BufSize: Integer; const TotalSize: Int64;
|
|
var Buf1, Buf2: T1024BitBuf;
|
|
var FinalBufs: Integer;
|
|
const SwapEndian: Boolean);
|
|
var P, Q : PByte;
|
|
I : Integer;
|
|
L : Int64;
|
|
begin
|
|
Assert(BufSize < 128, 'Final BufSize must be less than 128 bytes');
|
|
Assert(TotalSize >= BufSize, 'TotalSize >= BufSize');
|
|
|
|
P := @Buf;
|
|
Q := @Buf1[0];
|
|
if BufSize > 0 then
|
|
begin
|
|
Move(P^, Q^, BufSize);
|
|
Inc(Q, BufSize);
|
|
end;
|
|
Q^ := $80;
|
|
Inc(Q);
|
|
|
|
{$IFDEF DELPHI5}
|
|
// Delphi 5 sometimes reports fatal error (internal error C1093) when compiling:
|
|
// L := TotalSize * 8
|
|
L := TotalSize;
|
|
L := L * 8;
|
|
{$ELSE}
|
|
L := TotalSize * 8;
|
|
{$ENDIF}
|
|
if SwapEndian then
|
|
ReverseMem(L, 8);
|
|
if BufSize + 1 > 128 - Sizeof(Int64) * 2 then
|
|
begin
|
|
FillChar(Q^, 128 - BufSize - 1, #0);
|
|
Q := @Buf2[0];
|
|
FillChar(Q^, 128 - Sizeof(Int64) * 2, #0);
|
|
Inc(Q, 128 - Sizeof(Int64) * 2);
|
|
PInt64(Q)^ := 0;
|
|
Inc(Q, 8);
|
|
PInt64(Q)^ := L;
|
|
FinalBufs := 2;
|
|
end
|
|
else
|
|
begin
|
|
I := 128 - Sizeof(Int64) * 2 - BufSize - 1;
|
|
FillChar(Q^, I, #0);
|
|
Inc(Q, I);
|
|
PInt64(Q)^ := 0;
|
|
Inc(Q, 8);
|
|
PInt64(Q)^ := L;
|
|
FinalBufs := 1;
|
|
end;
|
|
end;
|
|
|
|
{ }
|
|
{ Utility functions SwapEndian, RotateLeftBits, RotateRightBits. }
|
|
{ Used by SHA1 and SHA256. }
|
|
{ }
|
|
{$IFDEF ASM386}
|
|
function SwapEndian(const Value: LongWord): LongWord; register; assembler;
|
|
asm
|
|
XCHG AH, AL
|
|
ROL EAX, 16
|
|
XCHG AH, AL
|
|
end;
|
|
{$ELSE}
|
|
function SwapEndian(const Value: LongWord): LongWord;
|
|
begin
|
|
Result := ((Value and $000000FF) shl 24) or
|
|
((Value and $0000FF00) shl 8) or
|
|
((Value and $00FF0000) shr 8) or
|
|
((Value and $FF000000) shr 24);
|
|
end;
|
|
{$ENDIF}
|
|
|
|
procedure SwapEndianBuf(var Buf; const Count: Integer);
|
|
var P : PLongWord;
|
|
I : Integer;
|
|
begin
|
|
P := @Buf;
|
|
for I := 1 to Count do
|
|
begin
|
|
P^ := SwapEndian(P^);
|
|
Inc(P);
|
|
end;
|
|
end;
|
|
|
|
{$IFDEF ASM386_DELPHI}
|
|
function RotateLeftBits(const Value: LongWord; const Bits: Byte): LongWord;
|
|
asm
|
|
MOV CL, DL
|
|
ROL EAX, CL
|
|
end;
|
|
{$ELSE}
|
|
function RotateLeftBits(const Value: LongWord; const Bits: Byte): LongWord;
|
|
var I : Integer;
|
|
R : LongWord;
|
|
begin
|
|
R := Value;
|
|
for I := 1 to Bits do
|
|
if R and $80000000 = 0 then
|
|
R := LongWord(R shl 1)
|
|
else
|
|
R := LongWord(R shl 1) or 1;
|
|
Result := R;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
{$IFDEF ASM386_DELPHI}
|
|
function RotateRightBits(const Value: LongWord; const Bits: Byte): LongWord;
|
|
asm
|
|
MOV CL, DL
|
|
ROR EAX, CL
|
|
end;
|
|
{$ELSE}
|
|
function RotateRightBits(const Value: LongWord; const Bits: Byte): LongWord;
|
|
var I, B : Integer;
|
|
begin
|
|
Result := Value;
|
|
if Bits >= 32 then
|
|
B := Bits mod 32
|
|
else
|
|
B := Bits;
|
|
for I := 1 to B do
|
|
if Result and 1 = 0 then
|
|
Result := Result shr 1
|
|
else
|
|
Result := (Result shr 1) or $80000000;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
|
|
|
|
{ }
|
|
{ Utility functions for Word64 arithmetic }
|
|
{ Used by SHA-512 }
|
|
{ }
|
|
procedure Word64InitZero(var A: Word64);
|
|
begin
|
|
A.LongWords[0] := 0;
|
|
A.LongWords[1] := 0;
|
|
end;
|
|
|
|
procedure Word64Not(var A: Word64);
|
|
begin
|
|
A.LongWords[0] := not A.LongWords[0];
|
|
A.LongWords[1] := not A.LongWords[1];
|
|
end;
|
|
|
|
procedure Word64AndWord64(var A: Word64; const B: Word64);
|
|
begin
|
|
A.LongWords[0] := A.LongWords[0] and B.LongWords[0];
|
|
A.LongWords[1] := A.LongWords[1] and B.LongWords[1];
|
|
end;
|
|
|
|
procedure Word64XorWord64(var A: Word64; const B: Word64);
|
|
begin
|
|
A.LongWords[0] := A.LongWords[0] xor B.LongWords[0];
|
|
A.LongWords[1] := A.LongWords[1] xor B.LongWords[1];
|
|
end;
|
|
|
|
procedure Word64AddWord64(var A: Word64; const B: Word64);
|
|
var C, D : Int64;
|
|
begin
|
|
C := Int64(A.LongWords[0]) + B.LongWords[0];
|
|
D := Int64(A.LongWords[1]) + B.LongWords[1];
|
|
if C >= $100000000 then
|
|
Inc(D);
|
|
A.LongWords[0] := C and $FFFFFFFF;
|
|
A.LongWords[1] := D and $FFFFFFFF;
|
|
end;
|
|
|
|
procedure Word64Shr(var A: Word64; const B: Byte);
|
|
var C : Byte;
|
|
begin
|
|
if B = 0 then
|
|
exit;
|
|
if B >= 64 then
|
|
Word64InitZero(A) else
|
|
if B < 32 then
|
|
begin
|
|
C := 32 - B;
|
|
A.LongWords[0] := (A.LongWords[0] shr B) or (A.LongWords[1] shl C);
|
|
A.LongWords[1] := A.LongWords[1] shr B;
|
|
end
|
|
else
|
|
begin
|
|
C := B - 32;
|
|
A.LongWords[0] := A.LongWords[1] shr C;
|
|
A.LongWords[1] := 0;
|
|
end;
|
|
end;
|
|
|
|
procedure Word64Ror(var A: Word64; const B: Byte);
|
|
var C, D : Byte;
|
|
E, F : LongWord;
|
|
begin
|
|
C := B mod 64;
|
|
if C = 0 then
|
|
exit;
|
|
if C < 32 then
|
|
begin
|
|
D := 32 - C;
|
|
E := (A.LongWords[1] shr C) or (A.LongWords[0] shl D);
|
|
F := (A.LongWords[0] shr C) or (A.LongWords[1] shl D);
|
|
end
|
|
else
|
|
begin
|
|
Dec(C, 32);
|
|
D := 32 - C;
|
|
E := (A.LongWords[0] shr C) or (A.LongWords[1] shl D);
|
|
F := (A.LongWords[1] shr C) or (A.LongWords[0] shl D);
|
|
end;
|
|
A.LongWords[1] := E;
|
|
A.LongWords[0] := F;
|
|
end;
|
|
|
|
procedure Word64SwapEndian(var A: Word64);
|
|
var B : Word64;
|
|
I : Integer;
|
|
begin
|
|
B := A;
|
|
for I := 0 to 7 do
|
|
A.Bytes[I] := B.Bytes[7 - I];
|
|
end;
|
|
|
|
procedure SwapEndianBuf64(var Buf; const Count: Integer);
|
|
var P : PWord64;
|
|
I : Integer;
|
|
begin
|
|
P := @Buf;
|
|
for I := 1 to Count do
|
|
begin
|
|
Word64SwapEndian(P^);
|
|
Inc(P);
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ MD5 hashing }
|
|
{ }
|
|
const
|
|
MD5Table_1 : array[0..15] of LongWord = (
|
|
$D76AA478, $E8C7B756, $242070DB, $C1BDCEEE,
|
|
$F57C0FAF, $4787C62A, $A8304613, $FD469501,
|
|
$698098D8, $8B44F7AF, $FFFF5BB1, $895CD7BE,
|
|
$6B901122, $FD987193, $A679438E, $49B40821);
|
|
MD5Table_2 : array[0..15] of LongWord = (
|
|
$F61E2562, $C040B340, $265E5A51, $E9B6C7AA,
|
|
$D62F105D, $02441453, $D8A1E681, $E7D3FBC8,
|
|
$21E1CDE6, $C33707D6, $F4D50D87, $455A14ED,
|
|
$A9E3E905, $FCEFA3F8, $676F02D9, $8D2A4C8A);
|
|
MD5Table_3 : array[0..15] of LongWord = (
|
|
$FFFA3942, $8771F681, $6D9D6122, $FDE5380C,
|
|
$A4BEEA44, $4BDECFA9, $F6BB4B60, $BEBFBC70,
|
|
$289B7EC6, $EAA127FA, $D4EF3085, $04881D05,
|
|
$D9D4D039, $E6DB99E5, $1FA27CF8, $C4AC5665);
|
|
MD5Table_4 : array[0..15] of LongWord = (
|
|
$F4292244, $432AFF97, $AB9423A7, $FC93A039,
|
|
$655B59C3, $8F0CCC92, $FFEFF47D, $85845DD1,
|
|
$6FA87E4F, $FE2CE6E0, $A3014314, $4E0811A1,
|
|
$F7537E82, $BD3AF235, $2AD7D2BB, $EB86D391);
|
|
|
|
{ Calculates a MD5 Digest (16 bytes) given a Buffer (64 bytes) }
|
|
{$IFOPT Q+}{$DEFINE QOn}{$Q-}{$ELSE}{$UNDEF QOn}{$ENDIF}
|
|
procedure TransformMD5Buffer(var Digest: T128BitDigest; const Buffer);
|
|
var A, B, C, D : LongWord;
|
|
P : PLongWord;
|
|
I : Integer;
|
|
J : Byte;
|
|
Buf : array[0..15] of LongWord absolute Buffer;
|
|
begin
|
|
A := Digest.Longs[0];
|
|
B := Digest.Longs[1];
|
|
C := Digest.Longs[2];
|
|
D := Digest.Longs[3];
|
|
|
|
P := @MD5Table_1;
|
|
for I := 0 to 3 do
|
|
begin
|
|
J := I * 4;
|
|
Inc(A, Buf[J] + P^ + (D xor (B and (C xor D)))); A := A shl 7 or A shr 25 + B; Inc(P);
|
|
Inc(D, Buf[J + 1] + P^ + (C xor (A and (B xor C)))); D := D shl 12 or D shr 20 + A; Inc(P);
|
|
Inc(C, Buf[J + 2] + P^ + (B xor (D and (A xor B)))); C := C shl 17 or C shr 15 + D; Inc(P);
|
|
Inc(B, Buf[J + 3] + P^ + (A xor (C and (D xor A)))); B := B shl 22 or B shr 10 + C; Inc(P);
|
|
end;
|
|
|
|
P := @MD5Table_2;
|
|
for I := 0 to 3 do
|
|
begin
|
|
J := I * 4;
|
|
Inc(A, Buf[J + 1] + P^ + (C xor (D and (B xor C)))); A := A shl 5 or A shr 27 + B; Inc(P);
|
|
Inc(D, Buf[(J + 6) mod 16] + P^ + (B xor (C and (A xor B)))); D := D shl 9 or D shr 23 + A; Inc(P);
|
|
Inc(C, Buf[(J + 11) mod 16] + P^ + (A xor (B and (D xor A)))); C := C shl 14 or C shr 18 + D; Inc(P);
|
|
Inc(B, Buf[J] + P^ + (D xor (A and (C xor D)))); B := B shl 20 or B shr 12 + C; Inc(P);
|
|
end;
|
|
|
|
P := @MD5Table_3;
|
|
for I := 0 to 3 do
|
|
begin
|
|
J := 16 - (I * 4);
|
|
Inc(A, Buf[(J + 5) mod 16] + P^ + (B xor C xor D)); A := A shl 4 or A shr 28 + B; Inc(P);
|
|
Inc(D, Buf[(J + 8) mod 16] + P^ + (A xor B xor C)); D := D shl 11 or D shr 21 + A; Inc(P);
|
|
Inc(C, Buf[(J + 11) mod 16] + P^ + (D xor A xor B)); C := C shl 16 or C shr 16 + D; Inc(P);
|
|
Inc(B, Buf[(J + 14) mod 16] + P^ + (C xor D xor A)); B := B shl 23 or B shr 9 + C; Inc(P);
|
|
end;
|
|
|
|
P := @MD5Table_4;
|
|
for I := 0 to 3 do
|
|
begin
|
|
J := 16 - (I * 4);
|
|
Inc(A, Buf[J mod 16] + P^ + (C xor (B or not D))); A := A shl 6 or A shr 26 + B; Inc(P);
|
|
Inc(D, Buf[(J + 7) mod 16] + P^ + (B xor (A or not C))); D := D shl 10 or D shr 22 + A; Inc(P);
|
|
Inc(C, Buf[(J + 14) mod 16] + P^ + (A xor (D or not B))); C := C shl 15 or C shr 17 + D; Inc(P);
|
|
Inc(B, Buf[(J + 5) mod 16] + P^ + (D xor (C or not A))); B := B shl 21 or B shr 11 + C; Inc(P);
|
|
end;
|
|
|
|
Inc(Digest.Longs[0], A);
|
|
Inc(Digest.Longs[1], B);
|
|
Inc(Digest.Longs[2], C);
|
|
Inc(Digest.Longs[3], D);
|
|
end;
|
|
{$IFDEF QOn}{$Q+}{$ENDIF}
|
|
|
|
procedure MD5InitDigest(var Digest: T128BitDigest);
|
|
begin
|
|
Digest.Longs[0] := $67452301;
|
|
Digest.Longs[1] := $EFCDAB89;
|
|
Digest.Longs[2] := $98BADCFE;
|
|
Digest.Longs[3] := $10325476;
|
|
end;
|
|
|
|
procedure MD5Buf(var Digest: T128BitDigest; const Buf; const BufSize: Integer);
|
|
var P : PByte;
|
|
I, J : Integer;
|
|
begin
|
|
I := BufSize;
|
|
if I <= 0 then
|
|
exit;
|
|
Assert(I mod 64 = 0, 'BufSize must be multiple of 64 bytes');
|
|
P := @Buf;
|
|
for J := 0 to I div 64 - 1 do
|
|
begin
|
|
TransformMD5Buffer(Digest, P^);
|
|
Inc(P, 64);
|
|
end;
|
|
end;
|
|
|
|
procedure MD5FinalBuf(var Digest: T128BitDigest; const Buf; const BufSize: Integer; const TotalSize: Int64);
|
|
var B1, B2 : T512BitBuf;
|
|
C : Integer;
|
|
begin
|
|
StdFinalBuf512(Buf, BufSize, TotalSize, B1, B2, C, False);
|
|
TransformMD5Buffer(Digest, B1);
|
|
if C > 1 then
|
|
TransformMD5Buffer(Digest, B2);
|
|
SecureClear512(B1);
|
|
if C > 1 then
|
|
SecureClear512(B2);
|
|
end;
|
|
|
|
function CalcMD5(const Buf; const BufSize: Integer): T128BitDigest;
|
|
var I, J : Integer;
|
|
P : PByte;
|
|
begin
|
|
MD5InitDigest(Result);
|
|
P := @Buf;
|
|
if BufSize <= 0 then
|
|
I := 0 else
|
|
I := BufSize;
|
|
J := (I div 64) * 64;
|
|
if J > 0 then
|
|
begin
|
|
MD5Buf(Result, P^, J);
|
|
Inc(P, J);
|
|
Dec(I, J);
|
|
end;
|
|
MD5FinalBuf(Result, P^, I, BufSize);
|
|
end;
|
|
|
|
function CalcMD5(const Buf: RawByteString): T128BitDigest;
|
|
begin
|
|
Result := CalcMD5(Pointer(Buf)^, Length(Buf));
|
|
end;
|
|
|
|
function MD5DigestToStrA(const Digest: T128BitDigest): RawByteString;
|
|
begin
|
|
SetLength(Result, Sizeof(Digest));
|
|
Move(Digest, Pointer(Result)^, Sizeof(Digest));
|
|
end;
|
|
|
|
function MD5DigestToHexA(const Digest: T128BitDigest): RawByteString;
|
|
begin
|
|
Result := DigestToHexA(Digest, Sizeof(Digest));
|
|
end;
|
|
|
|
function MD5DigestToHexW(const Digest: T128BitDigest): WideString;
|
|
begin
|
|
Result := DigestToHexW(Digest, Sizeof(Digest));
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ SHA hashing }
|
|
{ }
|
|
procedure SHA1InitDigest(var Digest: T160BitDigest);
|
|
begin
|
|
Digest.Longs[0] := $67452301;
|
|
Digest.Longs[1] := $EFCDAB89;
|
|
Digest.Longs[2] := $98BADCFE;
|
|
Digest.Longs[3] := $10325476;
|
|
Digest.Longs[4] := $C3D2E1F0;
|
|
end;
|
|
|
|
{ Calculates a SHA Digest (20 bytes) given a Buffer (64 bytes) }
|
|
{$IFOPT Q+}{$DEFINE QOn}{$Q-}{$ELSE}{$UNDEF QOn}{$ENDIF}
|
|
procedure TransformSHABuffer(var Digest: T160BitDigest; const Buffer; const SHA1: Boolean);
|
|
var A, B, C, D, E : LongWord;
|
|
W : array[0..79] of LongWord;
|
|
P, Q : PLongWord;
|
|
I : Integer;
|
|
J : LongWord;
|
|
begin
|
|
P := @Buffer;
|
|
Q := @W;
|
|
for I := 0 to 15 do
|
|
begin
|
|
Q^ := SwapEndian(P^);
|
|
Inc(P);
|
|
Inc(Q);
|
|
end;
|
|
for I := 0 to 63 do
|
|
begin
|
|
P := Q;
|
|
Dec(P, 16);
|
|
J := P^;
|
|
Inc(P, 2);
|
|
J := J xor P^;
|
|
Inc(P, 6);
|
|
J := J xor P^;
|
|
Inc(P, 5);
|
|
J := J xor P^;
|
|
if SHA1 then
|
|
J := RotateLeftBits(J, 1);
|
|
Q^ := J;
|
|
Inc(Q);
|
|
end;
|
|
|
|
A := Digest.Longs[0];
|
|
B := Digest.Longs[1];
|
|
C := Digest.Longs[2];
|
|
D := Digest.Longs[3];
|
|
E := Digest.Longs[4];
|
|
|
|
P := @W;
|
|
for I := 0 to 3 do
|
|
begin
|
|
Inc(E, (A shl 5 or A shr 27) + (D xor (B and (C xor D))) + P^ + $5A827999); B := B shr 2 or B shl 30; Inc(P);
|
|
Inc(D, (E shl 5 or E shr 27) + (C xor (A and (B xor C))) + P^ + $5A827999); A := A shr 2 or A shl 30; Inc(P);
|
|
Inc(C, (D shl 5 or D shr 27) + (B xor (E and (A xor B))) + P^ + $5A827999); E := E shr 2 or E shl 30; Inc(P);
|
|
Inc(B, (C shl 5 or C shr 27) + (A xor (D and (E xor A))) + P^ + $5A827999); D := D shr 2 or D shl 30; Inc(P);
|
|
Inc(A, (B shl 5 or B shr 27) + (E xor (C and (D xor E))) + P^ + $5A827999); C := C shr 2 or C shl 30; Inc(P);
|
|
end;
|
|
|
|
for I := 0 to 3 do
|
|
begin
|
|
Inc(E, (A shl 5 or A shr 27) + (D xor B xor C) + P^ + $6ED9EBA1); B := B shr 2 or B shl 30; Inc(P);
|
|
Inc(D, (E shl 5 or E shr 27) + (C xor A xor B) + P^ + $6ED9EBA1); A := A shr 2 or A shl 30; Inc(P);
|
|
Inc(C, (D shl 5 or D shr 27) + (B xor E xor A) + P^ + $6ED9EBA1); E := E shr 2 or E shl 30; Inc(P);
|
|
Inc(B, (C shl 5 or C shr 27) + (A xor D xor E) + P^ + $6ED9EBA1); D := D shr 2 or D shl 30; Inc(P);
|
|
Inc(A, (B shl 5 or B shr 27) + (E xor C xor D) + P^ + $6ED9EBA1); C := C shr 2 or C shl 30; Inc(P);
|
|
end;
|
|
|
|
for I := 0 to 3 do
|
|
begin
|
|
Inc(E, (A shl 5 or A shr 27) + ((B and C) or (D and (B or C))) + P^ + $8F1BBCDC); B := B shr 2 or B shl 30; Inc(P);
|
|
Inc(D, (E shl 5 or E shr 27) + ((A and B) or (C and (A or B))) + P^ + $8F1BBCDC); A := A shr 2 or A shl 30; Inc(P);
|
|
Inc(C, (D shl 5 or D shr 27) + ((E and A) or (B and (E or A))) + P^ + $8F1BBCDC); E := E shr 2 or E shl 30; Inc(P);
|
|
Inc(B, (C shl 5 or C shr 27) + ((D and E) or (A and (D or E))) + P^ + $8F1BBCDC); D := D shr 2 or D shl 30; Inc(P);
|
|
Inc(A, (B shl 5 or B shr 27) + ((C and D) or (E and (C or D))) + P^ + $8F1BBCDC); C := C shr 2 or C shl 30; Inc(P);
|
|
end;
|
|
|
|
for I := 0 to 3 do
|
|
begin
|
|
Inc(E, (A shl 5 or A shr 27) + (D xor B xor C) + P^ + $CA62C1D6); B := B shr 2 or B shl 30; Inc(P);
|
|
Inc(D, (E shl 5 or E shr 27) + (C xor A xor B) + P^ + $CA62C1D6); A := A shr 2 or A shl 30; Inc(P);
|
|
Inc(C, (D shl 5 or D shr 27) + (B xor E xor A) + P^ + $CA62C1D6); E := E shr 2 or E shl 30; Inc(P);
|
|
Inc(B, (C shl 5 or C shr 27) + (A xor D xor E) + P^ + $CA62C1D6); D := D shr 2 or D shl 30; Inc(P);
|
|
Inc(A, (B shl 5 or B shr 27) + (E xor C xor D) + P^ + $CA62C1D6); C := C shr 2 or C shl 30; Inc(P);
|
|
end;
|
|
|
|
Inc(Digest.Longs[0], A);
|
|
Inc(Digest.Longs[1], B);
|
|
Inc(Digest.Longs[2], C);
|
|
Inc(Digest.Longs[3], D);
|
|
Inc(Digest.Longs[4], E);
|
|
end;
|
|
{$IFDEF QOn}{$Q+}{$ENDIF}
|
|
|
|
procedure SHA1Buf(var Digest: T160BitDigest; const Buf; const BufSize: Integer);
|
|
var P : PByte;
|
|
I, J : Integer;
|
|
begin
|
|
I := BufSize;
|
|
if I <= 0 then
|
|
exit;
|
|
Assert(I mod 64 = 0, 'BufSize must be multiple of 64 bytes');
|
|
P := @Buf;
|
|
for J := 0 to I div 64 - 1 do
|
|
begin
|
|
TransformSHABuffer(Digest, P^, True);
|
|
Inc(P, 64);
|
|
end;
|
|
end;
|
|
|
|
procedure SHA1FinalBuf(var Digest: T160BitDigest; const Buf; const BufSize: Integer; const TotalSize: Int64);
|
|
var B1, B2 : T512BitBuf;
|
|
C : Integer;
|
|
begin
|
|
StdFinalBuf512(Buf, BufSize, TotalSize, B1, B2, C, True);
|
|
TransformSHABuffer(Digest, B1, True);
|
|
if C > 1 then
|
|
TransformSHABuffer(Digest, B2, True);
|
|
SwapEndianBuf(Digest, Sizeof(Digest) div Sizeof(LongWord));
|
|
SecureClear512(B1);
|
|
if C > 1 then
|
|
SecureClear512(B2);
|
|
end;
|
|
|
|
function CalcSHA1(const Buf; const BufSize: Integer): T160BitDigest;
|
|
var I, J : Integer;
|
|
P : PByte;
|
|
begin
|
|
SHA1InitDigest(Result);
|
|
P := @Buf;
|
|
if BufSize <= 0 then
|
|
I := 0 else
|
|
I := BufSize;
|
|
J := (I div 64) * 64;
|
|
if J > 0 then
|
|
begin
|
|
SHA1Buf(Result, P^, J);
|
|
Inc(P, J);
|
|
Dec(I, J);
|
|
end;
|
|
SHA1FinalBuf(Result, P^, I, BufSize);
|
|
end;
|
|
|
|
function CalcSHA1(const Buf: RawByteString): T160BitDigest;
|
|
begin
|
|
Result := CalcSHA1(Pointer(Buf)^, Length(Buf));
|
|
end;
|
|
|
|
function SHA1DigestToStrA(const Digest: T160BitDigest): RawByteString;
|
|
begin
|
|
SetLength(Result, Sizeof(Digest));
|
|
Move(Digest, Pointer(Result)^, Sizeof(Digest));
|
|
end;
|
|
|
|
function SHA1DigestToHexA(const Digest: T160BitDigest): RawByteString;
|
|
begin
|
|
Result := DigestToHexA(Digest, Sizeof(Digest));
|
|
end;
|
|
|
|
function SHA1DigestToHexW(const Digest: T160BitDigest): WideString;
|
|
begin
|
|
Result := DigestToHexW(Digest, Sizeof(Digest));
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ SHA224 Hashing }
|
|
{ }
|
|
{ SHA-224 is identical to SHA-256, except that: }
|
|
{ - the initial variable values h0 through h7 are different, and }
|
|
{ - the output is constructed by omitting h7 }
|
|
{ }
|
|
procedure SHA224InitDigest(var Digest: T256BitDigest);
|
|
begin
|
|
// The second 32 bits of the fractional parts of the square roots of the 9th through 16th primes 23..53
|
|
Digest.Longs[0] := $c1059ed8;
|
|
Digest.Longs[1] := $367cd507;
|
|
Digest.Longs[2] := $3070dd17;
|
|
Digest.Longs[3] := $f70e5939;
|
|
Digest.Longs[4] := $ffc00b31;
|
|
Digest.Longs[5] := $68581511;
|
|
Digest.Longs[6] := $64f98fa7;
|
|
Digest.Longs[7] := $befa4fa4;
|
|
end;
|
|
|
|
procedure SHA224Buf(var Digest: T256BitDigest; const Buf; const BufSize: Integer);
|
|
begin
|
|
SHA256Buf(Digest, Buf, BufSize);
|
|
end;
|
|
|
|
procedure SHA224FinalBuf(var Digest: T256BitDigest; const Buf; const BufSize: Integer; const TotalSize: Int64;
|
|
var OutDigest: T224BitDigest);
|
|
begin
|
|
SHA256FinalBuf(Digest, Buf, BufSize, TotalSize);
|
|
Move(Digest.Longs[0], OutDigest.Longs[0], SizeOf(T224BitDigest));
|
|
end;
|
|
|
|
function CalcSHA224(const Buf; const BufSize: Integer): T224BitDigest;
|
|
var D : T256BitDigest;
|
|
I, J : Integer;
|
|
P : PByte;
|
|
begin
|
|
SHA224InitDigest(D);
|
|
P := @Buf;
|
|
if BufSize <= 0 then
|
|
I := 0 else
|
|
I := BufSize;
|
|
J := (I div 64) * 64;
|
|
if J > 0 then
|
|
begin
|
|
SHA224Buf(D, P^, J);
|
|
Inc(P, J);
|
|
Dec(I, J);
|
|
end;
|
|
SHA224FinalBuf(D, P^, I, BufSize, Result);
|
|
end;
|
|
|
|
function CalcSHA224(const Buf: RawByteString): T224BitDigest;
|
|
begin
|
|
Result := CalcSHA224(Pointer(Buf)^, Length(Buf));
|
|
end;
|
|
|
|
function SHA224DigestToStrA(const Digest: T224BitDigest): RawByteString;
|
|
begin
|
|
SetLength(Result, Sizeof(Digest));
|
|
Move(Digest, Pointer(Result)^, Sizeof(Digest));
|
|
end;
|
|
|
|
function SHA224DigestToHexA(const Digest: T224BitDigest): RawByteString;
|
|
begin
|
|
Result := DigestToHexA(Digest, Sizeof(Digest));
|
|
end;
|
|
|
|
function SHA224DigestToHexW(const Digest: T224BitDigest): WideString;
|
|
begin
|
|
Result := DigestToHexW(Digest, Sizeof(Digest));
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ SHA256 hashing }
|
|
{ }
|
|
procedure SHA256InitDigest(var Digest: T256BitDigest);
|
|
begin
|
|
Digest.Longs[0] := $6a09e667;
|
|
Digest.Longs[1] := $bb67ae85;
|
|
Digest.Longs[2] := $3c6ef372;
|
|
Digest.Longs[3] := $a54ff53a;
|
|
Digest.Longs[4] := $510e527f;
|
|
Digest.Longs[5] := $9b05688c;
|
|
Digest.Longs[6] := $1f83d9ab;
|
|
Digest.Longs[7] := $5be0cd19;
|
|
end;
|
|
|
|
function SHA256Transform1(const A: LongWord): LongWord;
|
|
begin
|
|
Result := RotateRightBits(A, 7) xor RotateRightBits(A, 18) xor (A shr 3);
|
|
end;
|
|
|
|
function SHA256Transform2(const A: LongWord): LongWord;
|
|
begin
|
|
Result := RotateRightBits(A, 17) xor RotateRightBits(A, 19) xor (A shr 10);
|
|
end;
|
|
|
|
function SHA256Transform3(const A: LongWord): LongWord;
|
|
begin
|
|
Result := RotateRightBits(A, 2) xor RotateRightBits(A, 13) xor RotateRightBits(A, 22);
|
|
end;
|
|
|
|
function SHA256Transform4(const A: LongWord): LongWord;
|
|
begin
|
|
Result := RotateRightBits(A, 6) xor RotateRightBits(A, 11) xor RotateRightBits(A, 25);
|
|
end;
|
|
|
|
const
|
|
// first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311
|
|
SHA256K: array[0..63] of LongWord = (
|
|
$428a2f98, $71374491, $b5c0fbcf, $e9b5dba5, $3956c25b, $59f111f1, $923f82a4, $ab1c5ed5,
|
|
$d807aa98, $12835b01, $243185be, $550c7dc3, $72be5d74, $80deb1fe, $9bdc06a7, $c19bf174,
|
|
$e49b69c1, $efbe4786, $0fc19dc6, $240ca1cc, $2de92c6f, $4a7484aa, $5cb0a9dc, $76f988da,
|
|
$983e5152, $a831c66d, $b00327c8, $bf597fc7, $c6e00bf3, $d5a79147, $06ca6351, $14292967,
|
|
$27b70a85, $2e1b2138, $4d2c6dfc, $53380d13, $650a7354, $766a0abb, $81c2c92e, $92722c85,
|
|
$a2bfe8a1, $a81a664b, $c24b8b70, $c76c51a3, $d192e819, $d6990624, $f40e3585, $106aa070,
|
|
$19a4c116, $1e376c08, $2748774c, $34b0bcb5, $391c0cb3, $4ed8aa4a, $5b9cca4f, $682e6ff3,
|
|
$748f82ee, $78a5636f, $84c87814, $8cc70208, $90befffa, $a4506ceb, $bef9a3f7, $c67178f2
|
|
);
|
|
|
|
{$IFOPT Q+}{$DEFINE QOn}{$Q-}{$ELSE}{$UNDEF QOn}{$ENDIF}
|
|
procedure TransformSHA256Buffer(var Digest: T256BitDigest; const Buf);
|
|
var
|
|
I : Integer;
|
|
W : array[0..63] of LongWord;
|
|
P : PLongWord;
|
|
S0, S1, Maj, T1, T2, Ch : LongWord;
|
|
H : array[0..7] of LongWord;
|
|
begin
|
|
P := @Buf;
|
|
for I := 0 to 15 do
|
|
begin
|
|
W[I] := SwapEndian(P^);
|
|
Inc(P);
|
|
end;
|
|
for I := 16 to 63 do
|
|
begin
|
|
S0 := SHA256Transform1(W[I - 15]);
|
|
S1 := SHA256Transform2(W[I - 2]);
|
|
W[I] := W[I - 16] + S0 + W[I - 7] + S1;
|
|
end;
|
|
for I := 0 to 7 do
|
|
H[I] := Digest.Longs[I];
|
|
for I := 0 to 63 do
|
|
begin
|
|
S0 := SHA256Transform3(H[0]);
|
|
Maj := (H[0] and H[1]) xor (H[0] and H[2]) xor (H[1] and H[2]);
|
|
T2 := S0 + Maj;
|
|
S1 := SHA256Transform4(H[4]);
|
|
Ch := (H[4] and H[5]) xor ((not H[4]) and H[6]);
|
|
T1 := H[7] + S1 + Ch + SHA256K[I] + W[I];
|
|
H[7] := H[6];
|
|
H[6] := H[5];
|
|
H[5] := H[4];
|
|
H[4] := H[3] + T1;
|
|
H[3] := H[2];
|
|
H[2] := H[1];
|
|
H[1] := H[0];
|
|
H[0] := T1 + T2;
|
|
end;
|
|
for I := 0 to 7 do
|
|
Inc(Digest.Longs[I], H[I]);
|
|
end;
|
|
{$IFDEF QOn}{$Q+}{$ENDIF}
|
|
|
|
procedure SHA256Buf(var Digest: T256BitDigest; const Buf; const BufSize: Integer);
|
|
var P : PByte;
|
|
I, J : Integer;
|
|
begin
|
|
I := BufSize;
|
|
if I <= 0 then
|
|
exit;
|
|
Assert(I mod 64 = 0, 'BufSize must be multiple of 64 bytes');
|
|
P := @Buf;
|
|
for J := 0 to I div 64 - 1 do
|
|
begin
|
|
TransformSHA256Buffer(Digest, P^);
|
|
Inc(P, 64);
|
|
end;
|
|
end;
|
|
|
|
procedure SHA256FinalBuf(var Digest: T256BitDigest; const Buf; const BufSize: Integer; const TotalSize: Int64);
|
|
var B1, B2 : T512BitBuf;
|
|
C : Integer;
|
|
begin
|
|
StdFinalBuf512(Buf, BufSize, TotalSize, B1, B2, C, True);
|
|
TransformSHA256Buffer(Digest, B1);
|
|
if C > 1 then
|
|
TransformSHA256Buffer(Digest, B2);
|
|
SwapEndianBuf(Digest, Sizeof(Digest) div Sizeof(LongWord));
|
|
SecureClear512(B1);
|
|
if C > 1 then
|
|
SecureClear512(B2);
|
|
end;
|
|
|
|
function CalcSHA256(const Buf; const BufSize: Integer): T256BitDigest;
|
|
var I, J : Integer;
|
|
P : PByte;
|
|
begin
|
|
SHA256InitDigest(Result);
|
|
P := @Buf;
|
|
if BufSize <= 0 then
|
|
I := 0 else
|
|
I := BufSize;
|
|
J := (I div 64) * 64;
|
|
if J > 0 then
|
|
begin
|
|
SHA256Buf(Result, P^, J);
|
|
Inc(P, J);
|
|
Dec(I, J);
|
|
end;
|
|
SHA256FinalBuf(Result, P^, I, BufSize);
|
|
end;
|
|
|
|
function CalcSHA256(const Buf: RawByteString): T256BitDigest;
|
|
begin
|
|
Result := CalcSHA256(Pointer(Buf)^, Length(Buf));
|
|
end;
|
|
|
|
function SHA256DigestToStrA(const Digest: T256BitDigest): RawByteString;
|
|
begin
|
|
SetLength(Result, Sizeof(Digest));
|
|
Move(Digest, Pointer(Result)^, Sizeof(Digest));
|
|
end;
|
|
|
|
function SHA256DigestToHexA(const Digest: T256BitDigest): RawByteString;
|
|
begin
|
|
Result := DigestToHexA(Digest, Sizeof(Digest));
|
|
end;
|
|
|
|
function SHA256DigestToHexW(const Digest: T256BitDigest): WideString;
|
|
begin
|
|
Result := DigestToHexW(Digest, Sizeof(Digest));
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ SHA384 Hashing }
|
|
{ }
|
|
procedure SHA384InitDigest(var Digest: T512BitDigest);
|
|
begin
|
|
Digest.Word64s[0].LongWords[0] := $c1059ed8;
|
|
Digest.Word64s[0].LongWords[1] := $cbbb9d5d;
|
|
Digest.Word64s[1].LongWords[0] := $367cd507;
|
|
Digest.Word64s[1].LongWords[1] := $629a292a;
|
|
Digest.Word64s[2].LongWords[0] := $3070dd17;
|
|
Digest.Word64s[2].LongWords[1] := $9159015a;
|
|
Digest.Word64s[3].LongWords[0] := $f70e5939;
|
|
Digest.Word64s[3].LongWords[1] := $152fecd8;
|
|
Digest.Word64s[4].LongWords[0] := $ffc00b31;
|
|
Digest.Word64s[4].LongWords[1] := $67332667;
|
|
Digest.Word64s[5].LongWords[0] := $68581511;
|
|
Digest.Word64s[5].LongWords[1] := $8eb44a87;
|
|
Digest.Word64s[6].LongWords[0] := $64f98fa7;
|
|
Digest.Word64s[6].LongWords[1] := $db0c2e0d;
|
|
Digest.Word64s[7].LongWords[0] := $befa4fa4;
|
|
Digest.Word64s[7].LongWords[1] := $47b5481d;
|
|
end;
|
|
|
|
procedure SHA384Buf(var Digest: T512BitDigest; const Buf; const BufSize: Integer);
|
|
begin
|
|
SHA512Buf(Digest, Buf, BufSize);
|
|
end;
|
|
|
|
procedure SHA384FinalBuf(var Digest: T512BitDigest; const Buf; const BufSize: Integer; const TotalSize: Int64; var OutDigest: T384BitDigest);
|
|
begin
|
|
SHA512FinalBuf(Digest, Buf, BufSize, TotalSize);
|
|
Move(Digest, OutDigest, SizeOf(OutDigest));
|
|
end;
|
|
|
|
function CalcSHA384(const Buf; const BufSize: Integer): T384BitDigest;
|
|
var I, J : Integer;
|
|
P : PByte;
|
|
D : T512BitDigest;
|
|
begin
|
|
SHA384InitDigest(D);
|
|
P := @Buf;
|
|
if BufSize <= 0 then
|
|
I := 0 else
|
|
I := BufSize;
|
|
J := (I div 128) * 128;
|
|
if J > 0 then
|
|
begin
|
|
SHA384Buf(D, P^, J);
|
|
Inc(P, J);
|
|
Dec(I, J);
|
|
end;
|
|
SHA384FinalBuf(D, P^, I, BufSize, Result);
|
|
end;
|
|
|
|
function CalcSHA384(const Buf: RawByteString): T384BitDigest;
|
|
begin
|
|
Result := CalcSHA384(Pointer(Buf)^, Length(Buf));
|
|
end;
|
|
|
|
function SHA384DigestToStrA(const Digest: T384BitDigest): RawByteString;
|
|
begin
|
|
SetLength(Result, Sizeof(Digest));
|
|
Move(Digest, Pointer(Result)^, Sizeof(Digest));
|
|
end;
|
|
|
|
function SHA384DigestToHexA(const Digest: T384BitDigest): RawByteString;
|
|
begin
|
|
Result := DigestToHexA(Digest, Sizeof(Digest));
|
|
end;
|
|
|
|
function SHA384DigestToHexW(const Digest: T384BitDigest): WideString;
|
|
begin
|
|
Result := DigestToHexW(Digest, Sizeof(Digest));
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ SHA512 Hashing }
|
|
{ }
|
|
procedure SHA512InitDigest(var Digest: T512BitDigest);
|
|
begin
|
|
Digest.Word64s[0].LongWords[0] := $f3bcc908;
|
|
Digest.Word64s[0].LongWords[1] := $6a09e667;
|
|
Digest.Word64s[1].LongWords[0] := $84caa73b;
|
|
Digest.Word64s[1].LongWords[1] := $bb67ae85;
|
|
Digest.Word64s[2].LongWords[0] := $fe94f82b;
|
|
Digest.Word64s[2].LongWords[1] := $3c6ef372;
|
|
Digest.Word64s[3].LongWords[0] := $5f1d36f1;
|
|
Digest.Word64s[3].LongWords[1] := $a54ff53a;
|
|
Digest.Word64s[4].LongWords[0] := $ade682d1;
|
|
Digest.Word64s[4].LongWords[1] := $510e527f;
|
|
Digest.Word64s[5].LongWords[0] := $2b3e6c1f;
|
|
Digest.Word64s[5].LongWords[1] := $9b05688c;
|
|
Digest.Word64s[6].LongWords[0] := $fb41bd6b;
|
|
Digest.Word64s[6].LongWords[1] := $1f83d9ab;
|
|
Digest.Word64s[7].LongWords[0] := $137e2179;
|
|
Digest.Word64s[7].LongWords[1] := $5be0cd19;
|
|
end;
|
|
|
|
// BSIG0(x) = ROTR^28(x) XOR ROTR^34(x) XOR ROTR^39(x)
|
|
function SHA512Transform1(const A: Word64): Word64;
|
|
var T1, T2, T3 : Word64;
|
|
begin
|
|
T1 := A;
|
|
T2 := A;
|
|
T3 := A;
|
|
Word64Ror(T1, 28);
|
|
Word64Ror(T2, 34);
|
|
Word64Ror(T3, 39);
|
|
Word64XorWord64(T1, T2);
|
|
Word64XorWord64(T1, T3);
|
|
Result := T1;
|
|
end;
|
|
|
|
// BSIG1(x) = ROTR^14(x) XOR ROTR^18(x) XOR ROTR^41(x)
|
|
function SHA512Transform2(const A: Word64): Word64;
|
|
var T1, T2, T3 : Word64;
|
|
begin
|
|
T1 := A;
|
|
T2 := A;
|
|
T3 := A;
|
|
Word64Ror(T1, 14);
|
|
Word64Ror(T2, 18);
|
|
Word64Ror(T3, 41);
|
|
Word64XorWord64(T1, T2);
|
|
Word64XorWord64(T1, T3);
|
|
Result := T1;
|
|
end;
|
|
|
|
// SSIG0(x) = ROTR^1(x) XOR ROTR^8(x) XOR SHR^7(x)
|
|
function SHA512Transform3(const A: Word64): Word64;
|
|
var T1, T2, T3 : Word64;
|
|
begin
|
|
T1 := A;
|
|
T2 := A;
|
|
T3 := A;
|
|
Word64Ror(T1, 1);
|
|
Word64Ror(T2, 8);
|
|
Word64Shr(T3, 7);
|
|
Word64XorWord64(T1, T2);
|
|
Word64XorWord64(T1, T3);
|
|
Result := T1;
|
|
end;
|
|
|
|
// SSIG1(x) = ROTR^19(x) XOR ROTR^61(x) XOR SHR^6(x)
|
|
function SHA512Transform4(const A: Word64): Word64;
|
|
var T1, T2, T3 : Word64;
|
|
begin
|
|
T1 := A;
|
|
T2 := A;
|
|
T3 := A;
|
|
Word64Ror(T1, 19);
|
|
Word64Ror(T2, 61);
|
|
Word64Shr(T3, 6);
|
|
Word64XorWord64(T1, T2);
|
|
Word64XorWord64(T1, T3);
|
|
Result := T1;
|
|
end;
|
|
|
|
// CH( x, y, z) = (x AND y) XOR ( (NOT x) AND z)
|
|
function SHA512Transform5(const X, Y, Z: Word64): Word64;
|
|
var T1, T2 : Word64;
|
|
begin
|
|
T1 := X;
|
|
Word64AndWord64(T1, Y);
|
|
T2 := X;
|
|
Word64Not(T2);
|
|
Word64AndWord64(T2, Z);
|
|
Word64XorWord64(T1, T2);
|
|
Result := T1;
|
|
end;
|
|
|
|
// MAJ( x, y, z) = (x AND y) XOR (x AND z) XOR (y AND z)
|
|
function SHA512Transform6(const X, Y, Z: Word64): Word64;
|
|
var T1, T2, T3 : Word64;
|
|
begin
|
|
T1 := X;
|
|
Word64AndWord64(T1, Y);
|
|
T2 := X;
|
|
Word64AndWord64(T2, Z);
|
|
T3 := Y;
|
|
Word64AndWord64(T3, Z);
|
|
Word64XorWord64(T1, T2);
|
|
Word64XorWord64(T1, T3);
|
|
Result := T1;
|
|
end;
|
|
|
|
const
|
|
// first 64 bits of the fractional parts of the cube roots of the first eighty prime numbers
|
|
// (stored High LongWord first then Low LongWord)
|
|
SHA512K: array[0..159] of LongWord = (
|
|
$428a2f98, $d728ae22, $71374491, $23ef65cd, $b5c0fbcf, $ec4d3b2f, $e9b5dba5, $8189dbbc,
|
|
$3956c25b, $f348b538, $59f111f1, $b605d019, $923f82a4, $af194f9b, $ab1c5ed5, $da6d8118,
|
|
$d807aa98, $a3030242, $12835b01, $45706fbe, $243185be, $4ee4b28c, $550c7dc3, $d5ffb4e2,
|
|
$72be5d74, $f27b896f, $80deb1fe, $3b1696b1, $9bdc06a7, $25c71235, $c19bf174, $cf692694,
|
|
$e49b69c1, $9ef14ad2, $efbe4786, $384f25e3, $0fc19dc6, $8b8cd5b5, $240ca1cc, $77ac9c65,
|
|
$2de92c6f, $592b0275, $4a7484aa, $6ea6e483, $5cb0a9dc, $bd41fbd4, $76f988da, $831153b5,
|
|
$983e5152, $ee66dfab, $a831c66d, $2db43210, $b00327c8, $98fb213f, $bf597fc7, $beef0ee4,
|
|
$c6e00bf3, $3da88fc2, $d5a79147, $930aa725, $06ca6351, $e003826f, $14292967, $0a0e6e70,
|
|
$27b70a85, $46d22ffc, $2e1b2138, $5c26c926, $4d2c6dfc, $5ac42aed, $53380d13, $9d95b3df,
|
|
$650a7354, $8baf63de, $766a0abb, $3c77b2a8, $81c2c92e, $47edaee6, $92722c85, $1482353b,
|
|
$a2bfe8a1, $4cf10364, $a81a664b, $bc423001, $c24b8b70, $d0f89791, $c76c51a3, $0654be30,
|
|
$d192e819, $d6ef5218, $d6990624, $5565a910, $f40e3585, $5771202a, $106aa070, $32bbd1b8,
|
|
$19a4c116, $b8d2d0c8, $1e376c08, $5141ab53, $2748774c, $df8eeb99, $34b0bcb5, $e19b48a8,
|
|
$391c0cb3, $c5c95a63, $4ed8aa4a, $e3418acb, $5b9cca4f, $7763e373, $682e6ff3, $d6b2b8a3,
|
|
$748f82ee, $5defb2fc, $78a5636f, $43172f60, $84c87814, $a1f0ab72, $8cc70208, $1a6439ec,
|
|
$90befffa, $23631e28, $a4506ceb, $de82bde9, $bef9a3f7, $b2c67915, $c67178f2, $e372532b,
|
|
$ca273ece, $ea26619c, $d186b8c7, $21c0c207, $eada7dd6, $cde0eb1e, $f57d4f7f, $ee6ed178,
|
|
$06f067aa, $72176fba, $0a637dc5, $a2c898a6, $113f9804, $bef90dae, $1b710b35, $131c471b,
|
|
$28db77f5, $23047d84, $32caab7b, $40c72493, $3c9ebe0a, $15c9bebc, $431d67c4, $9c100d4c,
|
|
$4cc5d4be, $cb3e42b6, $597f299c, $fc657e2a, $5fcb6fab, $3ad6faec, $6c44198c, $4a475817
|
|
);
|
|
|
|
{$IFOPT Q+}{$DEFINE QOn}{$Q-}{$ELSE}{$UNDEF QOn}{$ENDIF}
|
|
procedure TransformSHA512Buffer(var Digest: T512BitDigest; const Buf);
|
|
var
|
|
I : Integer;
|
|
P : PWord64;
|
|
W : array[0..79] of Word64;
|
|
T1, T2, T3, T4, K : Word64;
|
|
H : array[0..7] of Word64;
|
|
begin
|
|
P := @Buf;
|
|
for I := 0 to 15 do
|
|
begin
|
|
W[I] := P^;
|
|
Word64SwapEndian(W[I]);
|
|
Inc(P);
|
|
end;
|
|
for I := 16 to 79 do
|
|
begin
|
|
T1 := SHA512Transform4(W[I - 2]);
|
|
T2 := W[I - 7];
|
|
T3 := SHA512Transform3(W[I - 15]); // bug in RFC (specifies I-5 instead of W[I-5])
|
|
T4 := W[I - 16];
|
|
Word64AddWord64(T1, T2);
|
|
Word64AddWord64(T1, T3);
|
|
Word64AddWord64(T1, T4);
|
|
W[I] := T1;
|
|
end;
|
|
for I := 0 to 7 do
|
|
H[I] := Digest.Word64s[I];
|
|
for I := 0 to 79 do
|
|
begin
|
|
// T1 = h + BSIG1(e) + CH(e,f,g) + Kt + Wt
|
|
T1 := H[7];
|
|
Word64AddWord64(T1, SHA512Transform2(H[4]));
|
|
Word64AddWord64(T1, SHA512Transform5(H[4], H[5], H[6]));
|
|
K.LongWords[0] := SHA512K[I * 2 + 1];
|
|
K.LongWords[1] := SHA512K[I * 2];
|
|
Word64AddWord64(T1, K);
|
|
Word64AddWord64(T1, W[I]);
|
|
// T2 = BSIG0(a) + MAJ(a,b,c)
|
|
T2 := SHA512Transform1(H[0]);
|
|
Word64AddWord64(T2, SHA512Transform6(H[0], H[1], H[2]));
|
|
// h = g g = f
|
|
// f = e e = d + T1
|
|
// d = c c = b
|
|
// b = a a = T1 + T2
|
|
H[7] := H[6];
|
|
H[6] := H[5];
|
|
H[5] := H[4];
|
|
H[4] := H[3];
|
|
Word64AddWord64(H[4], T1);
|
|
H[3] := H[2];
|
|
H[2] := H[1];
|
|
H[1] := H[0];
|
|
H[0] := T1;
|
|
Word64AddWord64(H[0], T2);
|
|
end;
|
|
for I := 0 to 7 do
|
|
Word64AddWord64(Digest.Word64s[I], H[I]);
|
|
end;
|
|
{$IFDEF QOn}{$Q+}{$ENDIF}
|
|
|
|
procedure SHA512Buf(var Digest: T512BitDigest; const Buf; const BufSize: Integer);
|
|
var P : PByte;
|
|
I, J : Integer;
|
|
begin
|
|
I := BufSize;
|
|
if I <= 0 then
|
|
exit;
|
|
Assert(I mod 128 = 0, 'BufSize must be multiple of 128 bytes');
|
|
P := @Buf;
|
|
for J := 0 to I div 128 - 1 do
|
|
begin
|
|
TransformSHA512Buffer(Digest, P^);
|
|
Inc(P, 128);
|
|
end;
|
|
end;
|
|
|
|
procedure SHA512FinalBuf(var Digest: T512BitDigest; const Buf; const BufSize: Integer; const TotalSize: Int64);
|
|
var B1, B2 : T1024BitBuf;
|
|
C : Integer;
|
|
begin
|
|
StdFinalBuf1024(Buf, BufSize, TotalSize, B1, B2, C, True);
|
|
TransformSHA512Buffer(Digest, B1);
|
|
if C > 1 then
|
|
TransformSHA512Buffer(Digest, B2);
|
|
SwapEndianBuf64(Digest, Sizeof(Digest) div Sizeof(Word64));
|
|
SecureClear1024(B1);
|
|
if C > 1 then
|
|
SecureClear1024(B2);
|
|
end;
|
|
|
|
function CalcSHA512(const Buf; const BufSize: Integer): T512BitDigest;
|
|
var I, J : Integer;
|
|
P : PByte;
|
|
begin
|
|
SHA512InitDigest(Result);
|
|
P := @Buf;
|
|
if BufSize <= 0 then
|
|
I := 0 else
|
|
I := BufSize;
|
|
J := (I div 128) * 128;
|
|
if J > 0 then
|
|
begin
|
|
SHA512Buf(Result, P^, J);
|
|
Inc(P, J);
|
|
Dec(I, J);
|
|
end;
|
|
SHA512FinalBuf(Result, P^, I, BufSize);
|
|
end;
|
|
|
|
function CalcSHA512(const Buf: RawByteString): T512BitDigest;
|
|
begin
|
|
Result := CalcSHA512(Pointer(Buf)^, Length(Buf));
|
|
end;
|
|
|
|
function SHA512DigestToStrA(const Digest: T512BitDigest): RawByteString;
|
|
begin
|
|
SetLength(Result, Sizeof(Digest));
|
|
Move(Digest, Pointer(Result)^, Sizeof(Digest));
|
|
end;
|
|
|
|
function SHA512DigestToHexA(const Digest: T512BitDigest): RawByteString;
|
|
begin
|
|
Result := DigestToHexA(Digest, Sizeof(Digest));
|
|
end;
|
|
|
|
function SHA512DigestToHexW(const Digest: T512BitDigest): WideString;
|
|
begin
|
|
Result := DigestToHexW(Digest, Sizeof(Digest));
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ RIPEMD160 }
|
|
{ 160 bit RIPEMD. }
|
|
{ }
|
|
|
|
// f(j, x, y, z) = x XOR y XOR z (0 <= j <= 15)
|
|
function RipeMD_F1(const X, Y, Z: LongWord): LongWord;
|
|
begin
|
|
Result := X xor Y xor Z;
|
|
end;
|
|
|
|
// f(j, x, y, z) = (x AND y) OR (NOT(x) AND z) (16 <= j <= 31)
|
|
function RipeMD_F2(const X, Y, Z: LongWord): LongWord;
|
|
begin
|
|
Result := (X and Y) or ((not X) and Z);
|
|
end;
|
|
|
|
// f(j, x, y, z) = (x OR NOT(y)) XOR z (32 <= j <= 47)
|
|
function RipeMD_F3(const X, Y, Z: LongWord): LongWord;
|
|
begin
|
|
Result := (X or (not Y)) xor Z;
|
|
end;
|
|
|
|
// f(j, x, y, z) = (x AND z) OR (y AND NOT(z)) (48 <= j <= 63)
|
|
function RipeMD_F4(const X, Y, Z: LongWord): LongWord;
|
|
begin
|
|
Result := (X and Z) or (Y and (not Z));
|
|
end;
|
|
|
|
// f(j, x, y, z) = x XOR (y OR NOT(z)) (64 <= j <= 79)
|
|
function RipeMD_F5(const X, Y, Z: LongWord): LongWord;
|
|
begin
|
|
Result := X xor (Y or (not Z));
|
|
end;
|
|
|
|
// f(j, x, y, z)
|
|
function RipeMD_F(const J: Byte; const X, Y, Z: LongWord): LongWord;
|
|
begin
|
|
case J of
|
|
0..15 : Result := RipeMD_F1(X, Y, Z);
|
|
16..31 : Result := RipeMD_F2(X, Y, Z);
|
|
32..47 : Result := RipeMD_F3(X, Y, Z);
|
|
48..63 : Result := RipeMD_F4(X, Y, Z);
|
|
64..79 : Result := RipeMD_F5(X, Y, Z);
|
|
else
|
|
raise EHashError.Create(hashInternalError, 'Internal error');
|
|
end;
|
|
end;
|
|
|
|
const
|
|
// K(j) = 0x00000000 (0 <= j <= 15)
|
|
// K(j) = 0x5A827999 (16 <= j <= 31) int(2**30 x sqrt(2))
|
|
// K(j) = 0x6ED9EBA1 (32 <= j <= 47) int(2**30 x sqrt(3))
|
|
// K(j) = 0x8F1BBCDC (48 <= j <= 63) int(2**30 x sqrt(5))
|
|
// K(j) = 0xA953FD4E (64 <= j <= 79) int(2**30 x sqrt(7))
|
|
RipeMD_K : array[0..4] of LongWord = (
|
|
$00000000,
|
|
$5A827999,
|
|
$6ED9EBA1,
|
|
$8F1BBCDC,
|
|
$A953FD4E );
|
|
|
|
// K'(j) = 0x50A28BE6 (0 <= j <= 15) int(2**30 x cbrt(2))
|
|
// K'(j) = 0x5C4DD124 (16 <= j <= 31) int(2**30 x cbrt(3))
|
|
// K'(j) = 0x6D703EF3 (32 <= j <= 47) int(2**30 x cbrt(5))
|
|
// K'(j) = 0x7A6D76E9 (48 <= j <= 63) int(2**30 x cbrt(7))
|
|
// K'(j) = 0x00000000 (64 <= j <= 79)
|
|
RipeMD_KP : array[0..4] of LongWord = (
|
|
$50A28BE6,
|
|
$5C4DD124,
|
|
$6D703EF3,
|
|
$7A6D76E9,
|
|
$00000000 );
|
|
|
|
// r(j) = j (0 <= j <= 15)
|
|
// r(16..31) = 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8
|
|
// r(32..47) = 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12
|
|
// r(48..63) = 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2
|
|
// r(64..79) = 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13
|
|
RipeMD_R : array[0..79] of Byte = (
|
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
|
7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
|
|
3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
|
|
1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
|
|
4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13 );
|
|
|
|
// r'(0..15) = 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12
|
|
// r'(16..31)= 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2
|
|
// r'(32..47)= 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13
|
|
// r'(48..63)= 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14
|
|
// r'(64..79)= 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11
|
|
RipeMD_RP : array[0..79] of Byte = (
|
|
5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
|
|
6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
|
|
15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
|
|
8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
|
|
12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11 );
|
|
|
|
// s(0..15) = 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8
|
|
// s(16..31) = 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12
|
|
// s(32..47) = 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5
|
|
// s(48..63) = 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12
|
|
// s(64..79) = 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6
|
|
RipeMD_S : array[0..79] of Byte = (
|
|
11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
|
|
7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
|
|
11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
|
|
11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
|
|
9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6 );
|
|
|
|
// s'(0..15) = 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6
|
|
// s'(16..31)= 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11
|
|
// s'(32..47)= 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5
|
|
// s'(48..63)= 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8
|
|
// s'(64..79)= 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11
|
|
RipeMD_SP : array[0..79] of Byte = (
|
|
8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
|
|
9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
|
|
9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
|
|
15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
|
|
8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11 );
|
|
|
|
// Pascal version of:
|
|
// function Word32Add(const A, B: LongWord): LongWord; assembler;
|
|
// asm
|
|
// ADD EAX, EDX
|
|
// end;
|
|
//
|
|
// Temporary turn Q off as an optimisation since Word32Add is frequently used
|
|
// and it can never overflow in any case
|
|
{$IFOPT Q+}{$DEFINE QOn}{$Q-}{$ELSE}{$UNDEF QOn}{$ENDIF}
|
|
function Word32Add(const A, B: LongWord): LongWord; {$IFDEF UseInline}inline;{$ENDIF}
|
|
var R : Int64;
|
|
begin
|
|
R := Int64(A) + Int64(B);
|
|
Result := LongWord(R and $FFFFFFFF);
|
|
end;
|
|
{$IFDEF QOn}{$Q+}{$ENDIF}
|
|
|
|
type
|
|
TRipeMD160Block = array[0..15] of LongWord;
|
|
PRipeMD160Block = ^TRipeMD160Block;
|
|
|
|
(*
|
|
It is assumed that the message after padding consists of t 16-word blocks
|
|
that will be denoted with X[i][j], with 0 <= i <= t-1 and 0 <= j <= 15.
|
|
The symbol [+] denotes addition modulo 2**32 and rol_s denotes cyclic left
|
|
shift (rotate) over s positions.
|
|
A := h0; B := h1; C := h2; D = h3; E = h4;
|
|
A' := h0; B' := h1; C' := h2; D' = h3; E' = h4;
|
|
for j := 0 to 79 {
|
|
T := rol_s(j)(A [+] f(j, B, C, D) [+] X[i][r(j)] [+] K(j)) [+] E;
|
|
A := E; E := D; D := rol_10(C); C := B; B := T;
|
|
T := rol_s'(j)(A' [+] f(79-j, B', C', D') [+] X[i][r'(j)] [+] K'(j)) [+] E';
|
|
A' := E'; E' := D'; D' := rol_10(C'); C' := B'; B' := T;
|
|
}
|
|
T := h1 [+] C [+] D'; h1 := h2 [+] D [+] E'; h2 := h3 [+] E [+] A';
|
|
h3 := h4 [+] A [+] B'; h4 := h0 [+] B [+] C'; h0 := T;
|
|
*)
|
|
procedure RipeMD160Block(var Digest: T160BitDigest; const Block: TRipeMD160Block);
|
|
var
|
|
H0, H1, H2, H3, H4 : LongWord;
|
|
A, B, C, D, E : LongWord;
|
|
AP, BP, CP, DP, EP : LongWord;
|
|
J, J16 : Byte;
|
|
T : LongWord;
|
|
begin
|
|
H0 := Digest.Longs[0];
|
|
H1 := Digest.Longs[1];
|
|
H2 := Digest.Longs[2];
|
|
H3 := Digest.Longs[3];
|
|
H4 := Digest.Longs[4];
|
|
|
|
// A := h0; B := h1; C := h2; D = h3; E = h4;
|
|
A := H0;
|
|
B := H1;
|
|
C := H2;
|
|
D := H3;
|
|
E := H4;
|
|
|
|
// A' := h0; B' := h1; C' := h2; D' = h3; E' = h4;
|
|
AP := H0;
|
|
BP := H1;
|
|
CP := H2;
|
|
DP := H3;
|
|
EP := H4;
|
|
|
|
for J := 0 to 79 do
|
|
begin
|
|
J16 := J div 16;
|
|
// T := rol_s(j)(A [+] f(j, B, C, D) [+] X[i][r(j)] [+] K(j)) [+] E;
|
|
T := Word32Add(A, RipeMD_F(J, B, C, D));
|
|
T := Word32Add(T, Block[RipeMD_R[J]]);
|
|
T := Word32Add(T, RipeMD_K[J16]);
|
|
T := RotateLeftBits(T, RipeMD_S[J]);
|
|
T := Word32Add(T, E);
|
|
// A := E; E := D; D := rol_10(C); C := B; B := T;
|
|
A := E;
|
|
E := D;
|
|
D := RotateLeftBits(C, 10);
|
|
C := B;
|
|
B := T;
|
|
// T := rol_s'(j)(A' [+] f(79-j, B', C', D') [+] X[i][r'(j)] [+] K'(j)) [+] E';
|
|
T := Word32Add(AP, RipeMD_F(79 - J, BP, CP, DP));
|
|
T := Word32Add(T, Block[RipeMD_RP[J]]);
|
|
T := Word32Add(T, RipeMD_KP[J16]);
|
|
T := RotateLeftBits(T, RipeMD_SP[J]);
|
|
T := Word32Add(T, EP);
|
|
// A' := E'; E' := D'; D' := rol_10(C'); C' := B'; B' := T;
|
|
AP := EP;
|
|
EP := DP;
|
|
DP := RotateLeftBits(CP, 10);
|
|
CP := BP;
|
|
BP := T;
|
|
end;
|
|
|
|
// T := h1 [+] C [+] D';
|
|
T := Word32Add(H1, C);
|
|
T := Word32Add(T, DP);
|
|
// h1 := h2 [+] D [+] E';
|
|
H1 := Word32Add(H2, D);
|
|
H1 := Word32Add(H1, EP);
|
|
// h2 := h3 [+] E [+] A';
|
|
H2 := Word32Add(H3, E);
|
|
H2 := Word32Add(H2, AP);
|
|
// h3 := h4 [+] A [+] B';
|
|
H3 := Word32Add(H4, A);
|
|
H3 := Word32Add(H3, BP);
|
|
// h4 := h0 [+] B [+] C';
|
|
H4 := Word32Add(H0, B);
|
|
H4 := Word32Add(H4, CP);
|
|
// h0 := T;
|
|
H0 := T;
|
|
|
|
Digest.Longs[0] := H0;
|
|
Digest.Longs[1] := H1;
|
|
Digest.Longs[2] := H2;
|
|
Digest.Longs[3] := H3;
|
|
Digest.Longs[4] := H4;
|
|
end;
|
|
|
|
// initial value (hexadecimal)
|
|
// h0 = 0x67452301; h1 = 0xEFCDAB89; h2 = 0x98BADCFE; h3 = 0x10325476; h4 = 0xC3D2E1F0;
|
|
procedure RipeMD160InitDigest(var Digest: T160BitDigest);
|
|
begin
|
|
Digest.Longs[0] := $67452301;
|
|
Digest.Longs[1] := $EFCDAB89;
|
|
Digest.Longs[2] := $98BADCFE;
|
|
Digest.Longs[3] := $10325476;
|
|
Digest.Longs[4] := $C3D2E1F0;
|
|
end;
|
|
|
|
procedure RipeMD160Buf(var Digest: T160BitDigest; const Buf; const BufSize: Integer);
|
|
var P : PRipeMD160Block;
|
|
I, J : Integer;
|
|
begin
|
|
I := BufSize;
|
|
if I <= 0 then
|
|
exit;
|
|
Assert(I mod 64 = 0, 'BufSize must be multiple of 64 bytes');
|
|
P := @Buf;
|
|
for J := 0 to I div 64 - 1 do
|
|
begin
|
|
RipeMD160Block(Digest, P^);
|
|
Inc(P);
|
|
end;
|
|
end;
|
|
|
|
procedure RipeMD160FinalBuf(var Digest: T160BitDigest; const Buf; const BufSize: Integer; const TotalSize: Int64);
|
|
var B1, B2 : T512BitBuf;
|
|
C : Integer;
|
|
begin
|
|
StdFinalBuf512(Buf, BufSize, TotalSize, B1, B2, C, False);
|
|
RipeMD160Block(Digest, PRipeMD160Block(@B1)^);
|
|
if C > 1 then
|
|
RipeMD160Block(Digest, PRipeMD160Block(@B2)^);
|
|
SecureClear512(B1);
|
|
if C > 1 then
|
|
SecureClear512(B2);
|
|
end;
|
|
|
|
function CalcRipeMD160(const Buf; const BufSize: Integer): T160BitDigest;
|
|
var I, J : Integer;
|
|
P : PByte;
|
|
begin
|
|
RipeMD160InitDigest(Result);
|
|
P := @Buf;
|
|
if BufSize <= 0 then
|
|
I := 0 else
|
|
I := BufSize;
|
|
J := (I div 64) * 64;
|
|
if J > 0 then
|
|
begin
|
|
RipeMD160Buf(Result, P^, J);
|
|
Inc(P, J);
|
|
Dec(I, J);
|
|
end;
|
|
RipeMD160FinalBuf(Result, P^, I, BufSize);
|
|
end;
|
|
|
|
function CalcRipeMD160(const Buf: RawByteString): T160BitDigest;
|
|
begin
|
|
Result := CalcRipeMD160(Pointer(Buf)^, Length(Buf));
|
|
end;
|
|
|
|
function RipeMD160DigestToStrA(const Digest: T160BitDigest): RawByteString;
|
|
begin
|
|
SetLength(Result, Sizeof(Digest));
|
|
Move(Digest, Pointer(Result)^, Sizeof(Digest));
|
|
end;
|
|
|
|
function RipeMD160DigestToHexA(const Digest: T160BitDigest): RawByteString;
|
|
begin
|
|
Result := DigestToHexA(Digest, Sizeof(Digest));
|
|
end;
|
|
|
|
function RipeMD160DigestToHexW(const Digest: T160BitDigest): WideString;
|
|
begin
|
|
Result := DigestToHexW(Digest, Sizeof(Digest));
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ HMAC utility functions }
|
|
{ }
|
|
procedure HMAC_KeyBlock512(const Key; const KeySize: Integer; var Buf: T512BitBuf);
|
|
var P : PAnsiChar;
|
|
begin
|
|
Assert(KeySize <= 64);
|
|
P := @Buf;
|
|
if KeySize > 0 then
|
|
begin
|
|
Move(Key, P^, KeySize);
|
|
Inc(P, KeySize);
|
|
end;
|
|
FillChar(P^, 64 - KeySize, #0);
|
|
end;
|
|
|
|
procedure HMAC_KeyBlock1024(const Key; const KeySize: Integer; var Buf: T1024BitBuf);
|
|
var P : PAnsiChar;
|
|
begin
|
|
Assert(KeySize <= 128);
|
|
P := @Buf;
|
|
if KeySize > 0 then
|
|
begin
|
|
Move(Key, P^, KeySize);
|
|
Inc(P, KeySize);
|
|
end;
|
|
FillChar(P^, 128 - KeySize, #0);
|
|
end;
|
|
|
|
procedure XORBlock512(var Buf: T512BitBuf; const XOR8: Byte);
|
|
var I : Integer;
|
|
P : PByte;
|
|
begin
|
|
P := @Buf;
|
|
for I := 0 to SizeOf(Buf) - 1 do
|
|
begin
|
|
P^ := P^ xor XOR8;
|
|
Inc(P);
|
|
end;
|
|
end;
|
|
|
|
procedure XORBlock1024(var Buf: T1024BitBuf; const XOR8: Byte);
|
|
var I : Integer;
|
|
P : PByte;
|
|
begin
|
|
P := @Buf;
|
|
for I := 0 to SizeOf(Buf) - 1 do
|
|
begin
|
|
P^ := P^ xor XOR8;
|
|
Inc(P);
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ HMAC-MD5 keyed hashing }
|
|
{ }
|
|
procedure HMAC_MD5Init(const Key: Pointer; const KeySize: Integer; var Digest: T128BitDigest; var K: T512BitBuf);
|
|
var S : T512BitBuf;
|
|
D : T128BitDigest;
|
|
begin
|
|
MD5InitDigest(Digest);
|
|
|
|
if KeySize > 64 then
|
|
begin
|
|
D := CalcMD5(Key^, KeySize);
|
|
HMAC_KeyBlock512(D, Sizeof(D), K);
|
|
end else
|
|
HMAC_KeyBlock512(Key^, KeySize, K);
|
|
|
|
Move(K, S, SizeOf(K));
|
|
XORBlock512(S, $36);
|
|
TransformMD5Buffer(Digest, S);
|
|
SecureClear512(S);
|
|
end;
|
|
|
|
procedure HMAC_MD5Buf(var Digest: T128BitDigest; const Buf; const BufSize: Integer);
|
|
begin
|
|
MD5Buf(Digest, Buf, BufSize);
|
|
end;
|
|
|
|
procedure HMAC_MD5FinalBuf(const K: T512BitBuf; var Digest: T128BitDigest; const Buf; const BufSize: Integer; const TotalSize: Int64);
|
|
var
|
|
FinBuf : packed record
|
|
K : T512BitBuf;
|
|
D : T128BitDigest;
|
|
end;
|
|
begin
|
|
MD5FinalBuf(Digest, Buf, BufSize, TotalSize + 64);
|
|
Move(K, FinBuf.K, SizeOf(K));
|
|
XORBlock512(FinBuf.K, $5C);
|
|
Move(Digest, FinBuf.D, SizeOf(Digest));
|
|
Digest := CalcMD5(FinBuf, SizeOf(FinBuf));
|
|
SecureClear(FinBuf, SizeOf(FinBuf));
|
|
end;
|
|
|
|
function CalcHMAC_MD5(const Key: Pointer; const KeySize: Integer; const Buf; const BufSize: Integer): T128BitDigest;
|
|
var I, J : Integer;
|
|
P : PByte;
|
|
K : T512BitBuf;
|
|
begin
|
|
HMAC_MD5Init(Key, KeySize, Result, K);
|
|
P := @Buf;
|
|
if BufSize <= 0 then
|
|
I := 0 else
|
|
I := BufSize;
|
|
J := (I div 64) * 64;
|
|
if J > 0 then
|
|
begin
|
|
HMAC_MD5Buf(Result, P^, J);
|
|
Inc(P, J);
|
|
Dec(I, J);
|
|
end;
|
|
HMAC_MD5FinalBuf(K, Result, P^, I, BufSize);
|
|
SecureClear512(K);
|
|
end;
|
|
|
|
function CalcHMAC_MD5(const Key: RawByteString; const Buf; const BufSize: Integer): T128BitDigest;
|
|
begin
|
|
Result := CalcHMAC_MD5(Pointer(Key), Length(Key), Buf, BufSize);
|
|
end;
|
|
|
|
function CalcHMAC_MD5(const Key, Buf: RawByteString): T128BitDigest;
|
|
begin
|
|
Result := CalcHMAC_MD5(Key, Pointer(Buf)^, Length(Buf));
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ HMAC-SHA1 keyed hashing }
|
|
{ }
|
|
procedure HMAC_SHA1Init(const Key: Pointer; const KeySize: Integer; var Digest: T160BitDigest; var K: T512BitBuf);
|
|
var D : T160BitDigest;
|
|
S : T512BitBuf;
|
|
begin
|
|
SHA1InitDigest(Digest);
|
|
|
|
if KeySize > 64 then
|
|
begin
|
|
D := CalcSHA1(Key^, KeySize);
|
|
HMAC_KeyBlock512(D, Sizeof(D), K);
|
|
end else
|
|
HMAC_KeyBlock512(Key^, KeySize, K);
|
|
|
|
Move(K, S, SizeOf(K));
|
|
XORBlock512(S, $36);
|
|
TransformSHABuffer(Digest, S, True);
|
|
SecureClear512(S);
|
|
end;
|
|
|
|
procedure HMAC_SHA1Buf(var Digest: T160BitDigest; const Buf; const BufSize: Integer);
|
|
begin
|
|
SHA1Buf(Digest, Buf, BufSize);
|
|
end;
|
|
|
|
procedure HMAC_SHA1FinalBuf(const K: T512BitBuf; var Digest: T160BitDigest; const Buf; const BufSize: Integer; const TotalSize: Int64);
|
|
var
|
|
FinBuf : packed record
|
|
K : T512BitBuf;
|
|
D : T160BitDigest;
|
|
end;
|
|
begin
|
|
SHA1FinalBuf(Digest, Buf, BufSize, TotalSize + 64);
|
|
Move(K, FinBuf.K, SizeOf(K));
|
|
XORBlock512(FinBuf.K, $5C);
|
|
Move(Digest, FinBuf.D, SizeOf(Digest));
|
|
Digest := CalcSHA1(FinBuf, SizeOf(FinBuf));
|
|
SecureClear(FinBuf, SizeOf(FinBuf));
|
|
end;
|
|
|
|
function CalcHMAC_SHA1(const Key: Pointer; const KeySize: Integer; const Buf; const BufSize: Integer): T160BitDigest;
|
|
var I, J : Integer;
|
|
P : PByte;
|
|
K : T512BitBuf;
|
|
begin
|
|
HMAC_SHA1Init(Key, KeySize, Result, K);
|
|
P := @Buf;
|
|
if BufSize <= 0 then
|
|
I := 0 else
|
|
I := BufSize;
|
|
J := (I div 64) * 64;
|
|
if J > 0 then
|
|
begin
|
|
HMAC_SHA1Buf(Result, P^, J);
|
|
Inc(P, J);
|
|
Dec(I, J);
|
|
end;
|
|
HMAC_SHA1FinalBuf(K, Result, P^, I, BufSize);
|
|
SecureClear512(K);
|
|
end;
|
|
|
|
function CalcHMAC_SHA1(const Key: RawByteString; const Buf; const BufSize: Integer): T160BitDigest;
|
|
begin
|
|
Result := CalcHMAC_SHA1(Pointer(Key), Length(Key), Buf, BufSize);
|
|
end;
|
|
|
|
function CalcHMAC_SHA1(const Key, Buf: RawByteString): T160BitDigest;
|
|
begin
|
|
Result := CalcHMAC_SHA1(Key, Pointer(Buf)^, Length(Buf));
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ HMAC-SHA256 keyed hashing }
|
|
{ }
|
|
procedure HMAC_SHA256Init(const Key: Pointer; const KeySize: Integer; var Digest: T256BitDigest; var K: T512BitBuf);
|
|
var D : T256BitDigest;
|
|
S : T512BitBuf;
|
|
begin
|
|
SHA256InitDigest(Digest);
|
|
|
|
if KeySize > 64 then
|
|
begin
|
|
D := CalcSHA256(Key^, KeySize);
|
|
HMAC_KeyBlock512(D, Sizeof(D), K);
|
|
end else
|
|
HMAC_KeyBlock512(Key^, KeySize, K);
|
|
|
|
Move(K, S, SizeOf(K));
|
|
XORBlock512(S, $36);
|
|
TransformSHA256Buffer(Digest, S);
|
|
SecureClear512(S);
|
|
end;
|
|
|
|
procedure HMAC_SHA256Buf(var Digest: T256BitDigest; const Buf; const BufSize: Integer);
|
|
begin
|
|
SHA256Buf(Digest, Buf, BufSize);
|
|
end;
|
|
|
|
procedure HMAC_SHA256FinalBuf(const K: T512BitBuf; var Digest: T256BitDigest; const Buf; const BufSize: Integer; const TotalSize: Int64);
|
|
var
|
|
FinBuf : packed record
|
|
K : T512BitBuf;
|
|
D : T256BitDigest;
|
|
end;
|
|
begin
|
|
SHA256FinalBuf(Digest, Buf, BufSize, TotalSize + 64);
|
|
Move(K, FinBuf.K, SizeOf(K));
|
|
XORBlock512(FinBuf.K, $5C);
|
|
Move(Digest, FinBuf.D, SizeOf(Digest));
|
|
Digest := CalcSHA256(FinBuf, SizeOf(FinBuf));
|
|
SecureClear(FinBuf, SizeOf(FinBuf));
|
|
end;
|
|
|
|
function CalcHMAC_SHA256(const Key: Pointer; const KeySize: Integer; const Buf; const BufSize: Integer): T256BitDigest;
|
|
var I, J : Integer;
|
|
P : PByte;
|
|
K : T512BitBuf;
|
|
begin
|
|
HMAC_SHA256Init(Key, KeySize, Result, K);
|
|
P := @Buf;
|
|
if BufSize <= 0 then
|
|
I := 0 else
|
|
I := BufSize;
|
|
J := (I div 64) * 64;
|
|
if J > 0 then
|
|
begin
|
|
HMAC_SHA256Buf(Result, P^, J);
|
|
Inc(P, J);
|
|
Dec(I, J);
|
|
end;
|
|
HMAC_SHA256FinalBuf(K, Result, P^, I, BufSize);
|
|
SecureClear512(K);
|
|
end;
|
|
|
|
function CalcHMAC_SHA256(const Key: RawByteString; const Buf; const BufSize: Integer): T256BitDigest;
|
|
begin
|
|
Result := CalcHMAC_SHA256(Pointer(Key), Length(Key), Buf, BufSize);
|
|
end;
|
|
|
|
function CalcHMAC_SHA256(const Key, Buf: RawByteString): T256BitDigest;
|
|
begin
|
|
Result := CalcHMAC_SHA256(Key, Pointer(Buf)^, Length(Buf));
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ HMAC-SHA512 keyed hashing }
|
|
{ }
|
|
procedure HMAC_SHA512Init(const Key: Pointer; const KeySize: Integer; var Digest: T512BitDigest; var K: T1024BitBuf);
|
|
var D : T512BitDigest;
|
|
S : T1024BitBuf;
|
|
begin
|
|
SHA512InitDigest(Digest);
|
|
|
|
if KeySize > 128 then
|
|
begin
|
|
D := CalcSHA512(Key^, KeySize);
|
|
HMAC_KeyBlock1024(D, Sizeof(D), K);
|
|
end else
|
|
HMAC_KeyBlock1024(Key^, KeySize, K);
|
|
|
|
Move(K, S, SizeOf(K));
|
|
XORBlock1024(S, $36);
|
|
TransformSHA512Buffer(Digest, S);
|
|
SecureClear1024(S);
|
|
end;
|
|
|
|
procedure HMAC_SHA512Buf(var Digest: T512BitDigest; const Buf; const BufSize: Integer);
|
|
begin
|
|
SHA512Buf(Digest, Buf, BufSize);
|
|
end;
|
|
|
|
procedure HMAC_SHA512FinalBuf(const K: T1024BitBuf; var Digest: T512BitDigest; const Buf; const BufSize: Integer; const TotalSize: Int64);
|
|
var
|
|
FinBuf : packed record
|
|
K : T1024BitBuf;
|
|
D : T512BitDigest;
|
|
end;
|
|
begin
|
|
SHA512FinalBuf(Digest, Buf, BufSize, TotalSize + 128);
|
|
Move(K, FinBuf.K, SizeOf(K));
|
|
XORBlock1024(FinBuf.K, $5C);
|
|
Move(Digest, FinBuf.D, SizeOf(Digest));
|
|
Digest := CalcSHA512(FinBuf, SizeOf(FinBuf));
|
|
SecureClear(FinBuf, SizeOf(FinBuf));
|
|
end;
|
|
|
|
function CalcHMAC_SHA512(const Key: Pointer; const KeySize: Integer; const Buf; const BufSize: Integer): T512BitDigest;
|
|
var I, J : Integer;
|
|
P : PByte;
|
|
K : T1024BitBuf;
|
|
begin
|
|
HMAC_SHA512Init(Key, KeySize, Result, K);
|
|
P := @Buf;
|
|
if BufSize <= 0 then
|
|
I := 0 else
|
|
I := BufSize;
|
|
J := (I div 128) * 128;
|
|
if J > 0 then
|
|
begin
|
|
HMAC_SHA512Buf(Result, P^, J);
|
|
Inc(P, J);
|
|
Dec(I, J);
|
|
end;
|
|
HMAC_SHA512FinalBuf(K, Result, P^, I, BufSize);
|
|
SecureClear1024(K);
|
|
end;
|
|
|
|
function CalcHMAC_SHA512(const Key: RawByteString; const Buf; const BufSize: Integer): T512BitDigest;
|
|
begin
|
|
Result := CalcHMAC_SHA512(Pointer(Key), Length(Key), Buf, BufSize);
|
|
end;
|
|
|
|
function CalcHMAC_SHA512(const Key, Buf: RawByteString): T512BitDigest;
|
|
begin
|
|
Result := CalcHMAC_SHA512(Key, Pointer(Buf)^, Length(Buf));
|
|
end;
|
|
|
|
|
|
(*
|
|
|
|
|
|
{ }
|
|
{ Fuch512 }
|
|
{ Fundamentals adaptive complexity hash }
|
|
{ }
|
|
const
|
|
FUCH512_MaxComplexity = $FF;
|
|
|
|
type
|
|
TFuch512State = record
|
|
Complexity : Byte;
|
|
State : array[0..15] of T512BitDigest;
|
|
Digest : T512BitDigest;
|
|
end;
|
|
|
|
procedure Fuch512Digest_ExpandKey(
|
|
var Digest: T512BitDigest;
|
|
const Key: Pointer; const KeySize: Integer;
|
|
const Complexity: Byte;
|
|
const IterationIdx: Integer);
|
|
var P, Q : PByte;
|
|
I : Integer;
|
|
N : Byte;
|
|
begin
|
|
Assert(Assigned(Key));
|
|
Assert(KeySize >= 0);
|
|
Assert(IterationIdx <= 15);
|
|
// xor digest with key size, complexity value, iteration idx and key data
|
|
Digest.Longs[0] := LongWord(KeySize);
|
|
Digest.Bytes[5] := Complexity;
|
|
Digest.Bytes[6] := Byte(IterationIdx and $FF);
|
|
Q := Key;
|
|
for I := 0 to KeySize - 1 do
|
|
begin
|
|
N := (I + 6) mod 64;
|
|
P := @Digest.Bytes[N];
|
|
P^ := P^ xor Q^;
|
|
Inc(Q);
|
|
end;
|
|
end;
|
|
|
|
procedure Fuch512_ExpandKey(
|
|
var State: TFuch512State;
|
|
const Key: Pointer; const KeySize: Integer;
|
|
const Complexity: Byte);
|
|
var I : Integer;
|
|
begin
|
|
// expand key
|
|
for I := 0 to 15 do
|
|
Fuch512Digest_ExpandKey(State.State[I], Key, KeySize, Complexity, I);
|
|
// obfuscate
|
|
for I := 0 to 15 do
|
|
Digest512XOR32(State.State[I], SHA512K[I]);
|
|
// obfuscate more
|
|
Digest512XOR32(State.State[0], CalcCRC32(Key^, KeySize)); // CRC32 of key
|
|
Digest512XOR32(State.State[1], CRC32Table[Byte(KeySize mod 256)]); // CRC32 of key size
|
|
Digest512XOR32(State.State[2], CRC32Table[Byte(KeySize mod 3)]); // CRC32 of key size
|
|
Digest512XOR32(State.State[3], CRC32Table[Byte(KeySize mod 23)]); // CRC32 of key size
|
|
Digest512XOR32(State.State[4], CRC32Table[Byte(KeySize mod 251)]); // CRC32 of key size
|
|
Digest512XOR32(State.State[5], CRC32Table[Complexity]); // CRC32 of complexity value
|
|
Digest512XOR32(State.State[6], SHA512K[16 + (KeySize mod 3)]); // modified key size
|
|
Digest512XOR32(State.State[7], SHA512K[19 + (KeySize mod 5)]); // modified key size
|
|
Digest512XOR32(State.State[8], SHA512K[24 + (KeySize mod 7)]); // modified key size
|
|
Digest512XOR32(State.State[9], SHA512K[31 + (KeySize mod 33)]); // modified key size
|
|
Digest512XOR32(State.State[10], SHA512K[64 + (Complexity mod 32)]); // modified complexity value
|
|
Digest512XOR32(State.State[11], MD5Table_1[KeySize mod 3]); // modified key size
|
|
Digest512XOR32(State.State[12], MD5Table_1[KeySize mod 5]); // modified key size
|
|
Digest512XOR32(State.State[13], MD5Table_1[KeySize mod 16]); // modified key size
|
|
Digest512XOR32(State.State[14], MD5Table_2[Complexity mod 16]); // modified complexity
|
|
Digest512XOR32(State.State[15], MD5Table_2[Complexity mod 11]); // modified complexity
|
|
end;
|
|
|
|
procedure Fuch512_Init(
|
|
var State: TFuch512State;
|
|
const Key: Pointer; const KeySize: Integer;
|
|
const Complexity: Byte);
|
|
begin
|
|
FillChar(State, SizeOf(State), 0);
|
|
State.Complexity := Complexity;
|
|
SHA512InitDigest(State.Digest);
|
|
Fuch512_ExpandKey(State, Key, KeySize, Complexity);
|
|
// Post condition:
|
|
// State.Digest = fixed seed
|
|
// State.State = obfuscated key
|
|
end;
|
|
|
|
procedure Fuch512_Block(
|
|
var State: TFuch512State;
|
|
const Buf: T512BitBuf);
|
|
var Dig : T512BitDigest;
|
|
I : Integer;
|
|
begin
|
|
// hash state
|
|
Dig := CalcSHA512(State.State, SizeOf(State.State));
|
|
for I := 0 to 14 do
|
|
State.State[I] := State.State[I + 1];
|
|
State.State[15] := Dig;
|
|
// hash buffer
|
|
Dig := CalcSHA512(Buf, SizeOf(Buf));
|
|
for I := 0 to 14 do
|
|
State.State[I] := State.State[I + 1];
|
|
State.State[15] := Dig;
|
|
|
|
// hash state
|
|
State.Digest := CalcSHA512(State.State, SizeOf(State.State));
|
|
end;
|
|
|
|
procedure Fuch512_Buf(
|
|
var State: TFuch512State;
|
|
const Buf; const BufSize: Integer);
|
|
begin
|
|
end;
|
|
|
|
procedure Fuch512_FinalBuf(
|
|
var State: TFuch512State;
|
|
const Buf; const BufSize: Integer);
|
|
begin
|
|
end;
|
|
|
|
*)
|
|
|
|
|
|
|
|
|
|
{ }
|
|
{ CalculateHash }
|
|
{ }
|
|
procedure CalculateHash(const HashType: THashType;
|
|
const Buf; const BufSize: Integer;
|
|
const Digest: Pointer;
|
|
const Key: Pointer; const KeySize: Integer);
|
|
begin
|
|
if KeySize > 0 then
|
|
case HashType of
|
|
hashHMAC_MD5 : P128BitDigest(Digest)^ := CalcHMAC_MD5(Key, KeySize, Buf, BufSize);
|
|
hashHMAC_SHA1 : P160BitDigest(Digest)^ := CalcHMAC_SHA1(Key, KeySize, Buf, BufSize);
|
|
hashHMAC_SHA256 : P256BitDigest(Digest)^ := CalcHMAC_SHA256(Key, KeySize, Buf, BufSize);
|
|
hashHMAC_SHA512 : P512BitDigest(Digest)^ := CalcHMAC_SHA512(Key, KeySize, Buf, BufSize);
|
|
else
|
|
raise EHashError.Create(hashNotKeyedHashType);
|
|
end
|
|
else
|
|
case HashType of
|
|
hashChecksum32 : PLongWord(Digest)^ := CalcChecksum32(Buf, BufSize);
|
|
hashXOR8 : PByte(Digest)^ := CalcXOR8(Buf, BufSize);
|
|
hashXOR16 : PWord(Digest)^ := CalcXOR16(Buf, BufSize);
|
|
hashXOR32 : PLongWord(Digest)^ := CalcXOR32(Buf, BufSize);
|
|
hashCRC16 : PWord(Digest)^ := CalcCRC16(Buf, BufSize);
|
|
hashCRC32 : PLongWord(Digest)^ := CalcCRC32(Buf, BufSize);
|
|
hashMD5 : P128BitDigest(Digest)^ := CalcMD5(Buf, BufSize);
|
|
hashSHA1 : P160BitDigest(Digest)^ := CalcSHA1(Buf, BufSize);
|
|
hashSHA256 : P256BitDigest(Digest)^ := CalcSHA256(Buf, BufSize);
|
|
hashSHA512 : P512BitDigest(Digest)^ := CalcSHA512(Buf, BufSize);
|
|
hashRipeMD160 : P160BitDigest(Digest)^ := CalcRipeMD160(Buf, BufSize);
|
|
hashHMAC_MD5 : P128BitDigest(Digest)^ := CalcHMAC_MD5(nil, 0, Buf, BufSize);
|
|
hashHMAC_SHA1 : P160BitDigest(Digest)^ := CalcHMAC_SHA1(nil, 0, Buf, BufSize);
|
|
hashHMAC_SHA256 : P256BitDigest(Digest)^ := CalcHMAC_SHA256(nil, 0, Buf, BufSize);
|
|
hashHMAC_SHA512 : P512BitDigest(Digest)^ := CalcHMAC_SHA512(nil, 0, Buf, BufSize);
|
|
else
|
|
raise EHashError.Create(hashInvalidHashType);
|
|
end;
|
|
end;
|
|
|
|
procedure CalculateHash(const HashType: THashType; const Buf; const BufSize: Integer; const Digest: Pointer; const Key: RawByteString);
|
|
begin
|
|
CalculateHash(HashType, Buf, BufSize, Digest, Pointer(Key), Length(Key));
|
|
end;
|
|
|
|
procedure CalculateHash(const HashType: THashType; const Buf: RawByteString; const Digest: Pointer; const Key: RawByteString);
|
|
begin
|
|
CalculateHash(HashType, Pointer(Buf)^, Length(Buf), Digest, Key);
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ System helper functions }
|
|
{ }
|
|
resourcestring
|
|
SSystemError = 'System error #%s';
|
|
|
|
{$IFDEF MSWIN}
|
|
{$IFDEF StringIsUnicode}
|
|
function GetLastOSErrorMessage: String;
|
|
const MAX_ERRORMESSAGE_LENGTH = 256;
|
|
var Err: LongWord;
|
|
Buf: array[0..MAX_ERRORMESSAGE_LENGTH - 1] of Word;
|
|
Len: LongWord;
|
|
begin
|
|
Err := Windows.GetLastError;
|
|
FillChar(Buf, Sizeof(Buf), #0);
|
|
Len := Windows.FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, nil, Err, 0,
|
|
@Buf, MAX_ERRORMESSAGE_LENGTH, nil);
|
|
if Len = 0 then
|
|
Result := Format(SSystemError, [IntToStr(Err)])
|
|
else
|
|
Result := StrPas(PWideChar(@Buf));
|
|
end;
|
|
{$ELSE}
|
|
function GetLastOSErrorMessage: String;
|
|
const MAX_ERRORMESSAGE_LENGTH = 256;
|
|
var Err: LongWord;
|
|
Buf: array[0..MAX_ERRORMESSAGE_LENGTH - 1] of Byte;
|
|
Len: LongWord;
|
|
begin
|
|
Err := Windows.GetLastError;
|
|
FillChar(Buf, Sizeof(Buf), #0);
|
|
Len := Windows.FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nil, Err, 0,
|
|
@Buf, MAX_ERRORMESSAGE_LENGTH, nil);
|
|
if Len = 0 then
|
|
Result := Format(SSystemError, [IntToStr(Err)])
|
|
else
|
|
Result := StrPas(PAnsiChar(@Buf));
|
|
end;
|
|
{$ENDIF}
|
|
{$ELSE}
|
|
{$IFDEF UNIX}
|
|
{$IFDEF FREEPASCAL}
|
|
function GetLastOSErrorMessage: String;
|
|
begin
|
|
Result := SysErrorMessage(GetLastOSError);
|
|
end;
|
|
{$ELSE}
|
|
function GetLastOSErrorMessage: String;
|
|
var Err: LongWord;
|
|
Buf: array[0..1023] of AnsiChar;
|
|
begin
|
|
Err := BaseUnix.fpgeterrno;
|
|
FillChar(Buf, Sizeof(Buf), #0);
|
|
libc.strerror_r(Err, @Buf, SizeOf(Buf));
|
|
if Buf[0] = #0 then
|
|
Result := Format(SSystemError, [IntToStr(Err)])
|
|
else
|
|
Result := StrPas(@Buf);
|
|
end;
|
|
{$ENDIF}{$ENDIF}{$ENDIF}
|
|
|
|
|
|
|
|
{ }
|
|
{ AHash }
|
|
{ }
|
|
class function AHash.BlockSize: Integer;
|
|
begin
|
|
Result := -1;
|
|
end;
|
|
|
|
procedure AHash.ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64);
|
|
begin
|
|
ProcessBuf(Buf, BufSize);
|
|
end;
|
|
|
|
procedure AHash.Init(const Digest: Pointer; const Key: Pointer; const KeySize: Integer);
|
|
begin
|
|
Assert(Assigned(Digest));
|
|
FDigest := Digest;
|
|
FTotalSize := 0;
|
|
InitHash(Digest, Key, KeySize);
|
|
end;
|
|
|
|
procedure AHash.Init(const Digest: Pointer; const Key: RawByteString);
|
|
begin
|
|
Init(Digest, Pointer(Key), Length(Key));
|
|
end;
|
|
|
|
procedure AHash.HashBuf(const Buf; const BufSize: Integer; const FinalBuf: Boolean);
|
|
var I, D : Integer;
|
|
P : PAnsiChar;
|
|
begin
|
|
Inc(FTotalSize, BufSize);
|
|
|
|
D := BlockSize;
|
|
if D < 0 then
|
|
D := 64;
|
|
P := @Buf;
|
|
I := (BufSize div D) * D;
|
|
if I > 0 then
|
|
begin
|
|
ProcessBuf(P^, I);
|
|
Inc(P, I);
|
|
end;
|
|
|
|
I := BufSize mod D;
|
|
if FinalBuf then
|
|
ProcessFinalBuf(P^, I, FTotalSize)
|
|
else
|
|
if I > 0 then
|
|
raise EHashError.Create(hashInvalidBufferSize, 'Non final buffer must be multiple of block size');
|
|
end;
|
|
|
|
procedure AHash.HashFile(const FileName: String; const Offset: Int64; const MaxCount: Int64);
|
|
const ChunkSize = 8192;
|
|
var Handle : Integer;
|
|
Buf : Pointer;
|
|
I, C : Integer;
|
|
Left : Int64;
|
|
Fin : Boolean;
|
|
begin
|
|
if FileName = '' then
|
|
raise EHashError.Create(hashInvalidFileName);
|
|
Handle := FileOpen(FileName, fmOpenReadWrite or fmShareDenyNone);
|
|
if Handle = -1 then
|
|
raise EHashError.Create(hashFileOpenError, IntToStr(GetLastError));
|
|
if Offset > 0 then
|
|
I := FileSeek(Handle, Offset, 0) else
|
|
if Offset < 0 then
|
|
I := FileSeek(Handle, Offset, 2) else
|
|
I := 0;
|
|
if I = -1 then
|
|
raise EHashError.Create(hashFileSeekError, IntToStr(GetLastError));
|
|
try
|
|
GetMem(Buf, ChunkSize);
|
|
try
|
|
if MaxCount < 0 then
|
|
Left := High(Int64) else
|
|
Left := MaxCount;
|
|
repeat
|
|
if Left > ChunkSize then
|
|
C := ChunkSize else
|
|
C := Left;
|
|
if C = 0 then
|
|
begin
|
|
I := 0;
|
|
Fin := True;
|
|
end else
|
|
begin
|
|
I := FileRead(Handle, Buf^, C);
|
|
if I = -1 then
|
|
raise EHashError.Create(hashFileReadError, IntToStr(GetLastError));
|
|
Dec(Left, I);
|
|
Fin := (I < C) or (Left <= 0);
|
|
end;
|
|
HashBuf(Buf^, I, Fin);
|
|
until Fin;
|
|
finally
|
|
FreeMem(Buf, ChunkSize);
|
|
end;
|
|
finally
|
|
FileClose(Handle);
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ TChecksum32Hash }
|
|
{ }
|
|
procedure TChecksum32Hash.InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer);
|
|
begin
|
|
PLongWord(Digest)^ := 0;
|
|
end;
|
|
|
|
procedure TChecksum32Hash.ProcessBuf(const Buf; const BufSize: Integer);
|
|
begin
|
|
PLongWord(FDigest)^ := PLongWord(FDigest)^ + CalcChecksum32(Buf, BufSize);
|
|
end;
|
|
|
|
class function TChecksum32Hash.DigestSize: Integer;
|
|
begin
|
|
Result := 4;
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ TXOR8Hash }
|
|
{ }
|
|
procedure TXOR8Hash.InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer);
|
|
begin
|
|
PByte(Digest)^ := 0;
|
|
end;
|
|
|
|
procedure TXOR8Hash.ProcessBuf(const Buf; const BufSize: Integer);
|
|
begin
|
|
PByte(FDigest)^ := PByte(FDigest)^ xor CalcXOR8(Buf, BufSize);
|
|
end;
|
|
|
|
class function TXOR8Hash.DigestSize: Integer;
|
|
begin
|
|
Result := 1;
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ TXOR16Hash }
|
|
{ }
|
|
procedure TXOR16Hash.InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer);
|
|
begin
|
|
PWord(Digest)^ := 0;
|
|
end;
|
|
|
|
procedure TXOR16Hash.ProcessBuf(const Buf; const BufSize: Integer);
|
|
begin
|
|
PWord(FDigest)^ := PWord(FDigest)^ xor CalcXOR16(Buf, BufSize);
|
|
end;
|
|
|
|
class function TXOR16Hash.DigestSize: Integer;
|
|
begin
|
|
Result := 2;
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ TXOR32Hash }
|
|
{ }
|
|
procedure TXOR32Hash.InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer);
|
|
begin
|
|
PLongWord(Digest)^ := 0;
|
|
end;
|
|
|
|
procedure TXOR32Hash.ProcessBuf(const Buf; const BufSize: Integer);
|
|
begin
|
|
PLongWord(FDigest)^ := PLongWord(FDigest)^ xor CalcXOR32(Buf, BufSize);
|
|
end;
|
|
|
|
class function TXOR32Hash.DigestSize: Integer;
|
|
begin
|
|
Result := 4;
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ TCRC16Hash }
|
|
{ }
|
|
procedure TCRC16Hash.InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer);
|
|
begin
|
|
CRC16Init(PWord(Digest)^);
|
|
end;
|
|
|
|
procedure TCRC16Hash.ProcessBuf(const Buf; const BufSize: Integer);
|
|
begin
|
|
PWord(FDigest)^ := CRC16Buf(PWord(FDigest)^, Buf, BufSize);
|
|
end;
|
|
|
|
class function TCRC16Hash.DigestSize: Integer;
|
|
begin
|
|
Result := 2;
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ TCRC32Hash }
|
|
{ }
|
|
procedure TCRC32Hash.InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer);
|
|
begin
|
|
CRC32Init(PLongWord(Digest)^);
|
|
end;
|
|
|
|
procedure TCRC32Hash.ProcessBuf(const Buf; const BufSize: Integer);
|
|
begin
|
|
PLongWord(FDigest)^ := CRC32Buf(PLongWord(FDigest)^, Buf, BufSize);
|
|
end;
|
|
|
|
class function TCRC32Hash.DigestSize: Integer;
|
|
begin
|
|
Result := 4;
|
|
end;
|
|
|
|
|
|
{ }
|
|
{ TAdler32Hash }
|
|
{ }
|
|
procedure TAdler32Hash.InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer);
|
|
begin
|
|
Adler32Init(PLongWord(Digest)^);
|
|
end;
|
|
|
|
procedure TAdler32Hash.ProcessBuf(const Buf; const BufSize: Integer);
|
|
begin
|
|
PLongWord(FDigest)^ := Adler32Buf(PLongWord(FDigest)^, Buf, BufSize);
|
|
end;
|
|
|
|
class function TAdler32Hash.DigestSize: Integer;
|
|
begin
|
|
Result := 4;
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ TELFHash }
|
|
{ }
|
|
procedure TELFHash.InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer);
|
|
begin
|
|
ELFInit(PLongWord(Digest)^);
|
|
end;
|
|
|
|
procedure TELFHash.ProcessBuf(const Buf; const BufSize: Integer);
|
|
begin
|
|
PLongWord(FDigest)^ := ELFBuf(PLongWord(FDigest)^, Buf, BufSize);
|
|
end;
|
|
|
|
class function TELFHash.DigestSize: Integer;
|
|
begin
|
|
Result := 4;
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ TMD5Hash }
|
|
{ }
|
|
procedure TMD5Hash.InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer);
|
|
begin
|
|
MD5InitDigest(P128BitDigest(FDigest)^);
|
|
end;
|
|
|
|
procedure TMD5Hash.ProcessBuf(const Buf; const BufSize: Integer);
|
|
begin
|
|
MD5Buf(P128BitDigest(FDigest)^, Buf, BufSize);
|
|
end;
|
|
|
|
procedure TMD5Hash.ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64);
|
|
begin
|
|
MD5FinalBuf(P128BitDigest(FDigest)^, Buf, BufSize, TotalSize);
|
|
end;
|
|
|
|
class function TMD5Hash.DigestSize: Integer;
|
|
begin
|
|
Result := 16;
|
|
end;
|
|
|
|
class function TMD5Hash.BlockSize: Integer;
|
|
begin
|
|
Result := 64;
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ TSHA1Hash }
|
|
{ }
|
|
procedure TSHA1Hash.InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer);
|
|
begin
|
|
SHA1InitDigest(P160BitDigest(FDigest)^);
|
|
end;
|
|
|
|
procedure TSHA1Hash.ProcessBuf(const Buf; const BufSize: Integer);
|
|
begin
|
|
SHA1Buf(P160BitDigest(FDigest)^, Buf, BufSize);
|
|
end;
|
|
|
|
procedure TSHA1Hash.ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64);
|
|
begin
|
|
SHA1FinalBuf(P160BitDigest(FDigest)^, Buf, BufSize, TotalSize);
|
|
end;
|
|
|
|
class function TSHA1Hash.DigestSize: Integer;
|
|
begin
|
|
Result := 20;
|
|
end;
|
|
|
|
class function TSHA1Hash.BlockSize: Integer;
|
|
begin
|
|
Result := 64;
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ TSHA256Hash }
|
|
{ }
|
|
procedure TSHA256Hash.InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer);
|
|
begin
|
|
SHA256InitDigest(P256BitDigest(FDigest)^);
|
|
end;
|
|
|
|
procedure TSHA256Hash.ProcessBuf(const Buf; const BufSize: Integer);
|
|
begin
|
|
SHA256Buf(P256BitDigest(FDigest)^, Buf, BufSize);
|
|
end;
|
|
|
|
procedure TSHA256Hash.ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64);
|
|
begin
|
|
SHA256FinalBuf(P256BitDigest(FDigest)^, Buf, BufSize, TotalSize);
|
|
end;
|
|
|
|
class function TSHA256Hash.DigestSize: Integer;
|
|
begin
|
|
Result := 32;
|
|
end;
|
|
|
|
class function TSHA256Hash.BlockSize: Integer;
|
|
begin
|
|
Result := 64;
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ TSHA512Hash }
|
|
{ }
|
|
procedure TSHA512Hash.InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer);
|
|
begin
|
|
SHA512InitDigest(P512BitDigest(FDigest)^);
|
|
end;
|
|
|
|
procedure TSHA512Hash.ProcessBuf(const Buf; const BufSize: Integer);
|
|
begin
|
|
SHA512Buf(P512BitDigest(FDigest)^, Buf, BufSize);
|
|
end;
|
|
|
|
procedure TSHA512Hash.ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64);
|
|
begin
|
|
SHA512FinalBuf(P512BitDigest(FDigest)^, Buf, BufSize, TotalSize);
|
|
end;
|
|
|
|
class function TSHA512Hash.DigestSize: Integer;
|
|
begin
|
|
Result := 64;
|
|
end;
|
|
|
|
class function TSHA512Hash.BlockSize: Integer;
|
|
begin
|
|
Result := 128;
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ TRipeMD160Hash }
|
|
{ }
|
|
procedure TRipeMD160Hash.InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer);
|
|
begin
|
|
RipeMD160InitDigest(P160BitDigest(FDigest)^);
|
|
end;
|
|
|
|
procedure TRipeMD160Hash.ProcessBuf(const Buf; const BufSize: Integer);
|
|
begin
|
|
RipeMD160Buf(P160BitDigest(FDigest)^, Buf, BufSize);
|
|
end;
|
|
|
|
procedure TRipeMD160Hash.ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64);
|
|
begin
|
|
RipeMD160FinalBuf(P160BitDigest(FDigest)^, Buf, BufSize, TotalSize);
|
|
end;
|
|
|
|
class function TRipeMD160Hash.DigestSize: Integer;
|
|
begin
|
|
Result := 20;
|
|
end;
|
|
|
|
class function TRipeMD160Hash.BlockSize: Integer;
|
|
begin
|
|
Result := 64;
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ THMAC_MD5Hash }
|
|
{ }
|
|
destructor THMAC_MD5Hash.Destroy;
|
|
begin
|
|
SecureClear512(FKey);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure THMAC_MD5Hash.InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer);
|
|
begin
|
|
HMAC_MD5Init(Key, KeySize, P128BitDigest(FDigest)^, FKey);
|
|
end;
|
|
|
|
procedure THMAC_MD5Hash.ProcessBuf(const Buf; const BufSize: Integer);
|
|
begin
|
|
HMAC_MD5Buf(P128BitDigest(FDigest)^, Buf, BufSize);
|
|
end;
|
|
|
|
procedure THMAC_MD5Hash.ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64);
|
|
begin
|
|
HMAC_MD5FinalBuf(FKey, P128BitDigest(FDigest)^, Buf, BufSize, TotalSize);
|
|
end;
|
|
|
|
class function THMAC_MD5Hash.DigestSize: Integer;
|
|
begin
|
|
Result := 16;
|
|
end;
|
|
|
|
class function THMAC_MD5Hash.BlockSize: Integer;
|
|
begin
|
|
Result := 64;
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ THMAC_SHA1Hash }
|
|
{ }
|
|
destructor THMAC_SHA1Hash.Destroy;
|
|
begin
|
|
SecureClear512(FKey);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure THMAC_SHA1Hash.InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer);
|
|
begin
|
|
HMAC_SHA1Init(Key, KeySize, P160BitDigest(FDigest)^, FKey);
|
|
end;
|
|
|
|
procedure THMAC_SHA1Hash.ProcessBuf(const Buf; const BufSize: Integer);
|
|
begin
|
|
HMAC_SHA1Buf(P160BitDigest(FDigest)^, Buf, BufSize);
|
|
end;
|
|
|
|
procedure THMAC_SHA1Hash.ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64);
|
|
begin
|
|
HMAC_SHA1FinalBuf(FKey, P160BitDigest(FDigest)^, Buf, BufSize, TotalSize);
|
|
end;
|
|
|
|
class function THMAC_SHA1Hash.DigestSize: Integer;
|
|
begin
|
|
Result := 20;
|
|
end;
|
|
|
|
class function THMAC_SHA1Hash.BlockSize: Integer;
|
|
begin
|
|
Result := 64;
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ THMAC_SHA256Hash }
|
|
{ }
|
|
destructor THMAC_SHA256Hash.Destroy;
|
|
begin
|
|
SecureClear512(FKey);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure THMAC_SHA256Hash.InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer);
|
|
begin
|
|
HMAC_SHA256Init(Key, KeySize, P256BitDigest(FDigest)^, FKey);
|
|
end;
|
|
|
|
procedure THMAC_SHA256Hash.ProcessBuf(const Buf; const BufSize: Integer);
|
|
begin
|
|
HMAC_SHA256Buf(P256BitDigest(FDigest)^, Buf, BufSize);
|
|
end;
|
|
|
|
procedure THMAC_SHA256Hash.ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64);
|
|
begin
|
|
HMAC_SHA256FinalBuf(FKey, P256BitDigest(FDigest)^, Buf, BufSize, TotalSize);
|
|
end;
|
|
|
|
class function THMAC_SHA256Hash.DigestSize: Integer;
|
|
begin
|
|
Result := 32;
|
|
end;
|
|
|
|
class function THMAC_SHA256Hash.BlockSize: Integer;
|
|
begin
|
|
Result := 64;
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ THMAC_SHA512Hash }
|
|
{ }
|
|
destructor THMAC_SHA512Hash.Destroy;
|
|
begin
|
|
SecureClear1024(FKey);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure THMAC_SHA512Hash.InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer);
|
|
begin
|
|
HMAC_SHA512Init(Key, KeySize, P512BitDigest(FDigest)^, FKey);
|
|
end;
|
|
|
|
procedure THMAC_SHA512Hash.ProcessBuf(const Buf; const BufSize: Integer);
|
|
begin
|
|
HMAC_SHA512Buf(P512BitDigest(FDigest)^, Buf, BufSize);
|
|
end;
|
|
|
|
procedure THMAC_SHA512Hash.ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64);
|
|
begin
|
|
HMAC_SHA512FinalBuf(FKey, P512BitDigest(FDigest)^, Buf, BufSize, TotalSize);
|
|
end;
|
|
|
|
class function THMAC_SHA512Hash.DigestSize: Integer;
|
|
begin
|
|
Result := 64;
|
|
end;
|
|
|
|
class function THMAC_SHA512Hash.BlockSize: Integer;
|
|
begin
|
|
Result := 128;
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ HashString }
|
|
{ }
|
|
function HashString(const StrBuf: Pointer; const StrLength: Integer; const Slots: LongWord; const CaseSensitive: Boolean): LongWord;
|
|
var P : PAnsiChar;
|
|
I, J : Integer;
|
|
|
|
procedure CRC32StrBuf(const Size: Integer);
|
|
begin
|
|
if CaseSensitive then
|
|
Result := CRC32Buf(Result, P^, Size)
|
|
else
|
|
Result := CRC32BufNoCase(Result, P^, Size);
|
|
end;
|
|
|
|
begin
|
|
// Return 0 for an empty string
|
|
Result := 0;
|
|
if (StrLength <= 0) or not Assigned(StrBuf) then
|
|
exit;
|
|
|
|
if not CRC32TableInit then
|
|
InitCRC32Table;
|
|
Result := $FFFFFFFF;
|
|
P := StrBuf;
|
|
|
|
if StrLength <= 48 then // Hash everything for short strings
|
|
CRC32StrBuf(StrLength)
|
|
else
|
|
begin
|
|
// Hash first 16 bytes
|
|
CRC32StrBuf(16);
|
|
|
|
// Hash last 16 bytes
|
|
Inc(P, StrLength - 16);
|
|
CRC32StrBuf(16);
|
|
|
|
// Hash 16 bytes sampled from rest of string
|
|
I := (StrLength - 48) div 16;
|
|
P := StrBuf;
|
|
Inc(P, 16);
|
|
for J := 1 to 16 do
|
|
begin
|
|
CRC32StrBuf(1);
|
|
Inc(P, I + 1);
|
|
end;
|
|
end;
|
|
|
|
// Mod into slots
|
|
if (Slots <> 0) and (Slots <> High(LongWord)) then
|
|
Result := Result mod Slots;
|
|
end;
|
|
|
|
function HashString(const S: RawByteString; const Slots: LongWord; const CaseSensitive: Boolean): LongWord;
|
|
begin
|
|
Result := HashString(Pointer(S), Length(S), Slots, CaseSensitive);
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ Hash by THashType }
|
|
{ }
|
|
const
|
|
HashTypeClasses : array[THashType] of THashClass = (
|
|
TChecksum32Hash, TXOR8Hash, TXOR16Hash, TXOR32Hash,
|
|
TCRC16Hash, TCRC32Hash,
|
|
TAdler32Hash,
|
|
TELFHash,
|
|
TMD5Hash, TSHA1Hash, TSHA256Hash, TSHA512Hash, TRipeMD160Hash,
|
|
THMAC_MD5Hash, THMAC_SHA1Hash, THMAC_SHA256Hash, THMAC_SHA512Hash);
|
|
|
|
function GetHashClassByType(const HashType: THashType): THashClass;
|
|
begin
|
|
Result := HashTypeClasses[HashType];
|
|
end;
|
|
|
|
function GetDigestSize(const HashType: THashType): Integer;
|
|
begin
|
|
Result := GetHashClassByType(HashType).DigestSize;
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ Self testing code }
|
|
{ }
|
|
{$IFDEF HASH_SELFTEST}
|
|
{$ASSERTIONS ON}
|
|
procedure SelfTest;
|
|
const
|
|
QuickBrownFoxStr = 'The quick brown fox jumps over the lazy dog';
|
|
var
|
|
MillionA, TenThousandA : RawByteString;
|
|
S, T : RawByteString;
|
|
U : WideString;
|
|
begin
|
|
SetLength(S, 5);
|
|
FillChar(S[1], 5, #1);
|
|
SecureClearStrA(S);
|
|
Assert(S = '');
|
|
|
|
SetLength(U, 5);
|
|
FillChar(U[1], 10, #1);
|
|
SecureClearStrW(U);
|
|
Assert(U = '');
|
|
|
|
S := 'ABC';
|
|
SecureClearStrA(S);
|
|
|
|
U := 'ABC';
|
|
SecureClearStrW(U);
|
|
|
|
SetLength(MillionA, 1000000);
|
|
FillChar(MillionA[1], 1000000, Ord('a'));
|
|
SetLength(TenThousandA, 10000);
|
|
FillChar(TenThousandA[1], 10000, Ord('a'));
|
|
|
|
Assert(CalcChecksum32('') = 0);
|
|
Assert(CalcChecksum32('A') = 65);
|
|
Assert(CalcChecksum32('Fundamentals') = 1250);
|
|
|
|
Assert(CalcXOR8('') = 0);
|
|
Assert(CalcXOR8('A') = 65);
|
|
Assert(CalcXOR8('Fundamentals') = 52);
|
|
|
|
Assert(CalcXOR16('') = 0);
|
|
Assert(CalcXOR16('A') = 65);
|
|
Assert(CalcXOR16('AB') = $4241);
|
|
Assert(CalcXOR16('what do ya want for nothing?') = $1915);
|
|
Assert(CalcXOR16('Fundamentals') = $0034);
|
|
|
|
Assert(CalcXOR32('') = 0);
|
|
Assert(CalcXOR32('A') = 65);
|
|
Assert(CalcXOR32('ABCD') = $44434241);
|
|
Assert(CalcXOR32('what do ya want for nothing?') = $743B6D2E);
|
|
Assert(CalcXOR32('Fundamentals')= $79677953);
|
|
|
|
Assert(CalcCRC16('') = $FFFF);
|
|
Assert(CalcCRC16('what do ya want for nothing?') = $581A);
|
|
Assert(CalcCRC16('Fundamentals') = $0B48);
|
|
|
|
Assert(CalcCRC32('') = 0);
|
|
Assert(CalcCRC32('what do ya want for nothing?') = $6BC70A6C);
|
|
Assert(CalcCRC32('Fundamentals') = $C0488691);
|
|
|
|
Assert(CalcAdler32('Wikipedia') = $11E60398);
|
|
|
|
Assert(IsValidISBN('3880530025'));
|
|
|
|
Assert(IsValidLUHN('49927398716'));
|
|
|
|
Assert(HashString('Fundamentals', 0, False) = HashString('fundamentalS', 0, False));
|
|
|
|
Assert(WideString(MD5DigestToHexA(CalcMD5(''))) = MD5DigestToHexW(CalcMD5('')));
|
|
Assert(MD5DigestToHexA(CalcMD5('')) = 'd41d8cd98f00b204e9800998ecf8427e');
|
|
Assert(MD5DigestToHexA(CalcMD5('Delphi Fundamentals')) = 'ea98b65da23d19756d46a36faa481dd8');
|
|
|
|
Assert(WideString(SHA1DigestToHexA(CalcSHA1(''))) = SHA1DigestToHexW(CalcSHA1('')));
|
|
Assert(SHA1DigestToHexA(CalcSHA1('')) = 'da39a3ee5e6b4b0d3255bfef95601890afd80709');
|
|
Assert(SHA1DigestToHexA(CalcSHA1('Fundamentals')) = '052d8ad81d99f33b2eb06e6d194282b8675fb201');
|
|
Assert(SHA1DigestToHexA(CalcSHA1(QuickBrownFoxStr)) = '2fd4e1c67a2d28fced849ee1bb76e7391b93eb12');
|
|
Assert(SHA1DigestToHexA(CalcSHA1(TenThousandA)) = 'a080cbda64850abb7b7f67ee875ba068074ff6fe');
|
|
|
|
Assert(WideString(SHA224DigestToHexA(CalcSHA224(''))) = SHA224DigestToHexW(CalcSHA224('')));
|
|
Assert(SHA224DigestToHexA(CalcSHA224('')) = 'd14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f');
|
|
Assert(SHA224DigestToHexA(CalcSHA224('Fundamentals')) = '1cccba6b3c6b08494733efb3a77fe8baef5bf6eeae89ec303ef4660e');
|
|
Assert(SHA224DigestToHexA(CalcSHA224(QuickBrownFoxStr)) = '730e109bd7a8a32b1cb9d9a09aa2325d2430587ddbc0c38bad911525');
|
|
Assert(SHA224DigestToHexA(CalcSHA224(TenThousandA)) = '00568fba93e8718c2f7dcd82fa94501d59bb1bbcba2c7dc2ba5882db');
|
|
|
|
Assert(WideString(SHA256DigestToHexA(CalcSHA256(''))) = SHA256DigestToHexW(CalcSHA256('')));
|
|
Assert(SHA256DigestToHexA(CalcSHA256('')) = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855');
|
|
Assert(SHA256DigestToHexA(CalcSHA256('Fundamentals')) = '915ff7435daeac2f66aa866e59bf293f101b79403dbdde2b631fd37fa524f26b');
|
|
Assert(SHA256DigestToHexA(CalcSHA256(QuickBrownFoxStr)) = 'd7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592');
|
|
Assert(SHA256DigestToHexA(CalcSHA256(TenThousandA)) = '27dd1f61b867b6a0f6e9d8a41c43231de52107e53ae424de8f847b821db4b711');
|
|
Assert(SHA256DigestToHexA(CalcSHA256(MillionA)) = 'cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0');
|
|
|
|
Assert(WideString(SHA384DigestToHexA(CalcSHA384(''))) = SHA384DigestToHexW(CalcSHA384('')));
|
|
Assert(SHA384DigestToHexA(CalcSHA384('')) = '38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b');
|
|
Assert(SHA384DigestToHexA(CalcSHA384('Fundamentals')) = 'cf9380b7d2e0237296093a0f5f09066f0cea0742ba752a1e6c60aed92998eda2c86c1549879007a94e9d75a4a7bdb6e8');
|
|
Assert(SHA384DigestToHexA(CalcSHA384(QuickBrownFoxStr)) = 'ca737f1014a48f4c0b6dd43cb177b0afd9e5169367544c494011e3317dbf9a509cb1e5dc1e85a941bbee3d7f2afbc9b1');
|
|
Assert(SHA384DigestToHexA(CalcSHA384(TenThousandA)) = '2bca3b131bb7e922bcd1de98c44786d32e6b6b2993e69c4987edf9dd49711eb501f0e98ad248d839f6bf9e116e25a97c');
|
|
|
|
Assert(WideString(SHA512DigestToHexA(CalcSHA512(''))) = SHA512DigestToHexW(CalcSHA512('')));
|
|
Assert(SHA512DigestToHexA(CalcSHA512('')) = 'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e');
|
|
Assert(SHA512DigestToHexA(CalcSHA512('Fundamentals')) = 'f430fed95ff285843bc68a5e2a1ad8275d7c242a504a5d0b23deb7f8252774a132c3672aeeffa9bf5c25449e8905cdb6f89097a3c88f20a6e0d8945bf4310dd6');
|
|
Assert(SHA512DigestToHexA(CalcSHA512(QuickBrownFoxStr)) = '07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6');
|
|
Assert(SHA512DigestToHexA(CalcSHA512(TenThousandA)) = '0593036f4f479d2eb8078ca26b1d59321a86bdfcb04cb40043694f1eb0301b8acd20b936db3c916ebcc1b609400ffcf3fa8d569d7e39293855668645094baf0e');
|
|
|
|
Assert(MD5DigestToHexA(CalcHMAC_MD5('', '')) = '74e6f7298a9c2d168935f58c001bad88');
|
|
Assert(MD5DigestToHexA(CalcHMAC_MD5('', 'Delphi Fundamentals')) = 'b9da02d5f94bd6eac410708a72b05d9f');
|
|
Assert(MD5DigestToHexA(CalcHMAC_MD5('Delphi Fundamentals', '')) = 'a09f3300c236156d27f4d031db7e91ce');
|
|
Assert(MD5DigestToHexA(CalcHMAC_MD5('Delphi', 'Fundamentals')) = '1c4e8a481c2c781eb43ca58d9324c37d');
|
|
|
|
Assert(SHA1DigestToHexA(CalcHMAC_SHA1('', '')) = 'fbdb1d1b18aa6c08324b7d64b71fb76370690e1d');
|
|
Assert(SHA1DigestToHexA(CalcHMAC_SHA1('', QuickBrownFoxStr)) = '2ba7f707ad5f187c412de3106583c3111d668de8');
|
|
Assert(SHA1DigestToHexA(CalcHMAC_SHA1('Fundamentals', QuickBrownFoxStr)) = '8b52855bbd09842d4ac3e4ff4c574c1f87d63e0b');
|
|
Assert(SHA1DigestToHexA(CalcHMAC_SHA1('Fundamentals', '')) = '2208ce7279f26fcb90dbc1900019aa9b2b85456a');
|
|
Assert(SHA1DigestToHexA(CalcHMAC_SHA1('Fundamentals', TenThousandA)) = '2f9cf91c82963b54fdbc0a26149be0c1f29746dc');
|
|
Assert(SHA1DigestToHexA(CalcHMAC_SHA1(TenThousandA, TenThousandA)) = 'cf792cef5570b47f3e1272581a5af87e5715defd');
|
|
|
|
Assert(SHA256DigestToHexA(CalcHMAC_SHA256('', '')) = 'b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad');
|
|
Assert(SHA256DigestToHexA(CalcHMAC_SHA256('', QuickBrownFoxStr)) = 'fb011e6154a19b9a4c767373c305275a5a69e8b68b0b4c9200c383dced19a416');
|
|
Assert(SHA256DigestToHexA(CalcHMAC_SHA256('Fundamentals', QuickBrownFoxStr)) = '853b22d0aa389d8123452710b3d09ed7f0b5afe4114896bfeb8cfd8818963146');
|
|
Assert(SHA256DigestToHexA(CalcHMAC_SHA256('Fundamentals', '')) = '28659c86585404fe0e87255bc9a2244ff1d921d48f9c5f8b12b4b40a064a20a3');
|
|
Assert(SHA256DigestToHexA(CalcHMAC_SHA256('Fundamentals', TenThousandA)) = '42347405bf2a459054bd95af2c48e070275d0d701ee62108b385a6e925c43163');
|
|
Assert(SHA256DigestToHexA(CalcHMAC_SHA256(TenThousandA, TenThousandA)) = '6b7576a741bd2eb2c1c12017d5f4984108ce25a3a427a3d5f52ba93c0ac85e1f');
|
|
|
|
Assert(SHA512DigestToHexA(CalcHMAC_SHA512('', '')) = 'b936cee86c9f87aa5d3c6f2e84cb5a4239a5fe50480a6ec66b70ab5b1f4ac6730c6c515421b327ec1d69402e53dfb49ad7381eb067b338fd7b0cb22247225d47');
|
|
Assert(SHA512DigestToHexA(CalcHMAC_SHA512('', QuickBrownFoxStr)) = '1de78322e11d7f8f1035c12740f2b902353f6f4ac4233ae455baccdf9f37791566e790d5c7682aad5d3ceca2feff4d3f3fdfd9a140c82a66324e9442b8af71b6');
|
|
Assert(SHA512DigestToHexA(CalcHMAC_SHA512('Fundamentals', QuickBrownFoxStr)) = 'f0352dff9b8984fb5fcfdd95de7f9db3df990723a2d909b99faf8cd4ccb9a5b1b840282c190ad41e521eb662512782bb9bf0fb81589cc101bfdc625914b1d8ed');
|
|
Assert(SHA512DigestToHexA(CalcHMAC_SHA512('Fundamentals', '')) = 'affa539a93acbb675e638aceb0456806564f19bec219c0b6c61d2cd675c37dc3cb7ef4f14831d9638b23d617e6e5c57f586f1804502e4b0b45027a1ae2b254e1');
|
|
Assert(SHA512DigestToHexA(CalcHMAC_SHA512('Fundamentals', TenThousandA)) = 'd6e309c24d7fab8da9db0382f50051821df6966fb22121cebfbb2a6623e9849e05f3c9aeba1448353faffbc3b0e52e618efee36d22bf06b9117adc42b33892c2');
|
|
Assert(SHA512DigestToHexA(CalcHMAC_SHA512(TenThousandA, TenThousandA)) = 'aacebd574e32713a306598b27583de5e253743dea5d3bd3ed7603fa97e098c9197b76584bf23bb21be242e2dd659626f70a9af68a29e0584890dc3a13480b4a3');
|
|
|
|
// Test cases from RFC 2202
|
|
Assert(MD5DigestToHexA(CalcHMAC_MD5('Jefe', 'what do ya want for nothing?')) = '750c783e6ab0b503eaa86e310a5db738');
|
|
SetLength(S, 16); FillChar(Pointer(S)^, 16, #$0B);
|
|
Assert(MD5DigestToHexA(CalcHMAC_MD5(S, 'Hi There')) = '9294727a3638bb1c13f48ef8158bfc9d');
|
|
SetLength(S, 16); FillChar(Pointer(S)^, 16, #$AA);
|
|
SetLength(T, 50); FillChar(Pointer(T)^, 50, #$DD);
|
|
Assert(MD5DigestToHexA(CalcHMAC_MD5(S, T)) = '56be34521d144c88dbb8c733f0e8b3f6');
|
|
SetLength(S, 80); FillChar(Pointer(S)^, 80, #$AA);
|
|
Assert(MD5DigestToHexA(CalcHMAC_MD5(S, 'Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data')) = '6f630fad67cda0ee1fb1f562db3aa53e');
|
|
|
|
Assert(SHA1DigestToHexA(CalcHMAC_SHA1('Jefe', 'what do ya want for nothing?')) = 'effcdf6ae5eb2fa2d27416d5f184df9c259a7c79');
|
|
SetLength(S, 20); FillChar(Pointer(S)^, 20, #$0B);
|
|
Assert(SHA1DigestToHexA(CalcHMAC_SHA1(S, 'Hi There')) = 'b617318655057264e28bc0b6fb378c8ef146be00');
|
|
SetLength(S, 80); FillChar(Pointer(S)^, 80, #$AA);
|
|
Assert(SHA1DigestToHexA(CalcHMAC_SHA1(S, 'Test Using Larger Than Block-Size Key - Hash Key First')) = 'aa4ae5e15272d00e95705637ce8a3b55ed402112');
|
|
|
|
// Test cases from RFC 4231
|
|
Assert(SHA256DigestToHexA(CalcHMAC_SHA256(#$0b#$0b#$0b#$0b#$0b#$0b#$0b#$0b#$0b#$0b#$0b#$0b#$0b#$0b#$0b#$0b#$0b#$0b#$0b#$0b, 'Hi There')) = 'b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7');
|
|
Assert(SHA256DigestToHexA(CalcHMAC_SHA256('Jefe', 'what do ya want for nothing?')) = '5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843');
|
|
SetLength(S, 131); FillChar(Pointer(S)^, 131, #$aa);
|
|
Assert(SHA256DigestToHexA(CalcHMAC_SHA256(S, 'This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.')) = '9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2');
|
|
// see RFC 4231 truncated case --> Assert(SHA256DigestToHex(CalcHMAC_SHA256(#$0c#$0c#$0c#$0c#$0c#$0c#$0c#$0c#$0c#$0c#$0c#$0c#$0c#$0c#$0c#$0c#$0c#$0c#$0c#$0c, 'Test With Truncation')) = 'a3b6167473100ee06e0c796c2955552b', 'CalcHMAC_SHA256');
|
|
|
|
Assert(SHA512DigestToHexA(CalcHMAC_SHA512(#$0b#$0b#$0b#$0b#$0b#$0b#$0b#$0b#$0b#$0b#$0b#$0b#$0b#$0b#$0b#$0b#$0b#$0b#$0b#$0b, 'Hi There')) = '87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854');
|
|
Assert(SHA512DigestToHexA(CalcHMAC_SHA512('Jefe', 'what do ya want for nothing?')) = '164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737');
|
|
SetLength(S, 131); FillChar(Pointer(S)^, 131, #$aa);
|
|
Assert(SHA512DigestToHexA(CalcHMAC_SHA512(S, 'This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.')) = 'e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58');
|
|
|
|
// RipeMD160
|
|
Assert(RipeMD160DigestToHexA(CalcRipeMD160('')) = '9c1185a5c5e9fc54612808977ee8f548b2258d31');
|
|
Assert(RipeMD160DigestToHexA(CalcRipeMD160('a')) = '0bdc9d2d256b3ee9daae347be6f4dc835a467ffe');
|
|
Assert(RipeMD160DigestToHexA(CalcRipeMD160('abc')) = '8eb208f7e05d987a9b044a8e98c6b087f15a0bfc');
|
|
Assert(RipeMD160DigestToHexA(CalcRipeMD160('message digest')) = '5d0689ef49d2fae572b881b123a85ffa21595f36');
|
|
Assert(RipeMD160DigestToHexA(CalcRipeMD160('abcdefghijklmnopqrstuvwxyz')) = 'f71c27109c692c1b56bbdceb5b9d2865b3708dbc');
|
|
Assert(RipeMD160DigestToHexA(CalcRipeMD160('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq')) = '12a053384a9c0c88e405a06c27dcf49ada62eb2b');
|
|
Assert(RipeMD160DigestToHexA(CalcRipeMD160('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789')) = 'b0e20b6e3116640286ed3a87a5713079b21f5189');
|
|
Assert(RipeMD160DigestToHexA(CalcRipeMD160('12345678901234567890123456789012345678901234567890123456789012345678901234567890')) = '9b752e45573d4b39f4dbd3323cab82bf63326bfb');
|
|
Assert(RipeMD160DigestToHexA(CalcRipeMD160(MillionA)) = '52783243c1697bdbe16d37f97f68f08325dc1528');
|
|
Assert(RipeMD160DigestToHexA(CalcRipeMD160('Fundamentals')) = '0b4dfcb4cf845bee8a53bad703e164b50e8199cc');
|
|
Assert(RipeMD160DigestToHexA(CalcRipeMD160('12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789')) = 'e5ad452926b1b80e69a8c116748386ed920fd80e'); // 119 bytes
|
|
Assert(RipeMD160DigestToHexA(CalcRipeMD160('123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890')) = '65aaa2d6fb77e63b02a56ed9eced04fe47da43c1'); // 120 bytes
|
|
Assert(RipeMD160DigestToHexA(CalcRipeMD160('1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567')) = '5ef3b16743e09d8ac8410d03e72bb2fabb507749'); // 127 bytes
|
|
Assert(RipeMD160DigestToHexA(CalcRipeMD160('12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678')) = 'e6841f68c8fe1a94cbb8b53d79056d139434b49a'); // 128 bytes
|
|
end;
|
|
{$ENDIF}
|
|
|
|
|
|
|
|
end.
|