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:
- padrão
- ALFINETE
- senha
- padrão
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 cryptfs
da ferramenta de linha de comando vdc
: checkpw
, 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 /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
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 queinit.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 ele 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 queinit.rc
execute seus comandospost-fs-data
. Eles criarão todos os diretórios ou links necessários e definirãovold.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 queinit.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 que
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 queinit.rc
execute seus comandospost-fs-data
. Eles criarão todos os diretórios ou links necessários e, em seguida, definirãovold.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 queinit.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.
Falha
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, 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 não criptografado. 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,
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:
- padrão
- ALFINETE
- senha
- padrão
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 cryptfs
da ferramenta de linha de comando vdc
: checkpw
, 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 /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 interface do usuário 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
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 queinit.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 exibe 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 ele 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 queinit.rc
execute seus comandospost-fs-data
. Eles criarão todos os diretórios ou links necessários e definirãovold.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 queinit.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.
Starting an encrypted device without default encryption
This is what happens when you boot up an encrypted device that has a set password. The device's password can be a pin, pattern, or password.
- Detect encrypted device with a password
Detect that the Android device is encrypted because the flag
ro.crypto.state = "encrypted"
vold
setsvold.decrypt
totrigger_restart_min_framework
because/data
is encrypted with a password. - Mount tmpfs
init
sets five properties to save the initial mount options given for/data
with parameters passed frominit.rc
.vold
uses these properties to set up the crypto mapping:-
ro.crypto.fs_type
-
ro.crypto.fs_real_blkdev
-
ro.crypto.fs_mnt_point
-
ro.crypto.fs_options
-
ro.crypto.fs_flags
(ASCII 8-digit hex number preceded by 0x)
-
- Start framework to prompt for password
The framework starts up and sees that
vold.decrypt
is set totrigger_restart_min_framework
. This tells the framework that it is booting on a tmpfs/data
disk and it needs to get the user password.First, however, it needs to make sure that the disk was properly encrypted. It sends the command
cryptfs cryptocomplete
tovold
.vold
returns 0 if encryption was completed successfully, -1 on internal error, or -2 if encryption was not completed successfully.vold
determines this by looking in the crypto metadata for theCRYPTO_ENCRYPTION_IN_PROGRESS
flag. If it's set, the encryption process was interrupted, and there is no usable data on the device. Ifvold
returns an error, the UI should display a message to the user to reboot and factory reset the device, and give the user a button to press to do so. - Decrypt data with password
Once
cryptfs cryptocomplete
is successful, the framework displays a UI asking for the disk password. The UI checks the password by sending the commandcryptfs checkpw
tovold
. If the password is correct (which is determined by successfully mounting the decrypted/data
at a temporary location, then unmounting it),vold
saves the name of the decrypted block device in the propertyro.crypto.fs_crypto_blkdev
and returns status 0 to the UI. If the password is incorrect, it returns -1 to the UI. - Stop framework
The UI puts up a crypto boot graphic and then calls
vold
with the commandcryptfs restart
.vold
sets the propertyvold.decrypt
totrigger_reset_main
, which causesinit.rc
to doclass_reset main
. This stops all services in the main class, which allows the tmpfs/data
to be unmounted. - Mount
/data
vold
then mounts the decrypted real/data
partition and prepares the new partition (which may never have been prepared if it was encrypted with the wipe option, which is not supported on first release). It sets the propertyvold.post_fs_data_done
to 0 and then setsvold.decrypt
totrigger_post_fs_data
. This causesinit.rc
to run itspost-fs-data
commands. They will create any necessary directories or links and then setvold.post_fs_data_done
to 1. Oncevold
sees the 1 in that property, it sets the propertyvold.decrypt
totrigger_restart_framework
. This causesinit.rc
to start services in classmain
again and also start services in classlate_start
for the first time since boot. - Start full framework
Now the framework boots all its services using the decrypted
/data
filesystem, and the system is ready for use.
Failure
A device that fails to decrypt might be awry for a few reasons. The device starts with the normal series of steps to boot:
- Detect encrypted device with a password
- Mount tmpfs
- Start framework to prompt for password
But after the framework opens, the device can encounter some errors:
- Password matches but cannot decrypt data
- User enters wrong password 30 times
If these errors are not resolved, prompt user to factory wipe :
If vold
detects an error during the encryption process, and if no data has been destroyed yet and the framework is up, vold
sets the property vold.encrypt_progress
to error_not_encrypted
. The UI prompts the user to reboot and alerts them the encryption process never started. If the error occurs after the framework has been torn down, but before the progress bar UI is up, vold
will reboot the system. If the reboot fails, it sets vold.encrypt_progress
to error_shutting_down
and returns -1; but there will not be anything to catch the error. This is not expected to happen.
If vold
detects an error during the encryption process, it sets vold.encrypt_progress
to error_partially_encrypted
and returns -1. The UI should then display a message saying the encryption failed and provide a button for the user to factory reset the device.
Storing the encrypted key
The encrypted key is stored in the crypto metadata. Hardware backing is implemented by using Trusted Execution Environment's (TEE) signing capability. Previously, we encrypted the master key with a key generated by applying scrypt to the user's password and the stored salt. In order to make the key resilient against off-box attacks, we extend this algorithm by signing the resultant key with a stored TEE key. The resultant signature is then turned into an appropriate length key by one more application of scrypt. This key is then used to encrypt and decrypt the master key. To store this key:
- Generate random 16-byte disk encryption key (DEK) and 16-byte salt.
- Apply scrypt to the user password and the salt to produce 32-byte intermediate key 1 (IK1).
- Pad IK1 with zero bytes to the size of the hardware-bound private key (HBK). Specifically, we pad as: 00 || IK1 || 00..00; one zero byte, 32 IK1 bytes, 223 zero bytes.
- Sign padded IK1 with HBK to produce 256-byte IK2.
- Apply scrypt to IK2 and salt (same salt as step 2) to produce 32-byte IK3.
- Use the first 16 bytes of IK3 as KEK and the last 16 bytes as IV.
- Encrypt DEK with AES_CBC, with key KEK, and initialization vector IV.
Changing the password
When a user elects to change or remove their password in settings, the UI sends the command cryptfs changepw
to vold
, and vold
re-encrypts the disk master key with the new password.
Encryption properties
vold
and init
communicate with each other by setting properties. Here is a list of available properties for encryption.
Vold properties
Property | Description |
---|---|
vold.decrypt trigger_encryption | Encrypt the drive with no password. |
vold.decrypt trigger_default_encryption | Check the drive to see if it is encrypted with no password. If it is, decrypt and mount it, else set vold.decrypt to trigger_restart_min_framework. |
vold.decrypt trigger_reset_main | Set by vold to shutdown the UI asking for the disk password. |
vold.decrypt trigger_post_fs_data | Set by vold to prep /data with necessary directories, et al. |
vold.decrypt trigger_restart_framework | Set by vold to start the real framework and all services. |
vold.decrypt trigger_shutdown_framework | Set by vold to shutdown the full framework to start encryption. |
vold.decrypt trigger_restart_min_framework | Set by vold to start the progress bar UI for encryption or prompt for password, depending on the value of ro.crypto.state . |
vold.encrypt_progress | When the framework starts up, if this property is set, enter the progress bar UI mode. |
vold.encrypt_progress 0 to 100 | The progress bar UI should display the percentage value set. |
vold.encrypt_progress error_partially_encrypted | The progress bar UI should display a message that the encryption failed, and give the user an option to factory reset the device. |
vold.encrypt_progress error_reboot_failed | The progress bar UI should display a message saying encryption completed, and give the user a button to reboot the device. This error is not expected to happen. |
vold.encrypt_progress error_not_encrypted | The progress bar UI should display a message saying an error occurred, no data was encrypted or lost, and give the user a button to reboot the system. |
vold.encrypt_progress error_shutting_down | The progress bar UI is not running, so it is unclear who will respond to this error. And it should never happen anyway. |
vold.post_fs_data_done 0 | Set by vold just before setting vold.decrypt to trigger_post_fs_data . |
vold.post_fs_data_done 1 | Set by init.rc or init.rc just after finishing the task post-fs-data . |
init properties
Property | Description |
---|---|
ro.crypto.fs_crypto_blkdev | Set by the vold command checkpw for later use by the vold command restart . |
ro.crypto.state unencrypted | Set by init to say this system is running with an unencrypted /data ro.crypto.state encrypted . Set by init to say this system is running with an encrypted /data . |
| These five properties are set by init when it tries to mount /data with parameters passed in from init.rc . vold uses these to setup the crypto mapping. |
ro.crypto.tmpfs_options | Set by init.rc with the options init should use when mounting the tmpfs /data filesystem. |
Init actions
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