Criptografia de metadados

O Android 7.0 e versões mais recentes oferecem suporte à criptografia baseada em arquivos (FBE, na sigla em inglês). A FBE permite que arquivos diferentes sejam criptografados com chaves diferentes que podem ser desbloqueadas de forma independente. Elas são usadas para criptografar o conteúdo e os nomes dos arquivos. Quando a FBE é usada, outras informações, como layouts de diretório, tamanhos de arquivo, permissões e horários de criação/modificação, não são criptografadas. Coletivamente, essas outras informações são conhecidas como metadados do sistema de arquivos.

O Android 9 introduziu suporte para criptografia de metadados. Com a criptografia de metadados, uma única chave presente no momento da inicialização criptografa qualquer conteúdo que não esteja criptografado pela FBE. Essa chave é protegida pelo KeyMint (antigo Keymaster), que, por sua vez, é protegido pela Inicialização verificada.

A criptografia de metadados está sempre ativada no armazenamento adotável quando a FBE está ativada. A criptografia de metadados também pode ser ativada no armazenamento interno. Os dispositivos lançados com o Android 11 ou versões mais recentes precisam ter a criptografia de metadados ativada no armazenamento interno.

Implementação no armazenamento interno

É possível configurar a criptografia de metadados no armazenamento interno de novos dispositivos configurando o sistema de arquivos metadata, mudando a sequência de inicialização e ativando a criptografia de metadados no arquivo fstab do dispositivo.

Pré-requisitos

A criptografia de metadados só pode ser configurada quando a partição de dados é formatada pela primeira vez. Por isso, esse recurso é apenas para dispositivos novos, e não é algo que uma OTA possa mudar.

A criptografia de metadados exige que o módulo dm-default-key esteja ativado no seu kernel. No Android 11 e versões mais recentes, o dm-default-key é compatível com os kernels comuns do Android, versão 4.14 e mais recentes. Essa versão do dm-default-key usa uma estrutura de criptografia independente de hardware e fornecedor chamada blk-crypto.

Para ativar o dm-default-key, use:

CONFIG_BLK_INLINE_ENCRYPTION=y
CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y
CONFIG_DM_DEFAULT_KEY=y

O dm-default-key usa hardware de criptografia inline (hardware que criptografa/descriptografa dados enquanto eles estão a caminho do/para o dispositivo de armazenamento) quando disponível. Se você não estiver usando hardware de criptografia inline, também será necessário ativar um fallback para a API de criptografia do kernel:

CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y

Quando não estiver usando hardware de criptografia inline, ative também qualquer aceleração disponível baseada em CPU, conforme recomendado na documentação do FBE.

No Android 10 e versões anteriores, dm-default-key não era compatível com o kernel comum do Android. Portanto, cabia aos fornecedores implementar dm-default-key.

Configurar o sistema de arquivos de metadados

Como nada na partição de dados do usuário pode ser lido até que a chave de criptografia de metadados esteja presente, a tabela de partição precisa separar uma partição chamada partição de metadados para armazenar os blobs do KeyMint que protegem essa chave. A partição de metadados precisa ter 16 MB.

fstab.hardware precisa incluir uma entrada para o sistema de arquivos de metadados que reside nessa partição, montando-a em /metadata, incluindo a flag formattable para garantir que ela seja formatada na inicialização. O sistema de arquivos f2fs não funciona em partições menores. Recomendamos usar o ext4. Exemplo:

/dev/block/bootdevice/by-name/metadata              /metadata          ext4        noatime,nosuid,nodev,discard                          wait,check,formattable

Para garantir que o ponto de montagem /metadata exista, adicione a seguinte linha a BoardConfig-common.mk:

BOARD_USES_METADATA_PARTITION := true

Mudanças na sequência de inicialização

Quando a criptografia de metadados é usada, o vold precisa estar em execução antes que o /data seja ativado. Para garantir que ele seja iniciado cedo o suficiente, adicione a seguinte estrofe a init.hardware.rc:

# We need vold early for metadata encryption
on early-fs
    start vold

O KeyMint precisa estar em execução e pronto antes que a inicialização tente montar /data.

init.hardware.rc já precisa conter uma instrução mount_all que monta o próprio /data na estrofe on late-fs. Antes dessa linha, adicione a diretiva para executar o serviço wait_for_keymaster:

on late-fs
    
    # Wait for Keymaster
    exec_start wait_for_keymaster

    # Mount RW partitions which need run fsck
    mount_all /vendor/etc/fstab.${ro.boot.hardware.platform} --late

Ativar a criptografia de metadados

Por fim, adicione keydirectory=/metadata/vold/metadata_encryption à coluna fs_mgr_flags da entrada fstab para userdata. Por exemplo, uma linha completa do fstab pode ter esta aparência:

/dev/block/bootdevice/by-name/userdata              /data              f2fs        noatime,nosuid,nodev,discard,inlinecrypt latemount,wait,check,fileencryption=aes-256-xts:aes-256-cts:inlinecrypt_optimized,keydirectory=/metadata/vold/metadata_encryption,quota,formattable

Por padrão, o algoritmo de criptografia de metadados no armazenamento interno é AES-256-XTS. Para modificar essa configuração, defina a opção metadata_encryption, também na coluna fs_mgr_flags:

  • Em dispositivos sem aceleração AES, a criptografia Adiantum pode ser ativada definindo metadata_encryption=adiantum.
  • Em dispositivos que oferecem suporte a chaves encapsuladas por hardware, a chave de criptografia de metadados pode ser encapsulada por hardware definindo metadata_encryption=aes-256-xts:wrappedkey_v0 (ou metadata_encryption=:wrappedkey_v0, já que aes-256-xts é o algoritmo padrão).

Como a interface do kernel para dm-default-key mudou no Android 11, também é necessário definir o valor correto para PRODUCT_SHIPPING_API_LEVEL em device.mk. Por exemplo, se o dispositivo for lançado com o Android 11 (API de nível 30), device.mk deverá conter:

PRODUCT_SHIPPING_API_LEVEL := 30

Você também pode definir a seguinte propriedade do sistema para forçar o uso da nova API dm-default-key, independente do nível da API de frete:

PRODUCT_PROPERTY_OVERRIDES += \
    ro.crypto.dm_default_key.options_format.version=2

Validação

Para verificar se a criptografia de metadados está ativada e funcionando corretamente, execute os testes descritos abaixo. Também fique atento aos problemas comuns descritos abaixo.

Testes

Comece executando o seguinte comando para verificar se a criptografia de metadados está ativada no armazenamento interno:

adb root
adb shell dmctl table userdata

A resposta precisa ser semelhante a esta:

Targets in the device-mapper table for userdata:
0-4194304: default-key, aes-xts-plain64 - 0 252:2 0 3 allow_discards sector_size:4096 iv_large_sectors

Se você substituiu as configurações de criptografia padrão definindo a opção metadata_encryption no fstab do dispositivo, a saída será um pouco diferente da acima. Por exemplo, se você ativou a criptografia Adiantum, o terceiro campo será xchacha12,aes-adiantum-plain64 em vez de aes-xts-plain64.

Em seguida, execute vts_kernel_encryption_test para verificar a correção da criptografia de metadados e do FBE:

atest vts_kernel_encryption_test

ou:

vts-tradefed run vts -m vts_kernel_encryption_test

Problemas comuns

Durante a chamada para mount_all, que monta a partição /data criptografada com metadados, init executa a ferramenta vdc. A ferramenta vdc se conecta a vold por binder para configurar o dispositivo criptografado com metadados e ativar a partição. Durante essa chamada, init fica bloqueado, e as tentativas de ler ou definir propriedades de init são bloqueadas até que mount_all seja concluído. Se, nesta etapa, qualquer parte do trabalho de vold for bloqueada direta ou indiretamente ao ler ou definir uma propriedade, ocorrerá um deadlock. É importante garantir que vold possa concluir o trabalho de leitura das chaves, interação com o KeyMint e montagem do diretório de dados sem interagir mais com init.

Se o KeyMint não estiver totalmente iniciado quando mount_all for executado, ele não responderá a vold até ler determinadas propriedades de init, resultando exatamente no deadlock descrito. Colocar exec_start wait_for_keymaster acima da invocação mount_all relevante, conforme definido, garante que o KeyMint esteja totalmente em execução antecipadamente e, assim, evita esse impasse.

Configuração no armazenamento adotável

Desde o Android 9, uma forma de criptografia de metadados é sempre ativada no armazenamento adaptável sempre que a FBE é ativada, mesmo quando a criptografia de metadados não está ativada no armazenamento interno.

No AOSP, há duas implementações de criptografia de metadados no armazenamento adotável: uma descontinuada baseada em dm-crypt e uma mais recente baseada em dm-default-key. Para garantir que a implementação correta seja selecionada para seu dispositivo, defina o valor correto para PRODUCT_SHIPPING_API_LEVEL em device.mk. Por exemplo, se o dispositivo for lançado com o Android 11 (API de nível 30), device.mk vai conter:

PRODUCT_SHIPPING_API_LEVEL := 30

Você também pode definir as seguintes propriedades do sistema para forçar o uso do novo método de criptografia de metadados de volume (e a nova versão padrão da política de FBE), independente do nível da API de envio:

PRODUCT_PROPERTY_OVERRIDES += \
    ro.crypto.volume.metadata.method=dm-default-key \
    ro.crypto.dm_default_key.options_format.version=2 \
    ro.crypto.volume.options=::v2

Método atual

Em dispositivos lançados com o Android 11 ou versões mais recentes, a criptografia de metadados no armazenamento adaptável usa o módulo do kernel dm-default-key, assim como no armazenamento interno. Consulte os pré-requisitos acima para saber quais opções de configuração do kernel ativar. O hardware de criptografia inline que funciona no armazenamento interno do dispositivo pode não estar disponível no armazenamento adaptável. Assim, CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y pode ser necessário.

Por padrão, o método de criptografia de metadados de volume dm-default-key usa o algoritmo de criptografia AES-256-XTS com setores criptográficos de 4.096 bytes. O algoritmo pode ser substituído definindo a propriedade do sistema ro.crypto.volume.metadata.encryption. O valor dessa propriedade tem a mesma sintaxe da opção metadata_encryption fstab descrita acima. Por exemplo, em dispositivos sem aceleração AES, a criptografia Adiantum pode ser ativada definindo ro.crypto.volume.metadata.encryption=adiantum.

Método legado

Em dispositivos lançados com o Android 10 e versões anteriores, a criptografia de metadados no armazenamento adotável usa o módulo do kernel dm-crypt em vez de dm-default-key:

CONFIG_DM_CRYPT=y

Ao contrário do método dm-default-key, o método dm-crypt faz com que o conteúdo do arquivo seja criptografado duas vezes: uma com uma chave FBE e outra com a chave de criptografia de metadados. Essa criptografia dupla reduz o desempenho e não é necessária para alcançar as metas de segurança da criptografia de metadados, já que o Android garante que as chaves FBE sejam pelo menos tão difíceis de comprometer quanto a chave de criptografia de metadados. Os fornecedores podem fazer personalizações no kernel para evitar a criptografia dupla, principalmente implementando a opção allow_encrypt_override, que o Android transmite para dm-crypt quando a propriedade do sistema ro.crypto.allow_encrypt_override é definida como true. Essas personalizações não são compatíveis com o kernel comum do Android.

Por padrão, o método de criptografia de metadados de volume dm-crypt usa o algoritmo de criptografia AES-128-CBC com ESSIV e setores criptográficos de 512 bytes. Isso pode ser substituído definindo as seguintes propriedades do sistema (que também são usadas para FDE):

  • ro.crypto.fde_algorithm seleciona o algoritmo de criptografia de metadados. As opções são aes-128-cbc e adiantum. O Adiantum só pode ser usado se o dispositivo não tiver aceleração AES.
  • ro.crypto.fde_sector_size seleciona o tamanho do setor de criptomoedas. As opções são 512, 1024, 2048 e 4096. Para a criptografia Adiantum, use 4096.