Save the date! Android Dev Summit is coming to Mountain View, CA on November 7-8, 2018.

Sistema Android Keystore

El sistema Android Keystore te permite almacenar claves criptográficas en un contenedor para que resulte más difícil extraerlo del dispositivo. Una vez que las claves se encuentran en el almacén de claves, se pueden usar para realizar operaciones criptográficas con el material de claves restante no exportable. Además, mediante prestaciones permite restringir el momento y la manera en que se pueden usar las claves; por ejemplo, la solicitud de autenticación del usuario para el uso de claves o la restricción de estas para su uso exclusivo en determinados modos criptográficos. Consulta la sección Funciones de seguridad para obtener más información.

La KeyChain API usa el sistema Keystore y la función de proveedor de Android Keystore introducida en Android 4.3 (nivel de API 18). En este documento se abarcan el momento y la forma en que debe usarse el proveedor de Android Keystore.

Funciones de seguridad

El sistema Android Keystore protege el material de claves contra usos no autorizados. En primer lugar, Android Keystore reduce el uso no autorizado de material de claves fuera del dispositivo Android evitando la extracción de este material de los procesos de la aplicación y del dispositivo Android en su totalidad. En segundo lugar, Android Keystore reduce el uso no autorizado de material de claves en el dispositivo Android haciendo que las apps especifiquen usos autorizados de sus claves y aplicando estas restricciones fuera de los procesos de las apps.

Prevención de extracción

El material de claves de las claves de Android Keystore está protegido contra la extracción mediante dos medidas de seguridad:
  • El material de claves nunca ingresa al proceso de la aplicación. Cuando una aplicación realiza operaciones criptográficas usando una clave de Android Keystore, el texto sin formato, el texto cifrado y los mensajes en segundo plano que se firmarán o verificarán se envían a un proceso del sistema que se ocupa de las operaciones criptográficas. Si el proceso de la app está comprometido, el atacante puede usar las claves de la app. Sin embargo, no podrá extraer el material de claves (por ejemplo, para usarlo fuera del dispositivo Android).
  • El material de claves puede estar vinculado al hardware seguro (p. ej., entorno de ejecución seguro (TEE) y elemento seguro (SE)) del dispositivo Android. Cuando se habilita esta función para una clave, su material de clave nunca se expone fuera del hardware seguro. Si Android OS se ve comprometido o un atacante puede leer el almacenamiento interno del dispositivo, el atacante puede usar las claves de Android Keystore de cualquier app del dispositivo Android, pero no podrá extraerlas de este. Esta función se habilita únicamente si el hardware seguro del dispositivo admite la combinación específica de algoritmo de la clave, modos de bloqueo, esquemas de relleno y resúmenes con la que se autoriza el uso de la clave. Si deseas averiguar si la función está habilitada para una clave, obtén un KeyInfo para la clave e inspecciona el valor de retorno de KeyInfo.isInsideSecurityHardware().

Autorizaciones de uso de las claves

Para mitigar el uso no autorizado de claves en el dispositivo Android, Android Keystore permite que las apps especifiquen usos autorizados de sus claves al generarlas o importarlas. Una vez que se genera o se importa una clave, no se pueden cambiar sus autorizaciones. Luego, Android Keystore aplica las autorizaciones cada vez que se use la clave. Esta es una función de seguridad avanzada que generalmente es útil solo si tus requisitos establecen que el compromiso del proceso de tu aplicación después de la generación o importación de la clave (pero no antes de esta ni durante su transcurso) no puede permitir el uso no autorizado de la clave.

Las autorizaciones de uso de claves compatibles pertenecen a las siguientes categorías:

  • Criptografía: algoritmo, operaciones o propósitos de clave autorizados (encriptación, desencriptación, firma y verificación), esquemas de relleno, modos de bloqueo, resúmenes con los que se puede usar la clave.
  • Intervalo de validez temporal: intervalo durante el cual está autorizado el uso de la clave.
  • Autenticación del usuario: la clave solo se puede usar si se autenticó al usuario en un período lo suficientemente reciente. Consulta Solicitud de autenticación del usuario para el uso de la clave.

Como medida de seguridad adicional, para las claves cuyo material de claves se encuentre dentro de hardware seguro (consulta KeyInfo.isInsideSecurityHardware()), se pueden aplicar algunas autorizaciones de uso de las claves mediante hardware seguro, según el dispositivo Android. Es probable que las autorizaciones criptográfica y de autenticación del usuario se apliquen mediante el hardware seguro. Por el contrario, es poco probable que las autorizaciones de intervalo de validez temporal se apliquen mediante el hardware seguro, ya que normalmente éste no cuenta con un reloj independiente y seguro que funcione en tiempo real.

Puedes averiguar si la autorización de autenticación del usuario de una clave se aplica mediante el hardware seguro con KeyInfo.isUserAuthenticationRequirementEnforcedBySecureHardware().

Elección entre Keychain o el proveedor de Android Keystore

Usa la KeyChain API cuando desees credenciales en todo el sistema. Cuando una app solicita el uso de cualquier credencial a través de la KeyChain API, los usuarios pueden elegir, a través de una IU proporcionada por el sistema, la credencial instalada a la cual puede acceder una app. Esto permite que varias apps usen el mismo conjunto de credenciales con el consentimiento del usuario.

