Skip to content

Symmetric (AES) key generation unsupported — blocks Google Wallet tap-to-pay on broken-TEE device (Unsupported algorithm: 32) #189

Description

@shogi-dojo

Summary

TEESimulator cannot generate symmetric (AES) keyguard/auth-bound keys. Google Wallet's tap-to-pay tokenization requests an AES-128 key (google_pay_keyguard_fuse_key), and handleGenerateKey throws IllegalArgumentException: Unsupported algorithm: 32 because it only implements asymmetric (EC/RSA) key pair generation. This blocks Google Wallet tap-to-pay setup on a device whose real TEE is unusable, even though Play Integrity MEETS_DEVICE_INTEGRITY passes.

Environment

  • Device: Motorola Moto X4 (payton)
  • ROM: LineageOS 22.2 (lineage_payton-userdebug 15 BP1A.250505.005), Android 15 / SDK 35
  • Keystore HAL: android.hardware.keymaster@3.0::IKeymasterDevice only — no KeyMint. keystore2 returns HARDWARE_TYPE_UNAVAILABLE for TRUSTED_ENVIRONMENT (i.e. real hardware attestation is dead; this is the exact "broken TEE" case v3.1 targets).
  • Root: Magisk 30.7 (30700), Zygisk enabled
  • TEESimulator: v3.2 (67-1f8412d-release)
  • Keybox: valid hardware keybox present at /data/adb/tricky_store/keybox.xml (EC+RSA, title=TEE certs, chains to Google Hardware Attestation Root, not expired)
  • tee_status: teeBroken=true / tee_broken=true (forced full simulation)
  • GMS: 26.24.34 (260400-938041327)
  • Google Wallet: 26.25.934502156

What works

  • Play Integrity MEETS_DEVICE_INTEGRITY passes (stable). TEESimulator correctly intercepts and generates the asymmetric attestation keys for com.google.android.gms.
  • Google Wallet online / in-app pay works (card saves to account).

What fails

Adding a card for tap-to-pay fails with the on-screen error "This device can't be set up to tap to pay." Root cause: TapAndPay's CheckOrGetStorageKeyStep requests generation of a symmetric key that TEESimulator can't create.

Logs

With teeBroken=true, TEESimulator correctly stops forwarding to the (dead) hardware and attempts software generation, but fails on the algorithm:

D TEESimulator: [TX_ID: 617] Intercept generateKey for packages=[com.google.android.gms, com.google.android.gsf] (uid=10134, pid=6797)
D TEESimulator: Handling generateKey google_pay_keyguard_fuse_key, attestKey=null
D TEESimulator: KeyParam: KEY_SIZE                  | Value: 128
D TEESimulator: KeyParam: ALGORITHM                 | Value: AES
D TEESimulator: KeyParam: PURPOSE                   | Value: ENCRYPT
D TEESimulator: KeyParam: BLOCK_MODE                | Value: CBC
D TEESimulator: KeyParam: PADDING                   | Value: PKCS7
D TEESimulator: KeyParam: USER_SECURE_ID            | Value: -3154595726481129346
D TEESimulator: KeyParam: USER_AUTH_TYPE            | Value: Unknown Value
D TEESimulator: KeyParam: AUTH_TIMEOUT              | Value: 315360000
E TEESimulator: java.lang.IllegalArgumentException: Unsupported algorithm: 32
E TEESimulator:     at org.matrix.TEESimulator.interception.keystore.shim.KeyMintSecurityLevelInterceptor.handleGenerateKey(...:231)

and the downstream generation/cert-chain failure:

I TEESimulator: Generating software key for google_pay_keyguard_fuse_key[-2400979114364529551].
I TEESimulator: Generating new attested key pair for alias: 'google_pay_keyguard_fuse_key' (UID: 10134)
E TEESimulator: Failed to generate software key pair.
E TEESimulator: Failed to generate attested key pair for alias 'google_pay_keyguard_fuse_key'.
E TEESimulator: java.lang.Exception: Failed to generate underlying software key pair.
E TEESimulator:     at t3.a.o(Unknown Source:100)
E TEESimulator:     at ...KeyMintSecurityLevelInterceptor.handleGenerateKey(...:231)
E TEESimulator: No key pair generated for UID 10134.
E TEESimulator: java.lang.Exception: CertificateGenerator failed to create key pair.
E TEESimulator:     at ...KeyMintSecurityLevelInterceptor.handleGenerateKey(...:308)

TapAndPay then reports the attestation error:

I TapAndPay: CheckOrGetStorageKeyStep. Start.
I TapAndPay: CheckOrGetStorageKeyStep. Response.
I TapAndPay: CheckOrGetStorageKeyStep. Attestation Error.

Analysis

The requested key is symmetric (ALGORITHM: AES, KEY_SIZE: 128, PURPOSE: ENCRYPT, BLOCK_MODE: CBC, PADDING: PKCS7) and auth/keyguard-bound (USER_SECURE_ID, USER_AUTH_TYPE, AUTH_TIMEOUT). handleGenerateKey appears to assume an asymmetric key pair and rejects Algorithm=32 (the KeyMint Algorithm::AES tag value). On a device with a working TEE this key is generated by the real hardware and never reaches the simulator, so the gap is only exposed in teeBroken=true full-simulation mode.

Suggested fix

In KeyMintSecurityLevelInterceptor.handleGenerateKey, handle symmetric algorithms (AES 32, HMAC/TRIPLE_DES) by generating and storing a raw secret key in the software key DB instead of routing through the asymmetric key-pair + certificate path. For AES it needs no attestation certificate chain — just a persisted key blob usable for later createOperation (ENCRYPT/DECRYPT). Honoring the USER_SECURE_ID / USER_AUTH_TYPE / AUTH_TIMEOUT (keyguard-bound) params would let Google Wallet's CheckOrGetStorageKeyStep succeed and unblock tap-to-pay on broken-TEE devices.

I'm happy to test a build against this exact repro (Moto X4 / payton, LOS 22.2, broken Keymaster 3.0).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions