A biblioteca Security oferece uma implementação das práticas recomendadas de segurança relacionadas a leitura e gravação de dados em repouso, bem como a 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 boa performance. 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.
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 classes abaixo 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 usando 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:- As chaves são criptografadas com um algoritmo de criptografia determinístico para que possam ser criptografadas e pesquisadas corretamente.
- Os valores são criptografados com o GCM AES-256 (em inglês) e não são determinísticos.
As próximas seções 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 as seguintes dependências, conforme adequado, 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:
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:
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 filename 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 filename 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
, transmitindotrue
parasetUserAuthenticationRequired()
e um valor maior que 0 como o primeiro argumento desetUserAuthenticationParameters()
. Solicite que o usuário insira as credenciais usando
createConfirmDeviceCredentialIntent()
. Aprenda a solicitar a autenticação do usuário para uso de chaves.Substitua
onActivityResult()
para receber o callback de credencial confirmado.
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:
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();
Suporte a dispositivos Android 5.0 e Android 5.1
A versão 1.1.0 da biblioteca Security permite oferecer suporte a dispositivos com o Android 5.0 (API de nível 21) ou mais recente. No Android 5.0 e Android 5.1 (API de nível 22), não é possível usar o Armazenamento de chaves do Android.
Ler arquivos
O snippet de código a seguir demonstra como usar
EncryptedFile
para ler o
conteúdo de um arquivo usando a versão 1.1.0 da biblioteca
Security:
Kotlin
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
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 usando a versão 1.1.0 da biblioteca
Security:
Kotlin
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 = File(DIRECTORY, "my_sensitive_data.txt") val encryptedFile = EncryptedFile.Builder(applicationContext, fileToWrite, mainKey, EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB ).build() // File cannot exist before using openFileOutput if (fileToWrite.exists()) { fileToWrite.delete() } val fileContent = "MY SUPER-SECRET INFORMATION" .toByteArray(StandardCharsets.UTF_8)) encryptedFile.openFileOutput().apply { write(fileContent) flush() close() }
Java
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. File fileToWrite = new File(DIRECTORY, "my_sensitive_data.txt"); EncryptedFile encryptedFile = new EncryptedFile.Builder(context, fileToWrite, mainKey, EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB ).build(); // File cannot exist before using openFileOutput if (fileToWrite.exists()) { fileToWrite.delete(); } byte[] fileContent = "MY SUPER-SECRET INFORMATION" .getBytes(StandardCharsets.UTF_8); OutputStream outputStream = encryptedFile.openFileOutput(); outputStream.write(fileContent); outputStream.flush(); outputStream.close();
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 usando a versão 1.1.0 da biblioteca
Security:
Kotlin
val context = applicationContext val mainKey = MasterKey.Builder(applicationContext) .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) .build() val sharedPreferences = EncryptedSharedPreferences.create( applicationContext, FILE_NAME, mainKey, EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM ) with (sharedPreferences.edit()) { // Edit the user's shared preferences... apply() }
Java
Context context = getApplicationContext(); MasterKey mainKey = new MasterKey.Builder(context) .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) .build(); SharedPreferences sharedPreferences = EncryptedSharedPreferences .create( context, FILE_NAME, mainKey, EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM ); SharedPreferences.Editor sharedPrefsEditor = sharedPreferences.edit(); // Edit the user's shared preferences... sharedPrefsEditor.apply();
Recomendados para você
- Observação: o texto do link aparece quando o JavaScript está desativado
- Executar código DEX incorporado diretamente no APK
- Tapjacking
- android:exported