Usa el proveedor de Android Keystore para permitir que una app individual almacene sus propias credenciales, a las cuales solo la app puede acceder. Esto permite que las apps administren credenciales que solo ellas pueden usar y proporciona los mismos beneficios de seguridad que ofrece la KeyChain API para las credenciales en todo el sistema. Este método no requiere la interacción del usuario para seleccionar las credenciales.

Uso del proveedor de Android Keystore

Para usar esta función, se emplean las clases KeyStore, KeyPairGenerator o KeyGenerator estándares junto con el proveedor de AndroidKeyStore introducido en Android 4.3 (nivel de API 18).

AndroidKeyStore está registrado como un tipo KeyStore para usarse con el método KeyStore.getInstance(type) y como proveedor para usarse con los métodos KeyPairGenerator.getInstance(algorithm, provider) y KeyGenerator.getInstance(algorithm, provider).

Generación de una nueva clave privada

Para generar una PrivateKey nueva, es necesario que también especifiques los atributos iniciales X.509 que tendrá el certificado autofirmado. Puedes usar KeyStore.setKeyEntry para reemplazar el certificado posteriormente por un certificado firmado por una entidad de certificación (CA).

Para generar la clave, usa un KeyPairGenerator con KeyPairGeneratorSpec:

/*
 * 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();

Generación de una nueva clave secreta

Para generar la clave, usa un KeyGenerator con KeyGenParameterSpec.

Cómo trabajar con entradas de Keystore

El uso del proveedor de AndroidKeyStore abarca todas las KeyStore API estándares.

Enumeración de entradas

Enumera entradas en el almacén de claves llamando al método aliases():

/*
 * Load the Android KeyStore instance using the the
 * "AndroidKeyStore" provider to list out what entries are
 * currently stored.
 */
KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
Enumeration<String> aliases = ks.aliases();

Firma y verificación de datos

Firma datos obteniendo la KeyStore.Entry del almacén de claves y usando las Signature API, como 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();

También puedes verificar datos con el método verify(byte[]):

