Android Keystore es un mecanismo de sistema en Android para almacenar de forma segura claves criptográficas en aislamiento de hardware. El sistema utiliza Trusted Execution Environment (TEE) en dispositivos con ARM TrustZone o un Secure Element dedicado para proteger las claves a nivel de chip. Según Android Open Source Project, Keystore admite los algoritmos RSA, EC, AES y HMAC con generación de claves directamente en el entorno seguro.
Puntos clave
Android Keystore es un proveedor criptográfico implementado en Android desde API 1 (Android 1.0), pero la compatibilidad completa con hardware apareció con Android 4.3 (API 18). Keystore resuelve el problema del almacenamiento seguro de claves privadas de modo que incluso si el sistema operativo se ve comprometido, un atacante no pueda extraer las claves en texto plano.
La arquitectura de Android Keystore consta de tres niveles: la API de aplicación (java.security.KeyStore), el servicio del sistema (keystore daemon) y el nivel de hardware (Keymaster HAL). La aplicación accede a través de la API estándar Java Cryptography Architecture (JCA), y el servicio del sistema enruta las solicitudes a Keymaster que se ejecuta en TEE.
Todas las operaciones criptográficas con claves (firma, descifrado) se realizan dentro de TEE o Secure Element. Las claves nunca abandonan el entorno seguro: la aplicación recibe solo un identificador (alias) para referenciar la clave. Esta es una diferencia fundamental con los KeyStore de software, donde las claves son potencialmente accesibles en la memoria del proceso.
El JKS (Java KeyStore) estándar o BKS (Bouncy Castle) almacenan claves en archivos protegidos por contraseña. Android Keystore almacena claves en aislamiento de hardware, donde están protegidas incluso del usuario root. JKS es vulnerable al acceso directo al sistema de archivos; Android Keystore no.
Otra diferencia: en Android Keystore, las claves tienen parámetros de uso estrictos (purpose — solo sign/verify/encrypt/decrypt) especificados en el momento de la generación. No se pueden cambiar después, lo que evita el mal uso de la clave.
Al crear una nueva clave, la aplicación llama a KeyPairGenerator o KeyGenerator con KeyGenParameterSpec, que contiene todos los parámetros de la clave futura. El sistema pasa la solicitud a Keymaster HAL, que genera la clave dentro de TEE y devuelve un identificador.
El método KeyGenParameterSpec.Builder acepta parámetros obligatorios: nombre de la clave en Keystore, propósito (PURPOSE_SIGN, PURPOSE_ENCRYPT), algoritmo (RSA, EC, AES). Adicionalmente: digest (SHA-256), padding (PKCS7), userAuthenticationRequired (biometría), keyValidityStart/End (restricciones de tiempo).
Después de establecer los parámetros, KeyPairGenerator.generateKeyPair() devuelve un KeyPair, donde PrivateKey es un objeto que delega operaciones a Keymaster. La clave pública se puede extraer, la privada no. Existe solo dentro de TEE.
import java.security.KeyPairGenerator
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
fun generateKey(alias: String) {
val spec = KeyGenParameterSpec.Builder(alias,
KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY
).setDigests(KeyProperties.DIGEST_SHA256)
.setSignaturePaddings(KeyProperties.SIGN_PADDING_RSA_PKCS1)
.setUserAuthenticationRequired(true)
.build()
val kpGen = KeyPairGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_RSA,
"AndroidKeyStore"
)
kpGen.initialize(spec)
kpGen.generateKeyPair()
}
Signature para ECDSA o RSA-PSS se crea a través de la API estándar: Signature.getInstance(algorithm).initSign(privateKey). La operación de firma se realiza en TEE: la aplicación pasa datos, Keymaster los firma en hardware y devuelve la firma. La clave y los datos no se mezclan en la memoria compartida.
Para la protección biométrica, el usuario debe autenticarse mediante BiometricPrompt antes de firmar. Sin autenticación exitosa, Keymaster no realiza la operación y devuelve CryptoAuthenticationException.
import java.security.KeyStore
import java.security.Signature
import androidx.biometric.BiometricPrompt
fun signWithBiometric(alias: String) {
val ks = KeyStore.getInstance("AndroidKeyStore")
ks.load(null)
val entry = ks.getEntry(alias, null) as KeyStore.PrivateKeyEntry
val signature = Signature.getInstance("SHA256withRSA")
signature.initSign(entry.privateKey)
// BiometricPrompt con CryptoObject(signature) solicita FaceID/PIN
}
Android admite dos modos de almacenamiento de claves: software (en dispositivos sin TEE) y hardware (en dispositivos con TEE o Secure Element). El modo depende de las capacidades del SoC y la versión de Android.
En dispositivos sin Trusted Execution Environment (anteriores a Android 4.3 o SoCs económicos), las claves se almacenan cifradas usando una clave maestra derivada de la contraseña de la pantalla de bloqueo. Este modo es menos seguro: las claves son accesibles en la memoria del proceso durante las operaciones criptográficas.
El nivel de protección se basa en el cifrado del archivo KeyStore con AES-256-GCM. La clave de cifrado se genera a partir de la contraseña o PIN del usuario mediante Scrypt (PBKDF2 con un alto número de iteraciones).
En dispositivos modernos se utiliza Keymaster 4.x en TEE (ARM TrustZone). Las claves se generan, almacenan y utilizan exclusivamente dentro de TrustZone. Incluso el kernel de Linux no tiene acceso a las claves privadas, solo Keymaster HAL puede realizar operaciones.
Secure Element (por ejemplo, eSE en Samsung Knox o StrongBox en Google Pixel 3+) es un chip separado con su propio procesador y memoria. Está certificado Common Criteria EAL 4+ y proporciona el máximo nivel de protección, incluida la protección contra manipulación física.
| Tipo | Ubicación de almacenamiento | Nivel de protección | Disponible desde API |
|---|---|---|---|
| Software | Archivo /data/misc/keystore | Medio (AES-256) | API 1+ |
| Keymaster 3 | TEE (TrustZone) | Alto | API 23+ |
| Keymaster 4 | TEE + Secure I/O | Muy alto | API 28+ |
| StrongBox | Secure Element de hardware | Máximo | API 28+, opcional |
Android Keystore está integrado en Java Cryptography Architecture (JCA). Para acceder al proveedor se utiliza KeyStore.getInstance("AndroidKeyStore"). La API está disponible desde API 18.
El método KeyStore.load(null) carga el contenedor KeyStore de la aplicación. No se requiere contraseña: Android utiliza el contexto de la aplicación y su UID para el control de acceso. Cada aplicación ve solo sus propias entradas a menos que se use un UID compartido.
Los métodos setEntry y getEntry funcionan con KeyStore.PrivateKeyEntry, SecretKeyEntry o TrustedCertificateEntry. El parámetro ProtectionParameter es siempre null para Android Keystore (la protección se implementa a nivel del sistema).
import java.security.KeyStore
import java.security.cert.Certificate
import android.security.keystore.KeyProtection
fun storeSecretKey(alias: String, key: SecretKey) {
val ks = KeyStore.getInstance("AndroidKeyStore")
ks.load(null)
val prot = KeyProtection.Builder(
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
).setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setUserAuthenticationRequired(true)
.build()
ks.setEntry(alias, KeyStore.SecretKeyEntry(key), prot)
}
Usando KeyCharacteristics, se puede determinar en qué entorno se almacena la clave: KeyStore de software, TEE o StrongBox. El método getKeyCharacteristics() devuelve un conjunto de banderas: FLAG_HARDWARE (keymaster), FLAG_SECURE_ELEMENT (StrongBox), FLAG_TRUSTED_USER_PRESENCE_REQUIRED (biometría).
Android Keystore admite una amplia gama de algoritmos criptográficos divididos en tres categorías: asimétricos, simétricos y MAC. La compatibilidad con algoritmos específicos depende de la versión de Keymaster HAL.
RSA (1024–4096 bits) — para firma (PKCS1, PSS) y cifrado (OAEP, PKCS1). EC (P-224, P-256, P-384, P-521) — para firma ECDSA y acuerdo de claves ECDH. AES (128, 256 bits) — para cifrado simétrico en modos CBC, CTR, GCM. HMAC (SHA1, SHA256, SHA512) — para autenticación de mensajes.
Para cada clave se especifica setPurposes para restringir las operaciones posibles. Una clave RSA con PURPOSE_SIGN no se puede usar para cifrado, incluso si un atacante tiene acceso a la API. Esto es una aplicación del uso de claves a nivel de hardware.
Keymaster incluye un contador de intentos fallidos de autenticación biométrica. Después de un número especificado de fallos (configurable mediante setInvalidatedByBiometricEnrollment), la clave se vuelve no disponible y requiere eliminación/regeneración. Cuando se eliminan todas las plantillas biométricas, todas las claves con userAuthenticationRequired=true se invalidan automáticamente.
También se admite Key Attestation (Android 8.1+): a solicitud de la aplicación, Keymaster firma un certificado con información sobre las características de la clave (hardware/software, algoritmo, propósitos). El servidor puede verificar este certificado para confirmar que la clave se creó en un entorno confiable.
Preguntas frecuentes
Java KeyStore almacena claves en un archivo protegido por contraseña (JKS, BKS). Android Keystore utiliza aislamiento de hardware mediante TEE o Secure Element. Java KeyStore es vulnerable al acceso root; Android Keystore no, porque las claves privadas nunca abandonan el entorno seguro.
Sí, mediante KeyStore.setEntry con KeyProtection. Sin embargo, la clave importada no tendrá protección de hardware — se almacenará en el Keystore de software, cifrada con una clave maestra. Para máxima seguridad, siempre genere claves dentro de Keystore.
Use KeyChain.isBoundKeyAlgorithm o verifique KeyCharacteristics después de la generación de la clave. La presencia de FLAG_HARDWARE en las características significa que la clave se creó en TEE. También puede consultar android.security.keystore.isHardwareBacked().
Cuando se desinstala la aplicación, Android elimina todas sus claves de Keystore. Los datos se pierden irreversiblemente. En la reinstalación, la aplicación debe generar nuevas claves. La copia de seguridad de claves a través de TEE es arquitectónicamente imposible.
En un dispositivo bloqueado, Keymaster no realiza ninguna operación. Las claves con userAuthenticationRequired=true requieren confirmación biométrica cada vez. Incluso con acceso root, un atacante no puede llamar a Keymaster directamente — solo a través del servicio Android Keystore.
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