Skip to main content
Associate
July 8, 2026
Question

Subject: STSAFE-A110 Local Envelope Unwrap fails with STSAFEA_CRYPTO_LIB_ISSUE (0x20) when using STSAFEA_ENCRYPTION_RESPONSE — Wrap succeeds wit

  • July 8, 2026
  • 1 reply
  • 21 views

Hi,

I'm integrating an STSAFE-A110 with stsafe-a-openssl-engine V2.0.0 on a Linux/aarch64 host (Jetson AGX Orin, Ubuntu 22.04, OpenSSL 3.0.2), communicating over I2C. I've resolved a number of earlier issues (wrong I2C bus, OpenSSL 3.0 API migration, host key pairing) and now have Host Key programming, Local Envelope key generation, Product Data query, Life Cycle State query, and Command Authorization Configuration query all succeeding against the physical chip.

Current issue: StSafeA_WrapLocalEnvelope and StSafeA_UnwrapLocalEnvelope behave asymmetrically.

My chip's Command Authorization Configuration reports:

  • Command 0x0E (Wrap Local Envelope): CommandAC = 0x03 (MAC), HostEncryptionFlags = 0x02 (command encryption)
  • Command 0x0F (Unwrap Local Envelope): CommandAC = 0x03 (MAC), HostEncryptionFlags = 0x01 (response encryption)

Calling Wrap with STSAFEA_MAC_HOST_CMAC, STSAFEA_ENCRYPTION_COMMAND succeeds and returns a plausible 488-byte wrapped envelope.

Calling Unwrap on that same output with STSAFEA_MAC_HOST_CMAC, STSAFEA_ENCRYPTION_RESPONSE fails with STSAFEA_CRYPTO_LIB_ISSUE (0x20), reported by StSafeA_DataDecryption in stsafea_crypto.c.

What I've isolated so far:

  • inlen passed to StSafeA_UnwrapLocalEnvelope is correct (488 = ENVELOPE_SIZE + 8).
  • StSafeA_AES_ECB_Encrypt (computing the initial value) and StSafeA_AES_CBC_Decrypt both report success (status 0x00) at the OpenSSL layer.
  • However, the resulting "decrypted" buffer contains no valid 0x80 padding marker anywhere near the expected offset — the tail bytes look like random noise, not a padded 480-byte envelope. So the CBC decrypt call succeeds mechanically but produces incorrect plaintext, which then fails StSafeA_DataDecryption's padding-marker validation.
  • The host CMAC sequence counter (pStSafeA->HostMacSequenceCounter) is freshly re-queried from the chip via StSafeA_GetHostMacSequenceCounter immediately before each CMAC-flagged command, so it isn't stale between the Wrap and Unwrap calls.
  • aHostCipherKey is a static array, unmodified between the two calls.
  • The ComputeInitialValue direction enum values look correct per the source (C_ENCRYPTION = 2, R_ENCRYPTION = 3).

I found a similar-sounding symptom in this thread (different command, EstablishKey, but same STSAFEA_ENCRYPTION_RESPONSE + STSAFEA_CRYPTO_LIB_ISSUE-adjacent behavior), where the resolution involved personalization profile (SPL02 vs SPL03) and a prerequisite pairing step from the X-CUBE-SAFEA1 example: [link to that thread]

Questions:

  1. Does Local Envelope Unwrap (response-encrypted) require a pairing/session step beyond basic host key programming (HostKeyPresenceFlag confirmed = 1) — similar to what's needed for EstablishKey with STSAFEA_ENCRYPTION_RESPONSE on SPL03 profiles?
  2. Is there a known issue with ComputeInitialValue's IV construction specifically for the R_ENCRYPTION case in this library version?
  3. Could you point me to documentation on the exact IV/counter semantics expected for response decryption, so I can verify against my host-side implementation?

Happy to share my ST Product Number / PersoId from a Product Data query if that helps identify my personalization profile.

Thanks in advance for any guidance.

1 reply

Associate
July 8, 2026

Follow-up: isolated the exact byte-level behavior

I've dug further and can now describe precisely what's happening on the wire, which should help pinpoint this.

Setup: 480-byte plaintext envelope → Wrap → 488-byte wrapped output (matches ENVELOPE_SIZE + 8, as expected) → feed that 488 bytes into Unwrap.

What I'm seeing:

  • My host-side pre-receive calculation for the expected Unwrap response length is InLocalEnvelopeSize(488) - 8 = 480 (the plaintext envelope size), which I believe is correct.
  • However, StSafeA_ReceiveResponse overwrites this with the length read directly from the chip's response frame header: 496 bytes, not 480.
  • After CBC decryption (which reports success at the OpenSSL API level, no errors), I dumped the decrypted buffer. Bytes 0–479 are byte-for-byte correct — they exactly match the original 480-byte plaintext I passed into Wrap.
  • Bytes 480–495 (the final 16-byte block) do not resolve to a valid padding pattern. StSafeA_DataDecryption's search for the 0x80 padding marker fails, and the function returns STSAFEA_CRYPTO_LIB_ISSUE (0x20).

My question: Is this final 16-byte block a legitimate part of the protocol — e.g., an R-MAC, response tag, or padding the chip adds to reach an AES block boundary (488 isn't a multiple of 16, so 496 would be the next boundary up) — that needs different handling than what StSafeA_DataDecryption's generic padding-removal logic assumes?

If so:

  1. Is this 16-byte trailer meant to be stripped/verified before AES-CBC decryption runs, rather than decrypted as part of the ciphertext?
  2. Is there a different padding scheme expected for Unwrap responses specifically, versus the generic 0x80-marker padding used elsewhere in the library?
  3. Is this something specific to my chip's personalization (Command Authorization Configuration shows Unwrap at 0x0F requires CommandAC=0x03 MAC + HostEncryptionFlags=0x01 response encryption), or is it a general property of the Wrap/Unwrap response format regardless of personalization?