O Google tem o compromisso de promover a igualdade racial para as comunidades negras. Saiba como.

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 e FileOutputStream, 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-rc03"

    // 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 keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC
val masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec)

val context = applicationContext
val fileToRead = "my_sensitive_data.txt"
val encryptedFile = EncryptedFile.Builder(
    File(DIRECTORY, fileToRead),
    context,
    masterKeyAlias,
    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.
KeyGenParameterSpec keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC;
String masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec);

Context context = getApplicationContext();
String fileToRead = "my_sensitive_data.txt";
EncryptedFile encryptedFile = new EncryptedFile.Builder(
        new File(DIRECTORY, fileToRead),
        context,
        masterKeyAlias,
        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 masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec)

// 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(
    File(DIRECTORY, fileToWrite),
    context,
    masterKeyAlias,
    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.
KeyGenParameterSpec keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC;
String masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec);

// 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(
        new File(DIRECTORY, fileToWrite),
        context,
        masterKeyAlias,
        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:

  1. Crie um objeto KeyGenParameterSpec.Builder, passando true para setUserAuthenticationRequired() e um valor maior que 0 para setUserAuthenticationValidityDurationSeconds().
  2. 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.

  3. 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 sharedPreferences = EncryptedSharedPreferences
    .create(
    FILE_NAME,
    masterKeyAlias,
    context,
    EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
    EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)

val sharedPrefsEditor = sharedPreferences.edit()

Java

EncryptedSharedPreferences sharedPreferences = EncryptedSharedPreferences
        .create(
                FILE_NAME,
                masterKeyAlias,
                context,
                EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
                EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
        );

SharedPreferences.Editor sharedPrefsEditor = sharedPreferences.edit();