0

I'm experiencing a problem integrating the output of my SHA256 with HMAC. The first/'inner' SHA256 matches the expected output but the second/'outer' does not.

I am following the first example here:

https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/HMAC_SHA256.pdf

I know:

  • My K0 is correct
  • My K0 xor ipad is correct
  • My K0 xor opad is correct
  • My Hash((Key^ipad)||text) is even correct

The problem is the ASCII representation from the final/outer sha256() is incorrect.

I get 218135127ad7a8e5967ce7b47499214d1df46a9589eb0bec7637c86021fd928d but it should be 8BB9A1DB9806F20DF7F77B82138C7914D174D59E13DC4D0169C9057B133E1D62

Code:

// Up to this point ipad, opad, K0, both XORs all match the expected values

const std::array<uint32_t, 8>& h_output_1 = Hash<BUFFER_SIZE>(&xor_1[0], 64, &message[0], message_length);
// This is correct
LOG("H_1: " << sha256::GetASCIIRepresentation(h_output_1));

const std::array<uint32_t, 8>& h_output_2 = Hash<BUFFER_SIZE>(&xor_2[0], 64, &h_output_1[0], 32);
// This is NOT correct
LOG("H_2: " << sha256::GetASCIIRepresentation(h_output_2));

Hash() appends the two buffers and calculates the SHA256.

Given the first SHA256 works I think the problem is how the 'inner' 8x uint32_ts SHA256 output is appended to K0 xor opad for the final 'outer' SHA256 calculation.

Given the first SHA256 works, can anyone suggest anything?

NB:

I cannot post GetSHA256() but it just returns the final state of the 8x uint32_ts used during the SHA256 transformations.

GetASCIIRepresentation() splits each uint32_t in to 8x 4-bit integers using masking and shifting, then converts to ASCII.

GetSHA256() and GetASCIIRepresentation() are unit tested and work correctly on message inputs beyond 512 bits.

intrigued_66
  • 16,082
  • 51
  • 118
  • 189

1 Answers1

0

std::array<uint32_t, 8>

This is very weird. Expected: std::array<uint8_t, 32>

I suspect you have a byte order problem.

While I've seen the output of a hash be expressed in uint32 before; the implementation was tagged with not being endian invariant and doesn't matter because of how it's used (local machine cache key).

Joshua
  • 40,822
  • 8
  • 72
  • 132
  • `std::array` because it returns the variables used during the SHA256 transformations and they are performed on 8x 32-bit integers (as per the spec). However, I agree I think I have a byte order problem, I just don't know what it is. – intrigued_66 Jul 18 '23 at 18:03
  • @intrigued_66: I'm used to the hash API surface always using byte vectors to ensure there is not. – Joshua Jul 18 '23 at 18:04
  • Do you know what the conversion should be to 32x uint8_ts? I tried having a go but it defeated me. – intrigued_66 Jul 18 '23 at 18:05
  • @intrigued_66: Either it's a big endian loop or it's a little endian loop. In this case since you know the correct answer, whichever one yields the correct answer on probing it must be correct. Use that one. – Joshua Jul 18 '23 at 18:06
  • Yup, i've just figured it. Thanks for confirming. Happy to give you the answer as you did help! – intrigued_66 Jul 18 '23 at 18:09