La crittografia dell'intero 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 salvati su disco e tutte le letture decriptano automaticamente i dati prima di restituirli al processo chiamante.
La crittografia completa del disco è stata introdotta in Android 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. Al momento, solo i file system ext4 e f2fs supportano la crittografia rapida.
- È stato aggiunto il flag fstab
forceencrypt
per la crittografia al primo avvio. - Aggiunto il supporto per sequenze e crittografia senza password.
- È stato aggiunto l'archiviazione della chiave di crittografia supportata dall'hardware utilizzando la funzionalità di firma del Trusted Execution Environment (TEE) (ad esempio in una TrustZone). Per ulteriori dettagli, vedi Memorizzazione della chiave criptata.
Attenzione:i dispositivi aggiornati ad Android 5.0 e poi crittografati possono essere riportati a uno 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 completa del disco di Android
La crittografia completa del disco di Android si basa su dm-crypt
, una funzionalità del kernel
che opera a livello di 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 non elaborato.
L'algoritmo di crittografia è Advanced Encryption Standard (AES) a 128 bit con cipher-block chaining (CBC) e ESSIV:SHA256. La chiave master è criptata con AES a 128 bit tramite chiamate alla libreria OpenSSL. Devi utilizzare almeno 128 bit per la chiave (256 è facoltativo).
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 a 128 bit generata in modo casuale e poi ne calcola l'hash con una password predefinita e un sale memorizzato. La password predefinita è "default_password". Tuttavia, l'hash risultante viene firmato anche tramite un TEE (ad esempio TrustZone), che utilizza un hash della firma per criptare la chiave master.
Puoi trovare la password predefinita definita nel file cryptfs.cpp di Android Open Source Project.
Quando l'utente imposta il PIN/pass o la password sul dispositivo, viene nuovamente criptata e memorizzata solo la chiave a 128 bit. ovvero le modifiche al PIN/alla password/al pattern dell'utente NON causano la ricrittografia dei dati utente. Tieni presente che il dispositivo gestito potrebbe essere soggetto a limitazioni di PIN, sequenza o password.
La crittografia è gestita da init
e vold
.
init
calls vold
e vold imposta le proprietà per attivare
gli eventi in init. Anche altre parti del sistema
esaminano le proprietà per svolgere attività come lo stato del report, richiedere una
password o richiedere il ripristino dei dati di fabbrica in caso di errore irreversibile. Per richiamare
le funzionalità di crittografia in vold
, il sistema utilizza lo strumento a riga di comando
vdc
con i comandi cryptfs
: checkpw
,
restart
, enablecrypto
, changepw
,
cryptocomplete
, verifypw
, setfield
,
getfield
, mountdefaultencrypted
, getpwtype
,
getpw
e clearpw
.
Per criptare, decriptare o cancellare /data
, /data
non deve essere montato. Tuttavia, per mostrare qualsiasi interfaccia utente (UI), il
framework deve essere avviato e richiede /data
per essere eseguito. Per
risolvere questo problema, viene montato un file system temporaneo su /data
.
In questo modo, Android può richiedere le password, mostrare l'avanzamento o suggerire una cancellazione dei dati in base alle esigenze. Impone la limitazione che, per passare dal file system temporaneo al vero file system /data
, il sistema deve arrestare ogni processo con file aperti nel file system temporaneo e riavviare questi processi nel file system /data
reale. A questo scopo, tutti i servizi
devono appartenere a uno dei tre gruppi: core
, main
e
late_start
.
core
: non si arresta mai dopo l'avvio.main
: arresta e riavvia dopo aver inserito la password del disco.late_start
: non viene avviato finché/data
non è stato decrittografato e montato.
Per attivare queste azioni, la proprietà vold.decrypt
è impostata su varie stringhe.
Per arrestare e riavviare i servizi, i comandi init
sono:
class_reset
: Arresta un servizio, ma consente di riavviarlo con class_start.class_start
: riavvia un servizio.class_stop
: arresta un servizio e aggiunge un flagSVC_DISABLED
. I servizi interrotti non rispondono aclass_start
.
Flows
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 precedentemente non criptato:
- Cripta un nuovo dispositivo con
forceencrypt
: crittografia obbligatoria al primo avvio (a partire da Android L). - Cripta un dispositivo esistente: crittografia avviata dall'utente (Android K e versioni precedenti).
- Cripta un nuovo dispositivo con
- Avvia un dispositivo criptato:
- Avvio di un dispositivo criptato senza password: avvio di un dispositivo criptato che non ha una password impostata (pertinente 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 non riuscire a criptare /data
.
Ciascun flusso è spiegato in dettaglio di seguito.
Criptare un nuovo dispositivo con forceencrypt
Questo è il normale primo avvio per un dispositivo Android 5.0.
- Rilevare il file system non criptato con il flag
forceencrypt
/data
non è criptato, ma deve esserlo perché lo richiedeforceencrypt
. Smonta/data
. - Inizia la crittografia
/data
vold.decrypt = "trigger_encryption"
attivainit.rc
, che fa sì chevold
cripti/data
senza password. (Nessuno è impostato perché dovrebbe essere un nuovo dispositivo.) - Monta tmpfs
vold
monta un tmpfs/data
(utilizzando le opzioni tmpfs diro.crypto.tmpfs_options
) e imposta la proprietàvold.encrypt_progress
su 0.vold
prepara tmpfs/data
per l'avvio di un sistema criptato e imposta la proprietàvold.decrypt
su:trigger_restart_min_framework
- Visualizzare il framework per mostrare l'avanzamento
Poiché il dispositivo non ha praticamente 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 Crittografare un dispositivo esistente.
- Quando
/data
è criptato, rimuovi il frameworkvold
impostavold.decrypt
sutrigger_default_encryption
, che avvia il serviziodefaultcrypto
. (In questo modo viene avviato il flusso riportato di seguito per il montaggio di un'unità userdata criptata predefinita.)trigger_default_encryption
controlla il tipo di crittografia per verificare se/data
è criptato con o senza password. Poiché i dispositivi Android 5.0 sono criptati al primo avvio, non dovrebbe essere impostata alcuna password, pertanto decriptiamo e montiamo/data
. - Supporto
/data
init
monta/data
su un RAMDisk tmpfs utilizzando i parametri che rileva daro.crypto.tmpfs_options
, impostato ininit.rc
. - Framework iniziale
vold
impostavold.decrypt
sutrigger_restart_framework
, che continua la normale procedura di avvio.
Criptare un dispositivo esistente
Questo è ciò che accade quando cripti un dispositivo Android K o versioni precedenti che è stato migrato a L.
Questo processo viene avviato dall'utente e nel codice viene chiamato "crittografia sul posto". Quando un utente sceglie di criptare un dispositivo, la UI si assicura che la batteria sia completamente carica e che l'alimentatore sia collegato in modo da avere energia sufficiente per completare la procedura di criptaggio.
Avviso:se il dispositivo si spegne per esaurimento della batteria prima di aver completato la crittografia, i dati dei file rimangono in uno stato di crittografia parziale. Il dispositivo deve essere ripristinato ai dati di fabbrica e tutti i dati vengono persi.
Per attivare la crittografia sul posto, vold
avvia un ciclo per leggere ogni
settore del dispositivo a blocchi reale e poi scriverlo
nel dispositivo a blocchi criptato. 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 il trigger on nonencrypted
init
per continuare l'avvio.
- Controlla password
L'interfaccia utente chiama
vold
con il comandocryptfs enablecrypto inplace
dovepasswd
è la password della schermata di blocco dell'utente. - Rimuovere il framework
vold
verifica la presenza di errori, restituisce -1 se non riesce a criptare e stampa un motivo nel log. Se può criptare, imposta la proprietàvold.decrypt
sutrigger_shutdown_framework
. In questo modo,init.rc
interrompe i servizi nelle classilate_start
emain
. - Creare un piè di pagina crittografico
- Creare un file breadcrumb
- Riavvia
- Rileva file breadcrumb
- Inizia la crittografia
/data
vold
configura quindi la mappatura della crittografia, che crea un dispositivo di crittografia a blocchi virtuale che esegue il mapping sul dispositivo a blocchi reale, ma cripta ogni settore durante la scrittura e decripta ogni settore durante la lettura.vold
quindi crea e scrive i metadati crittografici. - Durante la crittografia, monta tmpfs
vold
monta un tmpfs/data
(utilizzando le opzioni tmpfs diro.crypto.tmpfs_options
) e imposta la proprietàvold.encrypt_progress
su 0.vold
prepara tmpfs/data
per l'avvio di un sistema criptato e imposta la proprietàvold.decrypt
su:trigger_restart_min_framework
- Visualizzare il framework per mostrare l'avanzamento
trigger_restart_min_framework
fa sì cheinit.rc
avvii la classe di servizimain
. Quando il framework rileva chevold.encrypt_progress
è impostato su 0, visualizza l'interfaccia utente della barra di avanzamento, che esegue query su questa proprietà ogni cinque secondi e aggiorna una barra di avanzamento. Il ciclo di crittografia aggiornavold.encrypt_progress
ogni volta che crittografa un altro punto percentuale della partizione. - Quando
/data
è criptato, aggiorna il piè di pagina della crittografiaQuando
/data
viene criptato correttamente,vold
cancella il flagENCRYPTION_IN_PROGRESS
nei metadati.Quando il dispositivo viene sbloccato, 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
suerror_reboot_failed
e l'interfaccia utente deve mostrare un messaggio che chiede all'utente di premere un pulsante per riavviare. Questo problema non dovrebbe mai verificarsi.
Avviare un dispositivo criptato con la crittografia predefinita
Ecco cosa succede quando avvii un dispositivo criptato senza password. Poiché i dispositivi Android 5.0 vengono criptati al primo avvio, non dovrebbe essere impostata alcuna password e pertanto questo è lo stato di crittografia predefinita.
- Rilevare
/data
criptato senza passwordRileva che il dispositivo Android è criptato perché
/data
non può essere montato ed è impostato uno dei flagencryptable
oforceencrypt
.vold
impostavold.decrypt
sutrigger_default_encryption
, che avvia il serviziodefaultcrypto
.trigger_default_encryption
controlla il tipo di crittografia per vedere se/data
è criptato con o senza password. - Decrypt /data
Crea il dispositivo
dm-crypt
sul dispositivo a blocchi in modo che sia pronto per l'uso. - Mount /data
vold
, quindi monta la partizione/data
reale decrittografata e prepara la nuova partizione. Imposta la proprietàvold.post_fs_data_done
su 0 e poi impostavold.decrypt
sutrigger_post_fs_data
. In questo modoinit.rc
esegue i comandipost-fs-data
. Crea le directory o i link necessari e poi impostavold.post_fs_data_done
su 1.Quando
vold
vede l'1 in questa proprietà, imposta la proprietàvold.decrypt
su:trigger_restart_framework.
. In questo modo,init.rc
riavvia i servizi nella classemain
e avvia anche i servizi nella classelate_start
per la prima volta dall'avvio. - Framework iniziale
Ora il framework avvia tutti i suoi servizi utilizzando
/data
decrittografato e il sistema è pronto per l'uso.
Avviare un dispositivo criptato senza crittografia predefinita
Ecco cosa succede quando avvii un dispositivo criptato con una password impostata. La password del dispositivo può essere un PIN, una sequenza o una password.
- Rilevare un dispositivo criptato con una password
Rileva che il dispositivo Android è criptato perché il flag
ro.crypto.state = "encrypted"
vold
impostavold.decrypt
sutrigger_restart_min_framework
perché/data
è criptato con una password. - Monta tmpfs
init
imposta cinque proprietà per salvare le opzioni di montaggio iniziali fornite per/data
con i parametri passati dainit.rc
.vold
utilizza queste proprietà per configurare la mappatura delle criptovalute:ro.crypto.fs_type
ro.crypto.fs_real_blkdev
ro.crypto.fs_mnt_point
ro.crypto.fs_options
ro.crypto.fs_flags
(numero esadecimale di 8 cifre ASCII preceduto da 0x)
- Avvia il framework per richiedere la password
Il framework si avvia e rileva che
vold.decrypt
è impostato sutrigger_restart_min_framework
. Indica al framework che l'avvio avviene su un disco tmpfs/data
e che deve recuperare la password dell'utente.Prima, però, deve assicurarsi che il disco sia stato criptato correttamente. Invia il comando
cryptfs cryptocomplete
avold
.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
lo determina cercando nei metadati di crittografia il flagCRYPTO_ENCRYPTION_IN_PROGRESS
. Se è impostato, il processo di crittografia è stato interrotto e non sono presenti dati utilizzabili sul dispositivo. Sevold
restituisce un errore, l'interfaccia utente deve mostrare un messaggio all'utente per riavviare e ripristinare i dati di fabbrica del dispositivo e fornire un pulsante da premere per farlo. - Decriptare i dati con la password
Una volta che
cryptfs cryptocomplete
ha esito positivo, il framework mostra una UI che chiede la password del disco. La UI controlla la password inviando il comandocryptfs checkpw
avold
. Se la password è corretta (il che viene determinato montando correttamente il/data
decriptato in una posizione temporanea, quindi smontandolo),vold
salva il nome del dispositivo a blocchi decriptato 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. - Stop framework
La UI mostra un'immagine di avvio criptata e poi chiama
vold
con il comandocryptfs restart
.vold
imposta la proprietàvold.decrypt
sutrigger_reset_main
, il che fa sì cheinit.rc
eseguaclass_reset main
. In questo modo vengono arrestati tutti i servizi nella classe principale, il che consente di smontare tmpfs/data
. - Supporto
/data
vold
monta la partizione/data
reale decriptata e prepara la nuova partizione (che potrebbe non essere mai stata preparata se è 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 impostavold.decrypt
sutrigger_post_fs_data
. In questo modo,init.rc
esegue i comandipost-fs-data
. creano le directory o i link necessari e poi impostanovold.post_fs_data_done
su 1. Quandovold
rileva il valore 1 in questa proprietà, imposta la proprietàvold.decrypt
sutrigger_restart_framework
. In questo modo,init.rc
avvia di nuovo i servizi nella classemain
e avvia anche i servizi nella classelate_start
per la prima volta dall'avvio. - Avvia il framework completo
Ora il framework avvia tutti i suoi servizi utilizzando il file system
/data
decriptato e il sistema è pronto per l'uso.
Errore
Un dispositivo che non riesce a decriptare potrebbe non funzionare correttamente per diversi motivi. Il dispositivo inizia con la normale serie di passaggi di avvio:
- Rilevare un dispositivo criptato con una password
- Monta tmpfs
- Start framework to prompt for password
Tuttavia, dopo l'apertura del framework, il dispositivo potrebbe riscontrare alcuni errori:
- La password corrisponde, ma non è possibile 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 ancora stati 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 lo smontaggio del framework, ma
prima che venga visualizzata la barra di avanzamento dell'interfaccia utente, 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 ci sarà nulla
per rilevare l'errore. Questo problema non dovrebbe accadere.
Se vold
rileva un errore durante la procedura di crittografia, imposta
vold.encrypt_progress
su error_partially_encrypted
e restituisce -1. L'UI dovrebbe quindi mostrare un messaggio che indica che la crittografia
non è riuscita e fornire un pulsante per consentire all'utente di ripristinare i dati di fabbrica del dispositivo.
Memorizzare la chiave criptata
La chiave criptata viene archiviata nei metadati di crittografia. Il supporto hardware viene implementato utilizzando la funzionalità di firma del Trusted Execution Environment (TEE). In precedenza, criptavamo la chiave principale con una chiave generata applicando scrypt alla password dell'utente e al sale archiviato. Per rendere la chiave resiliente agli attacchi esterni, estendiamo questo algoritmo firmando la chiave risultante con una chiave TEE archiviata. La firma risultante viene quindi trasformata in una chiave di lunghezza appropriata mediante un'ulteriore applicazione di scrypt. Questa chiave viene poi utilizzata per criptare e decriptare la chiave master. Per memorizzare questa chiave:
- Genera una chiave di crittografia del disco (DEK) casuale di 16 byte e un sale di 16 byte.
- Applica scrypt alla password dell'utente e al sale per produrre la chiave intermedia 1 (IK1) di 32 byte.
- Riempi IK1 con byte zero fino alla dimensione della chiave privata associata all'hardware (HBK). Nello specifico, il padding è: 00 || IK1 || 00..00; un byte zero, 32 byte IK1, 223 byte zero.
- Firma IK1 con riempimento con HBK per produrre IK2 a 256 byte.
- Applica scrypt a IK2 e al sale (lo stesso del passaggio 2) per produrre IK3 di 32 byte.
- Utilizza i primi 16 byte di IK3 come KEK e gli ultimi 16 byte come IV.
- Cripta la DEK con AES_CBC, con la chiave KEK e il vettore di inizializzazione IV.
Cambiare la password
Quando un utente sceglie di modificare o rimuovere la password nelle impostazioni, la UI 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à Vold
Proprietà | Descrizione |
---|---|
vold.decrypt trigger_encryption |
Cripta l'unità senza password. |
vold.decrypt trigger_default_encryption |
Controlla l'unità per vedere se è criptata senza password.
In caso affermativo, 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 e così via. |
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 l'interfaccia utente della barra di avanzamento per la crittografia o per richiedere la password, a seconda del valore di ro.crypto.state . |
vold.encrypt_progress |
Quando il framework si avvia, se questa proprietà è impostata, inserisci 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 |
L'interfaccia utente della barra di avanzamento deve visualizzare un messaggio che indica che la crittografia non è riuscita e offrire all'utente un'opzione per ripristinare i dati di fabbrica del dispositivo. |
vold.encrypt_progress error_reboot_failed |
L'UI della barra di avanzamento deve mostrare un messaggio che indica che la crittografia è stata completata e fornire all'utente un pulsante per riavviare il dispositivo. Questo errore non dovrebbe verificarsi. |
vold.encrypt_progress error_not_encrypted |
L'UI della barra di avanzamento deve mostrare un messaggio che indica che si è verificato un errore, che nessun dato è stato criptato o perso e deve 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 risponda a questo errore. E non dovrebbe mai succedere. |
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 |
Impostato da init.rc o
init.rc subito dopo aver terminato l'attività post-fs-data . |
init properties
Proprietà | Descrizione |
---|---|
ro.crypto.fs_crypto_blkdev |
Impostato dal comando vold checkpw per un utilizzo 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. |
|
Queste cinque proprietà vengono impostate da
init quando tenta di montare /data con i parametri passati da
init.rc . vold utilizza questi valori per configurare la mappatura delle criptovalute. |
ro.crypto.tmpfs_options |
Impostato da init.rc con le opzioni che init deve utilizzare durante
il montaggio del file system tmpfs /data . |
init actions
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