Keystore in Android — What It Is, Architecture and Cryptography

Author: IT Sectr Published: 2026-04-04 Reading time: 9 min

Android Keystore is a cryptographic provider that generates and stores encryption keys in an isolated execution environment (TEE), inaccessible even to the operating system. According to AOSP Security Documentation (2025), Keystore is used in more than 80% of Android apps from the Google Play top 100 for protecting tokens and encrypting data. Understanding Android Keystore is critically important for secure key storage on Android.

Key Takeaways

  • Android Keystore — a system provider for generating and storing cryptographic keys in a hardware-isolated environment (TEE).
  • StrongBox Keymaster — a dedicated security chip with its own CPU and TRNG, certified Common Criteria EAL 4+.
  • KeyGenParameterSpec — a configurator for setting the algorithm, key size, biometric binding, and validity period.
  • TEE (Trusted Execution Environment) — an isolated area of the processor where cryptographic operations are performed without access from user space.
  • Keys from Keystore cannot be extracted — the private key never leaves TEE or StrongBox, even the app developer cannot read it.

What is Keystore in Android?

Android Keystore — a system component of the Android platform that provides an API for generating, storing, and using cryptographic keys in a protected environment. Unlike software cryptographic libraries (Bouncy Castle, Conscrypt), Keystore ensures that private keys never leave the isolated execution area.

Keystore first appeared in Android 4.3 (API 18) as a software provider with RSA support. Starting with Android 6.0 (API 23), Keystore received hardware support through the Keymaster Hardware Abstraction Layer (HAL), which delegates cryptographic operations to the Trusted Execution Environment (TEE) on compatible devices. According to Android Compatibility Definition Document (2025), all devices with Android 9+ are required to support hardware-backed Keystore via TEE or StrongBox.

Keys in Keystore are identified by an alias — a string that is passed when creating or loading a key. Keystore does not allow access to the raw key material: getEncoded() methods return null for keys created in Keystore. This is a fundamental difference from software keys — an attacker cannot extract the private key even with full control over the device.

Keystore is integrated with other Android security mechanisms: biometric authentication (BiometricPrompt), File-Based Encryption, and SafetyNet / Play Integrity verification functions. Keys can be configured for automatic deletion under certain conditions: when the passcode is removed, when a new fingerprint is added, or upon expiration.

Android Keystore Architecture

The Android Keystore architecture includes three implementation levels that differ in the degree of hardware protection. The level depends on the capabilities of the device’s hardware.

Hardware-backed Keystore (TEE)

TEE (Trusted Execution Environment) — an isolated area running in parallel with the main OS on the same processor. TEE uses ARM TrustZone technology, which splits the physical processor core into two virtual ones: Normal World (Android) and Secure World (TEE). Code in Secure World has access to memory and peripherals that are inaccessible from Normal World.

When an application calls a cryptographic operation through Keystore, the request is passed through Keymaster HAL to TEE, where the operation is performed in hardware. The result is returned to the application, but the private key remains in TEE’s protected memory. TEE is certified for compliance with the GlobalPlatform TEE Protection Profile and is a mandatory requirement for Android 9+ on devices with processors that support TrustZone.

TEE supports AES/GCM (128, 256 bit), RSA (2048, 4096 bit), EC (P-256, P-384, P-521) and HMAC-SHA256 algorithms. TEE performance is lower than software cryptography (by 20–40%), but for typical operations (JWT signing, session key decryption), the latency does not exceed 10–50 ms.

StrongBox Keymaster

StrongBox — a dedicated security chip, physically separate from the main processor. Unlike TEE, which shares processor time with Android, StrongBox has its own CPU, RAM, True Random Number Generator (TRNG), and secure storage (One-Time Programmable memory). StrongBox is certified for Common Criteria EAL 4+ and Secure IC Protection Profile.

StrongBox is available on devices with Android 9+ provided the corresponding chip is present (e.g., Titan M on Google Pixel, Knox on Samsung Galaxy). The developer enables StrongBox via the setIsStrongBoxBacked(true) flag in KeyGenParameterSpec. If hardware support is not available, the flag is ignored and Keystore falls back to TEE.

StrongBox limitations: supports a limited set of algorithms (AES-256, EC P-256, HMAC-SHA256), operation queue — no more than one at a time, operation count — limited by chip resources. StrongBox is not designed for high-load scenarios — use TEE for frequent operations and StrongBox only for critical keys (master encryption keys, signing keys).

Software-based Keystore

Software-based Keystore is a software implementation used on devices without hardware support for TEE or StrongBox. Keys are stored in encrypted form in the file system, but the private key may be temporarily decrypted in RAM. Software Keystore is less secure — an attacker with root access can intercept the key in memory.

Starting with Android 12 (API 31), Google requires hardware-backed Keystore for all new devices. Devices with Android 9–11 may have software Keystore on budget models. The developer can check the protection level via KeyStore.getKeyCharacteristics() — the SECURITY_LEVEL_TRUSTED_ENVIRONMENT or SECURITY_LEVEL_STRONGBOX attribute confirms hardware protection.

