The Android Keystore system lets you store cryptographic keys in a container to make them more difficult to extract from the device. Once keys are in the keystore, you can use them for cryptographic operations, with the key material remaining non-exportable. Also, the keystore system lets you restrict when and how keys can be used, such as requiring user authentication for key use or restricting keys to use only in certain cryptographic modes. See the Security Features section for more information.
The keystore system is used by the
KeyChain
API, introduced in Android 4.0 (API level 14), as well as the Android Keystore
provider feature, introduced in Android 4.3 (API level 18). This document goes
over when and how to use the Android Keystore system.
The Android Keystore system protects key material from unauthorized use in two ways. First, it reduces the risk of unauthorized use of key material from outside the Android device by preventing the extraction of the key material from application processes and from the Android device as a whole. Second, the keystore system reduces the risk of unauthorized use of key material within the Android device by making apps specify the authorized uses of their keys and then enforcing those restrictions outside of the apps' processes.
To check whether the feature is enabled for a key, obtain a
KeyInfo
for the key. The next step depends on your app’s target SDK version:
getSecurityLevel().
Return values matching
KeyProperties.SecurityLevelEnum.TRUSTED_ENVIRONMENT or
KeyProperties.SecurityLevelEnum.STRONGBOX indicate that the key
resides within secure hardware.KeyInfo.isInsideSecurityHardware().Devices running Android 9 (API level 28) or higher can include a StrongBox KeyMint, an implementation of the KeyMint HAL that is backed by StrongBox. While hardware security modules (HSMs) broadly refer to secure key storage solutions resistant to Linux kernel compromises, StrongBox specifically denotes implementations in embedded SEs or integrated Secure Enclaves (iSE), providing stronger isolation and tamper resistance compared to the TEE.
An implementation of StrongBox KeyMint must contain the following:
A subset of algorithms and key sizes are supported to accommodate low-power StrongBox implementations:
StrongBox also supports key attestation.
Use FEATURE_STRONGBOX_KEYSTORE to check whether StrongBox
is available on a device. If StrongBox is available, you can indicate a
preference for storing the key in the StrongBox KeyMint by passing true to the
following methods:
KeyGenParameterSpec.Builder.setIsStrongBoxBacked()KeyProtection.Builder.setIsStrongBoxBacked()If the StrongBox KeyMint does not support the specified algorithm or key size,
the framework will throw a StrongBoxUnavailableException. If this occurs, generate or import the
key without calling setIsStrongBoxBacked(true).
To avoid unauthorized use of keys on the Android device, Android Keystore lets apps specify authorized uses of their keys when they generate or import the keys. Once a key is generated or imported, its authorizations can't be changed. Authorizations are then enforced by the Android Keystore whenever the key is used. This is an advanced security feature that is generally useful only if your requirements are that a compromise of your application process after key generation/import (but not before or during) can't lead to unauthorized uses of the key.
Supported key use authorizations fall into the following categories:
As an additional security measure for keys whose key material is inside secure hardware (see
KeyInfo.isInsideSecurityHardware()
or, for apps targeting Android 10 (API level 29) or higher,
KeyInfo.getSecurityLevel()),
some key use authorizations might be enforced by the secure hardware,
depending on the Android device.
Secure hardware normally enforces cryptographic and user authentication
authorizations. However, secure hardware doesn't usually enforce temporal
validity interval authorizations, because it normally doesn't have an
independent, secure real-time clock.
You can query whether a key's user authentication authorization is enforced by
the secure hardware using
KeyInfo.isUserAuthenticationRequirementEnforcedBySecureHardware().
Use the KeyChain API when you want
system-wide credentials. When an app requests the use of any credential
through the KeyChain API, users can
choose, through a system-provided UI, which of the installed credentials
an app can access. This lets several apps use the
same set of credentials with user consent.
Use the Android Keystore provider to let an individual app store its own
credentials, which only that app can access.
This provides a way for apps to manage credentials that only they can use
while providing the same security benefits that the
KeyChain API provides for system-wide credentials.
This method doesn't require the user to select the credentials.
To use this feature, you use the standard KeyStore
and KeyPairGenerator or
KeyGenerator classes along with the
AndroidKeyStore provider introduced in Android 4.3 (API level 18).
AndroidKeyStore is registered as a KeyStore type for use with the KeyStore.getInstance(type)
method and as a provider for use with the KeyPairGenerator.getInstance(algorithm, provider) and KeyGenerator.getInstance(algorithm, provider) methods.
Because cryptographic operations may be time-consuming, apps should avoid using
AndroidKeyStore on their main thread to ensure that the app's UI remains
responsive. (StrictMode can help you find places where this is not the case.)
To generate a new KeyPair containing a
PrivateKey,
you must specify the initial X.509 attributes of the certificate. You can use
KeyStore.setKeyEntry()
to replace the certificate at a later time with a certificate signed
by a certificate authority (CA).
To generate the key pair, use a KeyPairGenerator
with KeyGenParameterSpec:
/* * Generate a new EC key pair entry in the Android Keystore by * using the KeyPairGenerator API. The private key can only be * used for signing or verification and only with SHA-256 or * SHA-512 as the message digest. */ val kpg: KeyPairGenerator = KeyPairGenerator.getInstance( KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore" ) val parameterSpec: KeyGenParameterSpec = KeyGenParameterSpec.Builder( alias, KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY ).run { setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512) build() } kpg.initialize(parameterSpec) val kp = kpg.generateKeyPair()
/* * Generate a new EC key pair entry in the Android Keystore by * using the KeyPairGenerator API. The private key can only be * used for signing or verification and only with SHA-256 or * SHA-512 as the message digest. */ KeyPairGenerator kpg = KeyPairGenerator.getInstance( KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore"); kpg.initialize(new KeyGenParameterSpec.Builder( alias, KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY) .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512) .build()); KeyPair kp = kpg.generateKeyPair();
Android 9 (API level 28) and higher lets you import encrypted keys securely into the keystore using an ASN.1‑encoded key format. The Keymaster then decrypts the keys in the keystore, so the content of the keys never appears as plaintext in the device's host memory. This process provides additional key decryption security.
To support secure importing of encrypted keys into the keystore, complete the following steps:
Generate a key pair that uses the
PURPOSE_WRAP_KEY
purpose. We recommend that you add attestation to this key pair as well.
On a server or machine that you trust, generate the ASN.1 message for the
SecureKeyWrapper.
The wrapper contains the following schema:
KeyDescription ::= SEQUENCE {
keyFormat INTEGER,
authorizationList AuthorizationList
}
SecureKeyWrapper ::= SEQUENCE {
wrapperFormatVersion INTEGER,
encryptedTransportKey OCTET_STRING,
initializationVector OCTET_STRING,
keyDescription KeyDescription,
secureKey OCTET_STRING,
tag OCTET_STRING
}
Create a
WrappedKeyEntry
object, passing in the ASN.1 message as a byte array.
Pass this WrappedKeyEntry object into the overload of
setEntry()
that accepts a
Keystore.Entry object.
You can access the AndroidKeyStore provider through
all the standard KeyStore APIs.
List entries in the keystore by calling the aliases() method:
/* * Load the Android KeyStore instance using the * AndroidKeyStore provider to list the currently stored entries. */ val ks: KeyStore = KeyStore.getInstance("AndroidKeyStore").apply { load(null) } val aliases: Enumeration<String> = ks.aliases()
/* * Load the Android KeyStore instance using the * AndroidKeyStore provider to list the currently stored entries. */ KeyStore ks = KeyStore.getInstance("AndroidKeyStore"); ks.load(null); Enumeration<String> aliases = ks.aliases();
Sign data by fetching the KeyStore.Entry from the keystore and using the
Signature APIs, such as sign():
/* * Use a PrivateKey in the KeyStore to create a signature over * some data. */ val ks: KeyStore = KeyStore.getInstance("AndroidKeyStore").apply { load(null) } val entry: KeyStore.Entry = ks.getEntry(alias, null) if (entry !is KeyStore.PrivateKeyEntry) { Log.w(TAG, "Not an instance of a PrivateKeyEntry") return null } val signature: ByteArray = Signature.getInstance("SHA256withECDSA").run { initSign(entry.privateKey) update(data) sign() }
/* * Use a PrivateKey in the KeyStore to create a signature over * some data. */ KeyStore ks = KeyStore.getInstance("AndroidKeyStore"); ks.load(null); KeyStore.Entry entry = ks.getEntry(alias, null); if (!(entry instanceof PrivateKeyEntry)) { Log.w(TAG, "Not an instance of a PrivateKeyEntry"); return null; } Signature s = Signature.getInstance("SHA256withECDSA"); s.initSign(((PrivateKeyEntry) entry).getPrivateKey()); s.update(data); byte[] signature = s.sign();
Similarly, verify data with the verify(byte[]) method:
/* * Verify a signature previously made by a private key in the * KeyStore. This uses the X.509 certificate attached to the * private key in the KeyStore to validate a previously * generated signature. */ val ks = KeyStore.getInstance("AndroidKeyStore").apply { load(null) } val entry = ks.getEntry(alias, null) as? KeyStore.PrivateKeyEntry if (entry == null) { Log.w(TAG, "Not an instance of a PrivateKeyEntry") return false } val valid: Boolean = Signature.getInstance("SHA256withECDSA").run { initVerify(entry.certificate) update(data) verify(signature) }
/* * Verify a signature previously made by a private key in the * KeyStore. This uses the X.509 certificate attached to the * private key in the KeyStore to validate a previously * generated signature. */ KeyStore ks = KeyStore.getInstance("AndroidKeyStore"); ks.load(null); KeyStore.Entry entry = ks.getEntry(alias, null); if (!(entry instanceof PrivateKeyEntry)) { Log.w(TAG, "Not an instance of a PrivateKeyEntry"); return false; } Signature s = Signature.getInstance("SHA256withECDSA"); s.initVerify(((PrivateKeyEntry) entry).getCertificate()); s.update(data); boolean valid = s.verify(signature);
When generating or importing a key into the AndroidKeyStore, you can specify that the key
is only authorized to be used if the user has been authenticated. The user is authenticated using a
subset of their secure lock screen credentials (pattern/PIN/password, biometric credentials).
This is an advanced security feature that is generally useful only if your requirements are that a compromise of your application process after key generation/import (but not before or during) can't bypass the requirement for the user to be authenticated to use the key.
When a key is only authorized to be used if the user has been authenticated, you can call
setUserAuthenticationParameters()
to configure it to operate in one of the following modes:
Each operation involving a specific key must be individually authorized by the user.
Your app starts this process by calling
authenticate()
on an instance of BiometricPrompt.
For each key that you create, you can choose to support a
strong
biometric credential, a
lock screen
credential, or both types of credentials. To determine whether the user has set up the credentials
that your app's key relies on, call
canAuthenticate().
If a key only supports biometric credentials, the key is invalidated by default whenever new
biometric enrollments are added. You can configure the key to remain valid when new biometric
enrollments are added. To do so, pass false into
setInvalidatedByBiometricEnrollment().
Learn more about how to add biometric authentication capabilities into your app, including how to show a biometric authentication dialog.
CipherKeyGeneratorKeyFactoryKeyStore (supports the same key types as KeyGenerator and KeyPairGenerator)KeyPairGeneratorMacSignatureSecretKeyFactoryContent and code samples on this page are subject to the licenses described in the Content License. Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.
Last updated 2026-03-06 UTC.