Crittografia completa del disco

La crittografia completa del disco è il processo di codifica di tutti i dati utente su un dispositivo Android utilizzando una chiave criptata. Una volta criptato un dispositivo, tutti i dati creati dall'utente vengono criptati automaticamente prima di essere impegnati su disco e tutte le letture decriptano automaticamente i dati prima di restituirli al processo di chiamata.

La crittografia completa del disco è stata introdotta su Android nella versione 4.4, ma Android 5.0 ha introdotto queste nuove funzionalità:

  • È stata creata la crittografia rapida, che cripta solo i blocchi utilizzati nella partizione dei dati per evitare che il primo avvio richieda molto tempo. Attualmente solo i file system ext4 e f2fs supportano la crittografia rapida.
  • È stato aggiunto il forceencrypt flag fstab per la crittografia al primo avvio.
  • È stato aggiunto il supporto per le sequenze e la crittografia senza password.
  • È stata aggiunta l'archiviazione con supporto hardware della chiave di crittografia utilizzando la funzionalità di firma TEE (Trusted Execution Environment) (ad esempio in un TrustZone). Per ulteriori dettagli, consulta Archiviazione della chiave criptata.

Attenzione: i dispositivi di cui è stato eseguito l'upgrade ad Android 5.0 e poi la crittografia possono essere ripristinati a uno stato non criptato tramite il ripristino dei dati di fabbrica. I nuovi dispositivi Android 5.0 criptati al primo avvio non possono essere ripristinati a uno stato non criptato.

Come funziona la crittografia dell'intero disco di Android

La crittografia dell'intero disco di Android si basa su dm-crypt, che è una funzionalità del kernel che funziona a livello di dispositivi a blocchi. Per questo motivo, la crittografia funziona con Embedded MultiMediaCard (eMMC) e dispositivi flash simili che si presentano al kernel come dispositivi di blocco. La crittografia non è possibile con YAFFS, che comunica direttamente con un chip Flash NAND non elaborato.

L'algoritmo di crittografia è l'algoritmo 128 Advanced Encryption Standard (AES) con CBC (cipher-block chaining) ed ESSIV:SHA256. La chiave master viene criptata con AES a 128 bit tramite chiamate alla libreria OpenSSL. Devi usare almeno 128 bit per la chiave (256 sono facoltativi).

Nota: gli OEM possono utilizzare 128 bit o più per criptare la chiave master.

In Android 5.0 esistono quattro tipi di stati della crittografia:

  • predefinito
  • PIN
  • password
  • pattern

Al primo avvio, il dispositivo crea una chiave master di 128 bit generata in modo casuale, quindi la sottopone ad hashing con una password predefinita e un valore salt memorizzato. La password predefinita è: "default_password" Tuttavia, l'hash risultante viene firmato anche tramite un TEE (come TrustZone), che utilizza un hash della firma per criptare la chiave master.

Puoi trovare la password predefinita definita nel file cryptfs.cpp del progetto Android Open Source.

Quando l'utente imposta il PIN/la pass o la password sul dispositivo, solo la chiave di 128 bit viene sottoposta a nuova crittografia e memorizzata. Ad esempio, le modifiche a PIN/pass/pattern dell'utente NON causano la nuova crittografia dei dati utente. Tieni presente che i dispositivi gestiti potrebbero essere soggetti a restrizioni relative a PIN, sequenza o password.

La crittografia è gestita da init e vold. init chiama vold e vold imposta le proprietà per attivare gli eventi in init. Altre parti del sistema esaminano anche le proprietà per svolgere attività come controllare lo stato dei report, chiedere una password o richiedere il ripristino dei dati di fabbrica in caso di errore fatale. Per richiamare le funzionalità di crittografia in vold, il sistema utilizza i comandi cryptfs dello strumento a riga di comando vdc: checkpw, restart, enablecrypto, changepw, cryptocomplete, verifypw, setfield, getfield, mountdefaultencrypted, getpwtype, getpw e clearpw.

