KeyStore (Android) es una implementación del proveedor criptográfico Java Cryptography Architecture (JCA) integrada en Android para el almacenamiento seguro de claves con capacidad de aislamiento por hardware. Desde Android 4.3 (API 18), KeyStore admite claves de hardware a través de Keymaster HAL, y a partir de Android 9 (API 28), StrongBox Keymaster para claves en un Secure Element dedicado. Según la Documentación de seguridad de Android, el proveedor “AndroidKeyStore” reemplaza a Bouncy Castle u OpenSSL KeyStore estándar, proporcionando protección a nivel de sistema contra la extracción no autorizada de claves.
Puntos clave
KeyStore en Android no es una aplicación o archivo separado, sino un proveedor criptográfico que implementa la interfaz java.security.KeyStore. Proporciona una API unificada para almacenar y usar claves privadas, claves simétricas y certificados de CA de confianza. El proveedor está registrado bajo el nombre “AndroidKeyStore” y es accesible mediante el KeyStore.getInstance() estándar.
Antes de Android 4.3, las operaciones criptográficas se realizaban mediante Bouncy Castle. Android 4.3 introdujo Keymaster HAL 1.0, permitiendo el uso de TEE en ARM TrustZone. Android 6.0 (API 23) agregó Keymaster 2.0 con autenticación biométrica por hardware. Android 9 (API 28) presentó Keymaster 4.0 y StrongBox Keymaster para un Secure Element dedicado.
Cada versión de Keymaster agrega nuevas capacidades y mejora el aislamiento de claves. Los dispositivos modernos (2022+) deben admitir Keymaster 4.0 para la certificación de Google Mobile Services, lo que garantiza la disponibilidad de TEE para todas las aplicaciones de Android.
Android KeyStore consta de tres capas: API de Java (KeyStore, KeyPairGenerator), proceso de sistema keystore (C++, se ejecuta como servicio del sistema) y Keymaster HAL (biblioteca en TEE o Secure Element). La aplicación llama a la API, el servicio keystore enruta la solicitud a Keymaster y la operación se realiza en el entorno seguro.
Todas las claves privadas se almacenan en TEE y no se pueden leer desde el espacio de usuario. Incluso el servicio de keystore del sistema no tiene acceso a las claves sin procesar, solo a los identificadores que apuntan a las claves dentro de Keymaster.
Android KeyStore implementa la interfaz estándar de proveedor de servicios JCA. Cuando una aplicación llama a Cipher.getInstance(“RSA/ECB/PKCS1Padding”, “AndroidKeyStore”), el Proveedor de seguridad de Android delega la operación a Keymaster a través de la cadena: Java → JNI → servicio keystore → Keymaster HAL.
El proveedor AndroidKeyStore se registra automáticamente al iniciar el proceso. Su prioridad es mayor que la de Bouncy Castle o Conscrypt. Por lo tanto, al llamar a KeyStore.getInstance() sin especificar un proveedor, se devuelve AndroidKeyStore en la mayoría de los casos. Para una invocación explícita, use KeyStore.getInstance(“AndroidKeyStore”).
Cada aplicación de Android tiene un contenedor aislado en KeyStore. Las aplicaciones con el mismo UID (shared userId) pueden compartir el acceso a ciertas claves, pero la configuración estándar garantiza que la aplicación A no pueda leer las claves de la aplicación B.
load(null) — inicialización de KeyStore. El parámetro siempre es null para AndroidKeyStore. setEntry — guarda una clave con KeyProtection especificada (propósitos, digest, padding). getEntry — obtiene KeyStore.PrivateKeyEntry, SecretKeyEntry o TrustedCertificateEntry. containsAlias — verifica si existe una clave. deleteEntry — elimina una clave de forma permanente.
import java.security.KeyStore
import java.security.KeyPairGenerator
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
object KeyStoreManager {
private val keyStore by lazy {
KeyStore.getInstance("AndroidKeyStore").apply { load(null) }
}
fun createRsaKey(alias: String) {
val spec = KeyGenParameterSpec.Builder(alias,
KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY
).setKeySize(2048)
.setDigests(KeyProperties.DIGEST_SHA256)
.setSignaturePaddings(KeyProperties.SIGN_PADDING_RSA_PKCS1)
.build()
val kpg = KeyPairGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_RSA,
"AndroidKeyStore"
)
kpg.initialize(spec)
kpg.generateKeyPair()
}
}
Android KeyStore admite un amplio conjunto de algoritmos criptográficos, que varía según la versión de Keymaster HAL en el dispositivo. Un desarrollador puede obtener la lista de algoritmos compatibles a través de KeyGenParameterSpec.Builder al intentar la generación; los parámetros incompatibles lanzan InvalidAlgorithmParameterException.
RSA (1024–4096 bits) — para firma (PKCS1, PSS con SHA-1/SHA-256/SHA-384/SHA-512) y cifrado (OAEP con SHA-1/SHA-256). EC (P-224, P-256, P-384, P-521) — para firma ECDSA y acuerdo de claves ECDH. X25519 y Ed25519 — desde Android 12 (API 31) para protocolos criptográficos modernos.
Para claves asimétricas, genere siempre dentro de Keymaster, NUNCA importe claves privadas. Las claves privadas importadas no están protegidas por hardware; se almacenan en la capa de software y son vulnerables si el proceso de la aplicación se ve comprometido.
AES (128, 256 bits) — para cifrado simétrico en modos CBC, CTR, GCM. HMAC (SHA-1, SHA-256, SHA-512) — para autenticación de mensajes. ChaCha20 (Android 12+) — para cifrado de flujo de alto rendimiento con autenticación Poly1305.
| Algoritmo | Keymaster | Propósito | API |
|---|---|---|---|
| RSA | KM 1.0+ | Firma, Cifrado | 18+ |
| EC | KM 1.0+ | ECDSA, ECDH | 18+ |
| AES | KM 2.0+ | Cifrado simétrico | 23+ |
| HMAC | KM 2.0+ | Código de autenticación | 23+ |
| ChaCha20 | KM 3.0+ | Cifrado de flujo | 31+ |
| X25519/Ed25519 | KM 3.0+ | Intercambio de claves | 31+ |
KeyStore.PrivateKeyEntry — contiene una clave privada (no exportable) y una cadena de certificados. KeyStore.SecretKeyEntry — para claves simétricas. KeyStore.TrustedCertificateEntry — para certificados de CA de confianza. Las claves públicas se pueden exportar mediante keyStore.getCertificate(alias).publicKey.
Veamos un escenario completo: generar una clave AES para cifrado de datos y generar una clave EC para firma con protección biométrica. Ambas claves se crean dentro de Android KeyStore con soporte de hardware.
Una clave AES se crea mediante KeyGenerator con KeyGenParameterSpec. Parámetros: PURPOSE_ENCRYPT + PURPOSE_DECRYPT, BLOCK_MODE_GCM (modo recomendado con autenticación), ENCRYPTION_PADDING_NONE (no se necesita padding para GCM).
import javax.crypto.KeyGenerator
import javax.crypto.Cipher
import javax.crypto.spec.GCMParameterSpec
fun generateAndEncrypt(alias: String, plainText: ByteArray): ByteArray {
val spec = KeyGenParameterSpec.Builder(alias,
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
).setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setKeySize(256)
.build()
val kg = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore")
kg.initialize(spec)
kg.generateKey()
val cipher = Cipher.getInstance("AES/GCM/NoPadding")
cipher.init(Cipher.ENCRYPT_MODE, getKeyFromStore(alias))
return cipher.doFinal(plainText)
}
Una clave EC con userAuthenticationRequired=true requiere autenticación del usuario antes de cada operación de firma. Para ello se utiliza BiometricPrompt con CryptoObject que contiene el objeto Signature. Después de la verificación biométrica exitosa, Keymaster permite la operación.
fun createBiometricSignKey(alias: String) {
val spec = KeyGenParameterSpec.Builder(alias,
KeyProperties.PURPOSE_SIGN
).setAlgorithmParameterSpec(
ECGenParameterSpec("secp256r1")
).setDigests(KeyProperties.DIGEST_SHA256)
.setUserAuthenticationRequired(true)
.setInvalidatedByBiometricEnrollment(true)
.build()
val kpg = KeyPairGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_EC,
"AndroidKeyStore"
)
kpg.initialize(spec)
kpg.generateKeyPair()
}
Android KeyStore proporciona garantías de seguridad a nivel de hardware que los KeyStore basados en software (JKS, BKS) no pueden ofrecer. Las claves están protegidas a nivel de SoC, e incluso el control total sobre el espacio de usuario de Android no permite extraer la clave privada.
Key Attestation es un mecanismo que permite a una aplicación (y al servidor) verificar el entorno en el que se creó una clave. Android Keystore firma un certificado que contiene una lista de características de la clave: algoritmo, tamaño, propósitos, hardware-backed (True/False), origen (GENERATED, IMPORTED). El servidor verifica la cadena de certificados hasta el certificado raíz de Google.
Esto es fundamental para las aplicaciones financieras: el servidor puede exigir que la clave se haya creado en un entorno de hardware (Hardware-Backed = True) y rechazar claves creadas en Keystore de software. Key Attestation previene ataques en los que un atacante reemplaza el Keystore por un emulador.
setInvalidatedByBiometricEnrollment(true) significa que Keymaster eliminará automáticamente la clave cuando se modifiquen o eliminen las plantillas biométricas del usuario. Esto protege contra ataques en los que un atacante agrega su huella digital a una cuenta existente. Después de agregar una nueva huella, las claves antiguas se vuelven inaccesibles.
El contador de intentos fallidos de autenticación biométrica también es gestionado por Keymaster. Después de maxBiometricAttempt (configurable por el fabricante, normalmente 5), Keymaster bloquea todas las operaciones con claves biométricas durante 30 segundos. Después de 10 intentos fallidos, hasta que se ingrese la contraseña del dispositivo (PIN secreto).
Preguntas frecuentes
Bouncy Castle (BKS) es un KeyStore de software que almacena claves en un archivo protegido por contraseña. Android KeyStore utiliza aislamiento por hardware TEE/StrongBox. Las claves BKS se pueden extraer con acceso root, las claves de Android KeyStore no. BKS es adecuado para certificados de CA, Android KeyStore es para claves privadas.
Sí, si especifica PURPOSE_ENCRYPT o PURPOSE_DECRYPT o PURPOSE_SIGN o PURPOSE_VERIFY al generar la clave. Sin embargo, la mejor práctica es crear claves separadas para diferentes operaciones. Esto limita el daño si una clave se ve comprometida y sigue el principio de mínimo privilegio.
Utilice KeyStore.getKeyCharacteristics(alias), disponible a través de android.security.keystore. El método devuelve un conjunto de banderas: FLAG_HARDWARE — clave en TEE, FLAG_SECURE_ELEMENT — clave en StrongBox. Si no hay banderas, la clave es solo software.
Todas las claves creadas con setInvalidatedByBiometricEnrollment(true) serán invalidadas automáticamente por Keymaster. Al intentar usarlas, la aplicación recibirá KeyPermanentlyInvalidatedException. Los datos cifrados con estas claves se perderán permanentemente.
Las claves de hardware (en TEE/StrongBox) no admiten copia de seguridad, están vinculadas a un dispositivo específico. Las claves de software pueden incluirse en la copia de seguridad de Google Drive. Para transferir datos entre dispositivos, cifre los datos en el servidor y descifrelos en el nuevo dispositivo.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también