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 4.4, mas o Android 5.0 apresentou estes novos recursos:

  • Criação de criptografia rápida, que criptografa apenas 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 oferecem suporte à criptografia rápida.
  • Adicionamos a flag fstab forceencrypt para criptografar na primeira inicialização.
  • Inclusão de suporte a padrões e criptografia sem senha.
  • Foi adicionado armazenamento com suporte de hardware da chave de criptografia usando o recurso de assinatura do ambiente de execução confiável (TEE), como em uma TrustZone. Consulte Como armazenar a chave criptografada para mais detalhes.

Atenção:os dispositivos que foram atualizados para o Android 5.0 e criptografados podem ser retornados a um estado não criptografado com a redefinição de dados de fábrica. 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 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 cadeamento de blocos de cifras (CBC) e ESSIV:SHA256. A chave mestra é criptografada com AES de 128 bits por chamadas à biblioteca OpenSSL. É necessário usar 128 bits ou mais para a chave (256 é opcional).

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 a converte em 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 mestra.

A senha padrão definida no projeto do Android Open Source cryptfs.cpp pode ser encontrada aqui.

Quando o usuário define o PIN/senha ou a senha no dispositivo, apenas a chave de 128 bits é criptografada novamente 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 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, 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 /data, /data não pode ser montado. No entanto, para mostrar qualquer interface do usuário (IU), o framework precisa ser iniciado e requer que /data seja 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 real, 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 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 a class_start.

Fluxos

Há quatro fluxos para um dispositivo criptografado. Um dispositivo é criptografado apenas uma vez e depois 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 existente: criptografia iniciada pelo usuário (Android K e versões anteriores).
  • Inicialize um dispositivo criptografado:
    • Inicialização de um dispositivo criptografado sem senha: inicialização de um dispositivo criptografado que não tem uma senha definida (relevante para dispositivos com o 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

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

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

    /data não está criptografado, mas precisa ser porque 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. Nenhuma está definida porque este é 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 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, 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 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 de início

    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 in-place, vold inicia um loop para ler cada setor do dispositivo de bloco real e, em seguida, gravar no dispositivo de bloco criptográfico. 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 init on nonencrypted 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. Montar tmpfs durante a criptografia

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

  9. Mostrar o framework para mostrar o progresso

    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. Atualize o rodapé de criptografia quando /data for criptografado

    Quando /data é criptografado, vold limpa 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 a 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 deve 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, 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 sobre o dispositivo de bloco 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. Eles criam os diretórios ou links necessários e definem 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. Framework de início

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

Iniciar um dispositivo criptografado sem 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

    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 é codificado 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 a senha

    O framework é iniciado e verifica 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 estiver definido, o processo de criptografia foi interrompido e não há 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 interface verifica a senha enviando o comando cryptfs checkpw para vold. Se a senha estiver correta (determinada pela montagem bem-sucedida do /data descriptografado em um local temporário e depois a desmontagem), 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

    O vold monta a partição /data real descriptografada e prepara a nova partição, que pode nunca ter sido preparada se ela foi criptografada com a opção de limpeza, que não tem suporte na 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 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.

  7. Iniciar 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 um dispositivo criptografado com uma senha
  2. Ativar o tmpfs
  3. Iniciar o framework para solicitar a 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 errada 30 vezes

Se esses erros não forem resolvidos, solicite ao usuário que faça uma redefinição de fábrica:

Se vold detectar um erro durante o processo de criptografia e se nenhum dado tiver sido destruído 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 alerta que o processo de criptografia não foi iniciado. Se o erro ocorrer depois que o framework for removido, mas antes que a IU da barra de progresso seja exibida, o vold reinicia 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 precisa 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 ao sal para produzir a chave intermediária de 32 bytes 1 (IK1).
  3. Preencha IK1 com zero bytes para o tamanho da chave privada vinculada ao hardware (HBK). Especificamente, preenchemos como: 00 || IK1 || 00..00; um byte zero, 32 bytes IK1, 223 bytes zero.
  4. Assine o IK1 com HBK para produzir o IK2 de 256 bytes.
  5. Aplique o scrypt em IK2 e no sal (o mesmo sal da etapa 2) para produzir IK3 de 32 bytes.
  6. Use 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 de 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. Caso contrário, defina vold.decrypt como trigger_restart_min_framework.
vold.decrypt trigger_reset_main Foi 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 pelo 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 pelo vold para iniciar a interface da barra de progresso para criptografia ou pedir 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 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 oferecer ao usuário a opção de redefinir o dispositivo para as configurações de fábrica.
vold.encrypt_progress error_reboot_failed A IU da barra de progresso precisa mostrar uma mensagem informando que a criptografia foi concluída e oferecer 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, 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. Portanto, não está claro quem responde a esse erro. E isso não deveria acontecer.
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 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 o sistema está em execução com um /data ro.crypto.state encrypted não criptografado. Definido por init para informar que o sistema está em execução 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 precisa usar ao montar o sistema de arquivos /data do 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