Problem:
I am trying to compute the SHA256 digests of single blocks (512 bit) on an STM32L552ZE-Q using mbedTLS the HASH device built into the STM32 I am using. Unfortunately, the digest doesn't agree with that of Python's SHA256 implementation, even for a single block of all-zeros.
Sample output:
Python: f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b
STM32, data-type= 1 bit: B20941D6177356919BCDF1F716029D5F53C81932439D59B98F04A5EE0E192A25
STM32, data-type != 1 bit 037D6DFB3A369A41E01100FDD53C35EE3FB69DDEC5830D61E1138D066A4C2285
Above results are very confusing. The STM32 reference manual for my MCU specifies that the HASH device operates on 32 bit words in big-endian and that messages need to account for that by specifying the data type to be 1, 8, 16 or 32 bit. Setting these values causes the bits to be reordered, though in my mind the ordering should NOT have an impact for an all-0 block because any permuation of a sequence of 64 0's is again just 64 0's. I clearly misunderstand something, as changing the data type (i.e. the reordering) causes the hash to change.
Python code:
from cryptography.hazmat.primitives import hashes
digest = hashes.Hash(hashes.SHA256())
by = b"\0" * 64
digest.update(by)
print(digest.finalize().hex())
STM32 code:
#define SHA256_INPUT_SIZE 64 // 512 bit
#define SHA256_OUTPUT_SIZE 32 // 256 bit
// (0) Initialize the HASH peripheral
MX_HASH_Init();
// (1) Create input buffer of size one block (512 bit, 64 byte) and initialize it with all 0-bytes
byte_t ibuf[SHA256_INPUT_SIZE];
memset(ibuf, 0, sizeof(ibuf));
// (2) Create output buffer of size 256 bit, 32 byte (setting it to all 1-bytes shouldn't be relevant)
byte_t obuf[SHA256_OUTPUT_SIZE];
memset(obuf, 1, sizeof(ibuf));
// (3) Compute the digest based on ibuf and store it into obuf
HAL_StatusTypeDef rv = HAL_HASHEx_SHA256_Start(&hhash, ibuf, SHA256_INPUT_SIZE, obuf, 10);
char debug_msg[MAX_PRINT_LEN];
// (4) Print an error message or the hash digest.
if(rv != HAL_OK){
sprintf(debug_msg, "ERROR: HAL_HASHEx_SHA256_Start failed on line %i\r\n", __LINE__);
}
else{
char hash_buf[SHA256_OUTPUT_SIZE * 3]; // For one byte of the output digest, e.g. value 24, we write THREE characters (except for last byte of output, we only write TWO characters).
// Here, for value 24 we would write "18:" for 24 not the last byte and "18" if it is the last byte.
memset(hash_buf, 1, sizeof(hash_buf));
bytes_to_hex_string(obuf, SHA256_OUTPUT_SIZE, hash_buf);
sprintf(debug_msg, "DEBUG: Hash output: %s\r\n", hash_buf);
}
print_debug(debug_msg);
Questions:
Visual representation of the reordering according to the "data-type":
Turns out that the problem was caused by me being sloppy and writing memset(obuf, 1, sizeof(ibuf));
instead of memset(obuf, 1, sizeof(obuf));
. This caused the memset to overwrite part of the input buffer to contain 256 1-bits. This also explains why the reordering feature of the STM32 caused the output to change...