Was a problem between unicode and ascii.
Code: Select all
;
; https://en.wikipedia.org/wiki/HMAC
;
; HMAC(M) = H((K XOR opad) + H((K XOR ipad) + M))
;
; M = message
; K = key
; opad = 0x5C
; ipad = 0x36
; H = hash function
;
; https://www.purebasic.fr/english/viewtopic.php?p=599038#p599038
CompilerIf #PB_Compiler_IsMainFile
EnableExplicit
CompilerEndIf
Procedure StringHMAC_HexStringToBin(*HexString.Ascii, *Destination.Ascii)
Protected HighNibble, LowNibble
If *HexString And *Destination
While *HexString\a
HighNibble = *HexString\a - '0'
If HighNibble > $f
HighNibble - $27
EndIf
*HexString + 2
LowNibble = *HexString\a - '0'
If LowNibble > $f
LowNibble - $27
EndIf
*HexString + 2
*Destination\a = HighNibble << 4 | LowNibble
*Destination + 1
;Debug Hex(HighNibble << 4 | LowNibble, #PB_Ascii)
Wend
EndIf
EndProcedure
Procedure.s StringHMAC(msg$, key$, cipher.i=#PB_Cipher_SHA1, bits.i=256, encode$="Hex")
#IPAD = $36
#OPAD = $5C
Protected.i i, BlockSize, cipherResultSize
Protected result$, innerHash$
Protected *tmp, *ptr.Ascii, *innerHash, *outerHash
; adjust the needed values for different ciphers
BlockSize = 64
Select cipher
Case #PB_Cipher_MD5
cipherResultSize = 16
Case #PB_Cipher_SHA1
cipherResultSize = 20
Case #PB_Cipher_SHA2
If bits > 256
BlockSize = 128
EndIf
cipherResultSize = bits / 8
Case #PB_Cipher_SHA3
Select bits
Case 224
BlockSize = 1152 / 8
Case 256
BlockSize = 1088 / 8
Case 384
BlockSize = 832 / 8
Case 512
BlockSize = 576 / 8
EndSelect
cipherResultSize = bits / 8
Default
ProcedureReturn "cipher not implemented"
EndSelect
; special rule if length of the key is larger then the blocksize:
; use H(K) instead of K
If StringByteLength(key$, #PB_Ascii) > BlockSize
key$ = StringFingerprint(key$, cipher, bits, #PB_Ascii)
*tmp = AllocateMemory(cipherResultSize)
If *tmp
StringHMAC_HexStringToBin(@key$, *tmp)
key$ = PeekS(*tmp, cipherResultSize, #PB_Ascii)
FreeMemory(*tmp)
EndIf
EndIf
*outerHash = AllocateMemory(BlockSize + cipherResultSize)
If *outerHash
; K XOR opad
*ptr = *outerHash
PokeS(*outerHash, key$, -1, #PB_Ascii|#PB_String_NoZero)
For i = 0 To BlockSize - 1
*ptr\a = *ptr\a ! #OPAD
*ptr + 1
Next i
*innerHash = AllocateMemory(BlockSize + StringByteLength(msg$, #PB_UTF8))
If *innerHash
; K XOR ipad
*ptr = *innerHash
PokeS(*innerHash, key$, -1, #PB_Ascii|#PB_String_NoZero)
For i = 0 To BlockSize - 1
*ptr\a = *ptr\a ! #IPAD
*ptr + 1
Next i
; (K XOR ipad) + M)
PokeS(*ptr, msg$, -1, #PB_UTF8|#PB_String_NoZero)
; H((K XOR ipad) + M))
innerHash$ = Fingerprint(*innerHash, MemorySize(*innerHash), cipher, bits)
; (K XOr opad) + H((K XOr ipad) + M)
StringHMAC_HexStringToBin(@innerHash$, *outerHash + BlockSize)
; H((K XOR opad) + H((K XOR ipad) + M))
result$ = Fingerprint(*outerHash, BlockSize + cipherResultSize, cipher, bits)
; optional result is coded in Base64
If LCase(encode$) = "base64"
*tmp = AllocateMemory(cipherResultSize)
If *tmp
StringHMAC_HexStringToBin(@result$, *tmp)
result$ = Base64Encoder(*tmp, MemorySize(*tmp))
FreeMemory(*tmp)
EndIf
EndIf
FreeMemory(*innerHash)
EndIf
FreeMemory(*outerHash)
EndIf
ProcedureReturn result$
EndProcedure
CompilerIf #PB_Compiler_IsMainFile
Define key$, msg$
UseMD5Fingerprint()
UseSHA1Fingerprint()
UseSHA2Fingerprint()
UseSHA3Fingerprint()
msg$ = "test string"
key$ = "testkey123"
Debug "Hex : " + StringHMAC(msg$, key$)
Debug "Base64: " + StringHMAC(msg$, key$, #PB_Cipher_SHA1, 0, "Base64")
Debug "PHP : XosSbTmfw5OJ4mh1NSupUH3l7HY="
; Example from:
; https://developer.twitter.com/en/docs/authentication/oauth-1-0a/creating-a-signature
msg$ = "POST&https%3A%2F%2Fapi.twitter.com%2F1.1%2Fstatuses%2Fupdate.json&include_entities%3Dtrue%26oauth_consumer_key%3Dxvz1evFS4wEEPTGEFPHBog%26oauth_nonce%3DkYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1318622958%26oauth_token%3D370773112-GmHxMAgYyLbNEtIKZeRNFsMKPR9EyMZeS9weJAEb%26oauth_version%3D1.0%26status%3DHello%2520Ladies%2520%252B%2520Gentlemen%252C%2520a%2520signed%2520OAuth%2520request%2521"
key$ = "kAcSOqF21Fu85e7zjz7ZN2U4ZRhfV3WpwPAoE3Z7kBw&LswwdoUaIvS8ltyTt5jkRh4J50vUPVVHtR2YPi5kE"
Debug ""
Debug "twitter " + StringHMAC(msg$, key$)
Debug "Should be: 842b5299887e88760212a056ac4ec2ee1626b549"
; following tests are verified by
; (https://www.freeformatter.com/hmac-generator.html) no SHA-3 calculations
; https://appdevtools.com/hmac-generator generates false SHA-3 !!!!!!
; https://www.liavaag.org/English/SHA-Generator/HMAC/
; https://wtools.io/generate-hmac-hash
Debug ""
Debug "test For non ASCII:"
msg$ = "Begrüßung"
key$ = "123"
Debug "msg: " + msg$
Debug "key: " + key$
Debug ""
Debug "SHA1 " + StringHMAC(msg$, key$)
Debug "Should be: 149b6e8402e9526bbcbc93dc99b0fea3b65e25b0"
msg$ = "PureBasic"
key$ = "123456"
Debug ""
Debug "All ciphers tests:"
Debug "msg: " + msg$
Debug "key: " + key$
Debug ""
Debug "MD5 " + StringHMAC(msg$, key$, #PB_Cipher_MD5)
Debug "Should be: bc2c0b90c3b8b46ebdab6a188ce7546c"
Debug ""
Debug "SHA1 " + StringHMAC(msg$, key$, #PB_Cipher_SHA1)
Debug "Should be: 9fa85352d7a125c06f1c0f4653633ee482b9e216"
Debug ""
Debug "SHA2 224 " + StringHMAC(msg$, key$, #PB_Cipher_SHA2, 224)
Debug "Should be: b230ab71aca84befc565276112a3c16356cbdbd70c465080e1c7ee89"
Debug ""
Debug "SHA2 256 " + StringHMAC(msg$, key$, #PB_Cipher_SHA2, 256)
Debug "Should be: 27d722c54c40d9b9b4e15db1e5da439b493f22872d469b7bc60ab73d05d7a486"
Debug ""
Debug "SHA2 384 " + StringHMAC(msg$, key$, #PB_Cipher_SHA2, 384)
Debug "Should be: c348fe1e3a4acfd2d180feaca699145100f0f6a0bc02472ee775b250a99a5dcca947496c86ae9ed62cda320f99e7bc54"
Debug ""
Debug "SHA2 512 " + StringHMAC(msg$, key$, #PB_Cipher_SHA2, 512)
Debug "Should be: cc0d17134c476566e6d19d9bb6f08ca127209b711cf1669d3169541d038de1dae9efd031f473b8f502326ee1aec1612dc2309da00f49c163746e4e1f85e305d1"
Debug ""
Debug "SHA3 224 " + StringHMAC(msg$, key$, #PB_Cipher_SHA3, 224)
Debug "Should be: 8a3e3c00fa9ecec23c8e14336936ea6b62b81e2742ac9c171e931a27"
Debug ""
Debug "SHA3 256 " + StringHMAC(msg$, key$, #PB_Cipher_SHA3, 256)
Debug "Should be: 56d40211ecbf9825d2545fadb2768aed781fe9bd0cbf33e874e2308e430241b7"
Debug ""
Debug "SHA3 384 " + StringHMAC(msg$, key$, #PB_Cipher_SHA3, 384)
Debug "Should be: af025b8dea23ee1db0ceaa60904ec28778a6e3a8c1d12924cf63c952a0689cc98e1df1cb448c2c7b7544cc33a26e3632"
Debug ""
Debug "SHA3 512 " + StringHMAC(msg$, key$, #PB_Cipher_SHA3, 512)
Debug "Should be: 7a46e0efc0fe813c992f2e86a70c304cc65b590e0cc6f3870936e0b96cf39d4aa98a480e66aae359d72f851c133e6b6a53fe06a1f7ebcd02186ab65c06f9a9fb"
CompilerEndIf