`sha256_hmac_init`: if `len < 64`, potentially uninitialised data is read
I could not find any Github issues about this, or any mention of this in the FAQ.
Describe the bug
When writing a custom kernel that uses sha256_hmac_init, it's very easy to get wrong results. This happens because even though sha256_hmac_init takes the length of the passed buffer as argument (len). The implementation of sha256_hmac_init assumes that this len is at least 64 bytes long.
To Reproduce
- Write a custom kernel that at some point contains the snippet:
u32 buf[8] = { 0 };
// omitted: fill buf with values
sha256_hmac_ctx_t ctx;
sha256_hmac_init(&ctx, buf, sizeof(buf));- Compile your kernel, and run it with a test hash.
- Observe that the test hash doesn't crack.
Expected behavior The test hash cracks.
Hashcat version:
- OS: Linux
- Distribution: Ubuntu 24.04
- Version: 5d5990ce38311260724aa914955c532e1f5188e9
Additional context
Looking at the implementation of sha256_hmac_init:
Notice that w is accessed as if it's a 16-element u32 array if len <= 64. In the example above, where the passed buffer was only 8 elements long, this caused sha256_hmac_init to read uninitialised memory, which leads to unpredictable results, and bugs that are very hard to track down.
I see a few options on how to resolve this, all of them seem to have their downsides. I'll order them based on my personal preference (from best to worst), as someone who occasionally builds a hashcat kernel, but not often enough to remember this footgun.
- Add a compile-time assert that
len == 64in theelsecase. I'm not sure if the way kernels are compiled currently allows for compiler-time asserts. I couldn't find any in the code. However, this would be a nice option, since this would fail at compile-time, and it should show the kernel developer exactly what's wrong. Another upside to this option, is that it would not change the code that the compiler produces forsha256_hmac_init, so it has no performance impact. - Add a separate branch for
len < 64, where the passed buffer is copied only up tolenand the rest of the buffer is padded with null bytes. This will always work, but it might be slower. It seems like just giving 64-bytes tosha256_hmac_initis always faster. In this option, it will work, but it will work silently, not letting the kernel developer know there's room for improvement. Thelen == 64case might be constant-folded by the compiler, so it seems plausible that there is no performance impact if the passed length is 64. - Add documentation to
sha256_hmac_initto never pass in a buffer that is shorter than 64 bytes. This is probably the easiest patch, but a comment in the header file might be easily overlooked by kernel developers.
I wonder what the hashcat maintainers think about this. Is this an issue worth fixing? If so, would any of the methods I mentioned be a good idea?
Source: hashcat/hashcat