O Google tem o compromisso de promover a igualdade racial para as comunidades negras. Saiba como.

Chaves embrulhadas em hardware

Como a maioria dos softwares de criptografia de disco e arquivo, a criptografia de armazenamento do Android tradicionalmente depende das chaves de criptografia brutas presentes na memória do sistema para que a criptografia possa ser realizada. Mesmo quando a criptografia é realizada por hardware dedicado em vez de software, o software geralmente ainda precisa gerenciar as chaves de criptografia brutas.

Isso tradicionalmente não é visto como um problema porque as chaves não estarão presentes durante um ataque offline, que é o principal tipo de ataque contra o qual a criptografia de armazenamento se destina a proteger. No entanto, há um desejo de proporcionar maior proteção contra outros tipos de ataques, como ataques de arranque a frio e ataques on-line onde um invasor pode ser capaz de vazar a memória do sistema sem comprometer totalmente o dispositivo.

Para resolver este problema, Android 11 introduziu o suporte para chaves envolto em hardware, onde o suporte de hardware está presente. Chaves embrulhadas por hardware são chaves de armazenamento que só são conhecidas na forma bruta por hardware dedicado; o software só vê e funciona com essas chaves na forma embrulhada (criptografada). Esse hardware deve ser capaz de gerar e importar chaves de armazenamento, agrupar chaves de armazenamento em formas efêmeras e de longo prazo, derivar subchaves, programar diretamente uma subchave em um mecanismo de criptografia embutido e retornar uma subchave separada para o software.

Nota: Um motor em linha cripto (ou hardware criptografia in-line) refere-se ao hardware que criptografa / descodifica dados ao mesmo tempo que está no seu caminho para / a partir do dispositivo de armazenamento. Normalmente, este é um controlador de host UFS ou eMMC que implementa as extensões de criptografia definidas pela especificação JEDEC correspondente.

Projeto

Esta seção apresenta o design do recurso de chaves incorporadas por hardware, incluindo o suporte de hardware necessário para ele. Esta discussão centra-se em criptografia baseada em arquivo (FBE), mas a solução se aplica a criptografia de metadados também.

Uma maneira de evitar a necessidade de chaves de criptografia brutas na memória do sistema seria mantê-las apenas nos slots de um mecanismo de criptografia embutido. No entanto, essa abordagem apresenta alguns problemas:

  • O número de chaves de criptografia pode exceder o número de slots de chaves.
  • Os mecanismos de criptografia embutidos só podem ser usados ​​para criptografar / descriptografar blocos completos de dados no disco. No entanto, no caso do FBE, o software ainda precisa ser capaz de fazer outro trabalho criptográfico, como criptografar nomes de arquivos e derivar identificadores de chave. O software ainda precisaria de acesso às chaves FBE brutas para fazer esse outro trabalho.

Para evitar esses problemas, as chaves de armazenamento em vez disso são feitas em chaves envolto em hardware, que só podem ser dobrados e utilizados por hardware dedicado. Isso permite que um número ilimitado de chaves seja suportado. Além disso, a hierarquia de chaves é modificada e parcialmente movida para este hardware, o que permite que uma subchave seja retornada ao software para tarefas que não podem usar um mecanismo de criptografia embutido.

Hierarquia de chave

As chaves podem ser derivadas a partir de outras chaves utilizando uma (função de derivação de chave) KDF tais como HKDF , resultando em uma hierarquia de chave.

O diagrama seguinte ilustra uma hierarquia de chave típico para FBE quando as chaves envolto por hardware não são usados:

Hierarquia de chave FBE (padrão)
Figura 1. hierarquia chave FBE (padrão)

A chave de classe FBE é a chave de criptografia bruta que o Android passa para o kernel do Linux para desbloquear um determinado conjunto de diretórios criptografados, como o armazenamento criptografado por credencial para um determinado usuário Android. (No kernel, esta chave é chamado de chave mestra fscrypt.) A partir desta chave, o kernel deriva as seguintes subchaves:

  • O identificador da chave. Isso não é usado para criptografia, mas sim um valor usado para identificar a chave com a qual um determinado arquivo ou diretório está protegido.
  • A chave de criptografia do conteúdo do arquivo
  • A chave de criptografia de nomes de arquivo

Em contraste, o diagrama a seguir descreve a hierarquia de chaves para o FBE quando as chaves embrulhadas por hardware são usadas:

Hierarquia de chave FBE (com chave envolvida por hardware)
Figura hierarquia de chave 2. FBE (com chave envolvido por hardware)

Em comparação com o caso anterior, um nível adicional foi adicionado à hierarquia de chaves e a chave de criptografia do conteúdo do arquivo foi realocada. O nó raiz ainda representa a chave que o Android passa para o Linux para desbloquear um conjunto de diretórios criptografados. No entanto, agora essa chave está em um formato embrulhado efêmero e, para ser usada, deve ser passada para um hardware dedicado. Este hardware deve implementar duas interfaces que usam uma chave encapsulada de forma efêmera:

  • Uma interface para derivar inline_encryption_key e directamente programá-lo em um keyslot do motor de criptografia embutida. Isso permite que o conteúdo do arquivo seja criptografado / descriptografado sem que o software tenha acesso à chave bruta. Nos kernels comuns do Android, esta interface corresponde ao blk_ksm_ll_ops::keyslot_program operação, que devem ser implementadas pelo driver de armazenamento.
  • Uma interface de derivar e retorno sw_secret ( "segredo software" - também chamado de o "segredo cru" em alguns lugares), que é a chave que o Linux usa para derivar as subchaves para tudo que não seja criptografia conteúdo do arquivo. Nos kernels comuns do Android, esta interface corresponde ao blk_ksm_ll_ops::derive_raw_secret operação, que devem ser implementadas pelo driver de armazenamento.

Derivar inline_encryption_key e sw_secret da chave armazenamento bruto, o hardware deve usar um KDF criptograficamente forte. Este KDF deve seguir as melhores práticas de criptografia; deve ter um nível de segurança de pelo menos 256 bits, ou seja, o suficiente para qualquer algoritmo usado posteriormente. Ele também deve usar um rótulo distinto, contexto e / ou string de informação específica do aplicativo ao derivar cada tipo de subchave, a fim de garantir que as subchaves resultantes sejam criptograficamente isoladas, ou seja, o conhecimento de uma delas não revela nenhuma outra. O alongamento de chaves não é necessário, pois a chave de armazenamento bruta já é uma chave uniformemente aleatória.

Tecnicamente, qualquer KDF que atenda aos requisitos de segurança pode ser usado. No entanto, para fins de teste, é necessário reimplementar o mesmo KDF no código de teste. Atualmente, um KDF foi revisado e implementado; ele pode ser encontrado no código fonte para vts_kernel_encryption_test . Recomenda-se que o uso de hardware este KDF, que usa NIST SP 800-108 "KDF no Counter Mode" com AES-256-CMAC como a PRF. Observe que, para ser compatível, todas as partes do algoritmo devem ser idênticas, incluindo a escolha de contextos KDF e rótulos para cada subchave.

Envolvimento de chave

Para atender aos objetivos de segurança de chaves incorporadas por hardware, dois tipos de combinação de chaves são definidos:

  • Embrulho efémera: o hardware codifica a chave em bruto utilizando uma chave que é gerado de forma aleatória em cada inicialização e não está directamente exposta do lado de fora do hardware.
  • Envolvimento de longo prazo: o hardware criptografa a chave crua usando uma chave única, persistente embutido no hardware que não está directamente exposta fora do hardware.

Todas as chaves passadas para o kernel Linux para desbloquear o armazenamento são embrulhadas efêmeras. Isso garante que, se um invasor conseguir extrair uma chave em uso da memória do sistema, essa chave ficará inutilizável não apenas fora do dispositivo, mas também no dispositivo após uma reinicialização.

Ao mesmo tempo, o Android ainda precisa ser capaz de armazenar uma versão criptografada das chaves no disco para que possam ser desbloqueadas em primeiro lugar. As chaves brutas funcionariam para esse propósito. No entanto, é desejável que as chaves brutas nunca estejam presentes na memória do sistema, de modo que elas nunca possam ser extraídas para serem usadas fora do dispositivo, mesmo se extraídas no momento da inicialização. Por esta razão, o conceito de embalagem de longo prazo é definido.

Para oferecer suporte ao gerenciamento de chaves agrupadas dessas duas maneiras diferentes, o hardware deve implementar as seguintes interfaces:

  • Interfaces para gerar e importar chaves de armazenamento, retornando-as na forma embalada de longo prazo. Essas interfaces são acessadas indiretamente através KeyMint, e eles correspondem ao TAG_STORAGE_KEY tag KeyMint. A capacidade "gerar" é usado por vold para gerar novas chaves de armazenamento para uso de Android, enquanto a capacidade "importação" é utilizado por vts_kernel_encryption_test de chaves de teste de importação.
  • Uma interface para converter uma chave de armazenamento encapsulada de longo prazo em uma chave de armazenamento encapsulada efêmeras. Isto corresponde ao convertStorageKeyToEphemeral método KeyMint. Este método é utilizado por ambos vold e vts_kernel_encryption_test , a fim de desbloquear o armazenamento.

O algoritmo de agrupamento de chave é um detalhe de implementação, mas deve usar um AEAD forte, como AES-256-GCM com IVs aleatórios.

Mudanças de software necessárias

O AOSP já tem uma estrutura básica para suportar chaves embrulhadas por hardware. Isto inclui o apoio nos componentes do espaço do usuário, tais como vold , bem como o suporte do kernel Linux em preto-cripto, fscrypt e dm-default-chave.

No entanto, algumas mudanças específicas de implementação são necessárias.

Mudanças de KeyMint

Implementação KeyMint do dispositivo deve ser modificado para suporte TAG_STORAGE_KEY e implementar o convertStorageKeyToEphemeral método.

Em Keymaster, exportKey foi usado em vez de convertStorageKeyToEphemeral .

Mudanças no kernel Linux

O motorista do Linux kernel para motor de criptografia em linha do dispositivo deve ser modificado para definir BLK_CRYPTO_FEATURE_WRAPPED_KEYS , fazer a keyslot_program() e keyslot_evict() operações de suporte de programação / expulsar chaves envolto em hardware, e implementar o derive_raw_secret() operação.

Testando

Embora a criptografia com chaves incorporadas por hardware seja mais difícil de testar do que a criptografia com chaves padrão, ainda é possível testar importando uma chave de teste e reimplementando a derivação de chave que o hardware faz. Isso é implementado em vts_kernel_encryption_test . Para executar este teste, execute:

atest -v vts_kernel_encryption_test

Leia o registro de teste e verificar se os casos de teste principais envolto em hardware (por exemplo FBEPolicyTest.TestAesInlineCryptOptimizedHwWrappedKeyPolicy e DmDefaultKeyTest.TestHwWrappedKey ) não foram ignorados devido ao suporte para teclas envolto em hardware não ser detectados, como os resultados do teste ainda será "passado" no Aquele caso.

Possibilitando

Uma vez que o suporte chave envolto em hardware do dispositivo está funcionando corretamente, você pode fazer as seguintes alterações do dispositivo fstab arquivo para fazer uso Android lo para FBE e criptografia de metadados:

  • FBE: adicionar o wrappedkey_v0 bandeira ao fileencryption parâmetro. Por exemplo, usar fileencryption=::inlinecrypt_optimized+wrappedkey_v0 . Para mais detalhes, consulte a documentação FBE .
  • Criptografia de metadados: adicionar o wrappedkey_v0 bandeira ao metadata_encryption parâmetro. Por exemplo, o uso metadata_encryption=:wrappedkey_v0 . Para mais detalhes, consulte a documentação criptografia metadados .