Trabalhe com dados de forma mais segura Parte do Android Jetpack.
A biblioteca Security fornece uma implementação das práticas recomendadas de segurança relacionadas à leitura e gravação de dados em repouso, bem como à criação e verificação de chaves.
A biblioteca usa o padrão de builder para fornecer configurações padrão seguras para os seguintes níveis de segurança:
- Segurança forte que equilibra ótima criptografia e bom desempenho. Esse nível de segurança é adequado para apps para o consumidor, como apps de chat e Internet banking, bem como apps empresariais que realizam verificação de revogação de certificados.
- Segurança máxima. Esse nível de segurança é adequado para apps que exigem um keystore no hardware e presença de usuário para fornecer acesso a chaves.
Este guia mostra como trabalhar com as configurações de segurança recomendadas da biblioteca Security e como ler e gravar dados criptografados armazenados em arquivos e preferências compartilhadas com facilidade e segurança.
Gerenciamento de chaves
A biblioteca Security usa um sistema de duas partes para o gerenciamento de chaves:
-
Um conjunto de chaves que contém uma ou mais chaves para criptografar um arquivo ou dados de preferências compartilhados. O conjunto de chaves é armazenado em
SharedPreferences
. -
Uma chave primária (
master
) que criptografa todos os conjuntos de chaves. Essa chave é armazenada por meio do sistema de keystore do Android.
Classes incluídas na biblioteca
A biblioteca Security contém as seguintes classes para fornecer dados mais seguros em repouso:
EncryptedFile
-
Fornece implementações personalizadas de
FileInputStream
eFileOutputStream
, concedendo ao app operações de leitura e gravação de streaming mais seguras.Para fornecer operações seguras de leitura e gravação a partir de fluxos de arquivos, a biblioteca Security usa o primitivo Criptografia autenticada de streaming com dados associados (AEAD, na sigla em inglês). Saiba mais sobre esse primitivo na documentação da biblioteca Tink (em inglês) no GitHub.
EncryptedSharedPreferences
-
Encapsula a classe
SharedPreferences
e criptografa automaticamente chaves e valores usando um método de dois esquemas:- Chaves são criptografadas por meio de um algoritmo de criptografia determinístico, para que possam ser criptografadas e pesquisadas corretamente.
- Valores são criptografados por meio de GCM AES-256 (link em inglês) e não são determinísticos.
As seções a seguir mostram como usar essas classes para realizar operações comuns com arquivos e preferências compartilhadas.
Incluir a biblioteca no seu projeto
Para usar a biblioteca Security, adicione a seguinte dependência ao arquivo build.gradle
do módulo
do app:
Groovy
dependencies { implementation "androidx.security:security-crypto:1.0.0" // For Identity Credential APIs implementation "androidx.security:security-identity-credential:1.0.0-alpha03" // For App Authentication APIs implementation "androidx.security:security-app-authenticator:1.0.0-alpha02" // For App Authentication API testing androidTestImplementation "androidx.security:security-app-authenticator:1.0.0-alpha01" }
Kotlin
dependencies { implementation("androidx.security:security-crypto:1.0.0") // For Identity Credential APIs implementation("androidx.security:security-identity-credential:1.0.0-alpha03") // For App Authentication APIs implementation("androidx.security:security-app-authenticator:1.0.0-alpha02") // For App Authentication API testing androidTestImplementation("androidx.security:security-app-authenticator:1.0.0-alpha01") }
Ler arquivos
O snippet de código a seguir demonstra como usar EncryptedFile
para ler o conteúdo de um arquivo de uma forma mais segura:
Kotlin
// Although you can define your own key generation parameter specification, it's // recommended that you use the value specified here. val keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC val mainKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec) val fileToRead = "my_sensitive_data.txt" val encryptedFile = EncryptedFile.Builder( File(DIRECTORY, fileToRead), applicationContext, mainKeyAlias, EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB ).build() val inputStream = encryptedFile.openFileInput() val byteArrayOutputStream = ByteArrayOutputStream() var nextByte: Int = inputStream.read() while (nextByte != -1) { byteArrayOutputStream.write(nextByte) nextByte = inputStream.read() } val plaintext: ByteArray = byteArrayOutputStream.toByteArray()
Java
Context context = getApplicationContext(); // Although you can define your own key generation parameter specification, it's // recommended that you use the value specified here. KeyGenParameterSpec keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC; String mainKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec); String fileToRead = "my_sensitive_data.txt"; EncryptedFile encryptedFile = new EncryptedFile.Builder( new File(DIRECTORY, fileToRead), context, mainKeyAlias, EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB ).build(); InputStream inputStream = encryptedFile.openFileInput(); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); int nextByte = inputStream.read(); while (nextByte != -1) { byteArrayOutputStream.write(nextByte); nextByte = inputStream.read(); } byte[] plaintext = byteArrayOutputStream.toByteArray();
Gravar arquivos
O snippet de código a seguir demonstra como usar EncryptedFile
para gravar o conteúdo de um arquivo de forma mais segura:
Kotlin
// Although you can define your own key generation parameter specification, it's // recommended that you use the value specified here. val keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC val mainKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec) // Create a file with this name, or replace an entire existing file // that has the same name. Note that you cannot append to an existing file, // and the file name cannot contain path separators. val fileToWrite = "my_sensitive_data.txt" val encryptedFile = EncryptedFile.Builder( File(DIRECTORY, fileToWrite), applicationContext, mainKeyAlias, EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB ).build() val fileContent = "MY SUPER-SECRET INFORMATION" .toByteArray(StandardCharsets.UTF_8) encryptedFile.openFileOutput().apply { write(fileContent) flush() close() }
Java
Context context = getApplicationContext(); // Although you can define your own key generation parameter specification, it's // recommended that you use the value specified here. KeyGenParameterSpec keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC; String mainKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec); // Create a file with this name, or replace an entire existing file // that has the same name. Note that you cannot append to an existing file, // and the file name cannot contain path separators. String fileToWrite = "my_sensitive_data.txt"; EncryptedFile encryptedFile = new EncryptedFile.Builder( new File(DIRECTORY, fileToWrite), context, mainKeyAlias, EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB ).build(); byte[] fileContent = "MY SUPER-SECRET INFORMATION" .getBytes(StandardCharsets.UTF_8); OutputStream outputStream = encryptedFile.openFileOutput(); outputStream.write(fileContent); outputStream.flush(); outputStream.close();
Para os casos de uso que exigem mais segurança, siga estas etapas:
- Crie um objeto
KeyGenParameterSpec.Builder
, passandotrue
parasetUserAuthenticationRequired()
e um valor maior que 0 parasetUserAuthenticationValidityDurationSeconds()
. Solicite que o usuário insira as credenciais usando
createConfirmDeviceCredentialIntent()
. Saiba mais sobre como solicitar a autenticação do usuário para uso de chaves.Substitua
onActivityResult()
para receber o callback de credencial confirmado.
Para saber mais, consulte Exigir autenticação do usuário para o uso de chaves.
Editar preferências compartilhadas
O snippet de código a seguir demonstra como usar EncryptedSharedPreferences
para editar o conjunto de preferências compartilhadas de um usuário de forma mais segura:
Kotlin
val sharedPrefsFile: String = FILE_NAME val sharedPreferences: SharedPreferences = EncryptedSharedPreferences.create( sharedPrefsFile, mainKeyAlias, applicationContext, EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM ) with (sharedPreferences.edit()) { // Edit the user's shared preferences... apply() }
Java
String sharedPrefsFile = FILE_NAME; SharedPreferences sharedPreferences = EncryptedSharedPreferences.create( sharedPrefsFile, mainKeyAlias, getApplicationContext(), EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM ); SharedPreferences.Editor sharedPrefsEditor = sharedPreferences.edit(); // Edit the user's shared preferences... sharedPrefsEditor.apply();