Skip to content

SHA1/SHA224/SHA256 state layouts are not memcpy-safe #742

Closed

Description

@karel-m

In my Perl bindings for libtomcrypt (CryptX), I support cloning digest/MAC contexts.

For a long time, I treated hash_state / hmac_state as effectively copyable by value, but with the current SHA1 and SHA224/SHA256 state layouts this is no longer that simple.

The issue is that these states now contain an internal pointer (state) which points into aligned storage inside the same struct (state_buf). After a raw struct copy, the cloned object still points into the original object’s buffer.

One "solution" would be to remove the clone() method from my Perl bindings, but before doing that I wanted to ask whether there is any chance that these state structs will become memcpy-friendly again.

Activity

  1. sjaeckel commented on Apr 26, 2026

    @sjaeckel
    Member

    As that mechanism exists for a reason, I guess there's not much that can be done to make it memcpy friendly again. Or is there and I simply didn't think of it yet!?

    We could expose a clone() function for the state, or provide an API that repairs the state after copy ...

    BTW this applies to AES as well...

  2. mkj commented on Apr 27, 2026

    @mkj
    Collaborator

    We could expose a clone() function for the state, or provide an API that repairs the state after copy ...

    A clone() API would be useful, Dropbear memcpys hash_state too. Would be worth highlighting the API change in release notes since code will still compile but won't work properly.

  3. MarekKnapek commented on May 6, 2026

    @MarekKnapek
    Contributor

    Oh, that is sad, LibTomCrypt project introduced these changes because of my changes about x86 optimization of those hash functions. Having the state being memcpy-able is very valuable. Surely, we could preserve this high value for the end users, by sacrificing a little bit of convenience on the library side.

    It could be done by many ways. One such idea is: Add the single line of md->sha1.state = LTC_ALIGN_BUF(md->sha1.state_buf, 16); as the first line of the sha1_process and the sha1_done functions. There should be almost no performance penalty as this line should expand into simple bitop on the CPU side.

  4. sjaeckel commented on May 6, 2026

    @sjaeckel
    Member

    FYI I've the clone API done, but not pushed yet.

    Add the single line of md->sha1.state = LTC_ALIGN_BUF(md->sha1.state_buf, 16); as the first line of the sha1_process and the sha1_done

    FMU That alone won't help, because you have the intermediate state to be copied.

    The idea is good!

    What could work is to check the alignment each time these two functions are called, and then recover the values from the buffer with the original alignment if it differs.

    I'll try this tomorrow!

  5. MarekKnapek commented on May 6, 2026

    @MarekKnapek
    Contributor

    Oh, sorry. My other idea was to store an integer there, instead of the pointer. The integer would track how many bytes of state_buf need to be "sacrificed" in order to obtain aligned buffer. Before each *_process and each *_done there would be an additional memmove.

    Other idea is to let the state to be non-aligned. Then modify the implementation, so that it loads the state from un-aligned buffer, does the computation, and finally stores the state into un-aligned buffer. This change would "just" replace any calls to _mm_load_si128 by calls to _mm_loadu_si128 instead. Similar with _mm_store_si128.

  6. sjaeckel commented on May 7, 2026

    @sjaeckel
    Member

    What could work is to check the alignment each time these two functions are called, and then recover the values from the buffer with the original alignment if it differs.

    I'll try this tomorrow!

    Tried it and it works. Now the question goes more in the direction of #756 ... what do we want to do when unaligned memory accesses happen ... I'll merge this for now and we answer that question in #756. The direction is clear now: no clone() API.

  7. linked a pull request that will close this issueMore fixes and improvements #758on May 7, 2026
  8. MarekKnapek commented on May 18, 2026

    @MarekKnapek
    Contributor

    Hi, I created two new branches and two new pull requests. One is #761 adding a unit test about memcpy-able hash state. It is failing with ASan enabled. Second is #762 fixing the hash algorithms such that they work with memcpy-ied states correctly now. Fixing the newly added unit test.

  9. sjaeckel commented on Jul 31, 2026

    @sjaeckel
    Member

    Fixed via #785

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions