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 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 na versão 4.4, mas o Android 5.0 introduziu estes novos recursos:

  • Criptografia rápida criada, que criptografa apenas 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 forceencrypt fstab para criptografar na primeira inicialização.
  • Adicionado suporte para padrões e criptografia sem senha.
  • Adicionado armazenamento da chave de criptografia com suporte de hardware usando o recurso de assinatura do Trusted Execution Environment (TEE) (como em um TrustZone). Consulte Armazenando a chave criptografada para obter mais detalhes.

Cuidado: os dispositivos atualizados para o Android 5.0 e depois criptografados podem retornar ao 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 ao 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 à biblioteca OpenSSL. Você deve usar 128 bits ou mais para a chave (sendo 256 opcional).

Nota: 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 o hash dela 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 é criptografada e armazenada novamente. (ou seja, alterações de PIN/senha/padrão do usuário NÃO causam nova criptografia 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 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 do usuário (IU), a estrutura deve ser iniciada e a estrutura requer /data para ser 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 mudar do sistema de arquivos temporário para o sistema de arquivos /data verdadeiro, 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 após iniciar.
  • main : Desligue e reinicie após inserir a senha do disco.
  • late_start : Não inicia até que /data tenha sido 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 um sinalizador SVC_DISABLED . Os serviços interrompidos não respondem a class_start .

Fluxos

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

  • Criptografe um dispositivo anteriormente não 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:
    • Iniciando um dispositivo criptografado sem senha: Inicializando 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 que possui uma senha definida.

Além desses fluxos, o dispositivo também pode falhar ao criptografar /data . Cada um dos fluxos é explicado detalhadamente a seguir.

Criptografe um novo dispositivo com forceencrypt

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

  1. Detecte sistema de arquivos não criptografado com sinalizador forceencrypt

    /data não é criptografado, mas precisa ser porque forceencrypt exige isso. Desmontar /data .

  2. Comece a criptografar /data

    vold.decrypt = "trigger_encryption" aciona init.rc , o que fará com que vold criptografe /data sem senha. (Nada está definido porque este deve ser um novo dispositivo.)

  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. Traga a estrutura para mostrar o progresso

    Como o dispositivo praticamente não tem dados para criptografar, a barra de progresso muitas vezes não aparece porque a criptografia acontece muito rapidamente. Consulte Criptografar um dispositivo existente para obter mais detalhes sobre a IU de progresso.

  5. Quando /data estiver criptografado, desative a estrutura

    vold define vold.decrypt para trigger_default_encryption que inicia o serviço defaultcrypto . (Isso inicia o fluxo abaixo para montar dados de usuário criptografados padrão.) trigger_default_encryption verifica o tipo de criptografia para ver se /data está criptografado com ou sem senha. Como os dispositivos Android 5.0 são criptografados na primeira inicialização, não deve haver nenhuma senha definida; portanto, descriptografamos e montamos /data .

  6. Montar /data

    init então monta /data em um RAMDisk tmpfs usando parâmetros obtidos em ro.crypto.tmpfs_options , que são definidos em init.rc .

  7. Iniciar estrutura

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

Criptografar um dispositivo existente

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

Este processo é iniciado pelo usuário e é conhecido como “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 para os padrões de fábrica e todos os dados serão perdidos.

Para ativar a criptografia local, vold inicia um loop para ler cada setor do dispositivo de bloco real e depois gravá-lo no dispositivo de bloco criptográfico. vold verifica se um setor está em uso antes de lê-lo e gravá-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 on nonencrypted init para continuar a inicialização.

  1. Verifique a senha

    A UI chama vold com o comando cryptfs enablecrypto inplace onde passwd é a senha da tela de bloqueio do usuário.

  2. Retire a estrutura

    vold verifica se há erros, retorna -1 se não puder criptografar e imprime um motivo no log. Se puder criptografar, ele define a propriedade vold.decrypt como trigger_shutdown_framework . Isso faz com que init.rc interrompa os serviços nas classes late_start e main .

  3. Crie um rodapé criptográfico
  4. Crie um arquivo de localização atual
  5. Reinício
  6. Detectar arquivo de localização atual
  7. Comece a criptografar /data

    vold então configura o mapeamento criptográfico, que cria um dispositivo de bloco criptográfico virtual que mapeia para o dispositivo de bloco real, mas criptografa cada setor à medida que é escrito e descriptografa cada setor à medida que é lido. vold então cria e grava os metadados criptográficos.

  8. Enquanto estiver criptografando, monte o 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

  9. Traga a estrutura para mostrar o progresso

    trigger_restart_min_framework faz com que init.rc inicie a classe main de serviços. Quando a estrutura vê que vold.encrypt_progress está definido como 0, ela abre a UI 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é criptográfico

    Quando /data é criptografado com sucesso, vold limpa o sinalizador ENCRYPTION_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 definirá a propriedade vold.encrypt_progress como error_reboot_failed e a UI deverá exibir uma mensagem solicitando ao usuário que pressione um botão para reinicializar. Não se espera que isso aconteça.

Iniciando um dispositivo criptografado com criptografia padrão

Isto é 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 nenhuma senha definida e, portanto, este é o estado de criptografia padrão .

  1. Detecte /data criptografados sem senha

    Detecte que o dispositivo Android está criptografado porque /data não pode ser montado e um dos sinalizadores encryptable ou forceencrypt está definido.

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

  2. Descriptografar /dados

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

  3. Montar /dados

    vold então monta a partição /data real descriptografada e então 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 seus comandos post-fs-data . Eles criarão todos os diretórios ou links necessários e definirão vold.post_fs_data_done como 1.

    Depois que vold vê 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 estrutura

    Agora a estrutura inicializa todos os seus serviços usando /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 que possui uma senha definida. A senha do dispositivo pode ser um PIN, padrão ou senha.

  1. Detecte dispositivo criptografado com uma senha

    Detecte que o dispositivo Android está criptografado porque o sinalizador 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 passados ​​de init.rc . vold usa estas propriedades para configurar o mapeamento criptográfico:

    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 ASCII de 8 dígitos precedido por 0x)
  3. Iniciar estrutura para solicitar senha

    A estrutura é inicializada e vê 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 obter a senha do usuário.

    Primeiro, porém, ele precisa ter certeza de que o disco foi criptografado corretamente. Ele envia o comando cryptfs cryptocomplete para vold . 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 sinalizador 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 UI deverá exibir uma mensagem ao usuário para reiniciar e redefinir o dispositivo de fábrica, e fornecer ao usuário um botão para pressionar para fazer isso.

  4. Descriptografar dados com senha

    Depois que cryptfs cryptocomplete for bem-sucedido, a estrutura exibirá uma IU solicitando 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 montagem bem-sucedida do /data descriptografado em um local temporário e depois desmontado), vold salva o nome do dispositivo de bloco descriptografado na propriedade ro.crypto.fs_crypto_blkdev e retorna o status 0 para a UI . Se a senha estiver incorreta, ela retornará -1 para a UI.

  5. Parar estrutura

    A IU exibe um gráfico de inicialização criptografada e depois 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 da classe principal, o que permite que tmpfs /data sejam desmontados.

  6. Montar /data

    vold então monta a partição /data real 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 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 seus comandos post-fs-data . Eles criarão quaisquer diretórios ou links necessários e, em seguida, definirão vold.post_fs_data_done como 1. Assim que vold vir o 1 nessa propriedade, ele definirá 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 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:

  1. Detecte dispositivo criptografado com uma senha
  2. Montar tmpfs
  3. Iniciar estrutura para solicitar senha

Mas após a abertura do framework, o dispositivo pode encontrar alguns erros:

  • A senha corresponde, mas não pode descriptografar os dados
  • O usuário digita a 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 após a desmontagem da estrutura, mas antes da interface da barra de progresso ser ativada, vold reinicializará o sistema. Se a reinicialização falhar, ele define vold.encrypt_progress como error_shutting_down e retorna -1; mas não haverá nada para capturar 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 IU deve então exibir uma mensagem informando que a criptografia falhou e fornecer um botão para o usuário redefinir o dispositivo para os padrões de fábrica.

Armazenando a chave criptografada

A chave criptografada é armazenada nos metadados criptográficos. O suporte de hardware é implementado usando o recurso de assinatura do Trusted Execution Environment (TEE). Anteriormente, criptografamos a chave mestra com uma chave gerada pela aplicação de scrypt à senha do usuário e ao salt armazenado. Para tornar a chave resiliente contra ataques externos, estendemos esse algoritmo assinando a chave resultante com uma chave TEE armazenada. A assinatura resultante é então transformada em uma chave de comprimento apropriado por mais uma aplicação de criptografia. Essa chave é então usada para criptografar e descriptografar a chave mestra. Para armazenar esta chave:

  1. Gere uma chave de criptografia de disco (DEK) aleatória de 16 bytes e salt de 16 bytes.
  2. Aplique scrypt à senha do usuário e ao salt para produzir a chave intermediária 1 de 32 bytes (IK1).
  3. Preencha IK1 com zero bytes no 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 IK1 preenchido com HBK para produzir IK2 de 256 bytes.
  5. Aplique scrypt ao IK2 e salt (o mesmo salt 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 DEK com AES_CBC, com chave KEK e vetor de inicialização IV.

Alterando 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 entre si definindo propriedades. Aqui está uma lista de propriedades disponíveis para criptografia.

Propriedades de Vold

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 estiver, 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 UI 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 o framework real e todos os serviços.
vold.decrypt trigger_shutdown_framework Definido por vold para desligar toda a estrutura para iniciar a criptografia.
vold.decrypt trigger_restart_min_framework Definido por vold para iniciar a UI da barra de progresso para criptografia ou solicitação de senha, dependendo do valor de ro.crypto.state .
vold.encrypt_progress Quando a estrutura for inicializada, se esta propriedade estiver definida, entre no modo UI da barra de progresso.
vold.encrypt_progress 0 to 100 A interface 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 para a configuração original.
vold.encrypt_progress error_reboot_failed A interface da barra de progresso deve exibir uma mensagem informando que a criptografia foi concluída e fornecer ao usuário um botão para reiniciar o dispositivo. Não se espera que esse erro aconteça.
vold.encrypt_progress error_not_encrypted A interface do usuário 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 reinicializar o sistema.
vold.encrypt_progress error_shutting_down A IU 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 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 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 pelo init para dizer que este sistema está sendo executado com um /data ro.crypto.state encrypted não criptografado. Definido pelo init para dizer que este sistema está sendo executado com /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 pelo init quando ele tenta montar /data com parâmetros passados ​​de init.rc . vold usa isso 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 iniciais

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