Chiavi avvolte nell'hardware

Come la maggior parte dei software di crittografia di dischi e file, la crittografia dell'archiviazione di Android si basa tradizionalmente sulle chiavi di crittografia non elaborate presenti nella memoria di sistema in modo che la crittografia possa essere eseguita. Anche quando la crittografia viene eseguita da hardware dedicato anziché da software, il software generalmente deve comunque gestire le chiavi di crittografia non elaborate.

Questo tradizionalmente non è visto come un problema perché le chiavi non saranno presenti durante un attacco offline, che è il principale tipo di attacco da cui la crittografia dell'archiviazione dovrebbe proteggere. Tuttavia, vi è il desiderio di fornire una maggiore protezione contro altri tipi di attacchi, come gli attacchi di avvio a freddo e gli attacchi online in cui un utente malintenzionato potrebbe essere in grado di perdere memoria di sistema senza compromettere completamente il dispositivo.

Per risolvere questo problema, Android 11 ha introdotto il supporto per le chiavi con wrapping hardware, dove è presente il supporto hardware. Le chiavi con wrapping hardware sono chiavi di archiviazione note solo in forma non elaborata all'hardware dedicato; il software vede e funziona solo con queste chiavi in ​​forma protetta (crittografata). Questo hardware deve essere in grado di generare e importare chiavi di archiviazione, avvolgere le chiavi di archiviazione in forme effimere ea lungo termine, derivare sottochiavi, programmare direttamente una sottochiave in un motore crittografico in linea e restituire una sottochiave separata al software.

Nota : un motore di crittografia in linea (o hardware di crittografia in linea ) si riferisce all'hardware che crittografa/decrittografa i dati mentre è in viaggio verso/dal dispositivo di archiviazione. Di solito si tratta di un controller host UFS o eMMC che implementa le estensioni crittografiche definite dalla corrispondente specifica JEDEC.

Progetto

Questa sezione presenta la struttura della funzionalità delle chiavi con wrapping hardware, incluso il supporto hardware necessario per essa. Questa discussione si concentra sulla crittografia basata su file (FBE), ma la soluzione si applica anche alla crittografia dei metadati .

Un modo per evitare di aver bisogno delle chiavi di crittografia non elaborate nella memoria di sistema sarebbe conservarle solo negli slot delle chiavi di un motore di crittografia in linea. Tuttavia, questo approccio incontra alcuni problemi:

  • Il numero di chiavi di crittografia può superare il numero di keyslot.
  • I motori di crittografia in linea possono essere utilizzati solo per crittografare/decrittografare interi blocchi di dati su disco. Tuttavia, nel caso di FBE, il software deve ancora essere in grado di eseguire altre attività crittografiche come la crittografia dei nomi di file e la derivazione di identificatori di chiavi. Il software avrebbe comunque bisogno di accedere alle chiavi FBE non elaborate per eseguire quest'altro lavoro.

Per evitare questi problemi, le chiavi di archiviazione vengono invece trasformate in chiavi con wrapping hardware , che possono essere scartate e utilizzate solo da hardware dedicato. Ciò consente di supportare un numero illimitato di chiavi. Inoltre, la gerarchia delle chiavi viene modificata e parzialmente spostata su questo hardware, il che consente di restituire una sottochiave al software per attività che non possono utilizzare un motore di crittografia in linea.

Gerarchia chiave

Le chiavi possono essere derivate da altre chiavi utilizzando una KDF (funzione di derivazione della chiave) come HKDF , risultando in una gerarchia di chiavi .

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

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

La chiave di classe FBE è la chiave di crittografia non elaborata che Android passa al kernel Linux per sbloccare un particolare set di directory crittografate, come l'archivio crittografato con credenziali per un particolare utente Android. (Nel kernel, questa chiave è chiamata chiave master fscrypt .) Da questa chiave, il kernel deriva le seguenti sottochiavi:

  • L'identificatore chiave. Questo non viene utilizzato per la crittografia, ma piuttosto è un valore utilizzato per identificare la chiave con cui è protetto un particolare file o directory.
  • La chiave di crittografia del contenuto del file
  • La chiave di crittografia dei nomi di file

Al contrario, il diagramma seguente illustra la gerarchia delle chiavi per FBE 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 ulteriore livello alla gerarchia delle chiavi e la chiave di crittografia del contenuto del file è stata riposizionata. Il nodo radice rappresenta ancora la chiave che Android passa a Linux per sbloccare un insieme di directory crittografate. Tuttavia, ora quella chiave è in una forma effimera e per essere utilizzata deve essere passata all'hardware dedicato. Questo hardware deve implementare due interfacce che accettano una chiave con wrapping temporaneo:

  • Un'interfaccia per derivare inline_encryption_key e programmarla direttamente in un keyslot del motore crittografico inline. Ciò consente di crittografare/decrittografare i contenuti dei file 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 derivare e restituire sw_secret ("software secret" -- chiamato anche "raw secret" in alcuni punti), che è la chiave che Linux usa per derivare le sottochiavi per qualsiasi cosa diversa dalla crittografia del contenuto 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 derivare inline_encryption_key e sw_secret dalla chiave di archiviazione non elaborata, l'hardware deve utilizzare un KDF crittograficamente avanzato. Questo KDF deve seguire le migliori pratiche di crittografia; deve avere un livello di sicurezza di almeno 256 bit, cioè sufficiente per qualsiasi algoritmo utilizzato in seguito. Deve inoltre utilizzare un'etichetta distinta, un contesto e/o una stringa di informazioni specifiche dell'applicazione durante la derivazione di ogni tipo di sottochiave per garantire che le sottochiavi risultanti siano crittograficamente isolate, ovvero la conoscenza di una di esse non ne riveli altre. L'estensione della chiave non è necessaria, poiché la chiave di archiviazione non elaborata è già una chiave uniformemente casuale.

