unit HKDF;
interface
uses
System.SysUtils, System.Hash, System.Classes;
type
THKDF =
class
public
class function HMAC_SHA256(
const Key, Data: TBytes): TBytes;
class function Extract(
const Salt, IKM: TBytes): TBytes;
class function Expand(
const PRK, Info: TBytes; L: Integer): TBytes;
class function DeriveKey(
const IKM, Salt, Info: TBytes; L: Integer): TBytes;
end;
{ THKDF }
implementation
class function THKDF.HMAC_SHA256(
const Key, Data: TBytes): TBytes;
begin
Result := THashSHA2.GetHMACAsBytes(Data, Key, THashSHA2.TSHA2Version.SHA256);
end;
class function THKDF.Extract(
const Salt, IKM: TBytes): TBytes;
var
ActualSalt: TBytes;
begin
if Length(Salt) = 0
then
begin
SetLength(ActualSalt, 32);
// SHA256 BlockSize
FillChar(ActualSalt[0], 32, 0);
end
else
ActualSalt := Salt;
Result := HMAC_SHA256(ActualSalt, IKM);
end;
class function THKDF.Expand(
const PRK, Info: TBytes; L: Integer): TBytes;
var
N, I: Integer;
T, Block: TBytes;
Counter: Byte;
HashLen: Integer;
begin
HashLen := 32;
// SHA256
N := (L + HashLen - 1)
div HashLen;
SetLength(Result, 0);
SetLength(T, 0);
for I := 1
to N
do
begin
Counter := I;
Block := T + Info + [Counter];
T := HMAC_SHA256(PRK, Block);
Result := Result + T;
end;
SetLength(Result, L);
end;
class function THKDF.DeriveKey(
const IKM, Salt, Info: TBytes; L: Integer): TBytes;
var
PRK: TBytes;
begin
PRK := Extract(Salt, IKM);
Result := Expand(PRK, Info, L);
end;
end.