More information about the Hash/HMAC/KDF routines
Introduction
The Hash unit
The specific units
The HMAC unit
The KDF unit
Examples
- It should be a computationally efficient public one-way function, i.e. is
easy to calculate the digest of a given message but it is computationally infeasible to find a
message that is mapped to given value. - It should be a computationally strong collision resistant function, i.e. it is computationally
infeasible to find two distinct messages which are mapped to the same
value.
- shared secrets and optional other info or
- pass phrases, (session) salts, and iteration counts according to PKCS#5
| © 2018 W.Ehrhardt | Last update Jan. 01, 2018 |
type
THashAlgorithm = (_MD4, _MD5, _RIPEMD160, _SHA1,
_SHA224, _SHA256, _SHA384, _SHA512,
_Whirlpool, _SHA512_224, _SHA512_256,
_SHA3_224, _SHA3_256, _SHA3_384, _SHA3_512,
_Blake2S_224, _Blake2S_256,
_Blake2B_384, _Blake2B_512); {Supported hash algorithms}
const
_RMD160 = _RIPEMD160; {Alias}
const
MaxBlockLen = 128; {Max. block length (buffer size), multiple of 4}
MaxDigestLen = 64; {Max. length of hash digest}
MaxStateLen = 16; {Max. size of internal state}
MaxOIDLen = 11; {Current max. OID length}
C_HashSig = $3D7A; {Signature for Hash descriptor}
C_HashVers = $00020002; {Version of Hash definitions}
C_MinHash = _MD4; {Lowest hash in THashAlgorithm}
C_MaxHash = _Blake2B_512;{Highest hash in THashAlgorithm}
type
THashState = packed array[0..MaxStateLen-1] of longint; {Internal state}
THashBuffer = packed array[0..MaxBlockLen-1] of byte; {hash buffer block}
THashDigest = packed array[0..MaxDigestLen-1] of byte; {hash digest}
PHashDigest = ^THashDigest; {pointer to hash digest}
THashBuf32 = packed array[0..MaxBlockLen div 4 -1] of longint; {type cast helper}
THashDig32 = packed array[0..MaxDigestLen div 4 -1] of longint; {type cast helper}
THMacBuffer = packed array[0..143] of byte; {hmac buffer block}
const
HASHCTXSIZE = 448; {Common size of enlarged padded old context}
{and new padded SHA3/SHAKE/Keccak context }
type
THashContext = packed record
Hash : THashState; {Working hash}
MLen : packed array[0..3] of longint; {max 128 bit msg length}
Buffer: THashBuffer; {Block buffer}
Index : longint; {Index in buffer}
Fill2 : packed array[213..HASHCTXSIZE] of byte;
end;
type
HashInitProc = procedure(var Context: THashContext);
{-initialize context}
HashUpdateXLProc = procedure(var Context: THashContext; Msg: pointer; Len: longint);
{-update context with Msg data}
HashFinalProc = procedure(var Context: THashContext; var Digest: THashDigest);
{-finalize calculation, clear context}
HashFinalBitProc = procedure(var Context: THashContext; var Digest: THashDigest; BData: byte; bitlen: integer);
{-finalize calculation with bitlen bits from BData, clear context}
type
TOID_Vec = packed array[1..MaxOIDLen] of longint; {OID vector}
POID_Vec = ^TOID_Vec; {ptr to OID vector}
type
THashName = string[19]; {Hash algo name type }
PHashDesc = ^THashDesc; {Ptr to descriptor }
THashDesc = packed record
HSig : word; {Signature=C_HashSig }
HDSize : word; {sizeof(THashDesc) }
HDVersion : longint; {THashDesc Version }
HBlockLen : word; {Blocklength of hash }
HDigestlen: word; {Digestlength of hash}
HInit : HashInitProc; {Init procedure }
HFinal : HashFinalProc; {Final procedure }
HUpdateXL : HashUpdateXLProc; {Update procedure }
HAlgNum : longint; {Algo ID, longint avoids problems with enum size/DLL}
HName : THashName; {Name of hash algo }
HPtrOID : POID_Vec; {Pointer to OID vec }
HLenOID : word; {Length of OID vec }
HFill : word;
HFinalBit : HashFinalBitProc; {Bit-API Final proc }
HReserved : packed array[0..19] of byte;
end;
const
BitAPI_Mask: array[0..7] of byte = ($00,$80,$C0,$E0,$F0,$F8,$FC,$FE);
BitAPI_PBit: array[0..7] of byte = ($80,$40,$20,$10,$08,$04,$02,$01);
procedure RegisterHash(AlgId: THashAlgorithm; PHash: PHashDesc);
{-Register algorithm with AlgID and Hash descriptor PHash^}
function FindHash_by_ID(AlgoID: THashAlgorithm): PHashDesc;
{-Return PHashDesc of AlgoID, nil if not found/registered}
function FindHash_by_Name(AlgoName: THashName): PHashDesc;
{-Return PHashDesc of Algo with AlgoName, nil if not found/registered}
procedure [Hash]Init(var Context: THashContext);
{-initialize context}
procedure [Hash]Update(var Context: THashContext; Msg: pointer; Len: word);
{-update context with Msg data}
procedure [Hash]UpdateXL(var Context: THashContext; Msg: pointer; Len: longint);
{-update context with Msg data}
procedure [Hash]Final(var Context: THashContext; var Digest: T[Hash]Digest);
{-finalize [Hash] calculation, clear context}
procedure [Hash]FinalEx(var Context: THashContext; var Digest: THashDigest);
{-finalize [Hash] calculation, clear context}
procedure [Hash]FinalBitsEx(var Context: THashContext; var Digest: THashDigest; BData: byte; bitlen: integer);
{-finalize [Hash] calculation with bitlen bits from BData (big-endian), clear context}
procedure [Hash]FinalBits(var Context: THashContext; var Digest: T[Hash]Digest; BData: byte; bitlen: integer);
{-finalize [Hash] calculation with bitlen bits from BData (big-endian), clear context}
function [Hash]SelfTest: boolean;
{-self test for [Hash]}
procedure [Hash]Full(var Digest: T[Hash]Digest; Msg: pointer; Len: word);
{-[Hash] of Msg with init/update/final}
procedure [Hash]FullXL(var Digest: T[Hash]Digest; Msg: pointer; Len: longint);
{-[Hash] of Msg with init/update/final}
procedure [Hash]File(fname: String; var Digest: T[Hash]Digest; var buf; bsize: word; var Err: word);
{-[Hash] of file, buf: buffer with at least bsize bytes}
type
THMAC_Context = record
hashctx: THashContext;
hmacbuf: THashBuffer;
phashd : PHashDesc;
end;
procedure hmac_init(var ctx: THMAC_Context; phash: PHashDesc; key: pointer; klen: word);
{-initialize HMAC context with hash descr phash^ and key}
procedure hmac_inits(var ctx: THMAC_Context; phash: PHashDesc; skey: Str255);
{-initialize HMAC context with hash descr phash^ and skey}
procedure hmac_update(var ctx: THMAC_Context; data: pointer; dlen: word);
{-HMAC data input, may be called more than once}
procedure hmac_updateXL(var ctx: THMAC_Context; data: pointer; dlen: longint);
{-HMAC data input, may be called more than once}
procedure hmac_final(var ctx: THMAC_Context; var mac: THashDigest);
{-end data input, calculate HMAC digest}
procedure hmac_final_bits(var ctx: THMAC_Context; var mac: THashDigest; BData: byte; bitlen: integer);
{-end data input with bitlen bits (MSB format) from BData, calculate HMAC digest}
function kdf1(phash: PHashDesc; Z: pointer; zLen: word; pOtherInfo: pointer; oiLen: word; var DK; dkLen: word): integer;
{-Derive key DK from shared secret Z using optional OtherInfo, hash function from phash}
function kdf2(phash: PHashDesc; Z: pointer; zLen: word; pOtherInfo: pointer; oiLen: word; var DK; dkLen: word): integer;
{-Derive key DK from shared secret Z using optional OtherInfo, hash function from phash}
function kdf3(phash: PHashDesc; Z: pointer; zLen: word; pOtherInfo: pointer; oiLen: word; var DK; dkLen: word): integer;
{-Derive key DK from shared secret Z using optional OtherInfo, hash function from phash}
function mgf1(phash: PHashDesc; pSeed: pointer; sLen: word; var Mask; mLen: word): integer;
{-Derive Mask from seed, hash function from phash, Mask Generation Function 1 for PKCS #1}
function pbkdf1(phash: PHashDesc; pPW: pointer; pLen: word; salt: pointer; C: longint; var DK; dkLen: word): integer;
{-Derive key DK from password pPW using 8 byte salt and iteration count C, uses hash function from phash}
function pbkdf1s(phash: PHashDesc; sPW: Str255; salt: pointer; C: longint; var DK; dkLen: word): integer;
{-Derive key DK from password string sPW using 8 byte salt and iteration count C, uses hash function from phash}
function pbkdf2(phash: PHashDesc; pPW: pointer; pLen: word; salt: pointer; sLen,C: longint; var DK; dkLen: longint): integer;
{-Derive key DK from password pPW using salt and iteration count C, uses hash function from phash}
function pbkdf2s(phash: PHashDesc; sPW: Str255; salt: pointer; sLen,C: longint; var DK; dkLen: longint): integer;
{-Derive key DK from password string sPW using salt and iteration count C, uses hash function from phash}
function hkdf(phash: PHashDesc; {Descriptor of the Hash to use}
pIKM: pointer; L_IKM: word; {input key material: addr/length}
salt: pointer; L_salt: word; {optional salt; can be nil: see below }
info: pointer; L_info: word; {optional context/application specific information}
var DK; dkLen: word): integer; {output key material: addr/length}
{-Derive key DK from input key material and salt/info, uses hash function from phash}
{ If salt=nil then phash^.HDigestLen binary zeros will be used as salt.}
function hkdfs(phash: PHashDesc; sIKM: Str255; {Hash; input key material as string}
salt: pointer; L_salt: word; {optional salt; can be nil: see below }
info: pointer; L_info: word; {optional context/application specific information}
var DK; dkLen: word): integer; {output key material: addr/length}
{-Derive key DK from input key material and salt/info, uses hash function from phash}
{ If salt=nil then phash^.HDigestLen binary zeros will be used as salt.}
function scrypt_kdf(pPW: pointer; pLen: word; salt: pointer; sLen,N,r,p: longint; var DK; dkLen: longint): integer;
{-Derive key DK from password pPW and salt using scrypt with parameters N,r,p}
function scrypt_kdfs(sPW: Str255; salt: pointer; sLen,N,r,p: longint; var DK; dkLen: longint): integer;
{-Derive key DK from password sPW and salt using scrypt with parameters N,r,p}
function scrypt_kdfss(sPW, salt: Str255; N,r,p: longint; var DK; dkLen: longint): integer;
{-Derive key DK from password sPW and salt using scrypt with parameters N,r,p}
phash := FindHash_by_Name(MyHash);
if phash=nil then begin
{Action for 'Hash function not found/registered.'}
exit;
end;
hmac_init(ctx, phash, @key, sizeof(key));
hmac_update(ctx, @data1, sizeof(data1));
hmac_updateXL(ctx, @data2, sizeof(data2));
{...}
hmac_final(ctx, mac);
hash functioncryptographicareMessage Authentication Code (MAC)HMACusesSHA3_FinalBit_LSBCCHGCHFCAFZCAdigestsfinger printsMAC taged2kHashTHashContextTHashDescarray[THashAlgorithm] of PHashDescFindHash_by…[Hash][Hash]Init[Hash]Update[Hash]Final[Hash]Update[Hash]FinalBitsBDataBitAPI_Mask[L mod 8][Hash]SelfTest[Hash]Full[Hash]FileHMACHMACnilkeyderivpb_kdfscryptCRC/Hash packageHashHMACHMACKDFspecificHMACkey derivationcollisions for SHA1