Per criptare, decriptare o cancellare i dati di /data, /data non deve essere montato. Tuttavia, per mostrare qualsiasi interfaccia utente (UI), il framework deve essere avviato e richiede l'esecuzione di /data. Per risolvere questo enigma, su /data viene montato un file system temporaneo. In questo modo Android può richiedere le password, mostrare i progressi o suggerire la cancellazione dei dati in base alle esigenze. Imporrà tuttavia la limitazione che, per passare dal file system temporaneo a quello reale /data, il sistema deve arrestare ogni processo con file aperti sul file system temporaneo e riavviare questi processi sul file system /data reale. Per farlo, tutti i servizi devono trovarsi in uno di tre gruppi: core, main e late_start.

  • core: non arrestarsi mai dopo l'avvio.
  • main: dopo aver inserito la password del disco, arresta e riavvia il sistema.
  • late_start: l'avvio non verrà avviato prima che /data sia stato decriptato e montato.

Per attivare queste azioni, la proprietà vold.decrypt è impostata su varie stringhe. Per uccidere e riavviare i servizi, i comandi init sono:

  • class_reset: arresta un servizio, ma consente il riavvio con class_start.
  • class_start: riavvia un servizio.
  • class_stop: arresta un servizio e aggiunge un flag SVC_DISABLED. I servizi interrotti non rispondono a class_start.

Flussi

Esistono quattro flussi per un dispositivo criptato. Un dispositivo viene criptato una sola volta e poi segue un normale flusso di avvio.

  • Criptare un dispositivo non criptato in precedenza:
    • Crittografa un nuovo dispositivo con forceencrypt: crittografia obbligatoria al primo avvio (a partire da Android L).
    • Crittografare un dispositivo esistente: crittografia avviata dall'utente (Android K e versioni precedenti).
  • Avvia un dispositivo criptato:
    • Avvio di un dispositivo criptato senza password: avvio di un dispositivo criptato per il quale non è stata impostata una password (rilevante per i dispositivi con Android 5.0 e versioni successive).
    • Avvio di un dispositivo criptato con una password: avvio di un dispositivo criptato con una password impostata.

Oltre a questi flussi, il dispositivo potrebbe anche non riuscire a criptare /data. Ciascun flusso è descritto in dettaglio di seguito.

Criptare un nuovo dispositivo con forceencrypt

Si tratta del normale primo avvio di un dispositivo con Android 5.0.

  1. Rileva il file system non criptato con il flag forceencrypt

    /data non è criptato, ma deve esserlo perché forceencrypt lo richiede. Smonta /data.

  2. Avvia la crittografia /data

    vold.decrypt = "trigger_encryption" attiva init.rc, che fa sì che vold cripta /data senza password. Non è impostato alcun valore perché si tratta di un nuovo dispositivo.

  3. Montare tmpfs

    vold monta un file system tmpfs /data (utilizzando le opzioni tmpfs di ro.crypto.tmpfs_options) e imposta la proprietà vold.encrypt_progress su 0. vold prepara il file tmpfs /data per l'avvio di un sistema criptato e imposta la proprietà vold.decrypt su: trigger_restart_min_framework

  4. Mostrare il framework per mostrare l'avanzamento

    Poiché il dispositivo praticamente non ha dati da criptare, la barra di avanzamento non viene visualizzata spesso perché la crittografia avviene molto rapidamente. Per ulteriori dettagli sull'interfaccia utente di avanzamento, consulta Eseguire la crittografia di un dispositivo esistente.

  5. Quando /data è criptato, rimuovi il framework

    vold imposta vold.decrypt su trigger_default_encryption, che avvia il servizio defaultcrypto. (Questo avvia il flusso di seguito per il montaggio di dati utente criptati predefiniti.) trigger_default_encryption controlla il tipo di crittografia per verificare se /data è criptato con o senza una password. Poiché i dispositivi Android 5.0 sono criptati al primo avvio, non dovrebbe essere impostata alcuna password. Pertanto, decrittografiamo e montiamo /data.

  6. Monta /data

    init monta quindi /data su un RAMDisk tmpfs utilizzando parametri acquisiti da ro.crypto.tmpfs_options, impostato in init.rc.

  7. Framework di avvio

    vold imposta vold.decrypt su trigger_restart_framework, che continua il consueto processo di avvio.

