Questions about the EUCLEAK on the Optiga Trust M

I understand there is a newly discovered physical attack vulnerability in the Optiga Trust M chip the Trezor Safe 3/5 uses for its secure element. I also understand it allows the attacker to extract the ECDSA secret from that chip. I’ve read the Trezor Safe 3/5 use an HMAC secret from the Optiga, not ECDSA, so it should not be affected.

Some questions,

  • Do I have it correct that HMAC and not ECDSA are the form of secret used to encrypt the pin and seed?
  • Is it reasonable to assume that an new attack to extract the HMAC could be devised based on this ECDSA attack?
  • Does anyone know where in the source code the Optiga gets called to grab its secret? I tried (briefly) to figure it out and couldn’t find it. Links would be awesome

Thanks!

1 Like

Regarding HMAC attacks

Adding some notes based on some of the reading I’ve done of the official report (google for it, it’s on Ninja Lab, can’t link here due to site rules)

It seems that this attack depends on snooping how modular inversion is implemented on the Optiga, which is something that HMAC does not use, AFAIK. This seems to imply this technique wouldn’t lead to an obvious attack that leaks the HMAC secret key in the Optiga. I would love to hear an expert’s opinion on this though.

1 Like

After reading the EUCLEAK disclosure, I become curious about how the Trezor actually uses the Optiga to store and encrypt its secrets. Can anyone offer a technical description of the process used?

From the official docs:

The Secure Element used in the Trezor Safe family of devices protects your PIN (without learning it), which releases a secret (stored on the Secure Element), which in turn protects your recovery seed (stored only on the Trezor general purpose chip, encrypted by both the device PIN and the secret stored on the Secure Element).

Guessing what this means more technically, I wonder if the process is something like:

On device initialization:

  • user inputs PIN → hash(PIN) → signed by the HMAC on the SE (secure element) → signed hash stored on the GPC (general purpose chip)

After generating the seed:

  • encrypt (using what algorithm? I don’t know) using the HMAC-sig(hash(PIN)) as the encryption key → store encrypted seed on GPC.

On regular login:

  • user inputs PIN → hash(PIN) → signed by the HMAC on the SE (secure element) → compare signed hash with the value we stored when we initialized → If match, allow access to the Trezor

When signing:

  • Take the HMAC-sig(hash(PIN)) and use that to decrypt the seed → sign txns with decrypted seed

Any technically oriented users already know how this is implemented?

I know I should read the source to get my answers, but that will take a while, and I do hope to get to it soon.

1 Like

You’re right that it’s not an ECDSA secret.

As for the rest, this is rather imprecise.

In reality, there is no “the secret” from the Optiga chip. Optiga is involved in multiple steps while deriving the secret, but it never learns the actual encryption key.

High-level, the algorithm is:

  1. start with your PIN as the basis of a key
  2. apply a series of “stretching” operations, using the output of the previous step as a key
  3. some of those use Optiga’s cryptographic operations and secrets, but because you are always chaining the previous step, knowing any secret(s) from Optiga is never enough.
  4. after the sequence is done, the last output is the decryption key.

Here’s pseudocode for the actual operations in play:

pin = get_pin_from_user()

stretched_value = pbkdf2(pin + storage_salt + external_salt)
# where storage_salt is a random value stored on the STM32
# external_salt is the "SD protect" secret, if present and enabled

for _ in range(2):  # repeat twice:
    digest = hmac(key=stretched_value, msg="")
    # this digest, and _not_ the stretched_value, will be sent to optiga:
    cmac = optiga_cmac(msg=digest, key_slot=optiga_symmetric_slot)
    ecdh = optiga_ecdh(msg=digest, key_slot=optiga_asymmetric_slot)
    # mix optiga results into stretched_value
    stretched_value = hmac(key=stretched_value, msg=cmac + ecdh)

# prepare another digest to send to optiga
digest = hmac(key=stretched_value, value="")
optiga_result = optiga_hmac(msg=digest, key=optiga_hmac_slot)
# mix optiga result into stretched_value
stretched_value = hmac(key=stretched_value, msg=optiga_result)

digest = hmac(key=stretched_value, msg="")
# use this digest to unlock a secret slot in the optiga
optiga_secret = optiga_read_slot(slot=optiga_secret_slot, key=digest)
# mix the optiga secret into stretched_value
stretched_value = hmac(key=stretched_value, msg=optiga_secret)

As you can see, there are multiple cryptographic operations in play: a symmetric CMAC operation, an asymmetric ECDH operation, a HMAC operation, and retrieval of a protected secret.

Importantly, all the operations feed into a secret value (stretched_value in the above code) that is never revealed to the Optiga. Even if all the different operations on the Optiga were broken, and you were able to extract all the different keys and secrets, the best you’ll get is a key dependent on the user’s PIN which you can try to brute-force.

Additionally, on the Safe 5, we are using the STM35U5 AES hardware key in the mix, which is another secret that can’t normally be extracted and you would need a completely separate exploit to grab it.

That would be a No.

Well, you start here and continue here, have fun :slight_smile: