Chiavi con wrapping hardware

Come la maggior parte del software di crittografia di dischi e file, la crittografia dello spazio di archiviazione di Android si basa tradizionalmente sulla presenza delle chiavi di crittografia non elaborate nella memoria di sistema perché la crittografia possa essere eseguita. Anche quando la crittografia viene eseguita da hardware dedicato anziché da software, in genere il software deve comunque e gestire le chiavi di crittografia non elaborate.

In genere questo non viene considerato come un problema perché le chiavi non sono presenti durante un attacco offline, che è il principale tipo di attacco che la crittografia ha lo scopo di proteggere. Tuttavia, c'è la volontà di fornire una protezione maggiore contro altri tipi di attacchi, come gli attacchi di cold boot e gli attacchi online in cui un malintenzionato potrebbe essere in grado di rubare la memoria del sistema senza compromettere completamente il dispositivo.

Per risolvere il problema, Android 11 ha introdotto il supporto per le chiavi con wrapping hardware, per le quali è presente il supporto hardware. Le chiavi con wrapping hardware sono chiavi di archiviazione note solo in forma non elaborata hardware dedicato; il software vede e utilizza queste chiavi solo nelle (criptato). Questo hardware deve essere in grado di generare e importare chiavi di archiviazione, eseguire il wrapping delle chiavi di archiviazione in forme effimere e a lungo termine, derivare sottochiavi, programmare direttamente una sottochiave in un motore di crittografia in linea e restituire una sottochiave separata al software.

Nota:un inline crypto Engine (oppure inline) l'hardware di crittografia) si riferisce all'hardware che cripta/decripta i dati mentre mentre è in viaggio verso/dal dispositivo di archiviazione. Di solito si tratta di un controllore host UFS o eMMC che implementa le estensioni di crittografia definite dalla corrispondente specifica JEDEC.

Design

Questa sezione illustra il design della funzionalità delle chiavi con wrapping hardware, incluso il supporto hardware necessario. Questa discussione si concentra sulla crittografia basata su file (FBE), ma gli si applica ai metadati crittografia.

Un modo per evitare di dover utilizzare le chiavi di crittografia non elaborate nella memoria di sistema è conservarle solo nelle keyslot di un motore di crittografia in linea. Tuttavia, questo approccio presenta alcuni problemi:

  • Il numero di chiavi di crittografia potrebbe superare il numero di slot delle chiavi.
  • I motori di crittografia in linea possono essere utilizzati solo per criptare/decriptare blocchi completi di su disco. Tuttavia, nel caso della crittografia lato client, il software deve comunque essere in grado di eseguire altri compiti di crittografia, come la crittografia dei nomi file e l'ottenimento degli identificatori delle chiavi. Il software avrebbe comunque bisogno di accedere alle chiavi FBE non elaborate per svolgere questo altro lavoro.

Per evitare questi problemi, le chiavi di archiviazione vengono invece trasformate in chiavi con wrapping hardware, che possono essere scompattate e utilizzate solo da hardware dedicato. In questo modo è possibile supportare un numero illimitato di chiavi. Nella Inoltre, la gerarchia delle chiavi è stata modificata e spostata parzialmente in questo hardware, che consente di restituire al software una sottochiave per attività che non possono utilizzare di crittografia in linea.

Gerarchia delle chiavi

Le chiavi possono essere derivate da altre chiavi utilizzando una KDF (funzione di derivazione delle chiavi) come HKDF, generando una gerarchia di chiavi.

Il seguente diagramma illustra una tipica gerarchia delle chiavi per FBE quando le chiavi con wrapping hardware non vengono utilizzate:

Gerarchia delle chiavi FBE (standard)
Figura 1. Gerarchia delle chiavi FBE (standard)

La chiave della classe FBE è la chiave di crittografia non elaborata che Android passa al kernel Linux per sbloccare un determinato insieme di directory criptate, ad esempio lo spazio di archiviazione con crittografia delle credenziali per un determinato utente Android. (Nel kernel, è denominata chiave master fscrypt.) Da questa chiave, il kernel ricava le seguenti sottochiavi:

  • L'identificatore della chiave. Non viene utilizzato per la crittografia, ma è un valore utilizzata per identificare la chiave con cui un determinato file o directory viene protette.
  • La chiave di crittografia dei contenuti del file
  • La chiave di crittografia dei nomi file

Al contrario, il seguente diagramma mostra la gerarchia delle chiavi per la crittografia lato client quando vengono utilizzate chiavi con wrapping hardware:

Gerarchia delle chiavi FBE (con chiave con wrapping hardware)
Figura 2. Gerarchia delle chiavi FBE (con chiave con wrapping hardware)

Rispetto al caso precedente, è stato aggiunto un livello aggiuntivo alla chiave della gerarchia di contenuti e la chiave di crittografia dei contenuti dei file è stata riposizionata. La radice rappresenta ancora la chiave che Android passa a Linux per sbloccare crittografate con le directory crittografate. Tuttavia, ora la chiave è in forma con wrapping temporaneo e per poter essere utilizzato, deve essere passato all'hardware dedicato. Questo hardware deve implementare due interfacce che prendono una chiave con wrapping temporaneo:

  • Un'interfaccia per ricavare inline_encryption_key e direttamente programmalo in un keyslot del motore di crittografia in linea. In questo modo, i contenuti dei file possono essere criptati/decriptati senza che il software abbia accesso alla chiave non elaborata. Nei kernel comuni di Android, questa interfaccia corrisponde all'operazione blk_crypto_ll_ops::keyslot_program, che deve essere implementata dal driver di archiviazione.
  • Un'interfaccia per dedurre e restituire sw_secret ("software secret", chiamata anche "raw secret" in alcuni casi), che è la chiave che Linux utilizza per dedurre le sottochiavi per tutto ciò che non è la crittografia dei contenuti dei file. Nei kernel comuni di Android, questa interfaccia corrisponde all'operazione blk_crypto_ll_ops::derive_sw_secret, che deve essere implementata dal driver di archiviazione.

per ricavare inline_encryption_key e sw_secret dal chiave di archiviazione non elaborata, l'hardware deve utilizzare un KDF con una crittografia efficace. Questo KDF deve seguire le best practice di crittografia; deve avere un'efficacia di sicurezza di almeno 256 bit, ovvero sufficiente per qualsiasi algoritmo utilizzato in un secondo momento. Deve inoltre utilizzare un parametro stringa di etichette, contesto e informazioni specifiche dell'app distinte, ricavando ciascun tipo di sottochiave per garantire che le sottochiavi risultanti sono crittograficamente isolati, ovvero la conoscenza di una di esse non rivela alcuna e l'altro. Lo stretching della chiave non è obbligatorio, poiché la chiave di archiviazione non elaborata è già in modo uniforme casuale.

Tecnicamente, è possibile utilizzare qualsiasi KDF che soddisfi i requisiti di sicurezza. Tuttavia, a scopo di test, è necessario implementare nuovamente lo stesso KDF in di eseguire il test. Attualmente, un KDF è stato esaminato e implementato; puoi trovare nel codice sorgente di vts_kernel_encryption_test. È consigliabile che l'hardware utilizzi questo KDF, che utilizza NIST SP 800-108 "KDF in Counter Mode" con AES-256-CMAC come PRF. Tieni presente che, per essere compatibili, parti dell'algoritmo devono essere identiche, inclusa la scelta dei contesti KDF ed etichette per ogni sottochiave.

Wrapping di chiavi

Per soddisfare gli obiettivi di sicurezza delle chiavi con wrapping hardware, sono definiti due tipi di wrapping delle chiavi:

  • Wrapping temporaneo: l'hardware cripta la chiave non elaborata utilizzando una chiave generata in modo casuale a ogni avvio e non esposta direttamente all'esterno dell'hardware.
  • Wrapping a lungo termine: l'hardware cripta la chiave non elaborata utilizzando una chiave permanente univoca integrata nell'hardware che non è direttamente esposta all'esterno dell'hardware.

Tutte le chiavi passate al kernel Linux per sbloccare lo spazio di archiviazione con wrapping temporaneo. In questo modo, se un malintenzionato riesce a estrarre una chiave in uso dalla memoria di sistema, questa non sarà utilizzabile non solo quando il dispositivo è spento, ma anche dopo un riavvio.

Allo stesso tempo, Android deve comunque poter archiviare una versione criptata delle chiavi sul disco, in modo da poter essere sbloccate in primo luogo. Le chiavi predefinite funzioneranno per questo scopo. Tuttavia, è preferibile che le chiavi non elaborate non siano mai presenti nella memoria di sistema in modo che non possano mai essere estratte per essere utilizzate al di fuori del dispositivo, anche se estratte all'avvio. Per questo motivo, è stato definito il concetto di wrapping a lungo termine.

