Crittografia dell'intero disco

La crittografia dell'intero disco è il processo di codifica di tutti i dati utente su un dispositivo Android utilizzando una chiave crittografata. Una volta crittografato un dispositivo, tutti i dati creati dall'utente vengono automaticamente crittografati prima di salvarli su disco e tutte le letture decrittografano automaticamente i dati prima di restituirli al processo chiamante.

La crittografia dell'intero disco è stata introdotta in Android nella versione 4.4, ma Android 5.0 ha introdotto queste nuove funzionalità:

  • Creata la crittografia veloce, che crittografa solo i blocchi utilizzati sulla partizione dati per evitare che il primo avvio richieda molto tempo. Solo i filesystem ext4 e f2fs attualmente supportano la crittografia veloce.
  • Aggiunto il flag fstab forceencrypt per crittografare al primo avvio.
  • Aggiunto supporto per pattern e crittografia senza password.
  • Aggiunta archiviazione supportata da hardware della chiave di crittografia utilizzando la funzionalità di firma TEE (Trusted Execution Environment) (come in TrustZone). Vedi Memorizzazione della chiave crittografata per maggiori dettagli.

Attenzione: i dispositivi aggiornati ad Android 5.0 e poi crittografati potrebbero tornare allo stato non crittografato tramite il ripristino dei dati di fabbrica. I nuovi dispositivi Android 5.0 crittografati al primo avvio non possono essere riportati a uno stato non crittografato.

Come funziona la crittografia dell'intero disco Android

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

L'algoritmo di crittografia è 128 Advanced Encryption Standard (AES) con cipher-block chaining (CBC) ed ESSIV:SHA256. La chiave principale viene crittografata con AES a 128 bit tramite chiamate alla libreria OpenSSL. È necessario utilizzare 128 bit o più per la chiave (256 sono facoltativi).

Nota: gli OEM possono utilizzare 128 bit o versioni successive per crittografare la chiave master.

Nella versione Android 5.0 sono disponibili quattro tipi di stati di crittografia:

  • predefinito
  • SPILLO
  • parola d'ordine
  • modello

Al primo avvio, il dispositivo crea una chiave master a 128 bit generata casualmente e quindi la sottopone ad hashing con una password predefinita e sale 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 crittografare la chiave principale.

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

Quando l'utente imposta il PIN/pass o la password sul dispositivo, solo la chiave a 128 bit viene nuovamente crittografata e archiviata. (ovvero, le modifiche al PIN/pass/sequenza utente NON causano la nuova crittografia dei dati utente.) Tieni presente che il dispositivo gestito può essere soggetto 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 eventi in init. Anche altre parti del sistema esaminano le proprietà per svolgere attività come segnalare lo stato, richiedere una password o richiedere il ripristino delle impostazioni di fabbrica in caso di errore irreversibile. Per richiamare le funzionalità di crittografia in vold , il sistema utilizza i comandi cryptfs dello strumento da riga di comando vdc : checkpw , restart , enablecrypto , changepw , cryptocomplete , verifypw , setfield , getfield , mountdefaultencrypted , getpwtype , getpw e clearpw .

Per crittografare, decrittografare o cancellare /data , /data non deve essere montato. Tuttavia, per mostrare qualsiasi interfaccia utente (UI), il framework deve essere avviato e richiede l'esecuzione /data . Per risolvere questo enigma, viene montato un filesystem temporaneo su /data . Ciò consente ad Android di richiedere password, mostrare progressi o suggerire la cancellazione dei dati secondo necessità. Impone la limitazione che per passare dal filesystem temporaneo al filesystem true /data , il sistema deve arrestare ogni processo con file aperti sul filesystem temporaneo e riavviare tali processi sul filesystem /data reale. Per fare ciò, tutti i servizi devono trovarsi in uno dei tre gruppi: core , main e late_start .

  • core : non spegnere mai dopo l'avvio.
  • main : arresta e riavvia dopo aver immesso la password del disco.
  • late_start : non si avvia finché /data non è stato decrittografato e montato.

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

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

Flussi

Esistono quattro flussi per un dispositivo crittografato. Un dispositivo viene crittografato solo una volta e quindi segue un normale flusso di avvio.

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

Oltre a questi flussi, il dispositivo può anche non riuscire a crittografare /data . Ciascuno dei flussi è spiegato in dettaglio di seguito.

