Android Keystore keeps cryptographic key material out of your app process and can bind it to secure hardware, so an attacker cannot copy the key. It does not stop a compromised app from asking the keystore to use the key. User authentication binding is what narrows that gap.
Extraction versus misuse
Android's documentation describes two threats. The first is using key material from outside the device, which the keystore addresses by blocking extraction from app processes and from the device. The second is misuse of keys within the device, which it reduces by having apps declare authorized uses and enforcing them outside the app process.
In practice, plaintext, ciphertext and data to be signed go to a system process that performs the operation. The key never enters your process. The docs state that if the app process is compromised, an attacker can use the app's keys but cannot extract them.
That distinction matters for design. A stolen key works anywhere. A key that is only usable on one device, through one app, is a smaller prize.
Hardware backing
Key material can be bound to a trusted execution environment or a secure element. The docs say this applies only if the hardware supports the exact combination of algorithm, block mode, padding and digest. On API 29 and above, KeyInfo.getSecurityLevel() reports TRUSTED_ENVIRONMENT or STRONGBOX. On API 28 and lower, use KeyInfo.isInsideSecurityHardware(). Check it rather than assuming.
StrongBox
StrongBox is available on Android 9 (API 28) and above on devices that include it. It is backed by an embedded secure element or integrated secure enclave with its own CPU, secure storage and true random number generator. You request it with setIsStrongBoxBacked(true); an unsupported algorithm or size throws StrongBoxUnavailableException, and you fall back to a normal key.
The documentation is direct about the cost: StrongBox is slower and more constrained, and most apps do not need it. Use it for high value keys, not by default.
Use authorizations
Authorizations are fixed when a key is generated or imported and cannot be changed later. They fall into three groups: cryptographic parameters, a validity time window, and user authentication. The docs note that secure hardware usually enforces the first and last but usually not time windows, because it typically lacks an independent secure clock.
User authentication binding
You can require a recent user authentication before the key works, either for a time window or for each operation. With AUTH_BIOMETRIC_STRONG, AUTH_DEVICE_CREDENTIAL or both, a compromised app process cannot use the key without the user passing the prompt. The docs say this protects against compromise after key creation, but not during or before it.
Two details trip people up. Biometric-only keys are invalidated by default when new biometrics are enrolled, so plan a re-enrollment path. And these checks need BiometricManager.canAuthenticate() to confirm the user has something enrolled.
A decision guide
- Low value local data: a software backed Keystore key is usually enough.
- Tokens and personal data: require hardware backing where available and verify the security level.
- Money movement or health records: add per-operation user authentication.
- Rare, very high value keys: consider StrongBox and test performance.
Remember that keys protect data only as far as the rest of the design goes. A token the server never revokes is still a problem.
Quick check
Does Keystore stop an attacker with code running inside my app?
It stops them copying the key, but they may be able to use it. Bind keys to user authentication for sensitive operations.
Should every app use StrongBox?
No. The Android docs say most apps do not need it, and it is slower with fewer concurrent operations.
Sources
Last reviewed: 19 October 2026.