Per supportare la gestione delle chiavi con wrapping in questi due modi diversi, l'hardware deve implementare le seguenti interfacce:

  • Interfacce per generare e importare chiavi di archiviazione, restituendole in formato con wrapping a lungo termine. Si accede a queste interfacce indirettamente KeyMint e corrispondono al tag KeyMint TAG_STORAGE_KEY. La funzionalità "genera" viene utilizzata da vold per generare nuove chiavi di archiviazione da utilizzare su Android, mentre la funzionalità "importa" viene utilizzata da vts_kernel_encryption_test per importare le chiavi di test.
  • Un'interfaccia per convertire una chiave di archiviazione con wrapping a lungo termine in una chiave di archiviazione con wrapping temporaneo. Corrisponde alla convertStorageKeyToEphemeral metodo KeyMint. Questo metodo viene utilizzato sia da vold che da vts_kernel_encryption_test per sbloccare lo spazio di archiviazione.

L'algoritmo del wrapping delle chiavi è un dettaglio di implementazione, ma deve utilizzare una AEAD potente come AES-256-GCM con IV casuali.

Modifiche software necessarie

AOSP dispone già di un framework di base per il supporto delle chiavi con wrapping hardware. Sono inclusi il supporto nei componenti dello spazio utente come vold, nonché il supporto del kernel Linux in blk-crypto, fscrypt e dm-default-key.

Tuttavia, sono necessarie alcune modifiche specifiche per l'implementazione.

Modifiche a KeyMint

L'implementazione KeyMint del dispositivo deve essere modificata per supportare TAG_STORAGE_KEY e implementare Metodo convertStorageKeyToEphemeral.

In Keymaster, è stato utilizzato exportKey anziché convertStorageKeyToEphemeral.

Modifiche al kernel Linux

Il driver del kernel Linux per il motore di crittografia in linea del dispositivo deve essere modificato per supportare le chiavi con wrapping hardware.

Per i kernel android14 e versioni successive, imposta BLK_CRYPTO_KEY_TYPE_HW_WRAPPED in blk_crypto_profile::key_types_supported, fai in modo che blk_crypto_ll_ops::keyslot_program e blk_crypto_ll_ops::keyslot_evict supportino la programmazione/l'espulsione delle chiavi con wrapping hardware e implementa blk_crypto_ll_ops::derive_sw_secret.

Per i kernel android12 e android13, imposta BLK_CRYPTO_FEATURE_WRAPPED_KEYS in blk_keyslot_manager::features, fai in modo che blk_ksm_ll_ops::keyslot_program e blk_ksm_ll_ops::keyslot_evict supportino la programmazione/l'espulsione delle chiavi con wrapping hardware e implementa blk_ksm_ll_ops::derive_raw_secret.

Per i kernel android11, imposta BLK_CRYPTO_FEATURE_WRAPPED_KEYS in keyslot_manager::features, crea keyslot_mgmt_ll_ops::keyslot_program e keyslot_mgmt_ll_ops::keyslot_evict, supporta la programmazione/l'espulsione delle chiavi con wrapping hardware e implementa keyslot_mgmt_ll_ops::derive_raw_secret.

Test

Sebbene la crittografia con chiavi con wrapping hardware sia più difficile da testare rispetto alla crittografia con chiavi standard, è comunque possibile eseguire il test importando una chiave di test e reimplementando la derivazione della chiave eseguita dall'hardware. Questo è implementato in vts_kernel_encryption_test. Per eseguire questo test, esegui:

atest -v vts_kernel_encryption_test

Leggi il log del test e verifica che gli scenari di test delle chiavi con wrapping hardware (ad esempio FBEPolicyTest.TestAesInlineCryptOptimizedHwWrappedKeyPolicy e DmDefaultKeyTest.TestHwWrappedKey) non siano stati ignorati a causa del mancato rilevamento del supporto per le chiavi con wrapping hardware, poiché in questo caso i risultati del test sono ancora "passati".

Attivare i tasti

Una volta che il supporto delle chiavi con wrapping hardware del dispositivo funziona correttamente, puoi apportare le seguenti modifiche al file fstab del dispositivo per fare in modo che Android lo utilizzi per la crittografia FBE e dei metadati:

  • FBE: aggiungi il flag wrappedkey_v0 al parammetro fileencryption. Ad esempio, utilizza fileencryption=::inlinecrypt_optimized+wrappedkey_v0. Per ulteriori dettagli, consulta FBE documentazione.
  • Crittografia dei metadati: aggiungi il flag wrappedkey_v0 al parametro metadata_encryption. Ad esempio, utilizza metadata_encryption=:wrappedkey_v0. Per ulteriori dettagli, consulta metadati documentazione sulla crittografia.