Tecnicamente, potrebbe essere utilizzato qualsiasi KDF che soddisfi i requisiti di sicurezza. Tuttavia, a scopo di test, è necessario reimplementare lo stesso KDF nel codice di test. Attualmente, un KDF è stato rivisto e implementato; può essere trovato nel codice sorgente per vts_kernel_encryption_test . Si consiglia all'hardware di utilizzare questo KDF, che utilizza NIST SP 800-108 "KDF in Counter Mode" con AES-256-CMAC come PRF. Si noti che per essere compatibili, tutte le parti dell'algoritmo devono essere identiche, inclusa la scelta dei contesti KDF e delle etichette per ciascuna sottochiave.

Avvolgimento chiave

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

  • Wrapping effimero : l'hardware crittografa la chiave grezza utilizzando una chiave che viene generata in modo casuale ad ogni avvio e non viene esposta direttamente all'esterno dell'hardware.
  • Wrapping a lungo termine : l'hardware crittografa la chiave grezza utilizzando una chiave univoca e persistente incorporata nell'hardware che non è esposta direttamente all'esterno dell'hardware.

Tutte le chiavi passate al kernel Linux per sbloccare l'archiviazione sono temporaneamente impacchettate. Ciò garantisce che se un utente malintenzionato è in grado di estrarre una chiave in uso dalla memoria di sistema, tale chiave sarà inutilizzabile non solo fuori dal dispositivo, ma anche sul dispositivo dopo un riavvio.

Allo stesso tempo, Android deve ancora essere in grado di memorizzare una versione crittografata delle chiavi su disco in modo che possano essere sbloccate in primo luogo. Le chiavi grezze funzionerebbero per questo scopo. Tuttavia, è auspicabile che le chiavi grezze non siano mai presenti nella memoria di sistema in modo che non possano mai essere estratte per essere utilizzate fuori dal dispositivo, anche se estratte al momento dell'avvio. Per questo motivo viene definito il concetto di avvolgimento a lungo termine.

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

  • Interfacce per generare e importare chiavi di archiviazione, restituendole in formato avvolto a lungo termine. Queste interfacce sono accessibili indirettamente tramite KeyMint e corrispondono al tag TAG_STORAGE_KEY TAG_STORAGE_KEY. L'abilità "genera" viene utilizzata da vold per generare nuove chiavi di archiviazione per l'utilizzo da parte di Android, mentre l'abilità "import" 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. Questo corrisponde al metodo convertStorageKeyToEphemeral KeyMint. Questo metodo viene utilizzato sia da vold che da vts_kernel_encryption_test per sbloccare l'archiviazione.

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

Sono necessarie modifiche al software

AOSP dispone già di un framework di base per supportare le chiavi con wrapping hardware. Ciò include il supporto nei componenti dello spazio utente come vold , così come il supporto del kernel Linux in blk-crypto , fscrypt e dm-default-key .

Tuttavia, sono necessarie alcune modifiche specifiche dell'implementazione.

KeyMint cambia

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

In Keymaster è stato utilizzato exportKey invece di convertStorageKeyToEphemeral .

Modifiche al kernel di Linux

Il driver del kernel Linux per il motore crittografico inline del dispositivo deve essere modificato per supportare le chiavi con wrapping hardware.

Per i kernel android14 e successivi, 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'eliminazione delle chiavi con wrapping hardware e implementa blk_crypto_ll_ops::derive_sw_secret .

Per i kernel android12 e android13 , impostare BLK_CRYPTO_FEATURE_WRAPPED_KEYS in blk_keyslot_manager::features , fare in modo che blk_ksm_ll_ops::keyslot_program e blk_ksm_ll_ops::keyslot_evict supportino la programmazione/eliminazione delle chiavi con wrapping hardware e implementare blk_ksm_ll_ops::derive_raw_secret .

Per i kernel android11 , impostare BLK_CRYPTO_FEATURE_WRAPPED_KEYS in keyslot_manager::features , fare in modo che keyslot_mgmt_ll_ops::keyslot_program e keyslot_mgmt_ll_ops::keyslot_evict supportino la programmazione/eliminazione delle chiavi con wrapping hardware e implementare keyslot_mgmt_ll_ops::derive_raw_secret .

Test

Sebbene la crittografia con chiavi hardware-wrapped 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

Leggere il registro del test e verificare che i casi di test delle chiavi con wrapping hardware (ad es FBEPolicyTest.TestAesInlineCryptOptimizedHwWrappedKeyPolicy e DmDefaultKeyTest.TestHwWrappedKey ) non siano stati ignorati a causa del mancato rilevamento del supporto per le chiavi con wrapping hardware, poiché i risultati del test verranno comunque "superati" in questo caso.

Abilitare

Una volta che il supporto della chiave 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 FBE e crittografia dei metadati:

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