Crittografa un nuovo dispositivo con forceencrypt

Questo è il normale primo avvio per un dispositivo Android 5.0.

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

    /data non è crittografato ma deve esserlo perché forceencrypt lo impone. Smonta /data .

  2. Inizia a crittografare /data

    vold.decrypt = "trigger_encryption" attiva init.rc , che farà sì vold crittografi /data senza password. (Nessuno è impostato perché dovrebbe trattarsi di un nuovo dispositivo.)

  3. Montare tmpfs

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

  4. Visualizza la struttura per mostrare i progressi

    Poiché il dispositivo non ha praticamente dati da crittografare, la barra di avanzamento spesso non viene effettivamente visualizzata perché la crittografia avviene molto rapidamente. Vedi Crittografare un dispositivo esistente per ulteriori dettagli sull'interfaccia utente di avanzamento.

  5. Quando /data viene crittografato, rimuovi il framework

    vold imposta vold.decrypt su trigger_default_encryption che avvia il servizio defaultcrypto . (In questo modo viene avviato il flusso riportato di seguito per il montaggio di un dato utente crittografato predefinito.) trigger_default_encryption controlla il tipo di crittografia per vedere se /data è crittografato con o senza password. Poiché i dispositivi Android 5.0 vengono crittografati al primo avvio, non dovrebbe essere impostata alcuna password; quindi decodifichiamo e montiamo /data .

  6. Monta /data

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

  7. Avvia quadro

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

Crittografa un dispositivo esistente

Questo è ciò che accade quando crittografi un dispositivo Android K o precedente non crittografato che è stato migrato a L.

Questo processo viene avviato dall'utente e nel codice viene denominato "crittografia interna". Quando un utente sceglie di crittografare un dispositivo, l'interfaccia utente si assicura che la batteria sia completamente carica e che l'adattatore CA sia collegato in modo che ci sia energia sufficiente per completare il processo di crittografia.

Avviso: se il dispositivo si esaurisce e si spegne prima di aver terminato la crittografia, i dati del file vengono lasciati in uno stato parzialmente crittografato. Il dispositivo deve essere ripristinato alle impostazioni di fabbrica e tutti i dati andranno persi.

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

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

  1. Controlla la password

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

  2. Togli il quadro

    vold controlla gli errori, restituisce -1 se non può crittografare e stampa un motivo nel registro. Se può crittografare, imposta la proprietà vold.decrypt su trigger_shutdown_framework . Ciò fa sì che init.rc interrompa i servizi nelle classi late_start e main .

  3. Crea un piè di pagina crittografico
  4. Crea un file breadcrumb
  5. Riavviare
  6. Rileva il file breadcrumb
  7. Inizia a crittografare /data

    vold quindi imposta la mappatura crittografica, che crea un dispositivo a blocchi crittografico virtuale che si mappa sul dispositivo a blocchi reale ma crittografa ogni settore mentre viene scritto e decrittografa ogni settore mentre viene letto. vold quindi crea e scrive i metadati crittografici.

  8. Durante la crittografia, monta tmpfs

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

  9. Visualizza la struttura per mostrare i progressi

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

  10. Quando /data è crittografato, aggiorna il footer crittografico

    Quando /data viene crittografato con successo, vold cancella il flag ENCRYPTION_IN_PROGRESS nei metadati.

    Quando il dispositivo viene sbloccato con successo, la password viene quindi utilizzata per crittografare la chiave principale e il footer crittografico viene aggiornato.

    Se il riavvio fallisce per qualche motivo, vold imposta la proprietà vold.encrypt_progress su error_reboot_failed e l'interfaccia utente dovrebbe visualizzare un messaggio che chiede all'utente di premere un pulsante per riavviare. Non si prevede che ciò accada mai.

Avvio di un dispositivo crittografato con crittografia predefinita

