Criptografia de disco completo

A criptografia de disco completo é o processo de codificar 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 gravados em 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 4.4, mas o Android 5.0 trouxe estes novos recursos:

  • Criamos a criptografia rápida, que criptografa apenas os blocos usados na partição de dados para evitar que a primeira inicialização demore muito. No momento, apenas os sistemas de arquivos ext4 e f2fs são compatíveis com a criptografia rápida.
  • Adicionamos a flag fstab forceencrypt para criptografar na primeira inicialização.
  • Agora é possível usar padrões e criptografia sem senha.
  • Adição do armazenamento da chave de criptografia com suporte de hardware usando a capacidade de assinatura do ambiente de execução confiável (TEE), como em uma TrustZone. Consulte Armazenar a chave criptografada para mais detalhes.

Atenção:os dispositivos atualizados para o Android 5.0 e criptografados podem ser retornados a um estado não criptografado com uma redefinição de fábrica. Não é possível retornar ao estado não criptografado os novos dispositivos Android 5.0 criptografados na primeira inicialização.

Como funciona a criptografia de disco completo do Android

A criptografia de disco completo do Android se baseia no dm-crypt, que é um recurso do kernel que funciona na camada de 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 encadeamento de blocos de cifra (CBC) e ESSIV:SHA256. A chave mestra é criptografada com AES de 128 bits por chamadas à biblioteca OpenSSL. Use 128 bits ou mais para a chave (256 é opcional).

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

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 a faz hash com uma senha padrão e um salt 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 principal.

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 a senha no dispositivo, apenas a chave de 128 bits é recriptografada e armazenada. Por exemplo, as mudanças de PIN/senha/padrão do usuário NÃO causam a recriptografia dos dados do usuário. Um dispositivo gerenciado pode estar sujeito a restrições de PIN, padrão ou senha.

A criptografia é gerenciada por init e vold. O init chama o vold, e o vold define propriedades para acionar eventos na inicialização. Outras partes do sistema também analisam as propriedades para realizar tarefas como informar o status, pedir uma senha ou solicitar uma redefinição de fábrica em caso de erro fatal. Para invocar recursos de criptografia no vold, o sistema usa a ferramenta de linha de comando comandos cryptfs do vdc: checkpw, restart, enablecrypto, changepw, cryptocomplete, verifypw, setfield, getfield, mountdefaultencrypted, getpwtype, getpw e clearpw.

Para criptografar, descriptografar ou limpar /data, /data não pode estar montado. No entanto, para mostrar qualquer interface do usuário (UI), o framework precisa ser iniciado e exige /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 limpeza de dados conforme necessário. Isso impõe a limitação de que, para alternar do sistema de arquivos temporário para o sistema de arquivos /data verdadeiro, 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 desligue depois de iniciar.
  • main: desligue e reinicie depois de inserir a senha do disco.
  • late_start: não é iniciado até que /data seja descriptografado e montado.

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

Flows

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:
    • Criptografar um novo dispositivo com forceencrypt: criptografia obrigatória na primeira inicialização (a partir do Android L).
    • Criptografar um dispositivo atual: criptografia iniciada pelo usuário (Android K e versões anteriores).
  • Inicializar 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).
    • Iniciar um dispositivo criptografado com uma senha: inicializar um dispositivo criptografado que tem uma senha definida.

Além desses fluxos, o dispositivo também pode não criptografar /data. Cada um dos fluxos é explicado em detalhes abaixo.