Criptare un dispositivo esistente

Questo accade quando esegui la crittografia di un dispositivo Android K o precedente non criptato di cui è stata eseguita la migrazione a L.

Questa procedura viene avviata dall'utente ed è indicata come "crittografia in situ" nel codice. Quando un utente sceglie di criptare un dispositivo, la UI verifica che la batteria sia completamente carica e che l'alimentatore CA sia collegato in modo che ci sia abbastanza energia per completare il processo di crittografia.

Avviso:se il dispositivo si scarica e si arresta prima del termine della crittografia, i dati dei file vengono lasciati in stato parzialmente criptato. Il dispositivo deve essere sottoposto a un ripristino dei dati di fabbrica e tutti i dati andranno persi.

Per abilitare la crittografia locale, vold avvia un loop per leggere ogni settore del dispositivo a blocchi reale e poi scriverlo sul dispositivo a blocchi crittografici. vold controlla se un settore è in uso prima di leggerlo e scriverlo, il che rende la crittografia molto più veloce su un nuovo dispositivo con pochi o nessun dato.

Stato del dispositivo: imposta ro.crypto.state = "unencrypted" ed esegui l'attivatore on nonencrypted init per continuare l'avvio.

  1. Verifica password

    L'interfaccia utente chiama vold con il comando cryptfs enablecrypto inplace dove passwd è la password della schermata di blocco dell'utente.

  2. Rimuovere il framework

    vold verifica la presenza di errori, restituisce -1 se non può criptare e stampa un motivo nel log. Se può eseguire la crittografia, imposta la proprietà vold.decrypt su trigger_shutdown_framework. Questo determina l'interruzione dei servizi init.rc nelle classi late_start e main.

  3. Creare un piè di pagina di crittografia
  4. Creare un file breadcrumb
  5. Riavvia
  6. Rileva file breadcrumb
  7. Avvia la crittografia /data

    vold quindi configura il crypto mapping, che crea un dispositivo a blocchi di crittografia virtuale che mappa sul dispositivo a blocchi reale, ma cripta ogni settore man mano che viene scritto e decripta ogni settore man mano che viene letto. vold quindi crea e scrive i metadati delle criptovalute.

  8. Durante l'operazione di crittografia, monta tmpfs

    vold monta un /data tmpfs (utilizzando le opzioni tmpfs da ro.crypto.tmpfs_options) e imposta la proprietà vold.encrypt_progress su 0. vold prepara il file tmpfs /data per l'avvio di un sistema criptato e imposta la proprietà vold.decrypt su: trigger_restart_min_framework

  9. Mostrare il framework per mostrare l'avanzamento

    trigger_restart_min_framework fa sì che init.rc avvii la classe di servizi main. Quando il framework rileva che vold.encrypt_progress è impostato su 0, viene visualizzata l'interfaccia utente della barra di avanzamento, che esegue query sulla proprietà ogni cinque secondi e aggiorna una barra di avanzamento. Il ciclo di crittografia aggiorna vold.encrypt_progress ogni volta che cripta un'altra percentuale della partizione.

  10. Quando /data è criptato, aggiorna il piè di pagina delle criptovalute

    Quando /data viene criptato correttamente, vold cancella il flag ENCRYPTION_IN_PROGRESS nei metadati.

    Una volta sbloccato il dispositivo, la password viene utilizzata per criptare la chiave master e il piè di pagina di crittografia viene aggiornato.

    Se il riavvio non riesce per qualche motivo, vold imposta la proprietà vold.encrypt_progress su error_reboot_failed e l'interfaccia utente dovrebbe mostrare un messaggio che chiede all'utente di premere un pulsante per riavviare. Non è previsto che questo accada.

Avviare un dispositivo criptato con la crittografia predefinita

