lightbulb_outline Please take our October 2018 developer survey. Start survey

Sistema de armazenamento de chaves do Android

O sistema de armazenamento de chaves do Android permite que você armazene chaves criptográficas em um contêiner para dificultar sua extração do dispositivo. Quando as chaves estão no armazenamento de chaves, elas podem ser usadas para operações criptográficas e o material das chaves permanece não exportável. Além disso, esse recurso oferece instalações para restringir como e quando as chaves podem ser usadas, por exemplo, solicitando a autenticação do usuário para usar as chaves ou restringindo o uso das chaves apenas em certos modos criptográficos. Consulte a seção Recursos de segurança para saber mais.

O sistema de armazenamento de chaves é usado pela KeyChain API e pelo recurso de provedor de armazenamento de chaves do Android introduzido no Android 4.3 (nível de API 18). Este documento explora quando e como usar o provedor de armazenamento de chaves do Android.

Recursos de segurança

O sistema de armazenamento de chaves do Android protege o material de chaves contra o uso não autorizado. Em primeiro lugar, o armazenamento de chaves do Android mitiga o uso não autorizado do material de chaves fora do dispositivo Android ao evitar sua extração dos processos do aplicativo e do dispositivo Android como um todo. Em segundo lugar, o armazenamento de chaves do Android mitiga o uso não autorizado do material de chaves no dispositivo Android fazendo com que os aplicativos especifiquem usos autorizados de suas chaves e aplicando essas restrições fora dos processos dos aplicativos.

Prevenção de extração

O material de chaves do armazenamento do Android é protegido contra a extração por duas medidas de segurança:
  • O material de chaves nunca entra no processo de aplicativos. Quando um aplicativo realiza operações criptográficas usando uma chave do armazenamento de chaves do Android, o texto simples, de cifra e as mensagens a serem assinadas ou verificadas são alimentadas, em segundo plano, a um processo de sistema que realiza as operações criptográficas. Se o processo do aplicativo for comprometido, o invasor poderá usar as chaves do aplicativo, mas não conseguirá extrair o material das chaves (por exemplo, para usá-lo fora do dispositivo Android).
  • O material de chaves pode ser vinculado ao hardware protegido (por exemplo, o Trusted Execution Environment (TEE) e o Secure Element (SE)) do dispositivo Android. Quando esse recurso é ativado para uma chave, seu material nunca é exposto fora do hardware protegido. Se o sistema operacional Android for comprometido ou se um invasor conseguir ler o armazenamento interno do dispositivo, ele poderá usar as chaves do armazenamento de chaves do Android de qualquer aplicativo no dispositivo, mas não extraí-las do dispositivo. Esse recurso é ativado apenas se o hardware protegido do dispositivo oferecer suporte à combinação específica de algoritmo de chave, modos de bloqueio, esquemas de preenchimento e resumos com a qual a chave tem autorização para ser usada. Para verificar se o recurso está ativado para uma chave, obtenha um KeyInfo para a chave e verifique o valor de retorno de KeyInfo.isInsideSecurityHardware().

Autorizações de uso de chaves

Para mitigar o uso não autorizado de chaves em um dispositivo Android, o armazenamento de chaves do Android permite que os aplicativos especifiquem usos autorizados de suas chaves ao gerá-las ou importá-las. Quando uma chave é gerada ou importada, suas autorizações não podem ser alteradas. Dessa forma, as autorizações são aplicadas pelo armazenamento de chaves do Android sempre que a chave for usada. Esse é um recurso de segurança avançado que geralmente é útil apenas se você precisar que um comprometimento do processo do seu aplicativo após uma geração/importação de chave (mas não antes ou durante) não cause usos não autorizados da chave.

As autorizações de uso de chaves com suporte se encaixam nas seguintes categorias:

  • criptografia: algoritmos, operações ou propósitos autorizados de chaves (criptografar, descriptografar, verificar), esquemas de preenchimento, modos de bloqueio e resumos com os quais a chave pode ser usada;
  • intervalo de validade temporal: intervalo de tempo durante o qual a chave tem o uso autorizado;
  • autenticação do usuário: a chave só pode ser usada se o usuário tiver sido autenticado recentemente. Consulte Exigir a autenticação do usuário para o uso de chaves.

Como medida de segurança adicional, para chaves cujo material se encontra em um hardware protegido (consulte KeyInfo.isInsideSecurityHardware()), algumas autorizações de uso de chaves podem ser aplicadas pelo hardware protegido, dependendo do dispositivo Android. As autorizações criptográfica e de autenticação do usuário provavelmente serão aplicadas pelo hardware protegido. É improvável que o hardware protegido aplique autorizações de intervalo de validade temporal, pois ele normalmente não tem um relógio de tempo real protegido e independente.

É possível consultar se a autorização de autenticação do usuário de uma chave será aplicada pelo hardware protegido usando KeyInfo.isUserAuthenticationRequirementEnforcedBySecureHardware().

