Question

I'm using the Microsoft example from http://msdn.microsoft.com/en-us/library/aa382379(v=vs.85).aspx. It compiles fine and appears work, returning the result:

48 f2 57 38 29 29 43 16 fd f4 db 58 31 e1 0c 74 48 8e d4 e2

However when I run the same calculation using C# code below, I get a different hash?

4C-2D-E3-61-BA-89-58-55-8D-E3-D0-49-ED-1F-B5-C1-15-65-6E-65

        HMAC hashMaker = new HMACSHA1(new byte[]{0x70,0x61,0x73,0x73,0x77,0x6F,0x72,0x64});
        byte[] hash = hashMaker.ComputeHash(new byte[] {0x6D,0x65,0x73,0x73,0x61,0x67,0x65});
        string hashStr = BitConverter.ToString(hash);

I fear the example C code is in correct in some way. What is going on here?

Was it helpful?

Solution

The posted C# code and C code linked (but not posted) do different things. The output will therefore be different as well.

The WinCrypt code performs the following:

  • Create a SHA1 hash of the key bytes
  • Derive a session key from the resulting hash using RC4
  • Initialize an HMAC_SHA1 digest using the derived key
  • Perform the HMAC CryptHashData with the HMAC
  • Request the resulting hash bytes

The C# code performs the following:

  • Create an HMAC_SHA1 using the key bytes as the actual key (no derivation)
  • Perform the HMAC via ComputeHash, returning the resulting hash digest

In other words, they're different because they're doing different things. Which one is "right" is dependent on what you're trying to do (which was not mentioned in the question).

OpenSSL Equivalent to the C# code

unsigned char key[] = { 0x70,0x61,0x73,0x73,0x77,0x6F,0x72,0x64 };
unsigned char bytes[] = { 0x6D,0x65,0x73,0x73,0x61,0x67,0x65 };
unsigned char md[32] = {0};
unsigned int md_len = (int)sizeof(md);

HMAC_CTX ctx;
HMAC_CTX_init(&ctx);
HMAC_Init(&ctx, key, (int)sizeof(key), EVP_sha1());
HMAC_Update(&ctx, bytes, sizeof(bytes));
HMAC_Final(&ctx, md, &md_len);

The resulting digest in md matches the C# code respectively (omitted, but take my word for it or test it yourself).

OTHER TIPS

I believe it is not possible to performs a HMAC with a non derive key using CryptoAPI CryptCreateHash.

However it is possible to perform HMAC SHA1/SHA256 using the BCrypt set of methods in the Cryptography API: Next Generation (CNG). See this question for an example.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top