Questo è ciò che accade quando avvii un dispositivo criptato senza password. Poiché i dispositivi Android 5.0 sono criptati al primo avvio, non dovrebbe essere impostata alcuna password, pertanto questo è lo stato di crittografia predefinita.

  1. Rileva /data criptato senza password

    Rileva che il dispositivo Android è criptato perché non è possibile montare /data e che è impostato uno dei flag encryptable o forceencrypt.

    vold imposta vold.decrypt su trigger_default_encryption, che avvia il servizio defaultcrypto. trigger_default_encryption controlla il tipo di crittografia per verificare se /data è criptato con o senza una password.

  2. Decripta /data

    Crea il dispositivo dm-crypt sul dispositivo a blocchi in modo che sia pronto per l'uso.

  3. Monta /data

    vold quindi monta la partizione /data reale decriptata e prepara la nuova partizione. Imposta la proprietà vold.post_fs_data_done su 0 e poi vold.decrypt su trigger_post_fs_data. In questo modo, init.rc esegue i suoi comandi post-fs-data. Creano eventuali directory o link necessari e impostano vold.post_fs_data_done su 1.

    Quando vold vede il numero 1 in quella proprietà, imposta la proprietà vold.decrypt su: trigger_restart_framework.. Ciò fa sì che init.rc avvii di nuovo i servizi nella classe main e avvierà di nuovo i servizi nella classe late_start per la prima volta dall'avvio.

  4. Framework di avvio

    Ora il framework avvia tutti i suoi servizi utilizzando il file /data decriptato e il sistema è pronto per l'uso.

Avviare un dispositivo criptato senza crittografia predefinita

