Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →Generate non-exportable keys in Android Keystore, request StrongBox when the device offers it, and verify the result with KeyInfo and remote attestation. Treat an emulator or virtual Android guest as a separate trust domain: a successful Keystore API call does not prove that tamper-resistant hardware exists.
Start with the trust boundary
Android Keystore keeps key material non-exportable and exposes only authorized cryptographic operations. KeyMint and the keystore2 service route those operations to the available security environment. Your design still needs an explicit threat model.
- Offline theft: someone copies the app’s files or a device backup.
- Compromised software: a rooted OS, malicious app, injected process or unsafe IPC path.
- Physical attack: probing, fault injection or side-channel attempts against the device.
- Rollback and cloning: an old app state is restored, or a virtual instance is duplicated.
StrongBox is intended for the last two categories, but it is optional and device-dependent. A TEE is also hardware-isolated, yet it has a different attack-resistance profile. Choose the required level before writing fallback behavior.
Generate an AES key with narrow authorizations
Create a key per installation, account or protection domain. Keep the alias separate from the encrypted data and never serialize key material.
val alias = "vault-$accountId"
val generator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES,
"AndroidKeyStore"
)
val spec = KeyGenParameterSpec.Builder(
alias,
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setRandomizedEncryptionRequired(true)
.setUserAuthenticationRequired(true)
// On API 30+, choose a timeout and authenticators appropriate to your product.
// .setUserAuthenticationParameters(30, KeyProperties.AUTH_BIOMETRIC_STRONG)
.build()
generator.init(spec)
val key = generator.generateKey()
Set only the purposes, algorithm, block modes, padding, digest and authentication requirements the feature actually needs. Keystore authorizations cannot be loosened later; generate a new alias when policy must become broader.
For keys that must be usable without a user prompt, omit user authentication deliberately and document that decision. For high-value data, bind use to a recent strong biometric or device credential, and decide how biometric-enrollment changes should invalidate the key.
Prefer StrongBox, but define a downgrade policy
StrongBox denotes a KeyMint implementation in a dedicated embedded secure element or integrated Secure Enclave. It has its own processor, protected storage, random-number generator and secure timer, together with tamper-resistance requirements. It generally supports fewer algorithms and concurrent operations and is slower than a TEE.
val pm = context.packageManager
val strongBoxAvailable = pm.hasSystemFeature(
PackageManager.FEATURE_STRONGBOX_KEYSTORE
)
try {
val builder = KeyGenParameterSpec.Builder(
alias,
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setRandomizedEncryptionRequired(true)
if (strongBoxAvailable && Build.VERSION.SDK_INT >= 28) {
builder.setIsStrongBoxBacked(true)
}
generator.init(builder.build())
generator.generateKey()
} catch (e: StrongBoxUnavailableException) {
// Either create a documented TEE-backed replacement or fail closed.
}
FEATURE_STRONGBOX_KEYSTORE is only a capability hint. Even when it is present, generation can fail because the requested algorithm, key size, quota or firmware does not meet StrongBox requirements. Catch StrongBoxUnavailableException and choose one policy:
- High-assurance workflow: fail closed and tell the user that a qualifying device is required.
- General-purpose workflow: create a TEE-backed key, record the downgrade, and limit what that key can protect.
Do not silently treat a software fallback as equivalent to StrongBox.
Inspect the resulting security level
After generation, inspect the key’s KeyInfo. On API 31 and newer, securityLevel distinguishes software, TrustedEnvironment and StrongBox.
val factory = SecretKeyFactory.getInstance(key.algorithm, "AndroidKeyStore")
val info = factory.getKeySpec(key, KeyInfo::class.java) as KeyInfo
if (Build.VERSION.SDK_INT >= 31) {
when (info.securityLevel) {
KeyProperties.SECURITY_LEVEL_STRONGBOX -> { /* required level met */ }
KeyProperties.SECURITY_LEVEL_TRUSTED_ENVIRONMENT -> { /* TEE */ }
KeyProperties.SECURITY_LEVEL_SOFTWARE -> { /* no hardware isolation */ }
}
}
On older releases, isInsideSecureHardware() can indicate hardware-backed storage but does not reliably tell you whether the implementation is a TEE or StrongBox. For a server decision, use attestation rather than a local boolean.
Encrypt correctly and minimize disclosure surfaces
With AES-GCM, let the platform create a fresh nonce (IV) for every encryption. Store the IV alongside the ciphertext; GCM’s authentication tag is included in the output of doFinal.
val cipher = Cipher.getInstance("AES/GCM/NoPadding")
cipher.init(Cipher.ENCRYPT_MODE, key)
val iv = cipher.iv
val ciphertextAndTag = cipher.doFinal(plaintext)
val decrypt = Cipher.getInstance("AES/GCM/NoPadding")
decrypt.init(Cipher.DECRYPT_MODE, key, GCMParameterSpec(128, iv))
val plaintext = decrypt.doFinal(ciphertextAndTag)
Never reuse a GCM IV with the same key and do not accept a caller-provided IV when randomized encryption is required. Store only the alias reference, IV, ciphertext and tag in app storage. Treat the following as separate disclosure paths:
- automatic backups and device-to-device transfers;
- logs, crash reports and analytics payloads;
- clipboard contents, screenshots and accessibility exports;
- IPC extras, intents, databases or caches that carry plaintext.
Configure backup rules for your recovery model. If a restored database cannot be decrypted because the Keystore key is device-bound, handle that state explicitly instead of retrying indefinitely.
Use attestation for remote enrollment
A server that relies on hardware isolation should enroll an attested asymmetric key, not trust a client-reported flag.
- Generate an EC or RSA key pair in
AndroidKeyStorewith a cryptographically random, single-use server challenge insetAttestationChallenge. Request StrongBox explicitly when required. - Send the public certificate chain to the service over an authenticated channel.
- Validate every certificate signature, validity period and chain termination against the Android attestation root set your service trusts.
- Parse the Android key-attestation extension. Confirm the challenge exactly, the expected package name and signing-certificate digest, key purposes and the requested security level.
- Require the appropriate
hardwareEnforcedauthorizations. For a StrongBox policy, accept only a StrongBox security level; a software-level record is not an acceptable substitute. - Check verified-boot state, device lock state, OS and vendor patch data required by your policy, and reject rollback or an unlocked bootloader when those conditions matter.
- Apply current certificate revocation and provisioning rules. Cache neither a permanent “trusted device” decision nor an attestation result without an expiry and re-enrollment strategy.
The attestation extension’s hardware-enforced fields are generated in secure hardware and are not controlled by the Android platform. A valid certificate chain with a software security level proves key provenance only at that lower level; it does not prove tamper-resistant hardware.
TEE, StrongBox, software and virtualized guests
| Option | Isolation and tamper resistance | Availability | Performance and algorithms | How to verify |
|---|---|---|---|---|
| Software Keystore | Relies on Android platform security; no hardware isolation | Broad | Broadest support | SecurityLevel=Software |
| TEE-backed KeyMint | Isolated secure environment that resists many remote attacks | Common on capable devices | Usually faster and more capable than StrongBox; exact support varies | TrustedEnvironment in key information or attestation |
| StrongBox KeyMint | Dedicated secure element or enclave with stronger isolation and tamper-resistance requirements | Optional and device-dependent | Slower, fewer algorithms and limited concurrent operations | StrongBox attestation plus verified-boot checks |
| Virtualized or emulated guest | Depends on the host and exposed virtual hardware; cannot be assumed to satisfy StrongBox requirements | Environment-dependent | Useful for functional testing; performance and features vary | Require production-valid attestation, otherwise treat as untrusted |
What virtualization changes
An Android Emulator or other virtual device may expose Keystore APIs, advertise a feature, or successfully generate a key while executing entirely in software or in host-controlled hardware. Those observations establish API compatibility, not a tamper-resistant boundary.
Use virtual devices to test encryption formats, authentication prompts, key invalidation, error handling and downgrade logic. For a policy that depends on physical isolation, require remote attestation showing the expected StrongBox or TrustedEnvironment level and acceptable verified-boot state. Reject software-level attestation, test roots and unverifiable chains. Consider each guest a separate trust domain: a snapshot can be copied, rolled back or cloned unless your server binds enrollment to fresh challenges and state.
Failure cases to test before shipping
- The device lacks
FEATURE_STRONGBOX_KEYSTORE. - StrongBox exists but rejects the requested algorithm, key size or authorization.
- The device is locked, the authentication timeout expires, or the user changes biometric enrollment.
- The key is invalidated, deleted, restored from backup or unavailable after a factory reset.
- The bootloader is unlocked, verified boot is not green, or patch levels fail policy.
- Attestation has the wrong challenge, package identity, certificate chain, revocation status or security level.
- A virtual guest reports StrongBox-like APIs but cannot produce production-trusted attestation.
- Decryption receives a modified IV, ciphertext or tag and fails closed without exposing plaintext.
Platform milestones and practical limits
Android 9 introduced embedded Secure Element support. Android 12 introduced KeyMint and the Rust keystore2 daemon. Android 13 added Curve25519 support. These are platform milestones, not guarantees of device coverage, benchmark results or uniform algorithm support.
StrongBox availability, attestation provisioning, supported algorithms and certificate revocation are device- and release-dependent. Base acceptance on the evidence your policy requires, not on a vendor label, emulator setting or a successful API call.
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