Escolher entre uma cadeia de chaves ou o provedor do armazenamento de chaves do Android

Use a KeyChain API quando quiser credenciais de sistema. Quando um aplicativo solicita o uso de qualquer credencial com a KeyChain API, os usuários podem escolher, por meio de uma IU fornecida pelo sistema, quais das credenciais instaladas podem ser acessadas por um aplicativo. Isso permite que vários aplicativos usem o mesmo conjunto de credenciais com o consentimento do usuário.

Use o provedor de armazenamento de chaves do Android para permitir que um aplicativo individual armazene suas próprias credenciais que apenas o próprio aplicativo pode acessar. Isso oferece uma maneira para que os aplicativos gerenciem credenciais que apenas eles podem usar, com os mesmos benefícios de segurança que a KeyChain API fornece para credenciais de sistema. Esse método não exige interação do usuário para selecionar as credenciais.

Usar o provedor do armazenamento de chaves do Android

Para usar esse recurso, use as classes padrão KeyStore e KeyPairGenerator ou KeyGenerator juntamente com o provedor de AndroidKeyStore introduzido no Android 4.3 (nível de API 18).

O AndroidKeyStore é registrado como um tipo KeyStore para uso com o método KeyStore.getInstance(type) e como um provedor para uso com os métodos KeyPairGenerator.getInstance(algorithm, provider) e KeyGenerator.getInstance(algorithm, provider).

Gerar uma nova chave privada

Para gerar uma nova PrivateKey, você também deve especificar os atributos X.509 iniciais que o certificado autoassinado terá. Você pode usar KeyStore.setKeyEntry para substituir o certificado posteriormente por um certificado assinado por uma Autoridade de Certificação (CA).

Para gerar a chave, use um KeyPairGenerator com 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();

Gerar uma nova chave secreta

Para gerar a chave, use um KeyGenerator com KeyGenParameterSpec.

Trabalhar com entradas do armazenamento de chaves

O uso do provedor de AndroidKeyStore é realizado por pelo de todas as APIs padrão do KeyStore.

Listar entradas

Liste entradas no armazenamento de chaves chamando o 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();

Assinar e verificar dados

Assine dados recuperando KeyStore.Entry do armazenamento de chaves e usando as APIs de Signature, 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();

Da mesma forma, verifique dados com o 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);

Exigir a autenticação do usuário para o uso de chaves

Ao gerar ou importar uma chave para o AndroidKeyStore, você pode especificar que a chave só pode ser usada se o usuário tiver sido autenticado. O usuário é autenticado usando um subconjunto de suas credenciais de bloqueio de tela (padrão/PIN/senha, impressão digital).

Esse é um recurso de segurança avançado que geralmente é útil apenas se você precisar que um comprometimento do processo do seu aplicativo após uma geração/importação de chave (mas não antes ou durante) não possa ignorar a exigência de autenticação do usuário para usar a chave.

Quando uma chave está autorizada a ser usada apenas se o usuário tiver sido autenticado, ela é configurada para operar em um de dois modos:

  • A autenticação do usuário autoriza o uso das chaves por um período de tempo. Todas as chaves nesse modo podem ser usadas assim que o usuário desbloqueia a tela ou confirma suas credenciais de bloqueio de tela usando o fluxo KeyguardManager.createConfirmDeviceCredentialIntent. A duração da autorização é especificada para cada chave usando setUserAuthenticationValidityDurationSeconds durante a geração ou importação da chave. Essas chaves só podem ser geradas ou importadas se a tela de bloqueio estiver ativada (consulte KeyguardManager.isDeviceSecure()). Essas chaves são permanentemente invalidadas se a tela de bloqueio for desativada (configurada como None, Swipe ou outro modo que não autentique o usuário) ou redefinida à força (por exemplo, por um administrador de dispositivo).
  • A autenticação do usuário autoriza uma operação criptográfica específica associada a uma chave. Nesse modo, cada operação que envolve a chave em questão deve ser autorizada individualmente pelo usuário. No momento, a única forma de autorização desse tipo é a autenticação por impressão digital: FingerprintManager.authenticate. Essas chaves só podem ser geradas ou importadas se pelo menos uma impressão digital tiver sido cadastrada (consulte FingerprintManager.hasEnrolledFingerprints). Essas chaves são invalidadas permanentemente se uma nova impressão for cadastrada ou se todas as impressões digitais forem descadastradas.

Algoritmos com suporte

Cifra

