[AHK V2] How to use raw bytes in bcrypt_sha256_hmac Topic is solved

Get help with using AutoHotkey (v2 or newer) and its commands and hotkeys
micasa
Posts: 24
Joined: 29 Dec 2018, 04:21

[AHK V2] How to use raw bytes in bcrypt_sha256_hmac

Post by micasa » 12 Feb 2019, 07:24

Hello, everyone.

This is a follow-up question to a question I asked last month:

https://www.autohotkey.com/boards/viewtopic.php?t=60434

I need to make an AWS API call that requires lots of setup using hash functions.

Thanks to @vvhitevvizard, I was able to obtain a Hex2Bin function that helped me get further along the process.

The final part of the setup looks like this in Python code:

Code: Select all

signature = hmac.new(signing_key, (string_to_sign).encode('utf-8'), hashlib.sha256).hexdigest()
signing_key is raw bytes. As far as I know, bcrypt_sha256_hmac by @jNizM cannot handle raw bytes as-is. Here is bcrypt_sha256_hmac:

Code: Select all

bcrypt_sha256_hmac(string, hmac)
{
    static BCRYPT_SHA256_ALGORITHM     := "SHA256"
    static BCRYPT_ALG_HANDLE_HMAC_FLAG := 0x00000008
    static BCRYPT_HASH_LENGTH          := "HashDigestLength"

    if !(hBCRYPT := DllCall("LoadLibrary", "str", "bcrypt.dll", "ptr"))
        throw Exception("Failed to load bcrypt.dll", -1)

    if (NT_STATUS := DllCall("bcrypt\BCryptOpenAlgorithmProvider", "ptr*", hAlgo, "ptr", &BCRYPT_SHA256_ALGORITHM, "ptr", 0, "uint", BCRYPT_ALG_HANDLE_HMAC_FLAG) != 0)
        throw Exception("BCryptOpenAlgorithmProvider: " NT_STATUS, -1)

    if (NT_STATUS := DllCall("bcrypt\BCryptGetProperty", "ptr", hAlgo, "ptr", &BCRYPT_HASH_LENGTH, "uint*", cbHash, "uint", 4, "uint*", cbResult, "uint", 0) != 0)
        throw Exception("BCryptGetProperty: " NT_STATUS, -1)

    VarSetCapacity(pbInput,  StrPut(string, "UTF-8"), 0) && cbInput  := StrPut(string, &pbInput,  "UTF-8") - 1
    VarSetCapacity(pbSecret, StrPut(hmac, "UTF-8"), 0)   && cbSecret := StrPut(hmac,   &pbSecret, "UTF-8") - 1
    VarSetCapacity(pbHash, cbHash, 0)
    if (NT_STATUS := DllCall("bcrypt\BCryptHash", "ptr", hAlgo, "ptr", &pbSecret, "uint", cbSecret, "ptr", &pbInput, "uint", cbInput, "ptr", &pbHash, "uint", cbHash) != 0)
        throw Exception("BCryptHash: " NT_STATUS, -1)

    loop cbHash
        hash .= Format("{:02x}", NumGet(pbHash, A_Index - 1, "uchar"))

    DllCall("bcrypt\BCryptCloseAlgorithmProvider", "ptr", hAlgo, "uint", 0)
    DllCall("FreeLibrary", "ptr", hBCRYPT)

    return hash
}
The line of interest is:

Code: Select all

VarSetCapacity(pbSecret, StrPut(hmac, "UTF-8"), 0)   && cbSecret := StrPut(hmac,   &pbSecret, "UTF-8") - 1
That line expects the parameter hmac (signing_key) to be UTF-8. StrPut doesn't have an option for raw bytes.

Does anyone know how to work around this? A solution in AHK V1 would also be welcomed.

Thanks in advance for any help and consideration.
just me
Posts: 9576
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [AHK V2] How to use raw bytes in bcrypt_sha256_hmac  Topic is solved

Post by just me » 12 Feb 2019, 10:20

If your 'signing_key' has binary contents, just pass the address of the variable and the size in bytes to the function:

Code: Select all

