Chiavi con wrapping hardware

Come la maggior parte del software di crittografia di file e dischi, 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 gestire le chiavi di crittografia non elaborate.

Tradizionalmente, questo non è considerato un problema perché le chiavi non sono presenti durante un attacco offline, che è il tipo di attacco principale contro cui è intesa la crittografia dello spazio di archiviazione. 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 questo problema, Android 11 ha introdotto il supporto per le chiavi con wrapping hardware, se è presente il supporto hardware. Le chiavi con wrapping hardware sono chiavi di archiviazione conosciute in forma non elaborata solo dall'hardware dedicato. Il software vede e utilizza queste chiavi solo in forma con wrapping (criptata). 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 host UFS o eMMC che implementa le estensioni di crittografia definite dal 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 aver bisogno delle chiavi di crittografia non elaborate nella memoria di sistema è quello di e conservarli solo negli slot delle chiavi di un motore di crittografia in linea. Tuttavia, questo approccio presenta alcuni problemi:

  • Il numero di chiavi di crittografia potrebbe superare il numero di keyslot.
  • 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 avrà comunque bisogno di accedere alle chiavi FBE non elaborate per fai quest'altro lavoro.

Per evitare questi problemi, le chiavi di archiviazione vengono 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. Nel 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 mostra una tipica gerarchia delle chiavi per la crittografia lato firmware 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 a Linux. per sbloccare un particolare set di directory criptate, come con crittografia delle credenziali per un determinato utente Android. (Nel kernel, è denominata chiave master fscrypt.) Da questa chiave, il kernel deriva 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 formato con wrapping temporaneo e per essere utilizzata deve essere passata a hardware dedicato. Questo hardware deve implementare due interfacce che accettano una chiave con wrapping temporaneo:

  • Un'interfaccia per dedurre inline_encryption_key e programmarla direttamente in una keyslot del motore crittografico 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 dell'operazione blk_crypto_ll_ops::derive_sw_secret, che deve essere implementato 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 seguito. Inoltre, deve utilizzare una stringa di informazioni distinta per etichetta, contesto e app al momento di dedurre ogni tipo di sottochiave per garantire che le sottochiavi risultanti siano isolate dal punto di vista crittografico, ovvero che la conoscenza di una non riveli le altre. Lo stretching della chiave non è necessario, poiché la chiave di archiviazione non elaborata è già una chiave uniformemente casuale.

Tecnicamente, è possibile utilizzare qualsiasi KDF che soddisfi i requisiti di sicurezza. Tuttavia, a scopo di test, è necessario implementare nuovamente lo stesso KDF nel codice di test. Al momento, è stato esaminato e implementato un KDF, che 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, tutte le parti dell'algoritmo devono essere identiche, inclusa la scelta dei contesti KDF e delle etichette per ogni sottochiave.

Wrapping delle 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. Questo assicura che se un utente malintenzionato sia in grado di estrarre un chiave in uso dalla memoria di sistema, questa chiave è inutilizzabile non solo fuori dal dispositivo, ma anche sul dispositivo 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. I dati non elaborati per questo scopo. Tuttavia, è preferibile che le chiavi non vengano mai memorizzate 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 con wrapping di un modulo a lungo termine. A queste interfacce si accede indirettamente tramite KeyMint e corrispondono al tag TAG_STORAGE_KEY KeyMint. 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 al convertStorageKeyToEphemeral metodo KeyMint. Questo metodo viene utilizzato sia da vold che da vts_kernel_encryption_test per sbloccare lo spazio di archiviazione.

L'algoritmo di wrapping delle chiavi è un dettaglio di implementazione, ma deve 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 il supporto delle chiavi con wrapping hardware. Questo include il supporto nei componenti dello spazio utente, come vold, nonché come il supporto kernel Linux in blk-crypto, fscrypt e dm-default-key.

Tuttavia, sono necessarie alcune modifiche specifiche dell'implementazione.

Modifiche a KeyMint

L'implementazione di KeyMint del dispositivo deve essere modificata per supportareTAG_STORAGE_KEY e implementare il metodoconvertStorageKeyToEphemeral.

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 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 android11 kernel, imposta BLK_CRYPTO_FEATURE_WRAPPED_KEYS tra keyslot_manager::features, metti keyslot_mgmt_ll_ops::keyslot_program e keyslot_mgmt_ll_ops::keyslot_evict supportare la programmazione/la rimozione di chiavi con wrapping hardware, e implementare 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 di test e verifica che gli scenari di test delle chiavi con wrapping hardware (ad esempio, FBEPolicyTest.TestAesInlineCryptOptimizedHwWrappedKeyPolicy e DmDefaultKeyTest.TestHwWrappedKey) non sono state ignorate a causa dell'assistenza di chiavi con wrapping hardware che non vengono rilevate, in quanto i risultati del test sono "superato" in quel caso.

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 alla fileencryption. Ad esempio, utilizza fileencryption=::inlinecrypt_optimized+wrappedkey_v0. Per ulteriori dettagli, consulta FBE documentazione.
  • Crittografia dei metadati: aggiungi il flag wrappedkey_v0 alla metadata_encryption. Ad esempio, utilizza metadata_encryption=:wrappedkey_v0. Per ulteriori dettagli, consulta la documentazione sulla crittografia dei metadati.