Este documento descreve a maneira correta de usar os recursos criptográficos do Android e inclui alguns exemplos de uso. Se o app exigir maior segurança de chave, use o sistema Android Keystore.
Especificar um provedor apenas com o sistema Android Keystore
Se você estiver usando o sistema Android Keystore, vai precisar especificar um provedor.
Em outras situações, no entanto, o Android não garante um provedor específico para um determinado algoritmo. Especificar um provedor sem usar o sistema Android Keystore pode causar problemas de compatibilidade em versões futuras.
Escolher um algoritmo recomendado
Quando você tem a liberdade de escolher qual algoritmo usar (por exemplo, quando não precisa de compatibilidade com um sistema de terceiros), recomendamos o uso destes algoritmos:
Classe | Recomendação |
---|---|
Cipher | AES no modo CBC ou GCM com chaves de 256 bits (como AES/GCM/NoPadding ) |
MessageDigest | Família SHA-2 (como SHA-256 ) |
Mac | HMAC da família SHA-2 (como HMACSHA256 ) |
Assinatura | Família SHA-2 com ECDSA (como SHA256withECDSA ) |
Executar operações criptográficas comuns
As próximas seções incluem snippets que demonstram como você pode concluir operações criptográficas comuns no seu app.
Criptografar uma mensagem
Kotlin
val plaintext: ByteArray = ... val keygen = KeyGenerator.getInstance("AES") keygen.init(256) val key: SecretKey = keygen.generateKey() val cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING") cipher.init(Cipher.ENCRYPT_MODE, key) val ciphertext: ByteArray = cipher.doFinal(plaintext) val iv: ByteArray = cipher.iv
Java
byte[] plaintext = ...; KeyGenerator keygen = KeyGenerator.getInstance("AES"); keygen.init(256); SecretKey key = keygen.generateKey(); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING"); cipher.init(Cipher.ENCRYPT_MODE, key); byte[] ciphertext = cipher.doFinal(plaintext); byte[] iv = cipher.getIV();
Gerar um resumo de mensagens
Kotlin
val message: ByteArray = ... val md = MessageDigest.getInstance("SHA-256") val digest: ByteArray = md.digest(message)
Java
byte[] message = ...; MessageDigest md = MessageDigest.getInstance("SHA-256"); byte[] digest = md.digest(message);
Gerar uma assinatura digital
Você precisa ter um objeto PrivateKey
contendo a chave de assinatura, que pode
ser gerada durante a execução, lida em um arquivo incluído no seu app ou adquirida em
alguma outra origem, dependendo das suas necessidades.
Kotlin
val message: ByteArray = ... val key: PrivateKey = ... val s = Signature.getInstance("SHA256withECDSA") .apply { initSign(key) update(message) } val signature: ByteArray = s.sign()
Java
byte[] message = ...; PrivateKey key = ...; Signature s = Signature.getInstance("SHA256withECDSA"); s.initSign(key); s.update(message); byte[] signature = s.sign();
Verificar uma assinatura digital
Você precisa ter um objeto PublicKey
contendo a chave pública do assinante,
que pode ser lida em um arquivo empacotado com seu app, extraída de um
certificado ou
adquirida em alguma outra origem, dependendo das suas necessidades.
Kotlin
val message: ByteArray = ... val signature: ByteArray = ... val key: PublicKey = ... val s = Signature.getInstance("SHA256withECDSA") .apply { initVerify(key) update(message) } val valid: Boolean = s.verify(signature)
Java
byte[] message = ...; byte[] signature = ...; PublicKey key = ...; Signature s = Signature.getInstance("SHA256withECDSA"); s.initVerify(key); s.update(message); boolean valid = s.verify(signature);
Complexidades de implementação
Alguns detalhes da implementação de criptografia do Android parecem incomuns, mas estão presentes devido a preocupações de compatibilidade. Esta seção discute as que você provavelmente encontrará.
Resumo da mensagem OAEP MGF1
As criptografias RSA OAEP são parametrizadas por dois resumos de mensagens diferentes: o resumo “principal”
e o resumo MGF1. Há identificadores Cipher
que incluem nomes
de resumo, como Cipher.getInstance("RSA/ECB/OAEPwithSHA-256andMGF1Padding")
,
que especificam o resumo principal e deixam o resumo MGF1 não especificado. Para o Android
Keystore, o SHA-1 é usado para o resumo MGF1. Para outros
provedores criptográficos do Android, os dois resumos são iguais.
Para ter mais controle sobre os resumos que seu app usa, solicite uma
criptografia com OAEPPadding, como em Cipher.getInstance("RSA/ECB/OAEPPadding")
, e
forneça um OAEPParameterSpec
a init()
para escolher explicitamente os dois resumos.
Isso é mostrado no código abaixo:
Kotlin
val key: Key = ... val cipher = Cipher.getInstance("RSA/ECB/OAEPPadding") .apply { // To use SHA-256 the main digest and SHA-1 as the MGF1 digest init(Cipher.ENCRYPT_MODE, key, OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT)) // To use SHA-256 for both digests init(Cipher.ENCRYPT_MODE, key, OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT)) }
Java
Key key = ...; Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPPadding"); // To use SHA-256 the main digest and SHA-1 as the MGF1 digest cipher.init(Cipher.ENCRYPT_MODE, key, new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT)); // To use SHA-256 for both digests cipher.init(Cipher.ENCRYPT_MODE, key, new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT));
Funcionalidades descontinuadas
As próximas seções descrevem as funcionalidades descontinuadas. Não use-as no seu app.
Algoritmos do Bouncy Castle
As implementações do Bouncy Castle (link em inglês) de vários algoritmos foram descontinuadas. Isso só afeta casos em que você solicita explicitamente o provedor do Bouncy Castle, conforme mostrado no exemplo a seguir:
Kotlin
Cipher.getInstance("AES/CBC/PKCS7PADDING", "BC") // OR Cipher.getInstance("AES/CBC/PKCS7PADDING", Security.getProvider("BC"))
Java
Cipher.getInstance("AES/CBC/PKCS7PADDING", "BC"); // OR Cipher.getInstance("AES/CBC/PKCS7PADDING", Security.getProvider("BC"));
Conforme observado na seção sobre como especificar um provedor apenas com o sistema Android Keystore, não é recomendável solicitar um provedor específico. Se você segue essa diretriz, essa descontinuação não afeta você.
Criptografias baseadas em senha sem um vetor de inicialização
As criptografias baseadas em senha (PBE, na sigla em inglês) que exigem um vetor de inicialização (IV, na sigla em inglês) podem adquiri-lo na chave, se ela for construída de forma correta ou em um IV transmitido explicitamente. Se você transmitir uma chave de PBE sem um IV e não transmitir um IV explícito, atualmente, as criptografias PBE no Android vão presumir um IV de zero.
Ao usar criptografias PBE, sempre transmita um IV explícito, conforme mostrado neste snippet de código:
Kotlin
val key: SecretKey = ... val cipher = Cipher.getInstance("PBEWITHSHA256AND256BITAES-CBC-BC") val iv = ByteArray(16) SecureRandom().nextBytes(iv) cipher.init(Cipher.ENCRYPT_MODE, key, IvParameterSpec(iv))
Java
SecretKey key = ...; Cipher cipher = Cipher.getInstance("PBEWITHSHA256AND256BITAES-CBC-BC"); byte[] iv = new byte[16]; new SecureRandom().nextBytes(iv); cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
Provedor de criptografia
No Android 9 (nível 28 da API) e versões mais recentes, o provedor de criptografia Java Cryptography Architecture
(JCA) foi removido. Se o app solicitar uma instância do
provedor de criptografia, por exemplo, chamar o método a seguir, ocorrerá um
NoSuchProviderException
.
Kotlin
SecureRandom.getInstance("SHA1PRNG", "Crypto")
Java
SecureRandom.getInstance("SHA1PRNG", "Crypto");
Biblioteca de criptografia de segurança do Jetpack
A biblioteca de criptografia de segurança do Jetpack foi descontinuada. Isso só afeta casos em que
há as seguintes dependências no arquivo build.gradle
do módulo do app:
Groovy
dependencies { implementation "androidx.security:security-crypto:1.0.0" }
Kotlin
dependencies { implementation("androidx.security:security-crypto:1.0.0") }
Algoritmos com suporte
Estes são os identificadores de algoritmo JCA com suporte no Android:
AlgorithmParameterGenerator
AlgorithmParameters
CertPathBuilder
CertPathValidator
CertStore
CertificateFactory
Cipher
KeyAgreement
KeyFactory
KeyGenerator
KeyManagerFactory
KeyPairGenerator
KeyStore
Mac
MessageDigest
SSLContext
SSLEngine.Supported
SSLSocket.Supported
SecretKeyFactory
SecureRandom
Signature
TrustManagerFactory