Algoritmo Com suporte (níveis de API) Observações
AES/CBC/NoPadding 23 e superior
AES/CBC/PKCS7Padding 23 e superior
AES/CTR/NoPadding 23 e superior
AES/ECB/NoPadding 23 e superior
AES/ECB/PKCS7Padding 23 e superior
AES/GCM/NoPadding 23 e superior Somente IVs de 12 bytes têm suporte.
RSA/ECB/NoPadding 18 e superior
RSA/ECB/PKCS1Padding 18 e superior
RSA/ECB/OAEPWithSHA-1AndMGF1Padding 23 e superior
RSA/ECB/OAEPWithSHA-224AndMGF1Padding 23 e superior
RSA/ECB/OAEPWithSHA-256AndMGF1Padding 23 e superior
RSA/ECB/OAEPWithSHA-384AndMGF1Padding 23 e superior
RSA/ECB/OAEPWithSHA-512AndMGF1Padding 23 e superior
RSA/ECB/OAEPPadding 23 e superior

KeyGenerator

Algoritmo Com suporte (níveis de API) Observações
AES 23 e superior Tamanhos com suporte: 128, 192, 256
HmacSHA1 23 e superior
  • Tamanhos com suporte: 8 a 1024 (inclusive), deve ser um múltiplo de 8
  • Tamanho padrão: 160
HmacSHA224 23 e superior
  • Tamanhos com suporte: 8 a 1024 (inclusive), deve ser um múltiplo de 8
  • Tamanho padrão: 224
HmacSHA256 23 e superior
  • Tamanhos com suporte: 8 a 1024 (inclusive), deve ser um múltiplo de 8
  • Tamanho padrão: 256
HmacSHA384 23 e superior
  • Tamanhos com suporte: 8 a 1024 (inclusive), deve ser um múltiplo de 8
  • Tamanho padrão: 384
HmacSHA512 23 e superior
  • Tamanhos com suporte: 8 a 1024 (inclusive), deve ser um múltiplo de 8
  • Tamanho padrão: 512

KeyFactory

Algoritmo Com suporte (níveis de API) Observações
EC 23 e superior Especificações de chaves com suporte: KeyInfo (somente chave privada), ECPublicKeySpec (somente chave pública), X509EncodedKeySpec (somente chave pública)
RSA 23 e superior Especificações de chaves com suporte: KeyInfo (somente chave privada), RSAPublicKeySpec (somente chave pública), X509EncodedKeySpec (somente chave pública)

KeyStore

O KeyStore oferece suporte aos mesmos tipos de chaves do que o KeyPairGenerator e o KeyGenerator.

KeyPairGenerator

Algoritmo Com suporte (níveis de API) Observações
DSA 19–22
EC 23 e superior
  • Tamanhos com suporte: 224, 256, 384, 521
  • Curvas de nomes com suporte: P-224 (secp224r1), P-256 (secp256r1 e prime256v1), P-384 (secp384r1), P-521 (secp521r1)

Antes do nível de API 23, as chaves EC podem ser geradas usando o KeyPairGenerator do KeyPairGeneratorSpec inicializado pelo algoritmo "RSA", cujo tipo de chave é definido como "EC" usando setKeyType(String). O nome de curva EC não pode ser especificado usando esse método; uma curva NIST P é automaticamente escolhida com base no tamanho de chave solicitado.

RSA 18 e superior
  • Tamanhos com suporte: 512, 768, 1024, 2048, 3072, 4096
  • Expoentes públicos com suporte: 3, 65537
  • Expoente público padrão: 65537

Mac

Algoritmo Com suporte (níveis de API) Observações
HmacSHA1 23 e superior
HmacSHA224 23 e superior
HmacSHA256 23 e superior
HmacSHA384 23 e superior
HmacSHA512 23 e superior

Signature

Algoritmo Com suporte (níveis de API) Observações
MD5withRSA 18 e superior
NONEwithECDSA 23 e superior
NONEwithRSA 18 e superior
SHA1withDSA 19–22
SHA1withECDSA 19 e superior
SHA1withRSA 18 e superior
SHA1withRSA/PSS 23 e superior
SHA224withDSA 20–22
SHA224withECDSA 20 e superior
SHA224withRSA 20 e superior
SHA224withRSA/PSS 23 e superior
SHA256withDSA 19–22
SHA256withECDSA 19 e superior
SHA256withRSA 18 e superior
SHA256withRSA/PSS 23 e superior
SHA384withDSA 19–22
SHA384withECDSA 19 e superior
SHA384withRSA 18 e superior
SHA384withRSA/PSS 23 e superior
SHA512withDSA 19–22
SHA512withECDSA 19 e superior
SHA512withRSA 18 e superior
SHA512withRSA/PSS 23 e superior

SecretKeyFactory

Algoritmo Com suporte (níveis de API) Observações
AES 23 e superior Especificações de chaves com suporte: KeyInfo
HmacSHA1 23 e superior Especificações de chaves com suporte: KeyInfo
HmacSHA224 23 e superior Especificações de chaves com suporte: KeyInfo
HmacSHA256 23 e superior Especificações de chaves com suporte: KeyInfo
HmacSHA384 23 e superior Especificações de chaves com suporte: KeyInfo
HmacSHA512 23 e superior Especificações de chaves com suporte: KeyInfo