| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876 |
- {
- This file is part of the Free Component Library.
- Copyright (c) 2021 by the Free Pascal team.
- SHA512/SHA384 and HMACSha512/HMACSha384 routines.
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- }
- unit fpsha512;
- {$mode ObjFPC}{$H+}
- {$modeswitch advancedrecords}
- { $define debugsha}
- interface
- uses
- Classes, SysUtils, fphashutils;
- Type
- THashBuffer = array[0..127] of Byte;
- { TSHA512 }
- TSHA512Base = record
- Context: array[0..7] of QWord;
- Buffer : THashBuffer;
- Index: UInt32;
- TotalLength: Int64;
- procedure Compress;
- procedure Final;
- procedure Init(Use384 : Boolean = False);
- procedure Update(PBuf: PByte; Size: UInt32); overload;
- procedure Update(const Value: TBytes); overload;
- {$IFDEF DEBUGSHA}
- private
- procedure DumpBuffer;
- procedure DumpHash;
- {$ENDIF DEBUGSHA}
- end;
- PSHA512Base = ^TSHA512Base;
- TSHA512Digest = packed array[0..63] of Byte;
- PSHA512Digest = ^TSHA512Digest;
- PSHA512 = ^TSHA512;
- TSHA512 = record
- Base : TSHA512Base;
- Digest: TSHA512Digest;
- function IsEqual(const ADigest: TSHA512Digest): Boolean;
- procedure OutputHexa(out Result: AnsiString);
- procedure Compress;
- procedure Final;
- procedure Init;
- procedure Update(PBuf: PByte; Size: UInt32); overload;
- procedure Update(const Value: TBytes); overload;
- // Calculate SHA512, return digest as bytes.
- class procedure DigestBytes(const Value: TBytes; out Result: TBytes) ; static;
- // Calculate SHA512, return digest as base64(url) string
- class procedure DigestBase64(const Value: TBytes; const IsURL: Boolean; out Result: AnsiString); static;
- // Calculate SHA512, return digest as HEX encoded string
- class procedure DigestHexa(const Value: TBytes; out Result: AnsiString); static;
- // HMAC using SHA512 as hash
- Class function HMAC(Key: PByte; KeySize: UInt32; Data: PByte; DataSize: UInt32; var aDigest: TSHA512Digest): Boolean; overload; static;
- class function HMAC(Key: PByte; KeySize: UInt32; Data: PByte; DataSize: UInt32; Data2: PByte; DataSize2: UInt32; Data3: PByte; DataSize3: UInt32; var aDigest: TSHA512Digest): Boolean; overload; static;
- // Calculate HMacSHA512, return digest as hex string.
- class function HMACHexa(const Key, Data: TBytes; out SignatureHexa: AnsiString): Boolean; overload; static;
- // Calculate SHA512 from a stream, return digest.
- class procedure Stream(aStream: TStream; out aDigest: TSHA512Digest); static; overload;
- class function Stream(aStream: TStream): TSHA512Digest; static; overload;
- // Digest Stream, result as HexaDecimal string.
- class procedure StreamHexa(aStream: TStream; out Result: AnsiString); static; overload;
- class Function StreamHexa(aStream: TStream): AnsiString; static overload;
- // Digest Stream, result as Base64-encoded string
- class procedure StreamBase64(aStream: TStream; isURL : Boolean; out Result: AnsiString); static; overload;
- class Function StreamBase64(aStream: TStream; isURL : Boolean): AnsiString; static; overload;
- // HKDF : Derive key of desired length from a salt,input key and info (RF5869, using HMACSHA512) .
- class function HKDF(const Salt, IKM, Info: TBytes; var Output: TBytes; const DesiredLen: Integer): Boolean; static;
- end;
- TSHA384Digest = packed array[0..47] of Byte;
- PSHA384Digest = ^TSHA384Digest;
- PSHA384 = ^TSHA384;
- TSHA384 = record
- Base : TSHA512Base;
- Digest: TSHA384Digest;
- function IsEqual(const ADigest: TSHA384Digest): Boolean;
- procedure OutputHexa(out Result: AnsiString);
- procedure Compress;
- procedure Final;
- procedure Init;
- procedure Update(PBuf: PByte; Size: UInt32); overload;
- procedure Update(const Value: TBytes); overload;
- // Calculate SHA384, return digest as bytes.
- class procedure DigestBytes(const Value: TBytes; out Result: TBytes) ; static;
- // Calculate SHA384, return digest as base64(url) string
- class procedure DigestBase64(const Value: TBytes; const IsURL: Boolean; out Result: AnsiString); static;
- // Calculate SHA384, return digest as HEX encoded string
- class procedure DigestHexa(const Value: TBytes; out Result: AnsiString); static;
- // HMAC using SHA384 as hash
- Class function HMAC(Key: PByte; KeySize: UInt32; Data: PByte; DataSize: UInt32; var aDigest: TSHA384Digest): Boolean; overload; static;
- class function HMAC(Key: PByte; KeySize: UInt32; Data: PByte; DataSize: UInt32; Data2: PByte; DataSize2: UInt32; Data3: PByte; DataSize3: UInt32; var aDigest: TSHA384Digest): Boolean; overload; static;
- // Calculate HMacSHA384, return digest as hex string.
- class function HMACHexa(const Key, Data: TBytes; out SignatureHexa: AnsiString): Boolean; overload; static;
- // Calculate SHA384 from a stream, return digest.
- class procedure Stream(aStream: TStream; out aDigest: TSHA384Digest); static; overload;
- class function Stream(aStream: TStream): TSHA384Digest; static; overload;
- // Digest Stream, result as HexaDecimal string.
- class procedure StreamHexa(aStream: TStream; out Result: AnsiString); static; overload;
- class Function StreamHexa(aStream: TStream): AnsiString; static overload;
- // Digest Stream, result as Base64-encoded string
- class procedure StreamBase64(aStream: TStream; isURL : Boolean; out Result: AnsiString); static; overload;
- class Function StreamBase64(aStream: TStream; isURL : Boolean): AnsiString; static; overload;
- // HKDF : Derive key of desired length from a salt,input key and info (RF5869, using HMACSHA384) .
- class function HKDF(const Salt, IKM, Info: TBytes; var Output: TBytes; const DesiredLen: Integer): Boolean; static;
- end;
- Const
- SHA512_DIGEST_SIZE = SizeOf(TSHA512Digest); // 64
- SHA384_DIGEST_SIZE = SizeOf(TSHA384Digest); // 48
- implementation
- Const
- Seed512Hash : Array[0..7] of QWord
- = (QWord($6A09E667F3BCC908),
- QWord($BB67AE8584CAA73B),
- QWord($3C6EF372FE94F82B),
- QWord($A54FF53A5F1D36F1),
- QWord($510E527FADE682D1),
- QWord($9B05688C2B3E6C1F),
- QWord($1F83D9ABFB41BD6B),
- QWord($5BE0CD19137E2179)
- );
- Seed384Hash : Array[0..7] of QWord
- = (QWord($cbbb9d5dc1059ed8),
- QWord($629a292a367cd507),
- QWord($9159015a3070dd17),
- QWord($152fecd8f70e5939),
- QWord($67332667ffc00b31),
- QWord($8eb44a8768581511),
- QWord($db0c2e0d64f98fa7),
- QWord($47b5481dbefa4fa4)
- );
- { ----------------------------------------------------------------------
- TSHA512Base
- ----------------------------------------------------------------------}
- procedure TSHA512Base.Init(Use384 : Boolean = False);
- Var
- I : Integer ;
- begin
- Self.Index := 0;
- Self.TotalLength := 0;
- FillChar(Buffer, Sizeof(Buffer), 0);
- if Not Use384 then
- begin
- For I:=0 to 7 do
- Context[i]:=Seed512Hash[i];
- end
- else
- begin
- For I:=0 to 7 do
- Context[i]:=Seed384Hash[i];
- end;
- end;
- {$IFDEF DEBUGSHA}
- procedure Tsha512Base.DumpBuffer;
- Var
- i : Integer;
- begin
- For I:=0 to SizeOf(Buffer)-1 do
- Write(IntToStr(Buffer[i]),',');
- Writeln;
- end;
- procedure TSHA512Base.DumpHash;
- Var
- i : Integer;
- begin
- For I:=0 to 7 do
- Write(IntToStr(Context[i]),' ');
- Writeln;
- end;
- {$ENDIF}
- procedure TSHA512Base.Update(const Value: TBytes);
- begin
- Update(PByte(Value), System.Length(Value));
- end;
- procedure TSHA512Base.Update(PBuf: PByte; Size: UInt32);
- var
- Len: UInt32;
- begin
- Inc(TotalLength, Int64(UInt32(Size)) * 8);
- while Size > 0 do
- begin
- Len:=Sizeof(Buffer)-Index;
- if Len <= UInt32(Size) then
- begin
- Move(PBuf^, Buffer[Index], Len);
- Dec(Size, Len);
- Inc(PBuf, Len);
- Compress;
- Self.Index := 0;
- end else
- begin
- Move(PBuf^, Buffer[Index], Size);
- Inc(Self.Index, Size);
- Size := 0;
- end;
- end;
- end;
- procedure TSHA512Base.Final;
- Var
- I : Integer;
- begin
- Buffer[Index] := $80;
- FillChar(Buffer[Index+1], SizeOf(Buffer)-Index-1, 0);
- if Index >= 112 then
- Compress;
- PQWord(@Buffer[112])^ := 0;
- PQWord(@Buffer[120])^ := SwapEndian(TotalLength);
- Compress;
- For I:=0 to 7 do
- Context[i] := NtoBE(Context[i]);
- end;
- procedure TSHA512Base.Compress;
- const
- K: array[0..79] of QWord = (
- QWord($428A2F98D728AE22),QWord($7137449123EF65CD),QWord($B5C0FBCFEC4D3B2F),QWord($E9B5DBA58189DBBC),
- QWord($3956C25BF348B538),QWord($59F111F1B605D019),QWord($923F82A4AF194F9B),QWord($AB1C5ED5DA6D8118),
- QWord($D807AA98A3030242),QWord($12835B0145706FBE),QWord($243185BE4EE4B28C),QWord($550C7DC3D5FFB4E2),
- QWord($72BE5D74F27B896F),QWord($80DEB1FE3B1696B1),QWord($9BDC06A725C71235),QWord($C19BF174CF692694),
- QWord($E49B69C19EF14AD2),QWord($EFBE4786384F25E3),QWord($0FC19DC68B8CD5B5),QWord($240CA1CC77AC9C65),
- QWord($2DE92C6F592B0275),QWord($4A7484AA6EA6E483),QWord($5CB0A9DCBD41FBD4),QWord($76F988DA831153B5),
- QWord($983E5152EE66DFAB),QWord($A831C66D2DB43210),QWord($B00327C898FB213F),QWord($BF597FC7BEEF0EE4),
- QWord($C6E00BF33DA88FC2),QWord($D5A79147930AA725),QWord($06CA6351E003826F),QWord($142929670A0E6E70),
- QWord($27B70A8546D22FFC),QWord($2E1B21385C26C926),QWord($4D2C6DFC5AC42AED),QWord($53380D139D95B3DF),
- QWord($650A73548BAF63DE),QWord($766A0ABB3C77B2A8),QWord($81C2C92E47EDAEE6),QWord($92722C851482353B),
- QWord($A2BFE8A14CF10364),QWord($A81A664BBC423001),QWord($C24B8B70D0F89791),QWord($C76C51A30654BE30),
- QWord($D192E819D6EF5218),QWord($D69906245565A910),QWord($F40E35855771202A),QWord($106AA07032BBD1B8),
- QWord($19A4C116B8D2D0C8),QWord($1E376C085141AB53),QWord($2748774CDF8EEB99),QWord($34B0BCB5E19B48A8),
- QWord($391C0CB3C5C95A63),QWord($4ED8AA4AE3418ACB),QWord($5B9CCA4F7763E373),QWord($682E6FF3D6B2B8A3),
- QWord($748F82EE5DEFB2FC),QWord($78A5636F43172F60),QWord($84C87814A1F0AB72),QWord($8CC702081A6439EC),
- QWord($90BEFFFA23631E28),QWord($A4506CEBDE82BDE9),QWord($BEF9A3F7B2C67915),QWord($C67178F2E372532B),
- QWord($CA273ECEEA26619C),QWord($D186B8C721C0C207),QWord($EADA7DD6CDE0EB1E),QWord($F57D4F7FEE6ED178),
- QWord($06F067AA72176FBA),QWord($0A637DC5A2C898A6),QWord($113F9804BEF90DAE),QWord($1B710B35131C471B),
- QWord($28DB77F523047D84),QWord($32CAAB7B40C72493),QWord($3C9EBE0A15C9BEBC),QWord($431D67C49C100D4C),
- QWord($4CC5D4BECB3E42B6),QWord($597F299CFC657E2A),QWord($5FCB6FAB3AD6FAEC),QWord($6C44198C4A475817)
- );
- type
- TQWordArray = Array[0..79] of QWord;
- var
- A, B, C, D, E, F, G, H: QWord;
- I: UInt32;
- t1, t2: QWord;
- W : TQWordArray;
- begin
- {$IFDEF DEBUGSHA} DumpHash; DumpBuffer; {$ENDIF}
- W:=Default(TQWordArray);
- a:= Context[0];
- b:= Context[1];
- c:= Context[2];
- d:= Context[3];
- e:= Context[4];
- f:= Context[5];
- g:= Context[6];
- h:= Context[7];
- // Fill first 16 QWords, swap endianness.
- Move(Buffer,W,SizeOf(THashBuffer));
- for i:= 0 to 15 do
- W[i]:= BeTON(W[i]);
- for i:= 0 to 79 do
- begin
- if I>=16 then
- W[i]:= W[i-16]
- // SIGMA4(x) = (ROR64(x, 19) ^ ROR64(x, 61) ^ SHR64(x, 6))
- + (((W[i-2] shr 19) or (W[i-2] shl 45))
- xor ((W[i-2] shr 61) or (W[i-2] shl 3))
- xor (W[i-2] shr 6))
- + W[i-7]
- // Sigma3 (x) = (ROR64(x, 1) ^ ROR64(x, 8) ^ SHR64(x, 7));
- + (((W[i-15] shr 1) or (W[i-15] shl 63))
- xor ((W[i-15] shr 8) or (W[i-15] shl 56))
- xor (W[i-15] shr 7));
- t1:= h
- // Sigma2(x) = (ROR64(x, 14) ^ ROR64(x, 18) ^ ROR64(x, 41))
- + (((e shr 14) or (e shl 50)) xor ((e shr 18) or (e shl 46)) xor ((e shr 41) or (e shl 23)))
- // CH(x, y, z) = (((x) & (y)) | (~(x) & (z)))
- + ((e and f) or (not e and g))
- + K[i] + W[i];
- t2:= // SIGMA1(x) = (ROR64(x, 28) ^ ROR64(x, 34) ^ ROR64(x, 39))
- (((a shr 28) or (a shl 36)) xor ((a shr 34) or (a shl 30)) xor ((a shr 39) or (a shl 25))) +
- // MAJ(x,y,z) = (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
- ((a and b) or (a and c) or (b and c));
- h:= g;
- g:= f;
- f:= e;
- e:= d + t1;
- d:= c;
- c:= b;
- b:= a;
- a:= t1 + t2;
- end;
- Inc(Context[0], A);
- Inc(Context[1], B);
- Inc(Context[2], C);
- Inc(Context[3], D);
- Inc(Context[4], E);
- Inc(Context[5], F);
- Inc(Context[6], G);
- Inc(Context[7], H);
- FillChar(Buffer,Sizeof(Buffer),0);
- {$IFDEF DEBUGSHA} DumpHash;{$ENDIF}
- end;
- { ----------------------------------------------------------------------
- TSHA512
- ----------------------------------------------------------------------}
- procedure TSHA512.Init;
- begin
- Base.Init(False);
- end;
- procedure TSHA512.Compress;
- begin
- Base.Compress;
- end;
- procedure TSHA512.Final;
- begin
- Base.Final;
- Move(Base.Context, Digest, Sizeof(Digest));
- end;
- function TSHA512.IsEqual(const ADigest: TSHA512Digest): Boolean;
- var
- Left, Right: TBytes;
- begin
- Left:=BytesFromVar(@ADigest, SizeOf(ADigest));
- Right:=BytesFromVar(@Self.Digest, SizeOf(Self.Digest));
- Result:=CompareMem(Pointer(Left), Pointer(Right),System.Length(Left));
- end;
- procedure TSHA512.Update(PBuf: PByte; Size: UInt32);
- begin
- Base.Update(PBuf,Size);
- end;
- procedure TSHA512.Update(const Value: TBytes);
- begin
- Base.Update(Value);
- end;
- class procedure TSHA512.DigestBytes(const Value: TBytes; out Result: TBytes);
- var
- lSHA512: TSHA512;
- begin
- lSHA512.Init;
- lSHA512.Update(Value);
- lSHA512.Final;
- BytesFromVar(Result, @lSHA512.Digest[0], SizeOf(lSHA512.Digest));
- end;
- class procedure TSHA512.DigestBase64(const Value: TBytes; const IsURL: Boolean; out Result: AnsiString);
- var
- S : TBytes;
- lSHA512: TSHA512;
- begin
- lSHA512.Init;
- lSHA512.Update(Value);
- lSHA512.Final;
- BytesFromVar(S, @lSHA512.Digest[0], SizeOf(lSHA512.Digest));
- BytesEncodeBase64(S, Result, IsURL, False, False);
- end;
- class procedure TSHA512.DigestHexa(const Value: TBytes; out Result: AnsiString);
- var
- SHA512: TSHA512;
- begin
- SHA512.Init;
- SHA512.Update(Value);
- SHA512.Final;
- SHA512.OutputHexa(Result);
- end;
- procedure TSHA512.OutputHexa(out Result: AnsiString);
- begin
- BytesToHexStr(Result,PByte(@Self.Digest),SizeOf(Self.Digest));
- end;
- class function TSHA512.HMAC(Key: PByte; KeySize: UInt32; Data: PByte; DataSize: UInt32; var aDigest: TSHA512Digest): Boolean;
- begin
- Result := HMAC(Key, KeySize, Data, DataSize, nil, 0, nil, 0, aDigest);
- end;
- {Generate a SHA512 HMAC (Hashed Message Authentication Code) using the Key and Data
- The SHA512 HMAC algorithm is:
- SHA512(Key xor oPad, SHA512(Key xor iPad, Data))
- Where iPad is the byte $36 repeated 128 times
- oPad is the byte $5c repeated 128 times
- If Key is more than 128 bytes it will be hashed to Key = SHA512(Key) instead
- If Key is less than 128 bytes it will be padded with zeros }
- class function TSHA512.HMAC(Key: PByte; KeySize: UInt32; Data: PByte; DataSize: UInt32; Data2: PByte; DataSize2: UInt32; Data3: PByte; DataSize3: UInt32; var aDigest: TSHA512Digest): Boolean;
- Type
- TBuf128 = array[0..127] of Byte;
- var
- Count: UInt32;
- KeyBuffer, PadBuffer: TBuf128;
- SHA512, SHA512_: TSHA512;
- begin
- Result:=False;
- if Key = nil then
- Exit;
- if Data = nil then
- Exit;
- KeyBuffer:=Default(TBuf128);
- SHA512.Init;
- if KeySize > 128 then
- begin
- SHA512.Update(Key, KeySize);
- SHA512.Final;
- System.Move(SHA512.Digest[0], KeyBuffer[0], SizeOf(SHA512.Digest));
- end else
- System.Move(Key^, KeyBuffer[0], KeySize);
- // XOR the key buffer with the iPad value
- for Count := 0 to 127 do
- PadBuffer[Count] := KeyBuffer[Count] xor $36;
- SHA512.Init;
- SHA512.Update(@PadBuffer, SizeOf(PadBuffer));
- SHA512.Update(Data, DataSize);
- if Data2 <> nil then
- SHA512.Update(Data2, DataSize2);
- if Data3 <> nil then
- SHA512.Update(Data3, DataSize3);
- SHA512.Final;
- // XOR the key buffer with the oPad value
- for Count := 0 to 127 do
- PadBuffer[Count] := KeyBuffer[Count] xor $5C;
- // SHA512 the key buffer and the result of the inner SHA512 (Outer)
- SHA512_.Init;
- SHA512_.Update(@PadBuffer, SizeOf(PadBuffer));
- SHA512_.Update(@SHA512.Digest, SizeOf(SHA512.Digest));
- SHA512_.Final;
- System.Move(SHA512_.Digest, aDigest, SizeOf(aDigest));
- // FillChar(KeyDigest, SizeOf(TSHA1Digest),0);
- // FillChar(KeyBuffer, SizeOf(TSHA1ByteBuffer),0);
- // FillChar(PadBuffer, SizeOf(TSHA1ByteBuffer),0);
- Result:=True;
- end;
- // @Result[64]
- class function TSHA512.HMACHexa(const Key, Data: TBytes; out SignatureHexa: AnsiString): Boolean; overload;
- var
- aDigest: TSHA512Digest;
- S: TBytes;
- begin
- aDigest:=Default(TSHA512Digest);
- Result := HMAC(PByte(Key),System.Length(Key), PByte(Data), System.Length(Data), aDigest);
- BytesFromVar(S, @aDigest[0], SizeOf(aDigest));
- BytesToHexStr(SignatureHexa,S);
- end;
- class procedure TSHA512.Stream(aStream: TStream; out aDigest: TSHA512Digest);
- const
- BUFFER_SIZE = 64*1024;
- var
- aLen : LongInt;
- lBuffer: TBytes;
- SHA512: TSHA512;
- begin
- lBuffer:=Nil;
- SHA512.Init;
- SetLength(lBuffer,BUFFER_SIZE);
- repeat
- aLen:=aStream.Read(lBuffer, BUFFER_SIZE);
- if aLen = 0 then
- Break;
- SHA512.Update(PByte(lBuffer),aLen);
- until aLen=0;
- SHA512.Final;
- aDigest:=SHA512.Digest;
- end;
- class function TSHA512.Stream(aStream: TStream): TSHA512Digest;
- begin
- Stream(aStream,Result);
- end;
- class procedure TSHA512.StreamHexa(aStream: TStream; out Result: AnsiString);
- Var
- B : TBytes;
- aDigest : TSHA512Digest;
- begin
- Stream(aStream,aDigest);
- BytesFromVar(B,@aDigest,SizeOf(TSHA512Digest));
- BytesToHexStr(Result,B);
- end;
- class function TSHA512.StreamHexa(aStream: TStream): AnsiString;
- begin
- Result:='';
- StreamHexa(aStream,Result);
- end;
- class procedure TSHA512.StreamBase64(aStream: TStream; isURL : Boolean; out Result: AnsiString);
- Var
- B : TBytes;
- aDigest : TSHA512Digest;
- begin
- Stream(aStream,aDigest);
- BytesFromVar(B,@aDigest,SizeOf(TSHA512Digest));
- BytesEncodeBase64(B,Result,isUrl,False,False);
- end;
- Class Function TSHA512.StreamBase64(aStream: TStream; isURL : Boolean): AnsiString;
- begin
- Result:='';
- StreamBase64(aStream,isURL,Result);
- end;
- class function TSHA512.HKDF(const Salt, IKM, Info: TBytes; var Output: TBytes; const DesiredLen: Integer): Boolean;
- var
- PRK, T: TSHA512Digest;
- Round: Byte;
- begin
- PRK:=Default(TSHA512Digest);
- T:=Default(TSHA512Digest);
- Result := HMAC(PByte(Salt), System.Length(Salt), PByte(IKM), Length(IKM), PRK);
- if not Result then
- Exit;
- Round := 1;
- while System.Length(Output) < DesiredLen do
- begin
- if System.Length(Output) = 0 then
- Result := HMAC(@PRK, SizeOf(PRK), PByte(Info), System.Length(Info), @Round, SizeOf(Round), nil, 0, T)
- else
- Result := HMAC(@PRK, SizeOf(PRK), @T, SizeOf(T), PByte(Info), System.Length(Info), @Round, SizeOf(Round), T);
- if not Result then
- Exit;
- Inc(Round);
- Output:=Concat(OutPut,BytesFromVar(@T,SizeOf(T)));
- if Length(Output) >= DesiredLen then
- Break;
- end;
- SetLength(Output,DesiredLen);
- end;
- { ----------------------------------------------------------------------
- TSHA384
- ----------------------------------------------------------------------}
- procedure TSHA384.Init;
- begin
- Base.Init(True);
- end;
- procedure TSHA384.Compress;
- begin
- Base.Compress;
- end;
- procedure TSHA384.Final;
- begin
- Base.Final;
- Move(Base.Context, Digest, Sizeof(Digest));
- end;
- function TSHA384.IsEqual(const ADigest: TSHA384Digest): Boolean;
- var
- Left, Right: TBytes;
- begin
- Left:=BytesFromVar(@ADigest, SizeOf(ADigest));
- Right:=BytesFromVar(@Self.Digest, SizeOf(Self.Digest));
- Result:=CompareMem(Pointer(Left), Pointer(Right),System.Length(Left));
- end;
- procedure TSHA384.Update(PBuf: PByte; Size: UInt32);
- begin
- Base.Update(PBuf,Size);
- end;
- procedure TSHA384.Update(const Value: TBytes);
- begin
- Base.Update(Value);
- end;
- class procedure TSHA384.DigestBytes(const Value: TBytes; out Result: TBytes);
- var
- lSHA384: TSHA384;
- begin
- lSHA384.Init;
- lSHA384.Update(Value);
- lSHA384.Final;
- BytesFromVar(Result, @lSHA384.Digest[0], SizeOf(lSHA384.Digest));
- end;
- class procedure TSHA384.DigestBase64(const Value: TBytes; const IsURL: Boolean; out Result: AnsiString);
- var
- S : TBytes;
- lSHA384: TSHA384;
- begin
- lSHA384.Init;
- lSHA384.Update(Value);
- lSHA384.Final;
- BytesFromVar(S, @lSHA384.Digest[0], SizeOf(lSHA384.Digest));
- BytesEncodeBase64(S, Result, IsURL, False, False);
- end;
- class procedure TSHA384.DigestHexa(const Value: TBytes; out Result: AnsiString);
- var
- SHA384: TSHA384;
- begin
- SHA384.Init;
- SHA384.Update(Value);
- SHA384.Final;
- SHA384.OutputHexa(Result);
- end;
- procedure TSHA384.OutputHexa(out Result: AnsiString);
- begin
- BytesToHexStr(Result,PByte(@Self.Digest),SizeOf(Self.Digest));
- end;
- class function TSHA384.HMAC(Key: PByte; KeySize: UInt32; Data: PByte; DataSize: UInt32; var aDigest: TSHA384Digest): Boolean;
- begin
- Result := HMAC(Key, KeySize, Data, DataSize, nil, 0, nil, 0, aDigest);
- end;
- {Generate a SHA384 HMAC (Hashed Message Authentication Code) using the Key and Data
- The SHA384 HMAC algorithm is:
- SHA384(Key xor oPad, SHA384(Key xor iPad, Data))
- Where iPad is the byte $36 repeated 128 times
- oPad is the byte $5c repeated 128 times
- If Key is more than 128 bytes it will be hashed to Key = SHA384(Key) instead
- If Key is less than 128 bytes it will be padded with zeros }
- class function TSHA384.HMAC(Key: PByte; KeySize: UInt32; Data: PByte; DataSize: UInt32; Data2: PByte; DataSize2: UInt32; Data3: PByte; DataSize3: UInt32; var aDigest: TSHA384Digest): Boolean;
- Type
- TBuf128 = array[0..127] of Byte;
- var
- Count: UInt32;
- KeyBuffer, PadBuffer: TBuf128;
- SHA384, SHA384_: TSHA384;
- begin
- Result:=False;
- if Key = nil then
- Exit;
- if Data = nil then
- Exit;
- KeyBuffer:=Default(TBuf128);
- SHA384.Init;
- if KeySize > 128 then
- begin
- SHA384.Update(Key, KeySize);
- SHA384.Final;
- System.Move(SHA384.Digest[0], KeyBuffer[0], SizeOf(SHA384.Digest));
- end else
- System.Move(Key^, KeyBuffer[0], KeySize);
- // XOR the key buffer with the iPad value
- for Count := 0 to 127 do
- PadBuffer[Count] := KeyBuffer[Count] xor $36;
- SHA384.Init;
- SHA384.Update(@PadBuffer, SizeOf(PadBuffer));
- SHA384.Update(Data, DataSize);
- if Data2 <> nil then
- SHA384.Update(Data2, DataSize2);
- if Data3 <> nil then
- SHA384.Update(Data3, DataSize3);
- SHA384.Final;
- // XOR the key buffer with the oPad value
- for Count := 0 to 127 do
- PadBuffer[Count] := KeyBuffer[Count] xor $5C;
- // SHA384 the key buffer and the result of the inner SHA384 (Outer)
- SHA384_.Init;
- SHA384_.Update(@PadBuffer, SizeOf(PadBuffer));
- SHA384_.Update(@SHA384.Digest, SizeOf(SHA384.Digest));
- SHA384_.Final;
- System.Move(SHA384_.Digest, aDigest, SizeOf(aDigest));
- // FillChar(KeyDigest, SizeOf(TSHA1Digest),0);
- // FillChar(KeyBuffer, SizeOf(TSHA1ByteBuffer),0);
- // FillChar(PadBuffer, SizeOf(TSHA1ByteBuffer),0);
- Result:=True;
- end;
- // @Result[64]
- class function TSHA384.HMACHexa(const Key, Data: TBytes; out SignatureHexa: AnsiString): Boolean; overload;
- var
- aDigest: TSHA384Digest;
- S: TBytes;
- begin
- aDigest:=Default(TSHA384Digest);
- Result := HMAC(PByte(Key),System.Length(Key), PByte(Data), System.Length(Data), aDigest);
- BytesFromVar(S, @aDigest[0], SizeOf(aDigest));
- BytesToHexStr(SignatureHexa,S);
- end;
- class procedure TSHA384.Stream(aStream: TStream; out aDigest: TSHA384Digest);
- const
- BUFFER_SIZE = 64*1024;
- var
- aLen : LongInt;
- lBuffer: TBytes;
- SHA384: TSHA384;
- begin
- lBuffer:=Nil;
- SHA384.Init;
- SetLength(lBuffer,BUFFER_SIZE);
- repeat
- aLen:=aStream.Read(lBuffer, BUFFER_SIZE);
- if aLen = 0 then
- Break;
- SHA384.Update(PByte(lBuffer),aLen);
- until aLen=0;
- SHA384.Final;
- aDigest:=SHA384.Digest;
- end;
- class function TSHA384.Stream(aStream: TStream): TSHA384Digest;
- begin
- Stream(aStream,Result);
- end;
- class procedure TSHA384.StreamHexa(aStream: TStream; out Result: AnsiString);
- Var
- B : TBytes;
- aDigest : TSHA384Digest;
- begin
- Stream(aStream,aDigest);
- BytesFromVar(B,@aDigest,SizeOf(TSHA384Digest));
- BytesToHexStr(Result,B);
- end;
- class function TSHA384.StreamHexa(aStream: TStream): AnsiString;
- begin
- Result:='';
- StreamHexa(aStream,Result);
- end;
- class procedure TSHA384.StreamBase64(aStream: TStream; isURL : Boolean; out Result: AnsiString);
- Var
- B : TBytes;
- aDigest : TSHA384Digest;
- begin
- Stream(aStream,aDigest);
- BytesFromVar(B,@aDigest,SizeOf(TSHA384Digest));
- BytesEncodeBase64(B,Result,isUrl,False,False);
- end;
- Class Function TSHA384.StreamBase64(aStream: TStream; isURL : Boolean): AnsiString;
- begin
- Result:='';
- StreamBase64(aStream,isURL,Result);
- end;
- class function TSHA384.HKDF(const Salt, IKM, Info: TBytes; var Output: TBytes; const DesiredLen: Integer): Boolean;
- var
- PRK, T: TSHA384Digest;
- Round: Byte;
- begin
- PRK:=Default(TSHA384Digest);
- T:=Default(TSHA384Digest);
- Result := HMAC(PByte(Salt), System.Length(Salt), PByte(IKM), Length(IKM), PRK);
- if not Result then
- Exit;
- Round := 1;
- while System.Length(Output) < DesiredLen do
- begin
- if System.Length(Output) = 0 then
- Result := HMAC(@PRK, SizeOf(PRK), PByte(Info), System.Length(Info), @Round, SizeOf(Round), nil, 0, T)
- else
- Result := HMAC(@PRK, SizeOf(PRK), @T, SizeOf(T), PByte(Info), System.Length(Info), @Round, SizeOf(Round), T);
- if not Result then
- Exit;
- Inc(Round);
- Output:=Concat(OutPut,BytesFromVar(@T,SizeOf(T)));
- if Length(Output) >= DesiredLen then
- Break;
- end;
- SetLength(Output,DesiredLen);
- end;
- end.
|