Supported Algorithms and Functions

Android Keystore supports a wide range of cryptographic algorithms, divided into categories depending on the key type. The choice of algorithm affects performance, compatibility, and security level.

AES (Advanced Encryption Standard) — symmetric encryption for protecting data on the device. Recommended mode: AES/GCM/NoPadding (256 bit). GCM provides authenticated encryption (AEAD) — integrity checking of encrypted data. IV (Initialization Vector) size: 12 bytes for GCM. Do not use AES/ECB — it does not provide adequate protection.

RSA (Rivest–Shamir–Adleman) — asymmetric encryption for protecting session keys and digital signatures. Recommended size: 2048 or 4096 bits. Modes: RSA/ECB/PKCS1Padding (encryption) and RSA/ECB/PKCS1Sign (signature). RSA 1024 is considered deprecated and is not recommended for new applications (NIST SP 800-131A Rev. 2).

EC (Elliptic Curve) — asymmetric cryptography on elliptic curves for signing and key exchange. Supported curves: secp256r1 (P-256, mandatory), secp384r1 (P-384) and secp521r1 (P-521). EC provides comparable security to RSA with significantly smaller key size. P-256 is recommended for most scenarios: it is supported by all devices and provides 128-bit security level.

HMAC (Hash-based Message Authentication Code) — symmetric message authentication. Supported hash functions: SHA-256, SHA-384, SHA-512. HMAC is used for verifying data integrity and authenticity, for example, for verifying webhook requests or checking configuration integrity.

All algorithms can be bound to biometric authentication via KeyGenParameterSpec.Builder.setUserAuthenticationRequired(true). On Android 11+ the setUserAuthenticationParameters() flag is available with a timeout (in seconds) during which the key is available after biometric authentication, without a repeated request.

Code Examples: Key Generation and Usage

Let’s look at practical examples of working with Android Keystore in Kotlin: generating an AES key, encrypting data, and creating an asymmetric pair for signing.

Generating an AES Key in Keystore

The example creates a 256-bit AES/GCM key with biometric authentication binding. The key is not exportable via getEncoded().

kotlin
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import java.security.KeyStore

private val keyStore = KeyStore.getInstance("AndroidKeyStore").apply { load(null) }

fun generateAesKey(alias: String) {
    val spec = KeyGenParameterSpec.Builder(
        alias,
        KeyProperties.PURPOSE_ENCRYPT or
        KeyProperties.PURPOSE_DECRYPT
    )
    .setKeySize(256)
    .setBlockModes(KeyProperties.KEY_BLOCK_MODE_GCM)
    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
    .setUserAuthenticationRequired(true)
    .setInvalidatedByBiometricEnrollment(true)
    .build()

    val generator = KeyGenerator.getInstance(
        KeyProperties.KEY_ALGORITHM_AES,
        "AndroidKeyStore"
    )
    generator.init(spec)
    generator.generateKey()
}

AES/GCM Data Encryption

The example encrypts data using a key from Android Keystore. Cipher gets the key by alias, initializes AES/GCM encryption, and returns the encrypted data along with the IV.

kotlin
fun encryptData(alias: String, plaintext: ByteArray): ByteArray {
    val cipher = Cipher.getInstance("AES/GCM/NoPadding")
    val secretKey = keyStore.getKey(alias, null) as SecretKey
    cipher.init(Cipher.ENCRYPT_MODE, secretKey)

    val iv = cipher.getIV()
    val encrypted = cipher.doFinal(plaintext)

    // IV + encrypted data
    return iv + encrypted
}

fun decryptData(alias: String, ciphertextWithIv: ByteArray): ByteArray {
    val iv = ciphertextWithIv.copyOfRange(0, 12)
    val encrypted = ciphertextWithIv.copyOfRange(12, ciphertextWithIv.size)

    val cipher = Cipher.getInstance("AES/GCM/NoPadding")
    val secretKey = keyStore.getKey(alias, null) as SecretKey
    val spec = GCMParameterSpec(128, iv)
    cipher.init(Cipher.DECRYPT_MODE, secretKey, spec)

    return cipher.doFinal(encrypted)
}

Generating an RSA Key Pair for Signing

The example creates an RSA-2048 key pair in Keystore with StrongBox binding. The private key is used for signing, the public key can be exported via getEncoded().

kotlin
fun generateRsaKeyPair(alias: String) {
    val spec = KeyGenParameterSpec.Builder(
        alias,
        KeyProperties.PURPOSE_SIGN or
        KeyProperties.PURPOSE_VERIFY
    )
    .setKeySize(2048)
    .setSignaturePaddings(
        KeyProperties.SIGNATURE_PADDING_RSA_PKCS1
    )
    .setDigests(KeyProperties.DIGEST_SHA256)
    .setIsStrongBoxBacked(true)
    .build()

    val pair = KeyPairGenerator.getInstance(
        KeyProperties.KEY_ALGORITHM_RSA,
        "AndroidKeyStore"
    ).apply { init(spec) }
     .generateKeyPair()

    // Public key can be exported
    val publicKey = pair.public // X509EncodedKeySpec
}