Questo è ciò che succede quando avvii un dispositivo criptato per cui è impostata una password. La password del dispositivo può essere un PIN, una sequenza o una password.

  1. Rilevare i dispositivi criptati con una password

    Rileva che il dispositivo Android è criptato perché il flag ro.crypto.state = "encrypted"

    vold imposta vold.decrypt su trigger_restart_min_framework perché /data è criptato con una password.

  2. Montare tmpfs

    init imposta cinque proprietà per salvare le opzioni di montaggio iniziale previste per /data con parametri passati da init.rc. vold utilizza queste proprietà per configurare la mappatura della crittografia:

    1. ro.crypto.fs_type
    2. ro.crypto.fs_real_blkdev
    3. ro.crypto.fs_mnt_point
    4. ro.crypto.fs_options
    5. ro.crypto.fs_flags (numero esadecimale ASCII di 8 cifre preceduto da 0x)
  3. Avvia il framework per richiedere la password

    Il framework si avvia e vede che vold.decrypt è impostato su trigger_restart_min_framework. Questo indica al framework che si sta avviando su un disco /data tmpfs e che deve ottenere la password dell'utente.

    Prima, però, deve assicurarsi che il disco sia stato criptato correttamente. Invia il comando cryptfs cryptocomplete a vold. vold restituisce 0 se la crittografia è stata completata correttamente, -1 in caso di errore interno o -2 se la crittografia non è stata completata correttamente. vold determina questo aspetto cercando nei metadati di crittografia per il flag CRYPTO_ENCRYPTION_IN_PROGRESS. Se impostato, la procedura di crittografia è stata interrotta e sul dispositivo non sono disponibili dati utilizzabili. Se vold restituisce un errore, la UI dovrebbe mostrare all'utente un messaggio per riavviare e ripristinare i dati di fabbrica del dispositivo e fornire all'utente un pulsante da premere per eseguire questa operazione.

  4. Decriptare i dati con password

    Dopo l'esito positivo di cryptfs cryptocomplete, il framework mostra una UI per richiedere la password del disco. L'interfaccia utente controlla la password inviando il comando cryptfs checkpw a vold. Se la password è corretta (il che viene stabilito montando correttamente /data decriptato in una posizione temporanea e poi smontandolo), vold salva il nome del dispositivo di blocco decriptato nella proprietà ro.crypto.fs_crypto_blkdev e restituisce lo stato 0 all'interfaccia utente. Se la password non è corretta, viene restituito -1 all'interfaccia utente.

  5. Framework di interruzione

    La UI mostra una grafica di avvio crittografico e quindi chiama vold con il comando cryptfs restart. vold imposta la proprietà vold.decrypt su trigger_reset_main, il che fa eseguire init.rc l'operazione class_reset main. In questo modo vengono interrotti tutti i servizi nella classe principale, il che consente di smontare il file system tmpfs /data.

  6. Monta /data

    Quindi, vold monta la partizione /data reale decriptata e prepara la nuova partizione (che potrebbe non essere mai stata preparata se fosse stata criptata con l'opzione di cancellazione, che non è supportata nella prima release). Imposta la proprietà vold.post_fs_data_done su 0 e poi imposta vold.decrypt su trigger_post_fs_data. In questo modo, init.rc eseguirà i suoi comandi post-fs-data. Questi agenti creano le directory o i link necessari e poi impostano vold.post_fs_data_done su 1. Quando vold vede il valore 1 in quella proprietà, imposta la proprietà vold.decrypt su trigger_restart_framework. In questo modo init.rc avvierà di nuovo i servizi nella classe main e avvierà anche i servizi nella classe late_start per la prima volta dall'avvio.

  7. Avvia il framework completo

    Ora il framework avvia tutti i servizi utilizzando il file system /data decriptato e il sistema è pronto per l'uso.

Errore

Un dispositivo che non riesce a decriptare potrebbe risultare errato per diversi motivi. Il dispositivo inizia con la normale serie di passaggi per l'avvio:

  1. Rilevare il dispositivo criptato con una password
  2. Monta tmpfs
  3. Avvia framework per richiedere la password

Tuttavia, dopo l'apertura del framework, il dispositivo potrebbe riscontrare alcuni errori:

  • La password corrisponde, ma non può decriptare i dati
  • L'utente inserisce la password errata 30 volte

Se questi errori non vengono risolti, chiedi all'utente di eseguire il ripristino dei dati di fabbrica:

Se vold rileva un errore durante il processo di crittografia e se non sono stati ancora distrutti dati e il framework è attivo, vold imposta la proprietà vold.encrypt_progress su error_not_encrypted. L'interfaccia utente chiede all'utente di riavviare il dispositivo e lo avvisa che la procedura di crittografia non è mai stata avviata. Se l'errore si verifica dopo la rimozione del framework, ma prima che l'interfaccia utente della barra di avanzamento sia attiva, vold riavvia il sistema. Se il riavvio non va a buon fine, vold.encrypt_progress viene impostato su error_shutting_down e viene restituito -1, ma non verrà rilevato alcun errore. Non è previsto che ciò accada.

Se vold rileva un errore durante il processo di crittografia, imposta vold.encrypt_progress su error_partially_encrypted e restituisce -1. La UI dovrebbe quindi visualizzare un messaggio che indica che la crittografia non è riuscita e fornire all'utente un pulsante per ripristinare i dati di fabbrica del dispositivo.

Memorizza la chiave criptata

La chiave criptata viene archiviata nei metadati della crittografia. Il supporto hardware viene implementato utilizzando la funzionalità di firma TEE (Trusted Execution Environment). In precedenza, la chiave master era criptata con una chiave generata applicando la crittografia alla password dell'utente e al sale archiviato. Per rendere la chiave resiliente agli attacchi off-box, estendiamo questo algoritmo firmando la chiave risultante con una chiave TEE memorizzata. La firma risultante viene quindi trasformata in una chiave di lunghezza appropriata da un'altra applicazione di scrypt. Questa chiave viene quindi usata per criptare e decriptare la chiave master. Per memorizzare questa chiave:

  1. Genera una chiave di crittografia del disco (DEK) casuale di 16 byte e un valore di salt di 16 byte.
  2. Applica la crittografia alla password dell'utente e al sale per produrre la chiave intermedia 1 (IK1) da 32 byte.
  3. Crea un pad IK1 con zero byte, in base alla dimensione della chiave privata associata all'hardware (HBK). Nello specifico, inseriamo spaziatura come segue: 00 || IK1 || 00..00; un byte zero, 32 byte IK1, 223 byte zero.
  4. Segno riempito IK1 con HBK per produrre un IK2 da 256-byte.
  5. Applica scrypt a IK2 e al sale (lo stesso sale del passaggio 2) per produrre IK3 di 32 byte.
  6. Utilizza i primi 16 byte di IK3 come KEK e gli ultimi 16 byte come IV.
  7. Cripta la DEK con AES_CBC, con la chiave KEK e il vettore di inizializzazione IV.

Cambiare la password

Quando un utente sceglie di cambiare o rimuovere la password nelle impostazioni, l'interfaccia utente invia il comando cryptfs changepw a vold e vold cripta di nuovo la chiave principale del disco con la nuova password.

Proprietà della crittografia

vold e init comunicano tra loro impostando le proprietà. Di seguito è riportato un elenco delle proprietà disponibili per la crittografia.

Proprietà Vold

Proprietà Descrizione
vold.decrypt trigger_encryption Crittografare il disco senza una password.
vold.decrypt trigger_default_encryption Controlla se l'unità è criptata senza password. Se è così, decriptalo e montalo, altrimenti imposta vold.decrypt su trigger_restart_min_framework.
vold.decrypt trigger_reset_main Impostato da vold per arrestare l'UI che richiede la password del disco.
vold.decrypt trigger_post_fs_data Impostato da vold per preparare /data con le directory necessarie, et al.
vold.decrypt trigger_restart_framework Impostato per iniziare il framework reale e tutti i servizi.
vold.decrypt trigger_shutdown_framework Impostato da vold per arrestare il framework completo per avviare la crittografia.
vold.decrypt trigger_restart_min_framework Impostalo per vold per avviare l'interfaccia utente della barra di avanzamento per la crittografia o la richiesta di password, a seconda del valore di ro.crypto.state.
vold.encrypt_progress Quando il framework si avvia, se questa proprietà è impostata, viene attivata la modalità UI della barra di avanzamento.
vold.encrypt_progress 0 to 100 L'interfaccia utente della barra di avanzamento deve mostrare il valore percentuale impostato.
vold.encrypt_progress error_partially_encrypted La UI della barra di avanzamento dovrebbe visualizzare un messaggio che informa che la crittografia non è riuscita e offrire all'utente la possibilità di ripristinare i dati di fabbrica del dispositivo.
vold.encrypt_progress error_reboot_failed La UI della barra di avanzamento dovrebbe mostrare un messaggio che indica che la crittografia è stata completata e deve essere fornito all'utente un pulsante per riavviare il dispositivo. Questo errore non dovrebbe verificarsi.
vold.encrypt_progress error_not_encrypted La UI della barra di avanzamento dovrebbe mostrare un messaggio che indica che si è verificato un errore, nessun dato criptato o è stato perso e all'utente un pulsante per riavviare il sistema.
vold.encrypt_progress error_shutting_down L'interfaccia utente della barra di avanzamento non è in esecuzione, quindi non è chiaro chi risponde all'errore. E non dovrebbe mai succedere comunque.
vold.post_fs_data_done 0 Impostato da vold poco prima di impostare vold.decrypt su trigger_post_fs_data.
vold.post_fs_data_done 1 Imposta init.rc o init.rc subito dopo aver completato l'attività post-fs-data.

proprietà init

Proprietà Descrizione
ro.crypto.fs_crypto_blkdev Impostato dal comando vold checkpw per un uso successivo dal comando vold restart.
ro.crypto.state unencrypted Impostato da init per indicare che questo sistema è in esecuzione con un /data ro.crypto.state encrypted non criptato. Impostato da init per indicare che questo sistema è in esecuzione con un /data criptato.

ro.crypto.fs_type
ro.crypto.fs_real_blkdev
ro.crypto.fs_mnt_point
ro.crypto.fs_options
ro.crypto.fs_flags

Queste cinque proprietà vengono impostate da init quando tenta di montare /data con i parametri passati da init.rc. vold li utilizza per configurare il crypto mapping.
ro.crypto.tmpfs_options Impostato da init.rc con le opzioni che init deve utilizzare per montare il file system tmpfs /data.

azioni di inizializzazione

on post-fs-data
on nonencrypted
on property:vold.decrypt=trigger_reset_main
on property:vold.decrypt=trigger_post_fs_data
on property:vold.decrypt=trigger_restart_min_framework
on property:vold.decrypt=trigger_restart_framework
on property:vold.decrypt=trigger_shutdown_framework
on property:vold.decrypt=trigger_encryption
on property:vold.decrypt=trigger_default_encryption