This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TM4C129ENCPDT: SHA256 SAVING and restoring Intermediate value

Part Number: TM4C129ENCPDT
Other Parts Discussed in Thread: SYSCONFIG

I wish to process part of a SHA256 HAS, save the intermediate result

later load the intermediate result, resume the hash on next bit of data and finalise the hash.

Manual says:

When the hash core is idle or done, a new hash operation can be started. Any additional information
needed by the hash core (mode of operation, data to process, input digest if not starting from
algorithm constants or continuing) must be provided by programming the SHA registers before the
core can accept the operation

However, I have not been able to find any examples of how this can be done

Does anyone have an example of what is required to save and restore the digest for a hash in progress so you can continue at a later time?

or is this not possible for SHA256, SHAMD5, SHA224?

  • Hello Barry,

    We don't have an example of that unfortunately, and our crypto expert is no longer with the team so we may be a bit challenged when it comes to trying to provide very detailed support however I will try and guide the best I can.

    Looking at the SHA Mode section of the datasheet, Section 15.1.5.1, there are a set of steps listed regarding how to start a new Hash. As part of Step 3, it is discussed that for intermediate hashes, you need to set the CLOSE_HASH bit to 0 until you send the final packet which must be hashed at which point you set the CLOSE_HASH bit to 1.

    So this would be how you can load chunks of data until you finish the hash.

    Another relevant passage of the datasheet is as follows:

    "This operation is repeated until the length of the message to hash is reached. The OUPUT_READY bit in the SHA_IRQSTATUS register then indicates that the hash operation is complete. If the IT_EN bit in the SHA_SYSCONFIG register is set, an interrupt (active low) is also generated to indicate the hash completion.

    The processor can then read the eight digest registers A through H that contain the hash and/or HMAC result. If the hash is an intermediate result of a larger hash, the digest count register must also be read and saved."

    So based on this, you would monitor the OUTPUT_READY bit, and then read the digest registers to retrieve your intermediate result. But you also need to read and save the content from the digest count register, which is SHA_DIGEST_COUNT. You would then write the SHA_DIGEST_COUNT register with the value saved when you do the next round of hashing.

    Note I saw the datasheet unfortunately has some typos so that register is referred to as both SHA_DIGESTCOUNT and SHA_DIGEST_COUNT - I will log this as a DS error, but please be aware of that if doing any searches.

    I would recommend you read over Table 15-5 on Page 1051 as well, as it discusses what settings and register writes need to be done in order to do a hash across 3 steps which should be in line with what you want to accomplish. I think you'll be able to use that to write out some code in order to meet your application requirements.

  • Hello Ralph

    Thanks for the response.

    From the information you have given me, I have got this to work and below is a simple example for MD5 so others know what I did (also works for sha1 sha256 etc).

    This code does a simple loop through a string and shows the three stages, Initial block, intermediate blocks and final block.

    I found a couple of important things to note:

    1 - You can only save the intermediate values after a full 64 byte write, so you need to make sure you buffer any smaller writes and do them as a single 64 byte block.  The final block can be 1 to 64 bytes.

    2 - When you a writing back the values you need to do this before you set the length of the new packet being written.  The length is set to the length of the current block, you do not need to know the final length till last block.

    uint8_t     hash[80];
    uint32_t    DigestCount;
    uint32_t    Intermediate[8];
    uint32_t *  ptr;
    uint16_t    offset;
    uint16_t    size;
    const char  hashStr[] = "abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890";
    
    	offset = 0;
    	while (offset < 144)
    	{
    		size = 144 - offset;
    		if (size > 64)
    		{
    			size = 64;
    		}
    		SHAMD5Reset(SHAMD5_BASE);
    		if (offset == 0)
    		{
    			SHAMD5ConfigSet(SHAMD5_BASE, SHAMD5_MODE_ALGO_MD5 | SHAMD5_MODE_ALGO_CONSTANT); // Load constant for first block
    		}
    		else if ((offset + size) == 144)
    		{
    			SHAMD5ConfigSet(SHAMD5_BASE, SHAMD5_MODE_ALGO_MD5 | SHAMD5_MODE_CLOSE_HASH);    // Don't load constant, close hash for last block
    		}
    		else
    		{
    			SHAMD5ConfigSet(SHAMD5_BASE, SHAMD5_MODE_ALGO_MD5);                             // Don't load constant
    		}
    
    		// Wait for the context to be ready before writing the mode.
    		while((HWREG(SHAMD5_BASE + SHAMD5_O_IRQSTATUS) & SHAMD5_INT_CONTEXT_READY) == 0)
    		{
    		}
    
    		if (offset != 0)                                                                 // Restore the starting point from intermediate values
    		{
    			HWREG(SHAMD5_BASE + SHAMD5_O_DIGEST_COUNT) = DigestCount;
    			for (x = 0; x < 8; x++)
    			{
    				HWREG(SHAMD5_BASE + SHAMD5_O_IDIGEST_A + (x * 4)) = Intermediate[x];
    			}
    		}
    
    		// Write the size of data we are adding.
    		SHAMD5HashLengthSet(SHAMD5_BASE, size);
    
    		// Wait until the engine has finished processing the previous block.
    		while((HWREG(SHAMD5_BASE + SHAMD5_O_IRQSTATUS) & SHAMD5_INT_INPUT_READY) == 0)
    		{
    		}
    
    		ptr = (uint32_t *)&hashStr[offset];
    		for (x = 0; x < size; x += 4)
    		{
    			HWREG(SHAMD5_BASE + SHAMD5_O_DATA_0_IN + x) = *ptr++;
    		}
    
    		// Wait until the output is ready
    		while((HWREG(SHAMD5_BASE + SHAMD5_O_IRQSTATUS) & SHAMD5_INT_OUTPUT_READY) == 0)
    		{
    		}
    
    		if ((offset + size) == 144)
    		{
    			SHAMD5ResultRead(SHAMD5_BASE, (uint32_t *)hash);                          // We have finished, get the result
    		}
    		else
    		{
    			// Read the digest count and intermediate data
    			DigestCount = HWREG(SHAMD5_BASE + SHAMD5_O_DIGEST_COUNT);
    			for (x = 0; x < 8; x++)
    			{
    				Intermediate[x] = HWREG(SHAMD5_BASE + SHAMD5_O_IDIGEST_A + (x * 4));
    			}
    		}
    		offset += size;
    	}
    
    

  • Hi Barry,

    Thanks a lot for sharing this code with the community, we really appreciate these follow-up posts!! I am sure others will be grateful in the future too.