Comviva
Comviva Logo
Cryptographic-Keys-1024×682

Introduction

Almost every mobile application handles sensitive data. From personal messages to financial transactions, protecting that data depends on one thing that is often overlooked: where the cryptographic keys are stored and how they are protected.

Improper cryptographic key management creates vulnerabilities that make applications susceptible to attacks and data breaches. This guide covers secure key generation, storage, and attestation in Android applications, focusing on hardware-backed keystores including the Trusted Execution Environment (TEE) and StrongBox

In 2026, two additional developments make this topic more critical than ever for Android developers. First, Google activated a new RKP (Remote Key Provisioning) root certificate on February 1, 2026, which all RKP-enabled devices must use by April 10, 2026. Applications that perform key attestation verification and do not trust the new root certificate will start failing. Second, the shift to KeyMint HAL (which replaces the Keymaster HAL on modern Android) introduces Curve25519 support and the keystore2 daemon rewritten in Rust for improved security. Both changes affect production fintech applications in 2026.

1. Understanding the Android Keystore System

1.1 What is the Android Keystore?

The Android Keystore system is a core component of the Android security architecture. It allows developers to securely generate, store, and use cryptographic keys within their applications. Keys stored in the Keystore cannot be extracted even if the application code or the device operating system is compromised.

  • Isolation: Keys are stored in a container that is inaccessible to other applications and the operating system.
  • Secure key operations: Cryptographic operations are performed within the Keystore itself, preventing direct access to raw key material.
  • Hardware protection: On supported devices, keys are stored and used within dedicated secure hardware modules.

Platform note for 2026: Android 12 introduced the KeyMint HAL, which replaces the Keymaster HAL but provides similar functionality. The new keystore2 daemon, rewritten in Rust, provides improved memory safety. Android 13 added Curve25519 support for signing and key agreement via KeyMint v2. On modern Android devices, the AndroidKeyStore provider routes to KeyMint rather than Keymaster.

1.2 Software vs Hardware-Backed Keystores

Understanding the three tiers of Android cryptographic key storage is essential before choosing an implementation strategy:

DimensionSoftware KeystoreTEE (TrustZone)StrongBox (SE/HSM)
Storage locationEncrypted file systemTEE isolated memory (ARM TrustZone)Dedicated SE or iSE chip (e.g. Titan M2)
Key extraction riskPossible via root/sophisticated attackExtremely difficult: kernel compromise cannot reach TEEImpractical: physically separate processor
Physical attack resistanceNoneLimited: shares SoC with main processorStrong: dedicated chip with anti-tamper circuitry
Frida hook vulnerabilityYes: software crypto is hookableKeys not extractable but operations can be hookedKeys not extractable but operations can be hooked
Hardware rate limitingNoneLimitedYes: 5 failures trigger 30s lockout; 24h after 139 attempts
API level requiredAnyStandard on modern AndroidAndroid 9 (API 28) or higher
PCI DSS / EMVCo complianceDoes not meet requirementsMeets baseline requirementsMeets highest requirements

2. TEE and StrongBox: The Two Hardware-Backed Options

2.1 Trusted Execution Environment (TEE)

The Trusted Execution Environment is a secure area within the main processor of an Android device, implemented using ARM TrustZone technology, which partitions the SoC into a Secure World and a Normal World at the hardware level. It provides hardware isolation between secure and non-secure execution environments. Even if the main OS is compromised, the TEE remains protected.

TEE-backed keys are generated inside the secure environment and never leave it. Root access on the Android side cannot reach TEE-backed key material. Even a fully compromised kernel cannot extract a TEE-backed key.

2.2 StrongBox

StrongBox was introduced in Android 9 (API level 28). Unlike the TEE, which shares the main SoC, StrongBox uses a dedicated secure processor such as a Secure Element or integrated Secure Enclave. On Pixel devices, this is Google’s Titan M2 chip. On Samsung devices, the Knox-secured Secure Element. The physical separation means that even if the main processor is compromised through a side-channel or hardware attack, StrongBox keys are not accessible.

StrongBox also enforces hardware rate limiting: five incorrect authentication attempts trigger a 30-second lockout, and after 139 attempts the lockout extends to 24 hours per attempt. This makes brute-forcing of UPI MPINs or wallet PINs practically impossible.

  • Dedicated HSM: Isolates keys from both the main processor and the TEE.
  • Tamper resistance: Resists physical attacks including chip probing, timing attacks, power analysis, and glitch attempts.
  • Enhanced features: Supports ID attestation and anti-replay protections.
  • Availability: Only available on devices with the required hardware. Requires Android 9 or higher.
  • Performance consideration: StrongBox is slower and more resource-constrained than TEE. It supports fewer concurrent operations. Use it for the highest-value keys only: authentication credentials, signing keys, and payment credentials.

