8

I need to calculate the HMAC by using the SHA256 hash function. I have a secret key encoded in base64 format. Also there is an online tool that correctly calculate the HMAC (verified). http://www.freeformatter.com/hmac-generator.html I wrote the following code snippet:

var signatureHashHexExpected = "559bd871bfd21ab76ad44513ed5d65774f9954d3232ab68dab1806163f806447";
var signature = "123456:some-string:2016-04-12T12:44:16Z";
var key = "AgQGCAoMDhASFAIEBggKDA4QEhQCBAYICgwOEBIUAgQ=";

var shaKeyBytes = Convert.FromBase64String(key);
using (var shaAlgorithm = new System.Security.Cryptography.HMACSHA256(shaKeyBytes))
{
    var signatureBytes = System.Text.Encoding.UTF8.GetBytes(signature);
    var signatureHashBytes = shaAlgorithm.ComputeHash(signatureBytes);
    var signatureHashHex = string.Concat(Array.ConvertAll(signatureHashBytes, b => b.ToString("X2"))).ToLower();

    System.Diagnostics.Debug.Assert(signatureHashHex == signatureHashHexExpected);
}

PROBLEM: My code does not generate the correct HMAC. I verified different steps by using different online tools and alternative C# implementations. Only the conversion from base64 is not confirmed. What am i missing?

UPDATE: Calculated signatureHashHex by my code is "a40e0477a02de1d134a5c55e4befa55d6fca8e29e0aa0a0d8acf7a4370208efc"

ANSWER: The issue was caused by a misleading documentation stating the key is provided in Base64 format. See the accepted answer:

var shaKeyBytes = System.Text.Encoding.UTF8.GetBytes(key);
kalitsov
  • 1,319
  • 3
  • 20
  • 33

2 Answers2

8

Your result is correct, the difference is because the tool you link to does not decode Base64 for the key value and treats it as a series of characters.

E.g. To duplicate its result treat your key as a string:

var shaKeyBytes = System.Text.Encoding.UTF8.GetBytes("AgQGCAoMDhASFAIEBggKDA4QEhQCBAYICgwOEBIUAgQ=");

Which yields

559bd871bfd21ab76ad44513ed5d65774f9954d3232ab68dab1806163f806447

(This is obviously not the right way to do it)

Alex K.
  • 171,639
  • 30
  • 264
  • 288
  • Bother to explain, why `GetBytes(...)` is "obviously wrong"? What if my keyphrase is `"This_is_my_secret_keyphrase"`? – derpirscher Apr 12 '16 at 14:10
  • Because a Base64 string is an encoded series of bytes and its those bytes (after decoding) that should be used, not the string itself. You don't order a new chair then just sit on the box. (`"This_is_my_secret_keyphrase"` is not Base64) – Alex K. Apr 12 '16 at 14:14
  • 1
    A simple string is also an encoded series of bytes. It's just a matter of interpretation. The format the passphrase is stored is completely irrelevant, as long as it can be converted to the correct byte vector used for encryption/decryption. What is the difference between `Convert.FromBase64String("VGhpc19pc19teV9zZWNyZXRfa2V5cGhyYXNl")` and `System.Text.Encoding.UTF8.GetBytes("This_is_my_secret_keyphrase")`? One just has to make sure, that both sides use the same method on the same input. I don't remember a requirement for the key to be a base64 string. – derpirscher Apr 12 '16 at 14:23
  • I don't understand the point of argument, *`GetBytes(...)` is "obviously wrong"* because its used with a value that was intended to be Base64 decoded but was not. – Alex K. Apr 12 '16 at 14:29
  • Guys, the issue was caused by a misleading documentation stating the key is provided in Base64 format. – kalitsov Apr 12 '16 at 14:30
0

HMAC: It is a message authentication code.It is used to verify the sender's data integrity and it is a forward only algorithm.It works on the shared secret key which is known by sender and receiver both.Before generating hash value we have to encode key and message. we can use either one of the encoding UTF8 or ASCIIEncoding.

UTF8 encoding:

var signature = "123456:some-string:2016-04-12T12:44:16Z";
var key = "AgQGCAoMDhASFAIEBggKDA4QEhQCBAYICgwOEBIUAgQ=";


var signatureBytes = System.Text.Encoding.UTF8.GetBytes(signature);
var shaKeyBytes = System.Text.Encoding.UTF8.GetBytes(key);

ASCIIEncoding Encoding:

var signature = "123456:some-string:2016-04-12T12:44:16Z";
var key = "AgQGCAoMDhASFAIEBggKDA4QEhQCBAYICgwOEBIUAgQ=";

var signatureBytes = System.Text.ASCIIEncoding.GetBytes(signature);
var shaKeyBytes = System.Text.ASCIIEncoding.GetBytes(key);

Now we can use this encoded message and key in the above code.

Sheo Dayal Singh
  • 1,591
  • 19
  • 11