Criptografia de disco completo

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 confirmados no disco, e todas as leituras descriptografam automaticamente os dados antes de serem retornados ao processo de chamada.

A criptografia de disco completo foi introduzida no Android na versão 4.4, mas o Android 5.0 introduziu estes novos recursos:

  • Criou a criptografia rápida, em que apenas os blocos usados na partição de dados são criptografados para evitar que a primeira inicialização demore muito tempo. No momento, apenas os sistemas de arquivos ext4 e f2fs oferecem suporte à criptografia rápida.
  • Foi adicionada a sinalização fstab forceencrypt para criptografar na primeira inicialização.
  • Inclusão de suporte a padrões e criptografia sem senha.
  • Inclusão de armazenamento protegido por hardware da chave de criptografia usando o recurso de assinatura do ambiente de execução confiável (TEE), como em um TrustZone. Consulte Como armazenar a chave criptografada para mais detalhes.

Cuidado:dispositivos atualizados para o Android 5.0 e depois criptografados podem ser retornados para um estado não criptografado após uma redefinição para a configuração original. Os novos dispositivos Android 5.0 criptografados na primeira inicialização não podem ser retornados 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 isso, 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 é o padrão de criptografia avançada (AES) de 128 bits com cadeamento de blocos de cifras (CBC) e ESSIV:SHA256. A chave mestra é criptografada com AES de 128 bits por chamadas para a biblioteca OpenSSL. Você precisa usar 128 bits ou mais para a chave, sendo 256 opcionais.

Observação: os OEMs podem usar 128 bits ou mais para criptografar a chave mestra.

Na versão Android 5.0, há quatro tipos de estados de criptografia:

  • padrão
  • PIN
  • senha
  • padrão

Na primeira inicialização, o dispositivo cria uma chave mestra de 128 bits gerada aleatoriamente e gera um hash com uma senha padrão e um sal armazenado. A senha padrão é: "default_password". No entanto, o hash resultante também é assinado por um TEE (como o TrustZone), que usa um hash da assinatura para criptografar a chave mestra.

Encontre 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. Por exemplo, mudanças de PIN/senha/padrão do usuário NÃO causam a recriptografia dos dados do usuário. 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 no init. Outras partes do sistema também analisam as propriedades para realizar tarefas como informar o status, solicitar uma senha ou solicitar a redefinição de fábrica no caso de um erro fatal. Para invocar os 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 excluir permanentemente /data, o /data não pode ser ativado. No entanto, para mostrar qualquer interface do usuário (interface), o framework precisa ser iniciado e /data para ser executado. Para resolver esse problema, um sistema de arquivos temporário é montado em /data. Isso permite que o Android solicite senhas, mostre o progresso ou sugira uma exclusão 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 precisa interromper todos os processos com arquivos abertos no sistema de arquivos temporário e reiniciar esses processos no sistema de arquivos /data real. Para isso, todos os serviços precisam estar em um dos três grupos: core, main e late_start.

  • core: nunca é encerrado após a inicialização.
  • main: desligue e reinicie após a senha do disco ser inserida.
  • late_start: não é iniciado até que /data seja descriptografado e ativado.

Para acionar essas ações, a propriedade vold.decrypt é definida como várias strings. Para encerrar e reiniciar os 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 uma flag SVC_DISABLED. Os serviços interrompidos não respondem a class_start.

Fluxos

Há quatro fluxos para um dispositivo criptografado. Um dispositivo é criptografado apenas uma vez e segue um fluxo de inicialização normal.

  • Criptografar um dispositivo que não estava criptografado:
    • 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 versões anteriores).
  • Inicialize um dispositivo criptografado:
    • Iniciar um dispositivo criptografado sem senha: inicializar um dispositivo criptografado que não tem uma senha definida (relevante para dispositivos com Android 5.0 e versões mais recentes).
    • Como iniciar um dispositivo criptografado com uma senha: inicializar um dispositivo criptografado que tenha uma senha definida.

Além desses fluxos, o dispositivo também pode falhar na criptografia de /data. Cada um dos fluxos é explicado em detalhes abaixo.

Criptografar um novo dispositivo com forceencrypt

