Tasti con hardware

Come la maggior parte dei software di crittografia di dischi e file, la crittografia di archiviazione di Android si basa tradizionalmente sulla presenza di chiavi di crittografia grezze nella memoria di sistema in modo che la crittografia possa essere eseguita. Anche quando la crittografia viene eseguita da un hardware dedicato anziché da un software, in genere il software deve comunque gestire le chiavi di crittografia grezze.

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 dello storage intende proteggere. Tuttavia, si desidera fornire una maggiore protezione contro altri tipi di attacchi, come gli attacchi con 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 i tasti con wrapper hardware , dove è presente il supporto hardware. Le chiavi con wrapper hardware sono chiavi di archiviazione note solo in forma grezza all'hardware dedicato; il software vede e funziona con queste chiavi solo in forma incapsulata (crittografata). Questo hardware deve essere in grado di generare e importare chiavi di archiviazione, racchiudere chiavi di archiviazione in forme effimere e a 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 sono 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 specifica JEDEC corrispondente.

Progetto

Questa sezione presenta la progettazione della funzionalità dei tasti con wrapper hardware, incluso il supporto hardware necessario. 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 grezze nella memoria di sistema sarebbe mantenerle 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 slot per chiavi.
  • I motori di crittografia in linea possono essere utilizzati solo per crittografare/decrittografare blocchi completi di dati su disco. Tuttavia, nel caso di FBE, il software deve ancora essere in grado di svolgere altre attività crittografiche, come la crittografia dei nomi dei file e la derivazione di identificatori di chiave. Il software avrebbe comunque bisogno dell'accesso alle chiavi FBE grezze per svolgere quest'altro lavoro.

Per evitare questi problemi, le chiavi di archiviazione vengono invece trasformate in chiavi con wrapper 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, consentendo 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 wrapper hardware:

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

La chiave della classe FBE è la chiave di crittografia grezza che Android passa al kernel Linux per sbloccare un particolare set di directory crittografate, come l'archivio con credenziali crittografate 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 viene protetto un particolare file o directory.
  • La chiave di crittografia del contenuto del file
  • La chiave di crittografia dei nomi file

Al contrario, il diagramma seguente illustra la gerarchia delle chiavi per FBE quando vengono utilizzate chiavi con wrapper hardware:

Gerarchia delle chiavi FBE (con chiave con wrapper hardware)
Figura 2. Gerarchia delle chiavi FBE (con chiave integrata nell'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 una serie di directory crittografate. Tuttavia, ora la chiave è in formato temporaneo e per poter essere utilizzata deve essere passata a un hardware dedicato. Questo hardware deve implementare due interfacce che accettano una chiave con wrapper temporaneo:

  • Un'interfaccia per derivare inline_encryption_key e programmarla direttamente in uno slot di chiave del motore di crittografia in linea. Ciò consente di crittografare/decrittografare il contenuto del file senza che il software abbia accesso alla chiave grezza. 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 ("segreto del software" -- chiamato anche "segreto grezzo" in alcuni posti), che è la chiave che Linux utilizza per derivare le sottochiavi per tutto tranne la 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 potente. Questo KDF deve seguire le migliori pratiche di crittografia; deve avere un livello di sicurezza di almeno 256 bit, sufficiente cioè per qualsiasi algoritmo utilizzato in seguito. Deve inoltre utilizzare un'etichetta distinta, un contesto e/o una stringa informativa specifica dell'applicazione quando deriva ciascun tipo di sottochiave per garantire che le sottochiavi risultanti siano crittograficamente isolate, ovvero la conoscenza di una di esse non ne riveli nessun'altra. L'estensione della chiave non è necessaria, poiché la chiave di archiviazione grezza è già una chiave uniformemente casuale.

Tecnicamente, potrebbe essere utilizzato qualsiasi KDF che soddisfi i requisiti di sicurezza. Tuttavia, a scopo di test, è necessario implementare nuovamente lo stesso KDF nel codice di test. Attualmente, una KDF è stata rivista e implementata; può essere trovato nel codice sorgente di 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. Tieni presente che per essere compatibile, tutte le parti dell'algoritmo devono essere identiche, inclusa la scelta dei contesti KDF e delle etichette per ciascuna sottochiave.

Avvolgimento delle chiavi

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

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

Tutte le chiavi passate al kernel Linux per sbloccare l'archiviazione sono protette in modo temporaneo. 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 racchiuse in questi due modi diversi, l'hardware deve implementare le seguenti interfacce:

  • Interfacce per generare e importare chiavi di archiviazione, restituendole in formato confezionato a lungo termine. A queste interfacce si accede indirettamente tramite KeyMint e corrispondono al tag KeyMint TAG_STORAGE_KEY . L'abilità "genera" viene utilizzata da vold per generare nuove chiavi di archiviazione utilizzabili da Android, mentre l'abilità "importa" viene utilizzata da vts_kernel_encryption_test per importare chiavi di test.
  • Un'interfaccia per convertire una chiave di archiviazione con wrapper a lungo termine in una chiave di archiviazione con wrapper temporaneo. Ciò corrisponde al metodo convertStorageKeyToEphemeral KeyMint. Questo metodo viene utilizzato sia da vold che da vts_kernel_encryption_test per sbloccare lo spazio di archiviazione.

L'algoritmo di key wraping è un dettaglio di implementazione, ma dovrebbe utilizzare un AEAD potente 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 wrapper hardware. Ciò include 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 dell’implementazione.

Modifiche a KeyMint

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 Linux

Il driver del kernel Linux per il motore di crittografia in linea del dispositivo deve essere modificato per supportare le chiavi con wrapper 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/eliminazione delle chiavi integrate nell'hardware e implementa blk_crypto_ll_ops::derive_sw_secret .

Per android12 e android13 kernels, set BLK_CRYPTO_FEATURE_WRAPPED_KEYS in blk_keyslot_manager::features , make blk_ksm_ll_ops::keyslot_program e blk_ksm_ll_ops::keyslot_evict Programm/evicting hardware keys, blk_ksm_ll_ops::derive_raw_secret .

Per i kernel android11 , imposta BLK_CRYPTO_FEATURE_WRAPPED_KEYS in keyslot_manager::features , fai in modo che keyslot_mgmt_ll_ops::keyslot_program e keyslot_mgmt_ll_ops::keyslot_evict supportino la programmazione/eliminazione delle chiavi incluse nell'hardware e implementa keyslot_mgmt_ll_ops::derive_raw_secret .

Test

Sebbene la crittografia con chiavi integrate nell'hardware sia più difficile da testare rispetto alla crittografia con chiavi standard, è comunque possibile testarla importando una chiave di prova 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 wrapper hardware (ad esempio FBEPolicyTest.TestAesInlineCryptOptimizedHwWrappedKeyPolicy e DmDefaultKeyTest.TestHwWrappedKey ) non siano stati ignorati a causa del mancato rilevamento del supporto per le chiavi con wrapper hardware, poiché i risultati del test verranno comunque "superati" in questo caso.

Abilitare

Una volta che il supporto della chiave inclusa nell'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 la crittografia dei metadati:

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