THX, TLM.
Here's a 'completed' version seeming to work still (quickly tested on quickhash.com/hmac and
Code: Select all
#NoEnv
SetBatchLines, -1
Algorithms := ["MD2", "MD4", "MD5", "SHA", "SHA256", "SHA384", "SHA512"]
Key := "key"
Msg := "The quick brown fox jumps over the lazy dog"
Out := "Text`t" . Msg . "`nKey`t" . Key . "`n"
Rows := 2 + Algorithms.MaxIndex() + 1
Gui, Margin, 10, 10
Gui, Font, , Courier New
Gui, Add, ListView, w980 r%Rows% -Hdr, 1|2
LV_Add("", "Text", Msg)
LV_Add("", "Key", Key)
For Each, Algo In Algorithms
LV_Add("", Algo, HMAC(Key, Msg, Algo))
LV_ModifyCol()
Gui, Show, , Results
Return
GuiCLose:
GuiEscape:
ExitApp
; ======================================================================================================================
; Function:
; Calculates a hash-based message authentication code (HMAC).
; -> en.wikipedia.org/wiki/Hash-based_message_authentication_code)
; Parameters:
; Key - Key as string.
; Message - Message as string.
; Algo - Hash algorithm to use (one of the string keys defined in Algorithms).
; Return values:
; Returns the hexadicimal HMAC value on success, otherwise an empty string ("").
; ======================================================================================================================
HMAC(Key, Message, Algo := "MD5") {
Static Algorithms := {MD2: {ID: 0x8001, Size: 64}
, MD4: {ID: 0x8002, Size: 64}
, MD5: {ID: 0x8003, Size: 64}
, SHA: {ID: 0x8004, Size: 64}
, SHA256: {ID: 0x800C, Size: 64}
, SHA384: {ID: 0x800D, Size: 128}
, SHA512: {ID: 0x800E, Size: 128}}
Static IC := 0x36 ; $iconst
Static OC := 0x5C ; $oconst
; Init --------------------------------------------------------------------------------------------------------------
If !Algorithms.HasKey(Algo)
Return ""
Hash := ""
HashLen := 0
AlgID := Algorithms[Algo].ID
BlockSize := Algorithms[Algo].Size
MsgLen := StrPut(Message, "UTF-8") - 1
KeyLen := StrPut(Key, "UTF-8") - 1
VarSetCapacity(K, KeyLen + 1, 0)
StrPut(Key, &K, KeyLen, "UTF-8")
If (KeyLen > BlockSize)
HMAC_Hash(&K, KeyLen, AlgID, KeyHash, KeyHashLen)
; Inner hash --------------------------------------------------------------------------------------------------------
VarSetCapacity(IP, BlockSize + MsgLen, IC) ; $ipad
Addr := KeyLen > BlockSize ? &KeyHash : &K
Length := KeyLen > BlockSize ? KeyHashLen : KeyLen
I := 0
While (I < Length) {
NumPut(NumGet(Addr + 0, I, "UChar") ^ IC, IP, I, "UChar")
I++
}
If (MsgLen)
StrPut(Message, &IP + BlockSize, MsgLen, "UTF-8")
HMAC_Hash(&IP, BlockSize + MsgLen, AlgID, InnerHash, InnerHashLen)
; Outer hash --------------------------------------------------------------------------------------------------------
VarSetCapacity(OP, BlockSize + InnerHashLen, OC) ; $opad
Addr := KeyLen > BlockSize ? &KeyHash : &K
Length := KeyLen > BlockSize ? KeyHashLen : KeyLen
I := 0
While (I < Length) {
NumPut(NumGet(Addr + 0, I, "UChar") ^ OC, OP, I, "UChar")
I++
}
Addr := &OP + BlockSize
I := 0
While (I < InnerHashLen) {
NumPut(NumGet(InnerHash, I, "UChar"), Addr + I, 0, "UChar")
I++
}
Return HMAC_Hash(&OP, BlockSize + InnerHashLen, AlgID)
}
; ======================================================================================================================
; Originally released by jNizM at
; http://www.autohotkey.com/board/topic/89237-bentschis-funktion-hash-von-strings-erweitert-um-sha2-klassen/
; Function:
; Calculates a hash.
; Parameters:
; DataAddr - Address of the data to hash.
; DataLength - Length of the data to hash.
; AlgID - ID of the hash algorithm to use (see HMAC() -> Algorithms).
; ------------- Optional:
; HashValue - Variable to return the binary hash value.
; HashLen - Variable to return the length of the binary hash.
; Return Values:
; Returns the hexadecimal hash value on success, otherwise an empty string ("").
; ======================================================================================================================
HMAC_Hash(DataAddr, DataLength, AlgID, ByRef HashValue := "", ByRef HashLength := 0) {
Static X := {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9
, 10: "A", 11: "B", 12: "C", 13: "D", 14: "E", 15: "F"}
Result := ""
If DllCall("advapi32.dll\CryptAcquireContext"
, "PtrP", Prov, "Ptr", 0, "Ptr", 0, "UInt", 24, "UInt", 0xF0000000) {
If DllCall("advapi32.dll\CryptCreateHash"
, "Ptr", Prov, "UInt", AlgID, "UInt", 0, "UInt", 0, "PtrP", Hash) {
If DllCall("advapi32.dll\CryptHashData"
, "Ptr", Hash, "Ptr", DataAddr, "UInt", DataLength, "UInt", 0) {
If DllCall("advapi32.dll\CryptGetHashParam"
, "Ptr", Hash, "UInt", 2, "Ptr", 0, "UIntP", HashLength, "UInt", 0) {
VarSetCapacity(HashValue, HashLength, 0)
If DllCall("advapi32.dll\CryptGetHashParam"
, "Ptr", Hash, "UInt", 2, "Ptr", &HashValue, "UIntP", HashLength, "UInt", 0) {
Loop, % HashLength
Result .= X[(V := NumGet(HashValue, A_Index - 1, "UChar")) >> 4] . X[V & 0x0F]
}
}
}
DllCall("advapi32.dll\CryptDestroyHash", "Ptr", Hash)
}
DllCall("advapi32.dll\CryPtreleaseContext", "Ptr", Prov, "UInt", 0)
}
Return Result
}