A criptografia de disco completo é o processo de codificação de todos os dados do usuário em um dispositivo Android usando uma chave criptografada. Depois que um dispositivo é criptografado, todos os dados criados pelo usuário são criptografados automaticamente antes de serem enviados para o disco e todas as leituras descriptografam automaticamente os dados antes de retorná-los ao processo de chamada.
A criptografia de disco completo foi introduzida no Android no 4.4, mas o Android 5.0 introduziu estes novos recursos:
- Criptografia rápida criada, que criptografa apenas os blocos usados na partição de dados para evitar que a primeira inicialização demore muito. Atualmente, apenas os sistemas de arquivos ext4 e f2fs suportam criptografia rápida.
- Adicionado o sinalizador fstab
forceencrypt
para criptografar na primeira inicialização. - Adicionado suporte para padrões e criptografia sem senha.
- Adicionado armazenamento baseado em hardware da chave de criptografia usando o recurso de assinatura do Trusted Execution Environment (TEE) (como em uma TrustZone). Consulte Armazenando a chave criptografada para obter mais detalhes.
Cuidado: os dispositivos atualizados para o Android 5.0 e depois criptografados podem retornar a um estado não criptografado pela redefinição dos dados de fábrica. Novos dispositivos Android 5.0 criptografados na primeira inicialização não podem retornar a um estado não criptografado.
Como funciona a criptografia de disco completo do Android
A criptografia de disco completo do Android é baseada em dm-crypt
, que é um recurso do kernel que funciona na camada do dispositivo de bloco. Por causa disso, a criptografia funciona com Embedded MultiMediaCard ( eMMC) e dispositivos flash semelhantes que se apresentam ao kernel como dispositivos de bloco. A criptografia não é possível com o YAFFS, que se comunica diretamente com um chip flash NAND bruto.
O algoritmo de criptografia é 128 Advanced Encryption Standard (AES) com cipher-block chaining (CBC) e ESSIV:SHA256. A chave mestra é criptografada com AES de 128 bits por meio de chamadas para a biblioteca OpenSSL. Você deve usar 128 bits ou mais para a chave (com 256 sendo opcional).
Observação: os OEMs podem usar 128 bits ou superior para criptografar a chave mestra.
Na versão Android 5.0, existem quatro tipos de estados de criptografia:
- predefinição
- PIN
- senha
- padronizar
Na primeira inicialização, o dispositivo cria uma chave mestra de 128 bits gerada aleatoriamente e, em seguida, faz um hash com uma senha padrão e sal armazenado. A senha padrão é: "default_password" No entanto, o hash resultante também é assinado por meio de um TEE (como TrustZone), que usa um hash da assinatura para criptografar a chave mestra.
Você pode encontrar a senha padrão definida no arquivo cryptfs.cpp do Android Open Source Project.
Quando o usuário define o PIN/senha ou senha no dispositivo, apenas a chave de 128 bits é recriptografada e armazenada. (ou seja, as alterações de PIN/senha/padrão do usuário NÃO causam a recriptografia dos dados do usuário.) Observe que o dispositivo gerenciado pode estar sujeito a restrições de PIN, padrão ou senha.
A criptografia é gerenciada por init
e vold
. init
chama vold
e vold define propriedades para acionar eventos em init. Outras partes do sistema também examinam as propriedades para realizar tarefas como relatar o status, solicitar uma senha ou solicitar a redefinição de fábrica no caso de um erro fatal. Para invocar recursos de criptografia em vold
, o sistema usa os comandos checkpw
da ferramenta de linha de comando vdc
: cryptfs
, restart
, enablecrypto
, changepw
, cryptocomplete
, verifypw
, setfield
, getfield
, mountdefaultencrypted
, getpwtype
, getpw
e clearpw
.
Para criptografar, descriptografar ou limpar /data
, /data
não deve ser montado. No entanto, para mostrar qualquer interface de usuário (UI), a estrutura deve iniciar e a estrutura requer que /data
seja executada. Para resolver esse enigma, um sistema de arquivos temporário é montado em /data
. Isso permite que o Android solicite senhas, mostre o progresso ou sugira uma limpeza de dados conforme necessário. Ele impõe a limitação de que, para alternar do sistema de arquivos temporário para o verdadeiro sistema de arquivos /data
, o sistema deve parar todos os processos com arquivos abertos no sistema de arquivos temporário e reiniciar esses processos no sistema de arquivos /data
real. Para fazer isso, todos os serviços devem estar em um dos três grupos: core
, main
e late_start
.
-
core
: Nunca desligue depois de iniciar. -
main
: Desligue e reinicie depois que a senha do disco for digitada. -
late_start
: não inicia até que/data
tenha sido descriptografado e montado.
Para acionar essas ações, a propriedade vold.decrypt
é configurada para várias cadeias de caracteres. Para matar e reiniciar serviços, os comandos init
são:
-
class_reset
: interrompe um serviço, mas permite que ele seja reiniciado com class_start. -
class_start
: Reinicia um serviço. -
class_stop
: Interrompe um serviço e adiciona um sinalizadorSVC_DISABLED
. Serviços parados não respondem aclass_start
.
Fluxos
Existem quatro fluxos para um dispositivo criptografado. Um dispositivo é criptografado apenas uma vez e segue um fluxo de inicialização normal.
- Criptografar um dispositivo não criptografado anteriormente:
- Criptografe um novo dispositivo com
forceencrypt
: criptografia obrigatória na primeira inicialização (a partir do Android L). - Criptografar um dispositivo existente: criptografia iniciada pelo usuário (Android K e anterior).
- Criptografe um novo dispositivo com
- Inicialize um dispositivo criptografado:
- Iniciar um dispositivo criptografado sem senha: inicializar um dispositivo criptografado sem senha definida (relevante para dispositivos com Android 5.0 e posterior).
- Iniciando um dispositivo criptografado com uma senha: inicializando um dispositivo criptografado com uma senha definida.
Além desses fluxos, o dispositivo também pode falhar ao criptografar /data
. Cada um dos fluxos é explicado em detalhes a seguir.
Criptografar um novo dispositivo com forceencrypt
Esta é a primeira inicialização normal para um dispositivo Android 5.0.
- Detectar sistema de arquivos não criptografado com sinalizador
forceencrypt
/data
não é criptografado, mas precisa ser porqueforceencrypt
exige isso. Desmontar/data
. - Comece a criptografar
/data
vold.decrypt = "trigger_encryption"
acionainit.rc
, o que fará com quevold
criptografe/data
sem senha. (Nenhum está definido porque este deve ser um novo dispositivo.) - Montar tmpfs
vold
monta um tmpfs/data
(usando as opções tmpfs dero.crypto.tmpfs_options
) e define a propriedadevold.encrypt_progress
como 0.vold
prepara o tmpfs/data
para inicializar um sistema criptografado e define a propriedadevold.decrypt
como:trigger_restart_min_framework
- Traga a estrutura para mostrar o progresso
Como o dispositivo praticamente não tem dados para criptografar, a barra de progresso geralmente não aparece porque a criptografia acontece muito rapidamente. Consulte Criptografar um dispositivo existente para obter mais detalhes sobre a interface do usuário de progresso.
- Quando
/data
é criptografado, desative a estruturavold
definevold.decrypt
comotrigger_default_encryption
que inicia o serviçodefaultcrypto
. (Isso inicia o fluxo abaixo para montar um userdata criptografado padrão.)trigger_default_encryption
verifica o tipo de criptografia para ver se/data
está criptografado com ou sem uma senha. Como os dispositivos Android 5.0 são criptografados na primeira inicialização, não deve haver senha definida; portanto, descriptografamos e montamos/data
. - Montar
/data
init
então monta/data
em um tmpfs RAMDisk usando parâmetros que ele pega dero.crypto.tmpfs_options
, que é definido eminit.rc
. - Estrutura inicial
vold
definevold.decrypt
comotrigger_restart_framework
, que continua o processo de inicialização normal.
Criptografar um dispositivo existente
Isso é o que acontece quando você criptografa um Android K não criptografado ou um dispositivo anterior que foi migrado para L.
Esse processo é iniciado pelo usuário e é chamado de “criptografia local” no código. Quando um usuário opta por criptografar um dispositivo, a IU garante que a bateria esteja totalmente carregada e que o adaptador CA esteja conectado para que haja energia suficiente para concluir o processo de criptografia.
Aviso: se o dispositivo ficar sem energia e desligar antes de terminar a criptografia, os dados do arquivo serão deixados em um estado parcialmente criptografado. O dispositivo deve ser redefinido de fábrica e todos os dados serão perdidos.
Para habilitar a criptografia local, vold
inicia um loop para ler cada setor do dispositivo de bloco real e, em seguida, gravá-lo no dispositivo de bloco de criptografia. vold
verifica se um setor está em uso antes de lê-lo e escrevê-lo, o que torna a criptografia muito mais rápida em um novo dispositivo que possui poucos ou nenhum dado.
Estado do dispositivo : Defina ro.crypto.state = "unencrypted"
e execute o gatilho init
on nonencrypted
criptografado para continuar a inicialização.
- Verifique a senha
A IU chama
vold
com o comandocryptfs enablecrypto inplace
ondepasswd
é a senha da tela de bloqueio do usuário. - Derrube o quadro
vold
verifica se há erros, retorna -1 se não puder criptografar e imprime um motivo no log. Se puder criptografar, ele definirá a propriedadevold.decrypt
comotrigger_shutdown_framework
. Isso faz com que oinit.rc
interrompa os serviços nas classeslate_start
emain
. - Criar um rodapé criptográfico
- Criar um arquivo breadcrumb
- Reinício
- Detectar arquivo breadcrumb
- Comece a criptografar
/data
vold
então configura o mapeamento de criptografia, que cria um dispositivo de bloco de criptografia virtual que mapeia para o dispositivo de bloco real, mas criptografa cada setor à medida que é gravado e descriptografa cada setor à medida que é lido.vold
então cria e grava os metadados criptográficos. - Enquanto estiver criptografando, monte tmpfs
vold
monta um tmpfs/data
(usando as opções tmpfs dero.crypto.tmpfs_options
) e define a propriedadevold.encrypt_progress
como 0.vold
prepara o tmpfs/data
para inicializar um sistema criptografado e define a propriedadevold.decrypt
como:trigger_restart_min_framework
- Traga a estrutura para mostrar o progresso
trigger_restart_min_framework
faz com queinit.rc
inicie a classemain
de serviços. Quando a estrutura vê quevold.encrypt_progress
está definido como 0, ela abre a interface do usuário da barra de progresso, que consulta essa propriedade a cada cinco segundos e atualiza uma barra de progresso. O loop de criptografia atualizavold.encrypt_progress
toda vez que criptografa outra porcentagem da partição. - Quando
/data
estiver criptografado, atualize o rodapé de criptografiaQuando
/data
é criptografado com sucesso,vold
limpa o sinalizadorENCRYPTION_IN_PROGRESS
nos metadados.Quando o dispositivo é desbloqueado com sucesso, a senha é usada para criptografar a chave mestra e o rodapé criptográfico é atualizado.
Se a reinicialização falhar por algum motivo,
vold
define a propriedadevold.encrypt_progress
comoerror_reboot_failed
e a IU deve exibir uma mensagem solicitando ao usuário que pressione um botão para reinicializar. Não se espera que isso ocorra.
Iniciando um dispositivo criptografado com criptografia padrão
Isso é o que acontece quando você inicializa um dispositivo criptografado sem senha. Como os dispositivos Android 5.0 são criptografados na primeira inicialização, não deve haver senha definida e, portanto, esse é o estado de criptografia padrão .
- Detectar
/data
criptografados sem senhaDetecte que o dispositivo Android está criptografado porque
/data
não pode ser montado e um dos sinalizadoresencryptable
ouforceencrypt
está definido.vold
definevold.decrypt
comotrigger_default_encryption
, que inicia o serviçodefaultcrypto
.trigger_default_encryption
verifica o tipo de criptografia para ver se/data
está criptografado com ou sem senha. - Descriptografar /dados
Cria o dispositivo
dm-crypt
sobre o dispositivo de bloco para que o dispositivo esteja pronto para uso. - Montar /dados
vold
então monta a partição real/data
descriptografada e prepara a nova partição. Ele define a propriedadevold.post_fs_data_done
como 0 e, em seguida, definevold.decrypt
comotrigger_post_fs_data
. Isso faz com que oinit.rc
execute seus comandospost-fs-data
. Eles criarão todos os diretórios ou links necessários evold.post_fs_data_done
como 1.Depois que
vold
vê o 1 nessa propriedade, ele define a propriedadevold.decrypt
como:trigger_restart_framework.
Isso faz com que oinit.rc
inicie os serviços na classemain
novamente e também inicie os serviços na classelate_start
pela primeira vez desde a inicialização. - Estrutura inicial
Agora a estrutura inicializa todos os seus serviços usando o
/data
descriptografado e o sistema está pronto para uso.
Iniciando um dispositivo criptografado sem criptografia padrão
Isso é o que acontece quando você inicializa um dispositivo criptografado com uma senha definida. A senha do dispositivo pode ser um alfinete, padrão ou senha.
- Detectar dispositivo criptografado com uma senha
Detectar que o dispositivo Android está criptografado porque o sinalizador
ro.crypto.state = "encrypted"
vold
definevold.decrypt
comotrigger_restart_min_framework
porque/data
é criptografado com uma senha. - Montar tmpfs
init
define cinco propriedades para salvar as opções iniciais de montagem fornecidas para/data
com parâmetros passados deinit.rc
.vold
usa essas propriedades para configurar o mapeamento criptográfico:-
ro.crypto.fs_type
-
ro.crypto.fs_real_blkdev
-
ro.crypto.fs_mnt_point
-
ro.crypto.fs_options
-
ro.crypto.fs_flags
(número hexadecimal ASCII de 8 dígitos precedido por 0x)
-
- Inicie a estrutura para solicitar a senha
A estrutura inicializa e vê que
vold.decrypt
está definido comotrigger_restart_min_framework
. Isso informa à estrutura que está inicializando em um disco tmpfs/data
e precisa obter a senha do usuário.Primeiro, no entanto, ele precisa ter certeza de que o disco foi criptografado corretamente. Ele envia o comando
cryptfs cryptocomplete
paravold
.vold
retorna 0 se a criptografia foi concluída com êxito, -1 em caso de erro interno ou -2 se a criptografia não foi concluída com êxito.vold
determina isso procurando nos metadados criptográficos o sinalizadorCRYPTO_ENCRYPTION_IN_PROGRESS
. Se estiver definido, o processo de criptografia foi interrompido e não há dados utilizáveis no dispositivo. Sevold
retornar um erro, a interface do usuário deve exibir uma mensagem para o usuário reiniciar e redefinir o dispositivo de fábrica e dar ao usuário um botão para pressionar para fazer isso. - Descriptografar dados com senha
Depois
cryptfs cryptocomplete
for bem-sucedido, a estrutura exibirá uma interface do usuário solicitando a senha do disco. A IU verifica a senha enviando o comandocryptfs checkpw
paravold
. Se a senha estiver correta (o que é determinado pela montagem bem-sucedida do/data
descriptografado em um local temporário e, em seguida, desmontando-o),vold
salva o nome do dispositivo de bloco descriptografado na propriedadero.crypto.fs_crypto_blkdev
e retorna o status 0 para a IU . Se a senha estiver incorreta, ela retornará -1 para a IU. - Estrutura de parada
A interface do usuário exibe um gráfico de inicialização criptográfica e, em seguida, chama
vold
com o comandocryptfs restart
.vold
define a propriedadevold.decrypt
comotrigger_reset_main
, o que faz com queinit.rc
façaclass_reset main
. Isso interrompe todos os serviços na classe principal, o que permite que tmpfs/data
seja desmontado. - Montar
/data
vold
então monta a partição real/data
descriptografada e prepara a nova partição (que pode nunca ter sido preparada se tiver sido criptografada com a opção de limpeza, que não é suportada no primeiro lançamento). Ele define a propriedadevold.post_fs_data_done
como 0 e, em seguida, definevold.decrypt
comotrigger_post_fs_data
. Isso faz com que oinit.rc
execute seus comandospost-fs-data
. Eles criarão todos os diretórios ou links necessários e, em seguida,vold.post_fs_data_done
como 1. Uma vez quevold
vê o 1 nessa propriedade, ele define a propriedadevold.decrypt
comotrigger_restart_framework
. Isso faz com que oinit.rc
inicie os serviços na classemain
novamente e também inicie os serviços na classelate_start
pela primeira vez desde a inicialização. - Iniciar estrutura completa
Agora a estrutura inicializa todos os seus serviços usando o sistema de arquivos
/data
descriptografado e o sistema está pronto para uso.
Fracasso
Um dispositivo que não consegue descriptografar pode estar errado por alguns motivos. O dispositivo inicia com a série normal de etapas para inicializar:
- Detectar dispositivo criptografado com uma senha
- Montar tmpfs
- Inicie a estrutura para solicitar a senha
Mas depois que a estrutura é aberta, o dispositivo pode encontrar alguns erros:
- A senha corresponde, mas não pode descriptografar os dados
- Usuário digita senha errada 30 vezes
Se esses erros não forem resolvidos, solicite ao usuário a limpeza de fábrica :
Se vold
detectar um erro durante o processo de criptografia e se nenhum dado tiver sido destruído ainda e a estrutura estiver ativa, vold
definirá a propriedade vold.encrypt_progress
como error_not_encrypted
. A IU solicita que o usuário reinicie e alerta que o processo de criptografia nunca foi iniciado. Se o erro ocorrer depois que a estrutura for desativada, mas antes que a interface do usuário da barra de progresso seja ativada, o vold
reinicializará o sistema. Se a reinicialização falhar, ela definirá vold.encrypt_progress
como error_shutting_down
e retornará -1; mas não haverá nada para detectar o erro. Não se espera que isso aconteça.
Se vold
detectar um erro durante o processo de criptografia, ele definirá vold.encrypt_progress
como error_partially_encrypted
e retornará -1. A interface do usuário deve exibir uma mensagem informando que a criptografia falhou e fornecer um botão para o usuário redefinir o dispositivo de fábrica.
Armazenando a chave criptografada
A chave criptografada é armazenada nos metadados de criptografia. O suporte de hardware é implementado usando o recurso de assinatura do Trusted Execution Environment (TEE). Anteriormente, criptografávamos a chave mestra com uma chave gerada aplicando scrypt à senha do usuário e ao salt armazenado. Para tornar a chave resiliente contra ataques fora da caixa, estendemos esse algoritmo assinando a chave resultante com uma chave TEE armazenada. A assinatura resultante é então transformada em uma chave de tamanho apropriado por mais uma aplicação de scrypt. Essa chave é usada para criptografar e descriptografar a chave mestra. Para armazenar esta chave:
- Gera chave de criptografia de disco aleatória de 16 bytes (DEK) e sal de 16 bytes.
- Aplique scrypt à senha do usuário e o sal para produzir a chave intermediária 1 de 32 bytes (IK1).
- Preencha IK1 com zero bytes para o tamanho da chave privada ligada ao hardware (HBK). Especificamente, preenchemos como: 00 || IK1 || 00..00; um byte zero, 32 bytes IK1, 223 bytes zero.
- Assine IK1 preenchido com HBK para produzir IK2 de 256 bytes.
- Aplique scrypt a IK2 e sal (o mesmo sal da etapa 2) para produzir IK3 de 32 bytes.
- Use os primeiros 16 bytes de IK3 como KEK e os últimos 16 bytes como IV.
- Criptografe DEK com AES_CBC, com chave KEK e vetor de inicialização IV.
Mudando a senha
Quando um usuário opta por alterar ou remover sua senha nas configurações, a IU envia o comando cryptfs changepw
para vold
e vold
criptografa novamente a chave mestra do disco com a nova senha.
Propriedades de criptografia
vold
e init
se comunicam definindo propriedades. Aqui está uma lista de propriedades disponíveis para criptografia.
Vold propriedades
Propriedade | Descrição |
---|---|
vold.decrypt trigger_encryption | Criptografe a unidade sem senha. |
vold.decrypt trigger_default_encryption | Verifique a unidade para ver se ela está criptografada sem senha. Se for, descriptografe e monte-o, caso contrário, defina vold.decrypt como trigger_restart_min_framework. |
vold.decrypt trigger_reset_main | Definido por vold para desligar a interface do usuário solicitando a senha do disco. |
vold.decrypt trigger_post_fs_data | Definido por vold para preparar /data com os diretórios necessários, et al. |
vold.decrypt trigger_restart_framework | Definido por vold para iniciar a estrutura real e todos os serviços. |
vold.decrypt trigger_shutdown_framework | Definido por vold para desligar a estrutura completa para iniciar a criptografia. |
vold.decrypt trigger_restart_min_framework | Definido por vold para iniciar a IU da barra de progresso para criptografia ou solicitação de senha, dependendo do valor de ro.crypto.state . |
vold.encrypt_progress | Quando a estrutura inicializar, se essa propriedade estiver definida, entre no modo de interface do usuário da barra de progresso. |
vold.encrypt_progress 0 to 100 | A IU da barra de progresso deve exibir o valor percentual definido. |
vold.encrypt_progress error_partially_encrypted | A IU da barra de progresso deve exibir uma mensagem informando que a criptografia falhou e dar ao usuário a opção de redefinir o dispositivo de fábrica. |
vold.encrypt_progress error_reboot_failed | A IU da barra de progresso deve exibir uma mensagem dizendo que a criptografia foi concluída e fornecer ao usuário um botão para reiniciar o dispositivo. Não é esperado que esse erro aconteça. |
vold.encrypt_progress error_not_encrypted | A IU da barra de progresso deve exibir uma mensagem informando que ocorreu um erro, nenhum dado foi criptografado ou perdido e fornecer ao usuário um botão para reiniciar o sistema. |
vold.encrypt_progress error_shutting_down | A interface do usuário da barra de progresso não está em execução, portanto, não está claro quem responderá a esse erro. E isso nunca deveria acontecer de qualquer maneira. |
vold.post_fs_data_done 0 | Definido por vold antes de definir vold.decrypt como trigger_post_fs_data . |
vold.post_fs_data_done 1 | Definido por init.rc ou init.rc logo após terminar a tarefa post-fs-data . |
propriedades de inicialização
Propriedade | Descrição |
---|---|
ro.crypto.fs_crypto_blkdev | Definido pelo comando vold checkpw para uso posterior pelo comando vold restart . |
ro.crypto.state unencrypted | Definido por init para dizer que este sistema está sendo executado com um /data ro.crypto.state encrypted . Definido por init para dizer que este sistema está sendo executado com um /data criptografado. |
| Essas cinco propriedades são definidas pelo init quando ele tenta montar /data com parâmetros passados de init.rc . vold os usa para configurar o mapeamento criptográfico. |
ro.crypto.tmpfs_options | Definido por init.rc com as opções que o init deve usar ao montar o sistema de arquivos tmpfs /data . |
ações de inicialização
on post-fs-data on nonencrypted on property:vold.decrypt=trigger_reset_main on property:vold.decrypt=trigger_post_fs_data on property:vold.decrypt=trigger_restart_min_framework on property:vold.decrypt=trigger_restart_framework on property:vold.decrypt=trigger_shutdown_framework on property:vold.decrypt=trigger_encryption on property:vold.decrypt=trigger_default_encryption