Questo è ciò che accade quando si avvia un dispositivo crittografato senza password. Poiché i dispositivi Android 5.0 vengono crittografati al primo avvio, non dovrebbe essere impostata alcuna password e pertanto questo è lo stato di crittografia predefinito .

  1. Rileva /data crittografati senza password

    Rileva che il dispositivo Android è crittografato perché /data non può essere montato e uno dei flag encryptable o forceencrypt è impostato.

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

  2. Decifra /data

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

  3. Monta /dati

    vold quindi monta la partizione reale /data decodificata e quindi prepara la nuova partizione. Imposta la proprietà vold.post_fs_data_done su 0 e quindi imposta vold.decrypt su trigger_post_fs_data . Ciò fa sì che init.rc esegua i suoi comandi post-fs-data . Creeranno tutte le directory o i collegamenti necessari e quindi imposteranno vold.post_fs_data_done su 1.

    Una volta che vold vede l'1 in quella proprietà, imposta la proprietà vold.decrypt su: trigger_restart_framework. Ciò fa sì che init.rc avvii nuovamente i servizi nella classe main e avvii anche i servizi nella classe late_start per la prima volta dall'avvio.

  4. Avvia quadro

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

Avvio di un dispositivo crittografato senza crittografia predefinita

Questo è ciò che accade quando si avvia un dispositivo crittografato con una password impostata. La password del dispositivo può essere un PIN, una sequenza o una password.

  1. Rileva dispositivo crittografato con una password

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

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

  2. Montare tmpfs

    init imposta cinque proprietà per salvare le opzioni di montaggio iniziali fornite per /data con i parametri passati da init.rc . vold utilizza queste proprietà per impostare la mappatura crittografica:

    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 tmpfs /data e che deve ottenere la password dell'utente.

    Innanzitutto, però, è necessario assicurarsi che il disco sia stato crittografato correttamente. Invia il comando cryptfs cryptocomplete a vold . vold restituisce 0 se la crittografia è stata completata con successo, -1 in caso di errore interno o -2 se la crittografia non è stata completata con successo. vold lo determina cercando nei metadati crittografici il flag CRYPTO_ENCRYPTION_IN_PROGRESS . Se è impostato, il processo di crittografia è stato interrotto e sul dispositivo non sono presenti dati utilizzabili. Se vold restituisce un errore, l'interfaccia utente dovrebbe visualizzare un messaggio all'utente per riavviare e ripristinare le impostazioni di fabbrica del dispositivo e fornire all'utente un pulsante da premere per farlo.

  4. Decrittografare i dati con password

    Una volta che cryptfs cryptocomplete ha esito positivo, il framework visualizza un'interfaccia utente che richiede la password del disco. L'interfaccia utente controlla la password inviando il comando cryptfs checkpw a vold . Se la password è corretta (il che viene determinato montando con successo il /data decrittografato in una posizione temporanea, quindi smontandolo), vold salva il nome del dispositivo a blocchi decrittografato nella proprietà ro.crypto.fs_crypto_blkdev e restituisce lo stato 0 all'interfaccia utente . Se la password non è corretta, restituisce -1 all'interfaccia utente.

  5. Smettere di quadro

    L'interfaccia utente visualizza un'immagine di avvio crittografato e quindi chiama vold con il comando cryptfs restart . vold imposta la proprietà vold.decrypt su trigger_reset_main , che fa sì che init.rc esegua class_reset main . Ciò arresta tutti i servizi nella classe principale, consentendo di smontare tmpfs /data .

  6. Monta /data

    vold quindi monta la partizione reale /data decriptata e prepara la nuova partizione (che potrebbe non essere mai stata preparata se fosse stata crittografata con l'opzione di cancellazione, che non è supportata al primo rilascio). Imposta la proprietà vold.post_fs_data_done su 0 e quindi imposta vold.decrypt su trigger_post_fs_data . Ciò fa sì che init.rc esegua i suoi comandi post-fs-data . Creeranno tutte le directory o i collegamenti necessari e quindi imposteranno vold.post_fs_data_done su 1. Una volta che vold vede 1 in quella proprietà, imposta la proprietà vold.decrypt su trigger_restart_framework . Ciò fa sì che init.rc avvii nuovamente i servizi nella classe main e avvii anche i servizi nella classe late_start per la prima volta dall'avvio.

  7. Avvia il quadro completo

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

Fallimento

Un dispositivo che non riesce a decrittografare potrebbe essere errato per alcuni motivi. Il dispositivo si avvia con la normale serie di passaggi per l'avvio:

  1. Rileva dispositivo crittografato con una password
  2. Montare tmpfs
  3. Avvia il framework per richiedere la password

Ma dopo l'apertura del framework, il dispositivo può riscontrare alcuni errori:

  • La password corrisponde ma non può decrittografare i dati
  • L'utente inserisce una password errata 30 volte

Se questi errori non vengono risolti, chiedi all'utente di cancellare le impostazioni di fabbrica :

Se vold rileva un errore durante il processo di crittografia e se nessun dato è stato ancora distrutto e il framework è attivo, vold imposta la proprietà vold.encrypt_progress su error_not_encrypted . L'interfaccia utente richiede all'utente di riavviare e avvisa che il processo di crittografia non è mai stato avviato. Se l'errore si verifica dopo che il framework è stato smontato, ma prima che la barra di avanzamento dell'interfaccia utente sia attiva, vold riavvierà il sistema. Se il riavvio fallisce, imposta vold.encrypt_progress su error_shutting_down e restituisce -1; ma non ci sarà nulla per rilevare l'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. L'interfaccia utente dovrebbe quindi visualizzare un messaggio che indica che la crittografia non è riuscita e fornire all'utente un pulsante per ripristinare le impostazioni di fabbrica del dispositivo.

Memorizzazione della chiave crittografata

La chiave crittografata è archiviata nei metadati crittografici. Il supporto hardware viene implementato utilizzando la funzionalità di firma TEE (Trusted Execution Environment). In precedenza, abbiamo crittografato la chiave master con una chiave generata applicando scrypt alla password dell'utente e al salt archiviato. Per rendere la chiave resistente 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 mediante un'ulteriore applicazione di scrypt. Questa chiave viene quindi utilizzata per crittografare e decrittografare la chiave principale. Per memorizzare questa chiave:

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

Modifica della password

Quando un utente sceglie di modificare o rimuovere la propria password nelle impostazioni, l'interfaccia utente invia il comando cryptfs changepw a vold e vold crittografa nuovamente la chiave master del disco con la nuova password.

Proprietà di crittografia

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

Proprietà di Vold

Proprietà Descrizione
vold.decrypt trigger_encryption Crittografa l'unità senza password.
vold.decrypt trigger_default_encryption Controlla l'unità per vedere se è crittografata senza password. Se lo è, decriptalo e montalo, altrimenti imposta vold.decrypt su trigger_restart_min_framework.
vold.decrypt trigger_reset_main Impostato da vold per arrestare l'interfaccia utente 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 da vold per avviare il framework reale e tutti i servizi.
vold.decrypt trigger_shutdown_framework Impostato da vold per arrestare l'intero framework per avviare la crittografia.
vold.decrypt trigger_restart_min_framework Impostato da vold per avviare la barra di avanzamento dell'interfaccia utente per la crittografia o la richiesta di password, a seconda del valore di ro.crypto.state .
vold.encrypt_progress All'avvio del framework, se questa proprietà è impostata, entra nella modalità UI della barra di avanzamento.
vold.encrypt_progress 0 to 100 L'interfaccia utente della barra di avanzamento dovrebbe visualizzare il valore percentuale impostato.
vold.encrypt_progress error_partially_encrypted La barra di avanzamento dell'interfaccia utente dovrebbe visualizzare un messaggio indicante che la crittografia non è riuscita e offrire all'utente un'opzione per ripristinare le impostazioni di fabbrica del dispositivo.
vold.encrypt_progress error_reboot_failed La barra di avanzamento dell'interfaccia utente dovrebbe visualizzare un messaggio che indica che la crittografia è stata completata e fornire all'utente un pulsante per riavviare il dispositivo. Non è previsto che si verifichi questo errore.
vold.encrypt_progress error_not_encrypted L'interfaccia utente della barra di avanzamento dovrebbe visualizzare un messaggio che indica che si è verificato un errore, che nessun dato è stato crittografato o perso e fornire 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 risponderà a questo errore. E comunque non dovrebbe mai succedere.
vold.post_fs_data_done 0 Impostato da vold appena prima di impostare vold.decrypt su trigger_post_fs_data .
vold.post_fs_data_done 1 Impostato da init.rc o init.rc subito dopo aver terminato l'attività post-fs-data .

proprietà iniziali

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

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 usa per impostare la mappatura crittografica.
ro.crypto.tmpfs_options Impostato da init.rc con le opzioni che init dovrebbe utilizzare durante il montaggio del filesystem tmpfs /data .

Azioni iniziali

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