EncryptedSharedPreferences é um componente da biblioteca AndroidX Security que fornece criptografia transparente dos dados salvos através da API SharedPreferences. Ao contrário das SharedPreferences comuns, onde os dados são armazenados em um arquivo XML simples, o EncryptedSharedPreferences criptografa automaticamente as chaves e os valores antes de gravar no disco. De acordo com Android Developers, a biblioteca usa AES-256 GCM para valores e AES-256 SIV (RFC 5297) para chaves, garantindo confidencialidade e integridade dos dados.
Principais Pontos
EncryptedSharedPreferences é uma classe do pacote androidx.security.crypto, apresentada no AndroidX Security 1.0.0 (2019). Ela implementa a interface SharedPreferences, mas todas as operações de escrita (putString, putInt, putBoolean, etc.) criptografam os dados antecipadamente, e as operações de leitura os descriptografam antes de retornar.
As SharedPreferences padrão salvam dados em um arquivo XML no diretório do aplicativo (/data/data/package/shared_prefs/). O arquivo não é criptografado — com acesso root ao dispositivo ou durante a análise de backup, todos os dados são lidos como XML simples. Tokens de autenticação, chaves de API e dados pessoais do usuário ficam acessíveis a um invasor.
EncryptedSharedPreferences resolve esse problema no nível da biblioteca: os dados são criptografados antes de serem gravados no disco e descriptografados quando lidos. O desenvolvedor não precisa chamar funções criptográficas manualmente — a API permanece idêntica às SharedPreferences comuns.
A biblioteca AndroidX Security v1.0.0 foi lançada em dezembro de 2019. O EncryptedSharedPreferences substituiu a abordagem obsoleta de criptografia manual via Cipher + SharedPreferences. A versão estável atual é 1.1.0-alpha06 (2024), compatível com API 19+. A biblioteca faz parte do Jetpack e não requer permissões adicionais.
De acordo com o Google Security Blog (2024), o EncryptedSharedPreferences é a maneira recomendada de armazenar configurações confidenciais do aplicativo que não exigem sincronização em nuvem. Para cenários mais complexos, recomenda-se Room com criptografia SQLCipher.
EncryptedSharedPreferences usa um esquema de criptografia de dois níveis: a Master Key é armazenada no Android Keystore e chaves derivadas são usadas para criptografia de dados. Isso combina a proteção do Keystore com o desempenho da criptografia simétrica.
Para valores, é usado AES-256 GCM (modo Galois/Counter) — um modo de criptografia autenticada (AEAD) que garante confidencialidade e integridade dos dados. Para chaves (nomes de parâmetros), é aplicado AES-256 SIV (RFC 5297) — criptografia determinística necessária para pesquisa de chaves sem revelar seu conteúdo.
Cada arquivo do EncryptedSharedPreferences contém pares chave-valor criptografados. A estrutura do arquivo inclui: primeiro um cabeçalho com metadados (versão, identificador de chave), depois uma lista de entradas criptografadas. O arquivo não é XML válido e não pode ser lido por editores de texto.
A classe MasterKey é responsável por criar e gerenciar uma chave mestra de 256 bits armazenada no Android Keystore. O MasterKey.Builder permite configurar: tipo de armazenamento (Keystore ou software), proteção biométrica e tempo de vida da chave. Por padrão, a chave mestra é gerada no Android Keystore com o algoritmo AES/GCM/NoPadding.
import androidx.security.crypto.MasterKey
import androidx.security.crypto.EncryptedSharedPreferences
fun getEncryptedPrefs() {
val masterKey = MasterKey.Builder(context)
.setKeyScheme(MasterKey.AES256_GCM_SPEC)
.build()
val prefs = EncryptedSharedPreferences.create(
context,
"secure_prefs",
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
}
EncryptedSharedPreferences.create aceita cinco parâmetros: contexto, nome do arquivo, chave mestra, esquema de criptografia de chaves e esquema de criptografia de valores. A escolha dos esquemas afeta o desempenho e o nível de segurança.
AES256_SIV — criptografia determinística: chaves idênticas sempre produzem o mesmo texto cifrado. Isso é necessário para pesquisa de chaves (SharedPreferences.getX(key)). Desvantagem: um invasor pode determinar quais chaves estão sendo usadas comparando textos cifrados repetidos. AES256_SIV2 — uma versão melhorada com randomização adicional.
Para valores, é usado AES256_GCM. O GCM adiciona um IV de 12 bytes (vetor de inicialização) e um tag de autenticação de 16 bytes a cada valor. Isso fornece confidencialidade (ninguém pode ler o valor) e autenticação (ninguém pode adulterar o valor sem ser detectado).
O método setUserAuthenticationRequired(true) no MasterKey.Builder requer confirmação biométrica antes de recuperar a chave mestra do Keystore. Isso adiciona uma camada extra: mesmo se o aplicativo estiver sendo executado em um dispositivo desbloqueado, um invasor não pode ler o EncryptedSharedPreferences sem Face ID ou Touch ID.
Importante: com setUserAuthenticationRequired, a chave mestra se torna indisponível se o usuário alterar ou remover os dados biométricos. É necessário lidar com KeyPermanentlyInvalidatedException e criar uma nova chave mestra com migração de dados.
fun createBiometricKey(): MasterKey {
return MasterKey.Builder(context)
.setKeyScheme(MasterKey.AES256_GCM_SPEC)
.setUserAuthenticationRequired(true)
.setRequestStrongBoxBacked(true)
.build()
}
fun writeSecureToken(token: String) {
try {
prefs.edit().putString("auth_token", token).apply()
} catch (e: KeyPermanentlyInvalidatedException) {
// A biometria mudou — é necessário recriar a chave
}
}
Vamos ver um exemplo completo de integração do EncryptedSharedPreferences em um aplicativo Android usando Kotlin. A biblioteca androidx.security:security-crypto é adicionada via Gradle.
No arquivo build.gradle (app), adicione: implementation "androidx.security:security-crypto:1.1.0-alpha06". Para projetos Kotlin, kotlin-stdlib também é necessário. A inicialização do MasterKey ocorre uma vez, normalmente em Application.onCreate ou através de um contêiner DI.
Após criar uma instância do EncryptedSharedPreferences, a API não difere das SharedPreferences comuns. edit() retorna um Editor, todos os métodos (putString, getString, putBoolean, getBoolean) funcionam da mesma forma. A única diferença é interna: os dados são criptografados ao escrever e descriptografados ao ler.
class AuthRepository(context: Context) {
private val prefs = createEncryptedPrefs(context)
fun saveCredentials(login: String, password: String) {
prefs.edit()
.putString("login", login)
.putString("password", password)
.apply()
}
fun getToken(): String? {
return prefs.getString("auth_token", null)
}
fun clearAll() {
prefs.edit().clear().apply()
}
}
Para migrar dados existentes de SharedPreferences não criptografadas para EncryptedSharedPreferences, é necessário: ler todos os dados do arquivo antigo, criar um novo EncryptedSharedPreferences, escrever todos os dados e excluir o arquivo antigo. O Google não fornece um migrador integrado — o desenvolvedor o implementa manualmente.
A escolha entre SharedPreferences e EncryptedSharedPreferences depende do tipo de dado armazenado. Para configurações de interface (tema, idioma, ordenação), as SharedPreferences comuns são suficientes. Para informações confidenciais (tokens, senhas, chaves), o EncryptedSharedPreferences é obrigatório.
EncryptedSharedPreferences é mais lento que o comum devido às operações criptográficas. Escrever um único valor de string leva ~5-15 ms (dependendo do tamanho dos dados e da aceleração de hardware AES). A leitura leva 2-5 ms. Para a maioria dos aplicativos isso é imperceptível, mas para operações em lote (migração, restauração) use apply() em vez de commit().
As SharedPreferences comuns não fornecem nenhuma proteção criptográfica: o arquivo XML pode ser lido por qualquer processo com acesso root ou via adb backup. O EncryptedSharedPreferences criptografa os dados no nível do aplicativo, e a chave mestra é armazenada no Android Keystore com proteção de hardware opcional (StrongBox).
| Característica | SharedPreferences | EncryptedSharedPreferences |
|---|---|---|
| Armazenamento | XML simples | Arquivo binário criptografado |
| Criptografia | Nenhuma | AES-256 GCM + SIV |
| Proteção de chaves | Nenhuma | Android Keystore + StrongBox |
| Desempenho | 0.1-1 ms | 2-15 ms |
| Recomendação | Configurações de UI | Tokens, chaves, PII |
Use EncryptedSharedPreferences para armazenar: tokens de atualização OAuth, chaves de API para serviços externos, email ou número de telefone do usuário e configurações confidenciais do aplicativo (PIN, flags de autenticação). O EncryptedSharedPreferences não é adequado para armazenar dados biométricos ou documentos grandes — use EncryptedFile ou Room com SQLCipher.
A regra geral: se um vazamento de dados prejudicar o usuário ou o negócio — use EncryptedSharedPreferences. Se os dados forem apenas cosméticos (tema, idioma, ordenação) — SharedPreferences comuns. Faz sentido implementar o EncryptedSharedPreferences desde o início, sem refatoração: substituí-lo em um projeto existente exigirá migração e tratamento de dados antigos não criptografados.
Lembre-se de que o EncryptedSharedPreferences não protege os dados durante a execução do aplicativo — apenas no disco. Se um invasor tiver acesso à memória do processo, os dados descriptografados podem ser interceptados. Use proteção adicional: ProGuard/DexGuard para ofuscação.
Perguntas Frequentes
Jetpack DataStore é uma alternativa mais moderna ao SharedPreferences, baseada em Flow e corrotinas Kotlin. O DataStore não criptografa dados por padrão, mas pode ser combinado com EncryptedSharedPreferences ou usado com criptografia manual via Proto DataStore com protocolos criptográficos.
Não recomendado. O EncryptedSharedPreferences é projetado para pequenos volumes (até 100-200 KB). Para dados maiores, use Room com SQLCipher ou criptografia de arquivos via EncryptedFile da mesma biblioteca AndroidX Security.
Não, não há migração de esquema automática. Ao alterar a estrutura de dados, o desenvolvedor deve ler manualmente os dados antigos através do KeyGen antigo e escrevê-los através do novo. Recomenda-se armazenar a versão do esquema em um parâmetro separado.
AndroidX Security 1.0.0 suporta API 19+ (Android KitKat). A versão 1.1.0-alpha06 também suporta API 19+. O StrongBox requer API 28+ e um dispositivo com suporte de hardware (Google Pixel 3+, Samsung Galaxy S9+).
Sim, o refresh token é um dos principais casos de uso. Criptografia AES-256 GCM, chave mestra no Keystore, proteção biométrica — um nível suficiente para tokens OAuth. Para tokens de acesso de curta duração também é adequado, embora algumas equipes prefiram armazená-los na memória.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também