/*
 * Verify a signature previously made by a PrivateKey in our
 * KeyStore. This uses the X.509 certificate attached to our
 * 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);

Solicitud de autenticación del usuario para el uso de la clave

Al generar una clave o importarla a AndroidKeyStore, puedes especificar que solo se autorice el uso de la clave si se ha autenticado el usuario. El usuario se autentica mediante un subconjunto de sus credenciales seguras de pantalla bloqueada (patrón/PIN/contraseña y huella dactilar).

Esta es una función de seguridad avanzada que generalmente es útil solo si tus requisitos indican que el compromiso del proceso de tu aplicación después de la generación o importación de la clave (pero no antes de esta ni durante su transcurso) no puede omitir el requisito por el cual se debe autenticar el usuario para que este pueda usar la clave.

Cuando se autoriza el uso de una clave solo si se ha autenticado el usuario, esta se configura para funcionar en uno de dos modos:

  • La autenticación del usuario permite el uso de claves durante un tiempo determinado. El uso de todas las claves en este modo se autoriza no bien el usuario desbloquea la pantalla bloqueada segura o confirma la credencial de la pantalla bloqueada segura usando el flujo KeyguardManager.createConfirmDeviceCredentialIntent. El período de validez de la autorización es específico para cada clave y se especifica usando setUserAuthenticationValidityDurationSeconds durante la generación o importación de la clave. Esas claves solo pueden generarse o importarse si la pantalla bloqueada segura está habilitada (consulta KeyguardManager.isDeviceSecure()). Estas claves se invalidan de forma permanente una vez que se inhabilita la pantalla bloqueada segura (restablecida en None, Swipe u otro modo que no autentique al usuario) o se fuerza su restablecimiento (p. ej., por parte de un administrador de dispositivos).
  • La autenticación del usuario autoriza una operación criptográfica específica asociada con una clave. En este modo, el usuario debe autorizar individualmente cada operación que incluya esa clave. Actualmente, el único medio para realizar una autorización como esta es la autenticación mediante huella dactilar: FingerprintManager.authenticate. Estas claves solo se pueden generar o importar si hay al menos una huella dactilar registrada (consulta FingerprintManager.hasEnrolledFingerprints). Estas claves se invalidan de forma permanente una vez que se registra una nueva huella dactilar o se anulan todas las huellas dactilares.

Algoritmos compatibles

Cifrado

Algoritmo Compatibilidad (niveles de API) Notas
AES/CBC/NoPadding 23 y posteriores
AES/CBC/PKCS7Padding 23 y posteriores
AES/CTR/NoPadding 23 y posteriores
AES/ECB/NoPadding 23 y posteriores
AES/ECB/PKCS7Padding 23 y posteriores
AES/GCM/NoPadding 23 y posteriores Solo se admiten IV de 12 bytes de extensión.
RSA/ECB/NoPadding 18 y posteriores
RSA/ECB/PKCS1Padding 18 y posteriores
RSA/ECB/OAEPWithSHA-1AndMGF1Padding 23 y posteriores
RSA/ECB/OAEPWithSHA-224AndMGF1Padding 23 y posteriores
RSA/ECB/OAEPWithSHA-256AndMGF1Padding 23 y posteriores
RSA/ECB/OAEPWithSHA-384AndMGF1Padding 23 y posteriores
RSA/ECB/OAEPWithSHA-512AndMGF1Padding 23 y posteriores
RSA/ECB/OAEPPadding 23 y posteriores

KeyGenerator

Algoritmo Compatibilidad (niveles de API) Notas
AES 23 y posteriores Tamaños admitidos: 128, 192 y 256.
HmacSHA1 23 y posteriores
  • Tamaños admitidos: 8--1024 (inclusive), deben ser múltiplos de 8.
  • Tamaño predeterminado: 160.
HmacSHA224 23 y posteriores
  • Tamaños admitidos: 8--1024 (inclusive), deben ser múltiplos de 8.
  • Tamaño predeterminado: 224.
HmacSHA256 23 y posteriores
  • Tamaños admitidos: 8--1024 (inclusive), deben ser múltiplos de 8.
  • Tamaño predeterminado: 256.
HmacSHA384 23 y posteriores
  • Tamaños admitidos: 8--1024 (inclusive), deben ser múltiplos de 8.
  • Tamaño predeterminado: 384.
HmacSHA512 23 y posteriores
  • Tamaños admitidos: 8--1024 (inclusive), deben ser múltiplos de 8.
  • Tamaño predeterminado: 512.

KeyFactory

Algoritmo Compatibilidad (niveles de API) Notas
EC 23 y posteriores Especificaciones de claves admitidas: KeyInfo (clave privada únicamente), ECPublicKeySpec (clave pública únicamente) y X509EncodedKeySpec (clave pública únicamente).
RSA 23 y posteriores Especificaciones de claves admitidas: KeyInfo (clave privada únicamente), RSAPublicKeySpec (clave pública únicamente) y X509EncodedKeySpec (clave pública únicamente)

KeyStore

KeyStore admite los mismos tipos de claves que KeyPairGenerator y KeyGenerator.

KeyPairGenerator

Algoritmo Compatibilidad (niveles de API) Notas
DSA 19 a 22
EC 23 y posteriores
  • Tamaños admitidos: 224, 256, 384 y 521.
  • Curvas designadas admitidas: P-224 (secp224r1), P-256 (también conocida como secp256r1 y prime256v1), P-384 (también conocida como secp384r1) y P-521 (también conocida como secp521r1).

En los niveles de API previos al 23, las claves EC pueden generarse usando KeyPairGenerator del algoritmo “RSA” inicializado KeyPairGeneratorSpec, cuyo tipo de clave se establece en “EC” usando setKeyType(String). El nombre de la curva de EC no se puede especificar usando este método; se selecciona automáticamente una curva P NIST según tamaño de clave solicitado.

RSA 18 y posteriores
  • Tamaños admitidos: 512, 768, 1024, 2048, 3072 y 4096.
  • Exponentes públicos admitidos: 3 y 65 537.
  • Exponente público predeterminado: 65 537.

Mac

Algoritmo Compatibilidad (niveles de API) Notas
HmacSHA1 23 y posteriores
HmacSHA224 23 y posteriores
HmacSHA256 23 y posteriores
HmacSHA384 23 y posteriores
HmacSHA512 23 y posteriores

Firma

Algoritmo Compatibilidad (niveles de API) Notas
MD5withRSA 18 y posteriores
NONEwithECDSA 23 y posteriores
NONEwithRSA 18 y posteriores
SHA1withDSA 19 a 22
SHA1withECDSA 19 y posteriores
SHA1withRSA 18 y posteriores
SHA1withRSA/PSS 23 y posteriores
SHA224withDSA 20 a 22
SHA224withECDSA 20 y posteriores
SHA224withRSA 20 y posteriores
SHA224withRSA/PSS 23 y posteriores
SHA256withDSA 19 a 22
SHA256withECDSA 19 y posteriores
SHA256withRSA 18 y posteriores
SHA256withRSA/PSS 23 y posteriores
SHA384withDSA 19 a 22
SHA384withECDSA 19 y posteriores
SHA384withRSA 18 y posteriores
SHA384withRSA/PSS 23 y posteriores
SHA512withDSA 19 a 22
SHA512withECDSA 19 y posteriores
SHA512withRSA 18 y posteriores
SHA512withRSA/PSS 23 y posteriores

SecretKeyFactory

Algoritmo Compatibilidad (niveles de API) Notas
AES 23 y posteriores Especificaciones de claves admitidas: KeyInfo
HmacSHA1 23 y posteriores Especificaciones de claves admitidas: KeyInfo
HmacSHA224 23 y posteriores Especificaciones de claves admitidas: KeyInfo
HmacSHA256 23 y posteriores Especificaciones de claves admitidas: KeyInfo
HmacSHA384 23 y posteriores Especificaciones de claves admitidas: KeyInfo
HmacSHA512 23 y posteriores Especificaciones de claves admitidas: KeyInfo