Best Practices for Android Keystore

Effective use of Android Keystore requires following rules that ensure maximum protection while maintaining performance.

Use KeyGenParameterSpec with the minimum necessary parameters: specify only those purpose, block modes, and paddings that are actually used. Redundant parameters (e.g., PURPOSE_ENCRYPT for a key that is only used for signing) create unnecessary attack vectors. Android recommends explicitly specifying digest for signing — SHA256 is the minimum acceptable level (SHA1 is deprecated).

Bind keys to biometrics for critical operations: setUserAuthenticationRequired(true) guarantees that the key can only be used after biometric authentication. On Android 11+ use setUserAuthenticationParameters() with a timeout (recommended 30–60 seconds) to avoid requesting biometrics for every operation within a single session. setInvalidatedByBiometricEnrollment(true) automatically deletes the key when a new fingerprint or face is enrolled — this prevents access with old biometric data.

Check the security level at initialization: use KeyStore.getKeyCharacteristics() to determine SECURITY_LEVEL. If the device only supports software Keystore (SECURITY_LEVEL_SOFTWARE), make a decision: either decline the functionality or use additional encryption (e.g., key wrapping via user password). Do not rely on StrongBox if it is not guaranteed — always specify the setIsStrongBoxBacked(true) flag and verify the result via getKeyCharacteristics.

Rotate keys on a schedule: cryptographic keys have a recommended lifetime. NIST SP 800-57 recommends changing AES keys every 1–2 years, RSA/EC pairs every 2–3 years. Implement a key rotation mechanism: check the key creation date at app launch (KeyGenParameterSpec.Builder.setKeyValidityStart/End) and generate a new key when it expires. Old data encrypted with the old key should be decrypted and re-encrypted with the new one.

Do not use Keystore for large data: Keystore is designed for storing keys (a few hundred bytes), not for encrypting large files. For data encryption, use the scheme: generate a random AES key (DEK — Data Encryption Key), encrypt the data with this key, and encrypt the DEK with a Keystore key (KEK — Key Encryption Key). Android EncryptedSharedPreferences uses exactly this scheme: master key in Keystore, data — AES-256 GCM.

Frequently Asked Questions

Can I get the private key from Android Keystore?

No, Android Keystore is designed so that the private key never leaves TEE or StrongBox. The getEncoded() method returns null for keys created in Keystore. The key can only be used through Cipher, Signature, or Mac API — the raw material is inaccessible.

What is the difference between TEE and StrongBox?

TEE (TrustZone) — virtual isolation on the same processor, uses time-sharing. StrongBox — a separate chip with its own CPU and memory. StrongBox is more secure (Common Criteria EAL 4+), but slower and supports fewer algorithms. TEE is suitable for frequent operations, StrongBox for critical keys.

How to check if a device supports StrongBox?

Use KeyStore.getKeyCharacteristics() after generating a key with the setIsStrongBoxBacked(true) flag. The SECURITY_LEVEL_STRONGBOX attribute confirms hardware support. If the device does not support StrongBox, Keystore falls back to TEE without error — you must explicitly check the security level.

What happens to keys when an app is uninstalled?

Keys in Keystore are automatically deleted when the app is uninstalled from the device. On Android 10+ keys may persist if the app has the allowBackup=true flag in its manifest, but they will be unavailable after reinstalling. It is recommended to generate keys again on a clean install.

Can I use one key on multiple devices?

No, Android Keystore is tied to the hardware of a specific device. A key generated in the TEE of one device cannot be transferred to another. For cross-platform encryption, use the scheme: Keystore protects the key on the device, and session keys are transmitted through a secure API using asymmetric encryption.

Summary

  • Android Keystore — a system provider for protecting cryptographic keys in a hardware-isolated environment (TEE or StrongBox).
  • TEE (TrustZone) — virtual isolation on the same processor, mandatory for Android 9+ on devices with TrustZone.
  • StrongBox — a dedicated security chip with Common Criteria EAL 4+ certification, enabled via setIsStrongBoxBacked(true).
  • KeyGenParameterSpec — the central class for configuring key parameters: algorithm, size, biometric binding, and rotation.
  • Keys cannot be extracted — private material is inaccessible via getEncoded(), operations are performed inside TEE/StrongBox.
  • Recommended algorithms — AES/GCM/NoPadding (256 bit) for encryption, EC P-256 for signing, RSA 2048 for asymmetric scenarios.
  • KEK/DEK scheme — Keystore stores the master key for protecting data encryption keys, ensuring both performance and security.

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project

Read also