|
@@ -0,0 +1,876 @@
|
|
|
|
+{
|
|
|
|
+ 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 sha512;
|
|
|
|
+
|
|
|
|
+{$mode ObjFPC}{$H+}
|
|
|
|
+{$modeswitch advancedrecords}
|
|
|
|
+{ $define debugsha}
|
|
|
|
+
|
|
|
|
+interface
|
|
|
|
+
|
|
|
|
+uses
|
|
|
|
+ Classes, SysUtils, hashutils;
|
|
|
|
+
|
|
|
|
+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.
|
|
|
|
+
|