bcrypt_sha256_hmac_addr(string, hmacAddr, hmacSize) ; <<<<< changed!
{
    static BCRYPT_SHA256_ALGORITHM     := "SHA256"
    static BCRYPT_ALG_HANDLE_HMAC_FLAG := 0x00000008
    static BCRYPT_HASH_LENGTH          := "HashDigestLength"

    if !(hBCRYPT := DllCall("LoadLibrary", "str", "bcrypt.dll", "ptr"))
        throw Exception("Failed to load bcrypt.dll", -1)

    if (NT_STATUS := DllCall("bcrypt\BCryptOpenAlgorithmProvider", "ptr*", hAlgo, "ptr", &BCRYPT_SHA256_ALGORITHM, "ptr", 0, "uint", BCRYPT_ALG_HANDLE_HMAC_FLAG) != 0)
        throw Exception("BCryptOpenAlgorithmProvider: " NT_STATUS, -1)

    if (NT_STATUS := DllCall("bcrypt\BCryptGetProperty", "ptr", hAlgo, "ptr", &BCRYPT_HASH_LENGTH, "uint*", cbHash, "uint", 4, "uint*", cbResult, "uint", 0) != 0)
        throw Exception("BCryptGetProperty: " NT_STATUS, -1)

    VarSetCapacity(pbInput,  StrPut(string, "UTF-8"), 0) && cbInput  := StrPut(string, &pbInput,  "UTF-8") - 1
    ; VarSetCapacity(pbSecret, StrPut(hmac, "UTF-8"), 0)   && cbSecret := StrPut(hmac,   &pbSecret, "UTF-8") - 1 ; <<<<< changed!
    VarSetCapacity(pbHash, cbHash, 0)
    if (NT_STATUS := DllCall("bcrypt\BCryptHash", "ptr", hAlgo, "ptr", hmacAddr, "uint", hmacSize, "ptr", &pbInput, "uint", cbInput, "ptr", &pbHash, "uint", cbHash) != 0) ; <<<<< changed!
        throw Exception("BCryptHash: " NT_STATUS, -1)

    loop cbHash
        hash .= Format("{:02x}", NumGet(pbHash, A_Index - 1, "uchar"))

    DllCall("bcrypt\BCryptCloseAlgorithmProvider", "ptr", hAlgo, "uint", 0)
    DllCall("FreeLibrary", "ptr", hBCRYPT)

    return hash
}
* not tested *
micasa
Posts: 24
Joined: 29 Dec 2018, 04:21

Re: [AHK V2] How to use raw bytes in bcrypt_sha256_hmac

Post by micasa » 12 Feb 2019, 11:03

just me wrote:
12 Feb 2019, 10:20
If your 'signing_key' has binary contents, just pass the address of the variable and the size in bytes to the function
@just me, thank you very much for your time and solution. I should have mentioned this in my OP, but the raw bytes are in an array, not a string. So, my naive attempt failed. (Sorry I am not a very skillful programmer).

As a test, I am using this:

Code: Select all

key := "12345abcde"
string := "안녕하세요"
bytes := []
Hex2Bin(bcrypt_sha256_hmac(string, key), bytes) ; get the bytes (confirmed to be equivalent to Python hmac digest)
signature := bcrypt_sha256_hmac_addr(string, &bytes, StrLen(bytes)) ; use the result of the previous step as the hmac
MsgBox(signature)
This gives a signature of 353d68c206dcf856557f1854990a4708fed6ed63c8ec4ef14a41c049003d26d5

I am guessing StrLen(bytes) is wrong because bytes is an array. I tried bytes.Length() but that threw an error (no object to invoke).

I am testing this against the following Python code:

Code: Select all

import hashlib
import hmac
key = "12345abcde"
string = "안녕하세요"
sign = hmac.new(key.encode("utf-8"), string.encode("utf-8"), hashlib.sha256).digest()
signature = hmac.new(sign, string.encode("utf-8"), hashlib.sha256).hexdigest()
print(signature)
That gives a signature of 44989b27e5c1669c9c4e03a93b14147aec9ef8a01479c257af37a130f64af7ba

If you have the time, could you please tell me how to call your modified function with that byte array?

Thank you for your help.
micasa
Posts: 24
Joined: 29 Dec 2018, 04:21

Re: [AHK V2] How to use raw bytes in bcrypt_sha256_hmac

Post by micasa » 12 Feb 2019, 11:30

I got it to work!! Thank you @just me!

I just noticed that the Hex2Bin function that @vvhitevvizard created for me has a return value with the size of the binary content:

Code: Select all

Hex2Bin(ByRef _s, ByRef _b, _f:=0x4){ ;_s:hex string, _b:byte array, _f:flags 4=CRYPT_STRING_HEX
;converts a hex string into an array of bytes:
	s:="Crypt32.dll\CryptStringToBinary"
	DllCall(s, 'str',_s, 'uint',n1:=StrLen(_s), 'uint',_f, 'ptr',0, 'uintp',n2, 'ptr',0, 'ptr',0)
	VarSetCapacity(_b, n2), DllCall(s, 'str',_s, 'uint',n1, 'uint',_f, 'str',_b, 'uintp',n2, 'ptr',0, 'ptr',0)
	return n2
}
Now, I just revised my code as follows and it works:

Code: Select all

key := "12345abcde"
string := "안녕하세요"
bytes := []
size := Hex2Bin(bcrypt_sha256_hmac(string, key), bytes)
signature := bcrypt_sha256_hmac_addr(string, &bytes, size)
MsgBox(signature)
The strange thing is that when I tried bytes.MaxIndex() or bytes.Length(), I was getting a "Not an object" error.

Thank you @just me and @@vvhitevvizard!
just me
Posts: 9576
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [AHK V2] How to use raw bytes in bcrypt_sha256_hmac

Post by just me » 12 Feb 2019, 11:40

AFAICS, Hex2Bin() does not create an AHK array. It's a simple memory buffer. Its size is returned by the function. So this may work:

Code: Select all

key := "12345abcde"
string := "안녕하세요"
bytes := ""
size := Hex2Bin(bcrypt_sha256_hmac(string, key), bytes) ; get the bytes (confirmed to be equivalent to Python hmac digest)
signature := bcrypt_sha256_hmac_addr(string, &bytes, size) ; use the result of the previous step as the hmac
MsgBox(signature)
Edit: Too late!
Post Reply

Return to “Ask for Help (v2)”