Criptografar um novo dispositivo com forceencrypt

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

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

    /data não está criptografado, mas precisa estar porque forceencrypt exige isso. Desconectar /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 está definido porque este deve ser um dispositivo novo.)

  3. Montar tmpfs

    vold monta um tmpfs /data (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 framework para exibir o progresso

    Como o dispositivo praticamente não tem dados para criptografar, a barra de progresso não aparece com frequência porque a criptografia acontece muito rápido. Consulte Criptografar um dispositivo atual 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. O trigger_default_encryption verifica o tipo de criptografia para saber se o /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 uma senha definida. Portanto, descriptografamos e montamos /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. Framework inicial

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

Criptografar um dispositivo

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

Esse processo é iniciado pelo usuário e é chamado de "criptografia in situ" no código. Quando um usuário seleciona criptografar um dispositivo, a interface 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 for desligado antes de terminar a criptografia, os dados do arquivo vão ficar 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 in situ, o vold inicia um loop para ler cada setor do dispositivo de bloco real e gravar no dispositivo de bloco criptografado. 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 com 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 o framework

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

  3. Criar um rodapé criptografado
  4. Criar um arquivo de rastreamento
  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 mapeia o dispositivo de bloco real, mas criptografa cada setor à medida que é gravado e descriptografa cada setor à medida que é lido. Em seguida, vold cria e grava os metadados de criptografia.

  8. Enquanto ele criptografa, monte o 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

  9. Mostrar framework para exibir o progresso

    trigger_restart_min_framework faz com que init.rc inicie a classe de serviços main. Quando o framework percebe 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 for criptografado, atualize o rodapé de criptografia

    Quando /data é criptografado, vold limpa a flag ENCRYPTION_IN_PROGRESS nos metadados.

    Quando o dispositivo é desbloqueado, a senha é usada para criptografar a chave principal, e o rodapé criptografado é 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 a criptografia padrão

É isso 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 há uma senha definida. Portanto, esse é o estado de criptografia padrão.

  1. Detectar /data criptografados sem senha

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

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

  2. Descriptografar /data

    Cria o dispositivo dm-crypt no dispositivo de bloco para que ele esteja pronto para uso.

  3. Montar /data

    Em seguida, 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 o init.rc execute os comandos post-fs-data. Eles criam os diretórios ou links necessários e definem vold.post_fs_data_done como 1.

    Quando vold vê o valor 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. Framework inicial

    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 é o que acontece quando você inicializa um dispositivo criptografado com uma senha definida. A senha do dispositivo pode ser um PIN, um padrão ou uma senha.

  1. Detectar um dispositivo criptografado com uma senha

    Detectar que 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 essas 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á inicializando em um disco tmpfs /data e precisa receber a senha do usuário.

    No entanto, primeiro é preciso verificar se o disco foi criptografado corretamente. Ele envia o comando cryptfs cryptocomplete para vold. vold retorna 0 se a criptografia for concluída com êxito, -1 em caso de erro interno ou -2 se a criptografia não for concluída com êxito. vold determina isso ao procurar nos metadados de criptografia a flag CRYPTO_ENCRYPTION_IN_PROGRESS. Se estiver definido, o processo de criptografia foi interrompido, e não há dados utilizáveis no dispositivo. Se vold retornar um erro, a interface vai mostrar uma mensagem para o usuário reiniciar e redefinir o dispositivo para a configuração original, além de dar a ele um botão para fazer isso.

  4. Descriptografar dados com senha

    Quando cryptfs cryptocomplete for concluído, o framework vai mostrar uma interface pedindo a senha do disco. A interface verifica a senha enviando o comando cryptfs checkpw para vold. Se a senha estiver correta (o que é determinado ao montar o /data descriptografado em um local temporário e desmontá-lo), o 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 vai retornar -1 para a interface.

  5. Estrutura de parada

    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, permitindo que o tmpfs /data seja desmontado.

  6. Montar /data

    Em seguida, o vold monta a partição /data real descriptografada e prepara a nova partição (que talvez nunca tenha sido preparada se foi criptografada com a opção de exclusão, que não é compatível com a primeira versã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. Eles criam os diretórios ou links necessários e definem vold.post_fs_data_done como 1. Quando o vold vê 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 a estrutura completa

    Agora, a estrutura 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 inicia com a série normal de etapas para inicializar:

  1. Detectar um dispositivo criptografado com uma senha
  2. Ativar tmpfs
  3. Iniciar o framework para pedir a senha

Mas, depois que a estrutura é aberta, o dispositivo pode encontrar alguns erros:

  • A senha corresponde, mas não é possível descriptografar os dados
  • O usuário digita a senha errada 30 vezes

Se esses erros não forem resolvidos, peça ao usuário para fazer uma redefinição de fábrica:

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 pede que o usuário reinicie o sistema e alerta que o processo de criptografia nunca foi iniciado. Se o erro ocorrer depois que o framework for desativado, mas antes da exibição da interface da barra de progresso, o vold reiniciará 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. Isso não deve acontecer.

Se vold detectar um erro durante o processo de criptografia, ele vai definir vold.encrypt_progress como error_partially_encrypted e retornar -1. Em seguida, a interface vai mostrar uma mensagem informando que a criptografia falhou e vai fornecer um botão para que o usuário redefina 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 a capacidade de assinatura do ambiente de execução confiável (TEE). Antes, criptografávamos a chave principal com uma chave gerada pela aplicação de scrypt à senha do usuário e ao sal 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 é 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) de 16 bytes e um salt de 16 bytes aleatórios.
  2. Aplique o scrypt à senha do usuário e ao salt para gerar uma chave intermediária de 32 bytes 1 (IK1).
  3. Adicione bytes zero ao IK1 até o tamanho da chave privada vinculada ao hardware (HBK, na sigla em inglês). Especificamente, fazemos o padding da seguinte forma: 00 || IK1 || 00..00; um byte zero, 32 bytes IK1, 223 bytes zero.
  4. Assine o IK1 com padding usando HBK para produzir IK2 de 256 bytes.
  5. Aplique scrypt ao IK2 e ao sal (o mesmo da etapa 2) para produzir o IK3 de 32 bytes.
  6. Use os primeiros 16 bytes de IK3 como KEK e os últimos 16 bytes como IV.
  7. Criptografa a DEK com AES_CBC, com a chave KEK e o vetor de inicialização IV.

Mudar a senha

Quando um usuário escolhe 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 definindo propriedades. Confira abaixo uma lista de propriedades disponíveis para criptografia.

Propriedades de volume

Propriedade Descrição
vold.decrypt trigger_encryption Criptografe a unidade sem senha.
vold.decrypt trigger_default_encryption Verifique se o disco está criptografado sem senha. Se for, descriptografe e monte. Caso contrário, defina vold.decrypt como trigger_restart_min_framework.
vold.decrypt trigger_reset_main Definido pelo vold para desligar a interface que pede a senha do disco.
vold.decrypt trigger_post_fs_data Definido por vold para preparar /data com os diretórios necessários etc.
vold.decrypt trigger_restart_framework Definido pelo vold para iniciar a estrutura real e todos os serviços.
vold.decrypt trigger_shutdown_framework Definido pelo vold para desligar a estrutura completa e iniciar a criptografia.
vold.decrypt trigger_restart_min_framework Definido pelo vold para iniciar a interface da barra de progresso para criptografia ou solicitar senha, dependendo do valor de ro.crypto.state.
vold.encrypt_progress Quando o framework é 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 mostrar 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 dar ao usuário a opção de fazer uma redefinição de fábrica no dispositivo.
vold.encrypt_progress error_reboot_failed A interface da barra de progresso precisa mostrar uma mensagem informando que a criptografia foi concluída e dar ao usuário um botão para reiniciar o dispositivo. Esse erro não deve acontecer.
vold.encrypt_progress error_not_encrypted A interface da barra de progresso precisa mostrar uma mensagem informando que ocorreu um erro, que nenhum dado foi criptografado ou perdido e dar 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.
vold.post_fs_data_done 0 Definido por vold pouco 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 a conclusão da 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 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 montar /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 deve usar ao ativar 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