3. Generating and Storing Keys Securely

3.1 Prioritising StrongBox for Key Generation

When generating cryptographic keys in Android, prioritise StrongBox for the highest available security level.

Step 1: Check for StrongBox support
boolean hasStrongBox = context.getPackageManager()
    .hasSystemFeature(PackageManager.FEATURE_STRONGBOX_KEYSTORE);
Step 2: Configure key generation parameters with StrongBox backing
KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder(
    keyAlias,
    KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
    .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
    .setKeySize(256)
    .setIsStrongBoxBacked(true) // Request StrongBox backing
    .build();
Step 3: Generate the key
KeyGenerator keyGenerator = KeyGenerator.getInstance(
    KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
keyGenerator.init(keyGenParameterSpec);
SecretKey secretKey = keyGenerator.generateKey();

Handle StrongBox failures gracefully with proper exception handling and a TEE fallback. After key generation, always verify the key is actually stored in StrongBox rather than assuming the operation succeeded.

3.2 Falling Back to TEE When StrongBox is Unavailable

If StrongBox is not available, TEE is the correct fallback. The key generation process is identical but omits the StrongBox backing flag:

KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder(
    keyAlias,
    KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
    .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
    .setKeySize(256)
    // No .setIsStrongBoxBacked() call
    .build();

 

Always verify the generated key is hardware-backed and not stored in software. If hardware-backed security is unavailable for a sensitive operation, inform the user or disable the sensitive feature rather than silently degrading to software-only storage.

3.3 Verifying Hardware-Backed Key Storage

Verification is critical for compliance assurance and confirms that keys are genuinely protected against extraction.

KeyFactory factory = KeyFactory.getInstance(
    secretKey.getAlgorithm(), "AndroidKeyStore");
KeyInfo keyInfo = (KeyInfo) factory.getKeySpec(secretKey, KeyInfo.class);

// Android 12 (API 31) and higher: use getSecurityLevel()
int securityLevel = keyInfo.getSecurityLevel();
boolean isHardwareBacked =
    securityLevel == KeyProperties.SECURITY_LEVEL_TRUSTED_ENVIRONMENT
    || securityLevel == KeyProperties.SECURITY_LEVEL_STRONGBOX;

// Android 9 to 11: use isInsideSecurityHardware()
// boolean isHardwareBacked = keyInfo.isInsideSecurityHardware();

 

Use getSecurityLevel() on Android 12 and higher. The older isInsideSecurityHardware() boolean is still available for API 28 to 30 compatibility but does not distinguish between TEE and StrongBox. For applications that need to enforce StrongBox specifically, check for SECURITY_LEVEL_STRONGBOX rather than accepting SECURITY_LEVEL_TRUSTED_ENVIRONMENT as sufficient.

4. Binding Keys to Biometric Authentication

Hardware-backed key storage prevents key extraction. It does not prevent an attacker with physical access to an unlocked device from using those keys through the application. The additional defence is requiring the user to authenticate before the key can be used, via biometric credentials or the device lock screen.

From Android 11 (API 30), use setUserAuthenticationParameters to bind a key to authentication:

KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(
    keyAlias,
    KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
    .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
    .setKeySize(256)
    .setIsStrongBoxBacked(true)
    // Require biometric (STRONG class) or device credential before use
    .setUserAuthenticationParameters(
        0, // 0 = require auth every time the key is used
        KeyProperties.AUTH_BIOMETRIC_STRONG
        | KeyProperties.AUTH_DEVICE_CREDENTIAL)
    .setInvalidatedByBiometricEnrollment(true)
    .build();

 

Important: when setInvalidatedByBiometricEnrollment is true, the key is permanently invalidated if the user adds, removes, or changes biometric enrolment. This is the correct setting for payment and authentication keys because it prevents an attacker from enrolling their own fingerprint to use the key. Your application must handle UserNotAuthenticatedException by prompting re-authentication, and handle KeyPermanentlyInvalidatedException by re-generating the key and re-onboarding the user.

5. Key Attestation: Verifying Hardware Backing Remotely

Key attestation is the mechanism by which your server can independently verify that a cryptographic key was generated inside genuine secure hardware on a real, unmodified Android device. It is the answer to the question: how does my backend know that the client’s key is actually in a TEE or StrongBox and not in a software keystore on an emulator or a rooted device?

The attestation flow for a fintech application:

  • Your server sends a nonce (random challenge) to the application.
  • The application generates a key pair in the AndroidKeyStore, passing the nonce as the attestation challenge.
  • Android builds a certificate chain rooted in the Google hardware attestation root. The certificate includes a KeyDescription extension containing the security level (SOFTWARE, TRUSTED_ENVIRONMENT, or STRONGBOX), boot state, and the attestation nonce.
  • The application sends the certificate chain to the server.
  • The server verifies the chain against the Google attestation root, checks the nonce matches to prevent replay, confirms the security level is TRUSTED_ENVIRONMENT or STRONGBOX, and verifies none of the certificates are revoked via the CRL.

Code to request attestation during key generation:

byte[] challenge = getServerNonce(); // Fetch from your server
KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(
    keyAlias,
    KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
    .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
    .setDigests(KeyProperties.DIGEST_SHA256)
    .setIsStrongBoxBacked(true)
    .setAttestationChallenge(challenge)
    .build();

 

Critical 2026 update: Google activated a new RKP (Remote Key Provisioning) attestation root certificate on February 1, 2026. All RKP-enabled devices (most devices sold in 2025 and later) must use this new root by April 10, 2026. If your server’s attestation verification only trusts the old root, attestation checks will start failing on modern devices. Update your trust anchors to accept both the old and new root certificates during the transition period. The certificate extension schema is unchanged; only the root changes.

6. Handling Exceptions and Security Failures

6.1 Custom Exception Handling

public class HardwareSecurityException extends Exception {
    public HardwareSecurityException(String message) {
        super(message);
    }
}

 

Throw this exception during key generation if the key is not hardware-backed. Provide specific error information rather than allowing the application to continue silently with degraded security.

6.2 Failing Securely

  • Disable sensitive features: Prevent access to features that require secure key storage rather than allowing them to run with weaker protection.
  • Inform the user: Provide clear messaging about the device’s security limitations.
  • Do not fall back to software storage for sensitive data: For applications handling financial transactions or authentication credentials, software-only storage is not an acceptable fallback.
  • Handle key invalidation: When using biometric-bound keys, always catch UserNotAuthenticatedException (re-prompt authentication) and KeyPermanentlyInvalidatedException (re-generate key and re-onboard the user). Do not treat key invalidation as an unexpected error; treat it as a normal lifecycle event.

7. Real-World Attacks That Hardware-Backed Keys Prevent (and Where They Do Not)

Understanding the specific attack classes that hardware-backed key storage addresses, and the ones it does not, is essential for fintech developers making security architecture decisions.

Attacks that hardware-backed keys prevent:

  • Key extraction via root access: Root access on the Android side cannot reach TEE or StrongBox key material. Software keys on a rooted device can be extracted in seconds.
  • Session token replay: When session tokens are signed by a hardware-bound private key, intercepted tokens cannot be replayed from another device because the signing key is non-exportable.
  • UPI MPIN or wallet PIN brute force: StrongBox’s hardware rate limiting (five attempts trigger a 30-second lockout; 24-hour lockouts after 139 total attempts) makes brute force computationally and temporally impractical.
  • Physical chip probing and side-channel attacks: StrongBox’s dedicated secure processor resists timing attacks, power analysis, and glitch attempts that can succeed against TEE on high-value targets.

Attacks that hardware-backed keys do NOT prevent (and how to mitigate them):

  • Frida and Xposed hooks on crypto operations: Hardware-backed keys cannot be extracted, but an attacker who can hook the application process can intercept plaintext and ciphertext at the points where they enter and leave the cryptographic operation. Mitigate with Play Integrity API attestation to detect modified APKs and Frida-injected processes. Hardware-backed keys are not a substitute for runtime application protection.
  • Attacker using keys on an unlocked device: A physical attacker with access to an unlocked device can trigger cryptographic operations through the application. Mitigate with biometric-bound keys as described in Section 4.
  • Modified APKs forging requests: A tampered APK on a device cannot produce valid hardware-signed requests, so the server can detect it. But this protection requires key attestation to be implemented on the server side as described in Section 5.

8. Compliance With Security Standards

Applications handling sensitive data must adhere to industry standards. Hardware-backed key storage is a requirement under these frameworks, not a recommendation.

  • EMVCo: Requires hardware-backed key storage for payment credential protection in mobile payment applications.
  • PCI DSS Requirement 3.6: Specifically covers cryptographic key management lifecycle requirements including key generation, distribution, storage, retirement, and destruction. Hardware-backed key generation in TEE or StrongBox satisfies the secure key storage requirements.
  • Key usage restrictions: Configure keys for specific purposes only. A key created for encryption should not be usable for signing.
  • Key rotation: Implement regular key rotation, particularly for long-lived application installations and after any security incident.
  • Secure deletion: Delete keys from the Keystore when no longer needed using KeyStore.deleteEntry().
  • Never log key material: Never log or transmit private keys, even in debug builds.
  • Never hardcode key aliases or secrets: Dynamically generated per-device key aliases tied to a user or device identifier are more resilient than fixed aliases.

9. Handling Devices Without TEE or StrongBox

Some devices lack hardware-backed security features due to age, cost, or manufacturer decisions. This is particularly relevant in markets where low-cost Android devices are common, including many emerging markets where mobile financial services see the highest growth.

The decision logic when hardware security is unavailable:

  • Check for StrongBox support first using hasSystemFeature(FEATURE_STRONGBOX_KEYSTORE).
  • If StrongBox is unavailable, attempt TEE-backed key generation and verify using getSecurityLevel().
  • If neither is available, do not silently fall back to software storage for sensitive operations.
  • For payment or authentication features: disable the feature and inform the user that their device does not meet the security requirements.
  • Consider using this as an onboarding gate. Display a clear message during first launch: ‘This application requires a device with hardware security features for your protection. Your current device does not support these features.’ This is better UX than a silent failure during a financial transaction.

Summary

Secure cryptographic key storage is the foundation of data protection in Android applications. The priority order is clear: use StrongBox when available, fall back to TEE, and never use software-only storage for sensitive data without making that limitation explicit to the user.

Verify hardware backing after every key generation. Bind authentication keys to biometric credentials. Implement key attestation to verify hardware backing remotely from your server. Update your attestation trust anchors for the 2026 RKP root certificate. Handle security failures by failing explicitly rather than silently degrading. And align key management practices with the compliance requirements of your domain, whether that is payments, authentication, or personal data protection.

FAQs

Both TEE (Trusted Execution Environment) and StrongBox are hardware-backed keystores in Android, but they provide different levels of security. The TEE uses ARM TrustZone technology to partition the main processor’s SoC into a Secure World and a Normal World, isolating key operations from the Android OS. StrongBox uses a completely separate dedicated secure processor, such as Google’s Titan M2 chip on Pixel devices, that is physically isolated from the main SoC. StrongBox provides stronger resistance against hardware-level attacks (chip probing, power analysis, glitch attacks) and enforces hardware rate limiting: five incorrect authentication attempts trigger a 30-second lockout. Use StrongBox for your highest-value keys: payment credentials, authentication private keys, and anything protecting financial transactions. Use TEE as a fallback when StrongBox is unavailable.

After generating a key in the Android Keystore, retrieve its KeyInfo and check the security level. On Android 12 (API 31) and higher, call keyInfo.getSecurityLevel() and check for SECURITY_LEVEL_TRUSTED_ENVIRONMENT or SECURITY_LEVEL_STRONGBOX. On Android 9 to 11, call keyInfo.isInsideSecurityHardware(). Do not skip this verification step. Key generation can silently fall back to software storage if the hardware request fails, and proceeding with a software-backed key for a sensitive operation without knowing it violates PCI DSS Requirement 3.6 and EMVCo requirements. For server-side verification, implement key attestation to cryptographically confirm the hardware security level remotely.

Android key attestation is the mechanism that allows your server to independently verify that a cryptographic key was generated inside genuine secure hardware (TEE or StrongBox) on a real, unmodified Android device. The flow is: your server sends a nonce to the app, the app generates a key pair inside the AndroidKeyStore using that nonce as the attestation challenge, Android produces a certificate chain rooted in the Google hardware attestation root containing the key’s security level and boot state, and the app sends this chain to your server for verification. The server confirms the chain is rooted in Google’s attestation root, the security level is TEE or StrongBox, and the nonce matches to prevent replay. Important for 2026: Google activated a new RKP attestation root certificate on February 1, 2026. Update your server’s trust anchors to accept both old and new roots during the transition period.

From Android 11 (API 30), use setUserAuthenticationParameters() when building your KeyGenParameterSpec. Pass 0 as the timeout (meaning authentication is required every time the key is used, not just at session start) and KeyProperties.AUTH_BIOMETRIC_STRONG to require a Class 3 strong biometric. Set setInvalidatedByBiometricEnrollment(true) to permanently invalidate the key if the user changes their biometric enrolment, preventing an attacker from enrolling their own fingerprint to use the key. Your application must handle two exceptions: UserNotAuthenticatedException (re-prompt biometric authentication before retrying the operation) and KeyPermanentlyInvalidatedException (re-generate the key and re-onboard the user). Biometric-bound keys are the recommended pattern for all payment credentials and authentication private keys in fintech applications.

Hardware-backed key storage in TEE or StrongBox prevents key extraction: the raw key material never leaves the secure hardware environment. However, it does not protect against Frida or Xposed hooks that intercept crypto operations at the application layer. An attacker who can inject a Frida script into the app process can hook Cipher.doFinal() to capture plaintext and ciphertext before encryption and after decryption, without ever needing the key itself. To defend against this, combine hardware-backed key storage with three additional layers: Play Integrity API to detect modified APKs and Frida-injected processes at runtime, certificate pinning to prevent traffic interception, and key attestation on your server to reject requests from compromised clients. Hardware-backed keys are the foundation of your mobile security model, not the complete solution.