Hi,
I'm implementing support for HTTP Message Signatures (https://www.rfc-editor.org/rfc/rfc9421.html), and it requires SHA256 hashing.
Up until now I've lived in a happy little bubble where I've assumed that encodeSHA256 produces the correct hash, but now I realize it doesn't.
The SHA256 hash of 'foobar' should be 'c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2'.
Here are a few ways to verify it:
https://gchq.github.io/CyberChef/#recipe=SHA2('256',64,160)&input=Zm9vYmFy
Linux:
echo -n foobar | sha256sum
Windows:
echo|set /p="foobar" > %TMP%/hash.txt |certutil -hashfile %TMP%/hash.txt SHA256 | findstr /v "hash"
However, using the encodeSHA256 method in CRMScript I get a totally different hash.
String NULL;
printLine(encodeSHA256("", "foobar"));
printLine(encodeSHA256(NULL, "foobar"));
Byte[] bytes = encodeHMACSHA256("", "foobar");
foreach (Byte b in bytes)
print(b.toHex(2));
// All of these give hash 'd7af9ac43019eb74b1787bc22cc8e81791045f48a94b334dab1a54213c4fc609', not the expected 'c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2'
Do we know why?
All Replies (4)
That is because the encodeSHA256 methods are SHA256 with HMAC. The first parameter for those functions are the secret value to use in the hash.
If you try for example this online tool (where you can enable and disable HMAC, and set the secret with HMAC), you will see that it produces different output with and without HMAC. And those two results matches with what you have written in the comment in your code: https://emn178.github.io/online-tools/sha256.html
Unfortunatly, when the name "encodeSHA256" was first created in CRMScript, noone thought about adding "HMAC" to the method name. The newer encodeHMACSHA256 (which returns a byte array) has gotten this incorporated in the method name.
Ah, got it!
So it's hmac-sha256, not sha256.
This uses the GCHQ tool with HMAC: https://gchq.github.io/CyberChef/#recipe=HMAC(%7B'option':'Hex','string':''%7D,'SHA256')&input=Zm9vYmFy
Since there is no encodeSHA256 method overload in CRMScript that just takes a single string, perhaps we could get this?
string encodeSHA256(string message)
That shouldn't break anything?
Currently the onsite customer uses a custom encodeSHA256 method like this, but when they migrate to Online in the future this won't work anymore.
String encodeSHA256(String value)
{
String command = 'cmd.exe /c echo|set /p="' + value + '" > %TMP%/hash.txt |certutil -hashfile %TMP%/hash.txt SHA256 | findstr /v "hash"';
return runProgram(command).stripLeadingAndTrailing("\n");
}
Alternatively I also see that the "HTTP Message Signatures" specification seems to have support for hmac-sha256 (https://www.rfc-editor.org/rfc/rfc9421.html#name-signing-a-request-using-hma), so we could try implementing that instead.
I am not in the position to decide if we will add a SHA256 without HMAC to CRMScript, but if you are able ot use hmac-SHA256, that is probably a better approach.
It could also be possible to implement SHA256 in CRMScript as well. ChatGPT can give you a JavaScript implementation which shouldn't be too hard to translate to CRMScript.
As a side note: the above implementation using cmd.exe does not seem very secure (seen from an isolated perspective) as the "value" parameter isn't escaped in any way.