Android Keystore
Android Keystore
1. What Is Android Keystore?
Android Keystore is a system service used to generate and securely store cryptographic keys.
The application can use a stored key for encryption, decryption or signing, but the secret/private key material remains non-exportable.
Android Application
|
| Requests cryptographic operation
v
Android Keystore
|
+-- Software-backed storage
|
+-- Hardware-backed TEE
|
+-- StrongBox security hardware---
2. Why Use Android Keystore?
It helps protect cryptographic keys from:
* Extraction from application files
* APK reverse engineering
* Accidental key exposure
* Unauthorized cryptographic operations
* Some attacks on the Android operating system
The key can also be configured so that it works only after biometric or device-credential authentication.
---
3. Classification of Keys
Symmetric key
The same key performs encryption and decryption.
Plain text
|
| AES secret key
v
Encrypted data
|
| Same AES key
v
Plain textCommon algorithm:
AESAsymmetric key pair
It contains two keys:
Public key -> Can be shared
Private key -> Remains protected in KeystoreCommon algorithms:
RSA
EC| Symmetric key | Asymmetric key |
|---|---|
| One secret key | Public and private key pair |
| Faster | Comparatively slower |
| Used for data encryption | Used for signing and key exchange |
| Example: AES | Examples: RSA and EC |
---
4. Key Generation
Keys are generated using:
* KeyGenerator for symmetric keys
* KeyPairGenerator for asymmetric keys
* KeyGenParameterSpec to define security rules
AES key generation
private const val KEY_ALIAS = "secure_data_key"
fun generateAesKey() {
val keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES,
"AndroidKeyStore"
)
val keySpec = KeyGenParameterSpec.Builder(
KEY_ALIAS,
KeyProperties.PURPOSE_ENCRYPT or
KeyProperties.PURPOSE_DECRYPT
)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(
KeyProperties.ENCRYPTION_PADDING_NONE
)
.setKeySize(256)
.build()
keyGenerator.init(keySpec)
keyGenerator.generateKey()
}Getting the generated key
fun getAesKey(): SecretKey? {
val keyStore = KeyStore.getInstance(
"AndroidKeyStore"
).apply {
load(null)
}
return keyStore.getKey(
KEY_ALIAS,
null
) as? SecretKey
}The alias is the name used to find the key later.
---
5. Non-Exportable Keys
A non-exportable key cannot be extracted as raw key bytes from Android Keystore.
Application asks:
"Decrypt this data"
Application does not receive:
"Here are the secret-key bytes"Instead, the app receives a key reference and asks Android Keystore to perform the cryptographic operation.
Application
|
| Cipher operation using key alias
v
Android Keystore
|
| Uses protected key internally
v
Encrypted or decrypted resultImportant clarification
Android Keystore protects the key, not automatically all application data.
The app must still:
1. Encrypt sensitive data with the key.
2. Store the encrypted data.
3. Protect the IV and authentication tag correctly.
4. Avoid logging plaintext data.
---
6. Normal Key vs Keystore Key
| Normal application key | Android Keystore key |
|---|---|
| May be stored as a string or byte array | Stored through the Keystore service |
| Can accidentally appear in memory or logs | Key material remains non-exportable |
| Can be extracted from application storage | Harder to extract |
| No built-in usage restrictions | Can require biometric authentication |
| Usually software-managed | May be hardware-backed |
---
7. Hardware-Backed Security
Android Keystore keys may be protected by secure hardware.
Main hardware options are:
Trusted Execution Environment
TEE is an isolated execution environment separate from the normal Android operating system.
Normal Android OS
|
| Sends operation
v
Trusted Execution Environment
|
| Uses protected key
v
Cryptographic resultStrongBox
StrongBox provides stronger isolation through dedicated secure hardware when supported by the device.
A hardware-backed key’s plaintext key material remains available only within secure hardware.
Comparison
| Software-backed | TEE-backed | StrongBox-backed |
|---|---|---|
| Protected by Android software | Protected inside secure execution environment | Protected by dedicated security hardware |
| Widest availability | Available on many devices | Not supported on every device |
| Lower hardware isolation | Strong isolation | Strongest isolation |
| Faster in some cases | Secure and practical | May be slower |
---
8. Requesting a StrongBox-Backed Key
fun generateStrongBoxKey() {
val keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES,
"AndroidKeyStore"
)
val keySpec = KeyGenParameterSpec.Builder(
"strongbox_key",
KeyProperties.PURPOSE_ENCRYPT or
KeyProperties.PURPOSE_DECRYPT
)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(
KeyProperties.ENCRYPTION_PADDING_NONE
)
.setIsStrongBoxBacked(true)
.build()
try {
keyGenerator.init(keySpec)
keyGenerator.generateKey()
} catch (exception: StrongBoxUnavailableException) {
// Generate a normal Keystore key as fallback.
}
}StrongBox support must not be assumed. The app should provide a secure fallback when it is unavailable. Android provides key attestation when stronger verification of hardware-backed key properties is required.
---
9. Checking Whether a Key Is Hardware-Backed
For an asymmetric private key:
fun getKeySecurityLevel(
privateKey: PrivateKey
): Int {
val keyFactory = KeyFactory.getInstance(
privateKey.algorithm,
"AndroidKeyStore"
)
val keyInfo = keyFactory.getKeySpec(
privateKey,
KeyInfo::class.java
)
return keyInfo.securityLevel
}Possible security levels include:
SOFTWARE
TRUSTED_ENVIRONMENT
STRONGBOXDo not assume that every Android Keystore key is hardware-backed.
---
10. Biometric-Protected Keys
A biometric-protected key can be used only after the user successfully authenticates.
User requests secure operation
|
v
BiometricPrompt
|
Success?
/ \
No Yes
| |
Reject Unlock key operationAndroid supports connecting a Keystore cryptographic operation to BiometricPrompt through CryptoObject.
---
11. Generating a Biometric-Protected Key
private const val BIOMETRIC_KEY =
"biometric_secure_key"
fun generateBiometricKey() {
val keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES,
"AndroidKeyStore"
)
val keySpec = KeyGenParameterSpec.Builder(
BIOMETRIC_KEY,
KeyProperties.PURPOSE_ENCRYPT or
KeyProperties.PURPOSE_DECRYPT
)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setEncryptionPaddings(
KeyProperties.ENCRYPTION_PADDING_PKCS7
)
.setUserAuthenticationRequired(true)
.setUserAuthenticationParameters(
0,
KeyProperties.AUTH_BIOMETRIC_STRONG
)
.setInvalidatedByBiometricEnrollment(true)
.build()
keyGenerator.init(keySpec)
keyGenerator.generateKey()
}Here:
Authentication duration = 0means authentication is required for every key use.
The key can also be configured for time-based authorization, where it remains usable for a limited period after authentication.
---
12. Using the Key with BiometricPrompt
Prepare the cipher
fun createCipher(): Cipher {
val keyStore = KeyStore.getInstance(
"AndroidKeyStore"
).apply {
load(null)
}
val key = keyStore.getKey(
BIOMETRIC_KEY,
null
) as SecretKey
return Cipher.getInstance(
"AES/CBC/PKCS7Padding"
).apply {
init(Cipher.ENCRYPT_MODE, key)
}
}Pass it to BiometricPrompt
val cipher = createCipher()
val cryptoObject =
BiometricPrompt.CryptoObject(cipher)
biometricPrompt.authenticate(
promptInfo,
cryptoObject
)Use it after successful authentication
override fun onAuthenticationSucceeded(
result: BiometricPrompt.AuthenticationResult
) {
val authenticatedCipher =
result.cryptoObject?.cipher
?: return
val encryptedData =
authenticatedCipher.doFinal(
sensitiveData.toByteArray()
)
}The biometric result authorizes the cryptographic operation; the app does not receive the user’s fingerprint or face data.---
13. Authentication Per Use vs Time-Based Authentication
| Authentication per use | Time-based authentication |
|---|---|
| User authenticates for every operation | Key remains available for a limited period |
Used with CryptoObject | May be unlocked after device authentication |
| Stronger control | More convenient |
| Suitable for payments and sensitive actions | Suitable for repeated low-risk operations |
Per-use:
Authenticate -> One operation -> Locked
Time-based:
Authenticate -> Key available for N seconds---
14. Biometric Enrollment and Key Invalidation
A biometric-protected key can be configured to become invalid when the user adds or changes biometric credentials.
Key generated
|
v
User adds new fingerprint
|
v
Key invalidated
|
v
App generates a new keyThe app should handle:
KeyPermanentlyInvalidatedExceptionand require the user to authenticate again or recreate the key.
---
15. Common Mistakes
1. Assuming every key is hardware-backed
Android Keystore may use software, TEE or StrongBox depending on the device and configuration.
2. Hardcoding encryption keys
Avoid:
const val KEY = "my-secret-key"Generate keys through Android Keystore.
3. Trying to export a private or secret key
Keystore keys are designed to be used through cryptographic operations, not extracted as raw bytes.
4. Encrypting without storing the IV
The IV is required for decryption.
Store:
Encrypted data + IV
Do not store:
Raw secret key5. Reusing an IV with AES-GCM
A new unpredictable IV must be used for each encryption operation with the same key.
6. Assuming StrongBox is always available
Handle StrongBoxUnavailableException and provide an appropriate fallback.
7. Using biometric authentication without CryptoObject
A normal biometric success only confirms authentication. For protecting a cryptographic operation, bind the Keystore cipher, signature or MAC through CryptoObject.
8. Not handling key invalidation
Keys may become unusable after biometric enrollment changes, lock-screen changes or security-policy changes.
9. Storing plaintext after encryption
Clear or avoid unnecessary plaintext copies after the secure operation.
---
16. Interview Questions and Answers
Q1. What is Android Keystore?
Android Keystore is a system service that generates and stores cryptographic keys while keeping secret and private key material non-exportable.
Q2. What types of keys can be generated?
It can generate symmetric keys such as AES and asymmetric key pairs such as RSA or EC.
Q3. What does non-exportable mean?
It means the application can use the key for cryptographic operations but cannot obtain its raw secret or private key bytes.
Q4. Is every Android Keystore key hardware-backed?
No. A key may be software-backed, TEE-backed or StrongBox-backed depending on the device and configuration.
Q5. What is hardware-backed security?
The key and cryptographic operations are protected inside secure hardware, reducing exposure to the normal Android operating system.
Q6. TEE vs StrongBox?
TEE is an isolated secure environment within the main processor. StrongBox uses dedicated secure hardware and provides stronger isolation but is not available on every device.
Q7. How do you check whether a key is hardware-backed?
Read its KeyInfo.securityLevel or verify its properties using key attestation when server-side assurance is required.
Q8. What is a biometric-protected key?
It is a Keystore key configured so that cryptographic operations require successful biometric or device authentication.
Q9. What is BiometricPrompt.CryptoObject?
It wraps a Cipher, Signature or Mac and binds that cryptographic operation to successful biometric authentication.
Q10. What happens when biometric enrollment changes?
The key may be permanently invalidated if it was configured with biometric-enrollment invalidation enabled.
Q11. Can Android Keystore encrypt complete files directly?
Keystore protects and operates with cryptographic keys. The application still performs encryption and stores the resulting ciphertext and required metadata.
Q12. What should happen when StrongBox is unavailable?
The app should catch StrongBoxUnavailableException and use a suitable fallback, such as a normal hardware-backed or Android Keystore key.
---
17. Final Interview Answer
> Android Keystore securely generates and stores cryptographic keys. Secret and private keys remain non-exportable, so the application uses them through encryption, decryption or signing operations without receiving the raw key material. Keys can be software-backed, TEE-backed or StrongBox-backed, depending on the device. For sensitive operations, a key can require biometric authentication by enabling user authentication during key generation and passing its cipher through BiometricPrompt.CryptoObject. The application should not assume hardware or StrongBox support and must handle unavailable hardware and key invalidation correctly.