Esta é a primeira inicialização normal de um dispositivo Android 5.0.

  1. Detectar o sistema de arquivos não criptografado com a flag forceencrypt

    O /data não está criptografado, mas precisa ser porque o forceencrypt exige isso. Desconecte /data.

  2. Começar a criptografar /data

    vold.decrypt = "trigger_encryption" aciona init.rc, o que faz com que vold criptografe /data sem senha. Nenhum é definido porque este deve ser um novo dispositivo.

  3. Montar tmpfs

    vold monta um /data tmpfs (usando as opções tmpfs de ro.crypto.tmpfs_options) e define a propriedade vold.encrypt_progress como 0. vold prepara o tmpfs /data para inicializar um sistema criptografado e define a propriedade vold.decrypt como: trigger_restart_min_framework

  4. Mostrar o framework para mostrar o progresso

    Como o dispositivo não tem dados para criptografia, a barra de progresso não aparece com frequência porque a criptografia acontece muito rápido. Consulte Como criptografar um dispositivo existente para mais detalhes sobre a interface de progresso.

  5. Quando /data estiver criptografado, remova o framework

    vold define vold.decrypt como trigger_default_encryption, o que inicia o serviço defaultcrypto. Isso inicia o fluxo abaixo para montar um userdata criptografado padrão. trigger_default_encryption verifica o tipo de criptografia para saber se /data está criptografado com ou sem uma senha. Como os dispositivos Android 5.0 são criptografados na primeira inicialização, não é necessário definir uma senha. Portanto, descriptografamos e ativamos /data.

  6. Montar /data

    Em seguida, init monta /data em um RAMDisk tmpfs usando parâmetros que ele coleta de ro.crypto.tmpfs_options, que é definido em init.rc.

  7. Iniciar framework

    vold define vold.decrypt como trigger_restart_framework, que continua o processo de inicialização normal.

Criptografar um dispositivo

Isso acontece quando você criptografa um dispositivo Android K ou anterior não criptografado que foi migrado para L.

Esse processo é iniciado pelo usuário e é chamado de "criptografia in-place" no código. Quando um usuário seleciona a criptografia de um dispositivo, a interface garante que a bateria esteja totalmente carregada e que o adaptador de CA esteja conectado para que haja energia suficiente para concluir o processo de criptografia.

Aviso: se o dispositivo ficar sem energia e for desligado antes de terminar a criptografia, os dados do arquivo serão deixados em um estado parcialmente criptografado. O dispositivo precisa ser redefinido para a configuração original, e todos os dados são perdidos.

Para ativar a criptografia no local, vold inicia uma repetição para ler cada setor do dispositivo de bloco real e gravá-lo no dispositivo de bloco de criptografia. O vold verifica se um setor está em uso antes de ler e gravar nele, o que torna a criptografia muito mais rápida em um novo dispositivo que tem poucos ou nenhum dado.

