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:
dependencies { implementation "androidx.security:security-crypto:1.0.0-rc04" // For Identity Credential APIs implementation "androidx.security:security-identity-credential: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 mainKey = MasterKey.Builder(applicationContext) .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) .build() val fileToRead = "my_sensitive_data.txt" val encryptedFile = EncryptedFile.Builder( applicationContext, File(DIRECTORY, fileToRead), mainKey, 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
// Although you can define your own key generation parameter specification, it's // recommended that you use the value specified here. Context context = getApplicationContext(); MasterKey mainKey = new MasterKey.Builder(context) .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) .build(); String fileToRead = "my_sensitive_data.txt"; EncryptedFile encryptedFile = new EncryptedFile.Builder(context, new File(DIRECTORY, fileToRead), mainKey, 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 mainKey = MasterKey.Builder(applicationContext) .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) .build() // Creates a file with this name, or replaces an existing file // that has the same name. Note that the file name cannot contain // path separators. val fileToWrite = "my_sensitive_data.txt" val encryptedFile = EncryptedFile.Builder( applicationContext, File(DIRECTORY, fileToWrite), mainKey, 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
// Although you can define your own key generation parameter specification, it's // recommended that you use the value specified here. Context context = getApplicationContext(); MasterKey mainKey = new MasterKey.Builder(context) .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) .build(); // Creates a file with this name, or replaces an existing file // that has the same name. Note that the file name cannot contain // path separators. String fileToWrite = "my_sensitive_data.txt"; EncryptedFile encryptedFile = new EncryptedFile.Builder(context, new File(DIRECTORY, fileToWrite), mainKey, 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( applicationContext, sharedPrefsFile, mainKey, 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( context, sharedPrefsFile, mainKey, EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM ); SharedPreferences.Editor sharedPrefsEditor = sharedPreferences.edit(); // Edit the user's shared preferences... sharedPrefsEditor.apply();