Estado do dispositivo: defina ro.crypto.state = "unencrypted" e execute o gatilho on nonencrypted init para continuar a inicialização.

  1. Verificar senha

    A interface chama vold com o comando cryptfs enablecrypto inplace, em que passwd é a senha da tela de bloqueio do usuário.

  2. Remover a estrutura

    vold verifica erros, retorna -1 se não puder criptografar e imprime um motivo no registro. Se a criptografia for possível, a propriedade vold.decrypt será definida como trigger_shutdown_framework. Isso faz com que init.rc interrompa os serviços nas classes late_start e main.

  3. Criar um rodapé de criptografia
  4. Criar um arquivo de migas de pão
  5. Reiniciar
  6. Detectar arquivo de navegação estrutural
  7. Começar a criptografar /data

    Em seguida, vold configura o mapeamento de criptografia, que cria um dispositivo de bloco de criptografia virtual que é mapeado para o dispositivo de bloco real, mas criptografa cada setor conforme é gravado e descriptografa cada setor conforme é lido. Em seguida, vold cria e grava os metadados de criptografia.

  8. Durante a criptografia, ative o tmpfs

    vold monta um /data de tmpfs (usando as opções de tmpfs de ro.crypto.tmpfs_options e define a propriedade vold.encrypt_progress como 0. vold prepara os tmpfs /data para inicializar um sistema criptografado e define a propriedade vold.decrypt como: trigger_restart_min_framework

  9. Mostrar o progresso do framework

    trigger_restart_min_framework faz com que init.rc inicie a classe de serviços main. Quando o framework detecta que vold.encrypt_progress está definido como 0, ele mostra a interface da barra de progresso, que consulta essa propriedade a cada cinco segundos e atualiza uma barra de progresso. O loop de criptografia atualiza vold.encrypt_progress sempre que criptografa outra porcentagem da partição.

  10. Quando /data estiver criptografado, atualize o rodapé de criptografia

    Quando /data for criptografado, vold limpará a flag ENCRYPTION_IN_PROGRESS nos metadados.

    Quando o dispositivo é desbloqueado, a senha é usada para criptografar a chave mestra, e o rodapé criptográfico é atualizado.

    Se a reinicialização falhar por algum motivo, vold vai definir a propriedade vold.encrypt_progress como error_reboot_failed, e a interface vai mostrar uma mensagem pedindo que o usuário pressione um botão para reiniciar. Isso não deve acontecer.

Iniciar um dispositivo criptografado com criptografia padrão

Isso acontece quando você inicializa um dispositivo criptografado sem senha. Como os dispositivos Android 5.0 são criptografados na primeira inicialização, não pode haver uma senha definida, portanto, esse é o estado de criptografia padrão.

  1. Detectar /data criptografados sem senha

    Detecta que o dispositivo Android está criptografado porque /data não pode ser montado e uma das flags encryptable ou forceencrypt está definida.

    vold define vold.decrypt como trigger_default_encryption, o que inicia o serviço defaultcrypto. O trigger_default_encryption verifica o tipo de criptografia para conferir se /data está criptografado com ou sem uma senha.

  2. Descriptografar /data

    Cria o dispositivo dm-crypt no dispositivo de transferência por blocos para que ele esteja pronto para uso.

  3. Montar /data

    O vold monta a partição /data real descriptografada e prepara a nova partição. Ele define a propriedade vold.post_fs_data_done como 0 e, em seguida, define vold.decrypt como trigger_post_fs_data. Isso faz com que init.rc execute os comandos post-fs-data. Ele cria todos os diretórios ou links necessários e, em seguida, define vold.post_fs_data_done como 1.

    Quando vold encontra o 1 nessa propriedade, ele define a propriedade vold.decrypt como: trigger_restart_framework.. Isso faz com que init.rc inicie os serviços na classe main novamente e também inicie os serviços na classe late_start pela primeira vez desde a inicialização.

  4. Iniciar framework

    Agora o framework inicializa todos os serviços usando o /data descriptografado, e o sistema está pronto para uso.

Iniciar um dispositivo criptografado sem a criptografia padrão

Isso acontece quando você inicializa um dispositivo criptografado que tem uma senha definida. A senha do dispositivo pode ser um PIN, um padrão ou uma senha.

  1. Detectar dispositivo criptografado com uma senha

    Detecte se o dispositivo Android está criptografado porque a flag ro.crypto.state = "encrypted"

    vold define vold.decrypt como trigger_restart_min_framework porque /data é criptografado com uma senha.

  2. Montar tmpfs

    init define cinco propriedades para salvar as opções de montagem iniciais fornecidas para /data com parâmetros transmitidos de init.rc. O vold usa estas propriedades para configurar o mapeamento de criptografia:

    1. ro.crypto.fs_type
    2. ro.crypto.fs_real_blkdev
    3. ro.crypto.fs_mnt_point
    4. ro.crypto.fs_options
    5. ro.crypto.fs_flags (Número hexadecimal de 8 dígitos ASCII precedido por 0x)
  3. Iniciar framework para solicitar senha

    O framework é iniciado e percebe que vold.decrypt está definido como trigger_restart_min_framework. Isso informa ao framework que ele está iniciando em um disco /data do tmpfs e precisa receber a senha do usuário.

    No entanto, primeiro, ele precisa verificar se o disco foi criptografado corretamente. Ele envia o comando cryptfs cryptocomplete para vold. vold retorna 0 se a criptografia foi concluída, -1 em caso de erro interno ou -2 se a criptografia não foi concluída. O vold determina isso procurando a flag CRYPTO_ENCRYPTION_IN_PROGRESS nos metadados de criptografia. Se ela estiver definida, o processo de criptografia será interrompido e não haverá dados utilizáveis no dispositivo. Se vold retornar um erro, a interface precisará mostrar uma mensagem para o usuário reiniciar e redefinir o dispositivo para a configuração original e fornecer um botão para que ele faça isso.

  4. Descriptografar dados com senha

    Quando cryptfs cryptocomplete for bem-sucedido, o framework vai mostrar uma interface que solicita a senha do disco. A IU verifica a senha enviando o comando cryptfs checkpw para vold. Se a senha estiver correta, o que é determinado pela ativação e desativação do /data descriptografado em um local temporário, vold vai salvar o nome do dispositivo de bloco descriptografado na propriedade ro.crypto.fs_crypto_blkdev e retornar o status 0 para a interface. Se a senha estiver incorreta, ela retornará -1 para a interface.

  5. Framework de interrupção

    A interface mostra um gráfico de inicialização de criptografia e chama vold com o comando cryptfs restart. vold define a propriedade vold.decrypt como trigger_reset_main, o que faz com que init.rc execute class_reset main. Isso interrompe todos os serviços na classe principal, o que permite que o /data do tmpfs seja desmontado.

  6. Montar /data

    Em seguida, vold monta a partição /data real descriptografada e prepara a nova partição, que pode nunca ter sido preparada se ela tivesse sido criptografada com a opção de exclusão permanente, que não é compatível com a primeira versão. Ele define a propriedade vold.post_fs_data_done como 0 e, em seguida, vold.decrypt como trigger_post_fs_data. Isso faz com que init.rc execute os comandos post-fs-data. Ele cria todos os diretórios ou links necessários e define vold.post_fs_data_done como 1. Quando vold encontra o 1 nessa propriedade, ele define a propriedade vold.decrypt como trigger_restart_framework. Isso faz com que init.rc inicie serviços na classe main novamente e também inicie serviços na classe late_start pela primeira vez desde a inicialização.

  7. Iniciar o framework completo

    Agora, o framework inicializa todos os 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 com problemas por alguns motivos. O dispositivo começa com a série normal de etapas para inicialização:

  1. Detectar dispositivo criptografado com uma senha
  2. Montar tmpfs
  3. Iniciar framework para solicitar senha

No entanto, depois que o framework é aberto, o dispositivo pode encontrar alguns erros:

  • A senha corresponde, mas não consegue descriptografar os dados
  • O usuário digita a senha incorreta 30 vezes

Se esses erros não forem resolvidos, solicite que o usuário faça a exclusão permanente para a configuração original:

Se vold detectar um erro durante o processo de criptografia e se nenhum dado tiver sido destruído ainda e o framework estiver ativo, vold definirá a propriedade vold.encrypt_progress como error_not_encrypted. A interface solicita que o usuário reinicie e informa que o processo de criptografia nunca foi iniciado. Se o erro ocorrer depois que o framework for removido, mas antes que a interface da barra de progresso esteja ativa, vold vai reinicializar o sistema. Se a reinicialização falhar, ela vai definir vold.encrypt_progress como error_shutting_down e retornar -1. No entanto, não haverá nada para detectar o erro. Isso não é esperado.

Se vold detectar um erro durante o processo de criptografia, ele definirá vold.encrypt_progress como error_partially_encrypted e retornará -1. A interface vai mostrar uma mensagem informando que a criptografia falhou e fornecer um botão para o usuário redefinir o dispositivo para a configuração original.

Armazenar a chave criptografada

A chave criptografada é armazenada nos metadados de criptografia. O suporte de hardware é implementado usando o recurso de assinatura do ambiente de execução confiável (TEE). Anteriormente, criptografávamos a chave mestra com uma chave gerada aplicando o scrypt à senha do usuário e ao sal armazenado. Para tornar a chave resistente a ataques fora da caixa, estendemos esse algoritmo assinando a chave resultante com uma chave TEE armazenada. A assinatura resultante é transformada em uma chave de comprimento adequado por mais uma aplicação de scrypt. Essa chave é usada para criptografar e descriptografar a chave mestra. Para armazenar essa chave:

  1. Gere uma chave de criptografia de disco (DEK, na sigla em inglês) aleatória de 16 bytes e um sal de 16 bytes.
  2. Aplique o scrypt à senha do usuário e o sal para produzir a chave intermediária 1 de 32 bytes (IK1).
  3. Preencha o IK1 com zero bytes para o tamanho da chave privada vinculada a hardware (HBK). Especificamente, preenchemos como: 00 || IK1 || 00..00; um byte zero, 32 IK1 bytes, 223 zero bytes.
  4. Assine o IK1 preenchido com HBK para produzir o IK2 de 256 bytes.
  5. Aplique o scrypt ao IK2 e um sal (o mesmo sal da etapa 2) para produzir o IK3 de 32 bytes.
  6. Usar os primeiros 16 bytes de IK3 como KEK e os últimos 16 bytes como IV.
  7. Criptografe a DEK com AES_CBC, com a chave KEK e o vetor de inicialização IV.

Mudar a senha

Quando um usuário decide mudar ou remover a senha nas configurações, a interface 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 entre si definindo propriedades. Confira uma lista de propriedades disponíveis para criptografia.

Propriedades do Vold

Propriedade Descrição
vold.decrypt trigger_encryption Criptografar a unidade sem senha.
vold.decrypt trigger_default_encryption Verifique se a unidade está criptografada sem senha. Se estiver, descriptografe e monte-o. Caso contrário, defina vold.decrypt como trigger_restart_min_framework.
vold.decrypt trigger_reset_main Definido pelo vold para encerrar a IU que solicita a senha do disco.
vold.decrypt trigger_post_fs_data Foi definido pelo vold para preparar /data com os diretórios necessários, entre outros.
vold.decrypt trigger_restart_framework Definido por vold para iniciar o framework real e todos os serviços.
vold.decrypt trigger_shutdown_framework O Vold é definido para encerrar o framework completo e iniciar a criptografia.
vold.decrypt trigger_restart_min_framework Definido por vold para iniciar a interface da barra de progresso para criptografia ou solicitar a senha, dependendo do valor de ro.crypto.state.
vold.encrypt_progress Quando o framework for iniciado, se essa propriedade estiver definida, entre no modo de interface da barra de progresso.
vold.encrypt_progress 0 to 100 A interface da barra de progresso precisa exibir o valor percentual definido.
vold.encrypt_progress error_partially_encrypted A interface da barra de progresso precisa mostrar uma mensagem informando que a criptografia falhou e oferecer ao usuário a opção de redefinir o dispositivo para a configuração original.
vold.encrypt_progress error_reboot_failed A interface da barra de progresso vai mostrar uma mensagem informando que a criptografia foi concluída e oferecer ao usuário um botão para reinicializar o dispositivo. Esse erro não deve acontecer.
vold.encrypt_progress error_not_encrypted A interface da barra de progresso precisa 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 da barra de progresso não está em execução, então não está claro quem responde a esse erro. E isso nunca deveria acontecer de qualquer maneira.
vold.post_fs_data_done 0 Defina por vold antes de definir vold.decrypt como trigger_post_fs_data.
vold.post_fs_data_done 1 Defina por init.rc ou init.rc logo após concluir a tarefa post-fs-data.

propriedades init

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 informar que este sistema está sendo executado com um /data ro.crypto.state encrypted não criptografado. Definido por init para informar que este sistema está sendo executado com um /data criptografado.

ro.crypto.fs_type
ro.crypto.fs_real_blkdev
ro.crypto.fs_mnt_point
ro.crypto.fs_options
ro.crypto.fs_flags

Essas cinco propriedades são definidas por init quando ele tenta ativar /data com parâmetros transmitidos de init.rc. O vold usa esses dados para configurar o mapeamento de criptografia.
ro.crypto.tmpfs_options Definido por init.rc com as opções que o init precisa usar ao ativar o sistema de arquivos /data tmpfs.

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