Full-disk encryption è il processo di codifica di tutti i dati dell’utente su un dispositivo Android usando una chiave cifrata. Una volta che un dispositivo è crittografato, tutti i dati creati dall’utente vengono automaticamente crittografati prima di impegnarli sul disco e tutti i dati letti vengono automaticamente decrittati prima di restituirli al processo chiamante.
La crittografia a disco intero è stata introdotta in Android nella 4.4, ma Android 5.0 ha introdotto queste nuove caratteristiche:
- Crittografia veloce creata, che cripta solo i blocchi usati sulla partizione dati per evitare che il primo avvio richieda molto tempo. Attualmente solo i filesystem ext4 e f2fs supportano la crittografia veloce.
- Aggiunto il flag
forceencrypt
fstab per criptare al primo avvio. - Aggiunto il supporto per i modelli e la crittografia senza password.
- Aggiunta la memorizzazione con supporto hardware della chiave di crittografia utilizzando la capacità di firma del Trusted Execution Environment (TEE) (come in una TrustZone). Vedere Memorizzazione della chiave crittografata per maggiori dettagli.
Attenzione: I dispositivi aggiornati ad Android 5.0 e poi crittografati possono essere riportati a uno stato non crittografato mediante un reset dei dati di fabbrica. I nuovi dispositivi Android 5.0 crittografati al primo avvio non possono essere riportati allo stato non crittografato.
- Come funziona la crittografia full-disk di Android
- Flows
- Crittografare un nuovo dispositivo con forceencrypt
- Criptare un dispositivo esistente
- Avvio di un dispositivo criptato con crittografia di default
- Avviare un dispositivo criptato senza crittografia predefinita
- Failure
- Memorizzazione della chiave crittografata
- Modifica della password
- Proprietà di crittografia
- Proprietà di crittografia
- init proprietà
- Azioni di init
Come funziona la crittografia full-disk di Android
La crittografia full-disk di Android si basa su dm-crypt
, che è una caratteristica del kernel che funziona al livello del dispositivo a blocchi. A causa di questo, 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 parla direttamente con un chip rawNAND flash.
L’algoritmo di crittografia è 128 Advanced Encryption Standard (AES) con cifratura a blocchi (CBC) e ESSIV:SHA256. La chiave principale è criptata con AES a 128 bit tramite chiamate alla libreria OpenSSL. Devi usare 128 bit o più per la chiave (256 è opzionale).
Nota: gli OEM possono usare 128 bit o più per crittografare la chiave principale.
Nella versione Android 5.0, ci sono quattro tipi di stati di crittografia:
- default
- PIN
- password
- pattern
Al primo avvio, il dispositivo crea una master key a 128 bit generata in modo casuale e poi la codifica con una password predefinita e un sale memorizzato. La password predefinita è: “default_password “Tuttavia, l’hash risultante è anche firmato attraverso un TEE (come TrustZone), che utilizza un hash della firma per crittografare la chiave principale.
È possibile trovare la password predefinita definita nell’Android Open Source Project cryptfs.cppfile.
Quando l’utente imposta il PIN/pass o la password sul dispositivo, solo la chiave a 128 bit viene nuovamente criptata e memorizzata. (Si noti che i dispositivi gestiti possono essere soggetti a restrizioni di PIN, modello o password.
La crittografia è gestita da init
e vold
.init
chiama vold
, e vold imposta le proprietà per attivare gli eventi init. Altre parti del sistema guardano anche alle proprietà per svolgere compiti come riferire lo stato, chiedere una password, o richiedere un reset di fabbrica nel caso di un errore fatale. Per invocare le funzioni di cifratura in vold
, il sistema usa i comandi cryptfs
dello strumento a riga di comandovdc
: 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 il framework richiede che /data
venga eseguito. Per risolvere questo enigma, viene montato un filesystem temporaneo su /data
, il che permette ad Android di richiedere la password, mostrare il progresso o suggerire una cancellazione dei dati secondo necessità. Impone la limitazione che per passare dal filesystem temporaneo al vero filesystem /data
, il sistema deve fermare ogni processo con file aperti sul filesystem temporaneo e riavviare quei processi sul vero filesystem /data
. Per fare questo, tutti i servizi devono essere in uno dei tre gruppi: core
, main
, elate_start
.
-
core
: Mai spento dopo l’avvio. -
main
: Si spegne e poi si riavvia dopo aver inserito la password del disco. -
late_start
: Non si avvia fino a quando/data
non è stato decriptato e montato.
Per innescare queste azioni, la proprietà vold.decrypt
è impostata su varie stringhe.Per uccidere e riavviare i servizi, i comandi init
sono:
-
class_reset
: Ferma un servizio ma ne permette il riavvio con class_start. -
class_start
: Riavvia un servizio. -
class_stop
: Ferma un servizio e aggiunge un flagSVC_DISABLED
. I servizi fermati non rispondono aclass_start
.
Flows
Ci sono quattro flussi per un dispositivo criptato. Un dispositivo viene criptato solo una volta e poi segue un normale flusso di avvio.
- Cifra un dispositivo precedentemente non cifrato:
- Codifica 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 precedenti).
- Codifica un nuovo dispositivo con
- Avviare un dispositivo crittografato:
- Avviare un dispositivo crittografato senza password: avvio di un dispositivo crittografato che non ha una password impostata (rilevante per i dispositivi con Android 5.0 e successivi).
- Avvio di un dispositivo crittografato con password: avvio di un dispositivo crittografato che ha una password impostata.
In aggiunta a questi flussi, il dispositivo può anche fallire la crittografia /data
.Ognuno dei flussi è spiegato in dettaglio di seguito.
Crittografare un nuovo dispositivo con forceencrypt
Questo è il normale primo avvio per un dispositivo Android 5.0.
- Rileva il filesystem non criptato con
forceencrypt
flag/data
non è criptato ma deve esserlo perchéforceencrypt
lo impone.Smonta/data
. - Iniziare la crittografia di
/data
vold.decrypt = "trigger_encryption"
innescainit.rc
, che causeràvold
per crittografare/data
senza password.(Nessuna è impostata perché questo dovrebbe essere un nuovo dispositivo.) - Mount tmpfs
vold
monta un tmpfs/data
(usando le opzioni tmpfs daro.crypto.tmpfs_options
) e imposta la proprietàvold.encrypt_progress
a 0.vold
prepara il tmpfs/data
per avviare un sistema criptato e imposta la proprietàvold.decrypt
a:trigger_restart_min_framework
- Porta in alto il quadro per mostrare il progresso
Perché il dispositivo non ha praticamente nessun dato da criptare, la barra di progresso spesso non apparirà perché la criptazione avviene così rapidamente. VedereCodificare un dispositivo esistente per maggiori dettagli sull’interfaccia utente di progresso.
- Quando
/data
è criptato, porta giù il frameworkvold
impostavold.decrypt
sutrigger_default_encryption
che avvia il serviziodefaultcrypto
. (Questo avvia il flusso sottostante per il montaggio di dati utente crittografati adefault.)trigger_default_encryption
controlla il tipo di crittografia per vedere se/data
è crittografato con o senza apassword. Poiché i dispositivi Android 5.0 sono crittografati al primo avvio, non dovrebbe essere impostata alcuna password; quindi decifriamo e montiamo/data
. - Mount
/data
init
quindi monta/data
su un RAMDisk tmpfs usando parametri che prende daro.crypto.tmpfs_options
, che è impostato ininit.rc
. - Avvia framework
Imposta
vold
atrigger_restart_framework
, che continua il solito processo di avvio.
Criptare un dispositivo esistente
Questo è ciò che accade quando si cripta un dispositivo Android K o precedente non crittografato che è stato migrato a L.
Questo processo è avviato dall’utente e si riferisce al codice come “inplace encryption”. Quando un utente seleziona di crittografare un dispositivo, l’UI si assicura che la batteria sia completamente carica e che l’adattatore AC sia collegato in modo che ci sia abbastanza potenza per finire il processo di crittografia.
Attenzione: Se il dispositivo esaurisce l’alimentazione e si spegne prima che abbia finito la crittografia, i dati dei file vengono lasciati in uno stato parzialmente crittografato. Il dispositivo deve essere resettato di fabbrica e tutti i dati sono persi.
Per abilitare la crittografia sul posto, vold
inizia un ciclo per leggere ogni settore del dispositivo di blocco reale e poi scriverlo nel dispositivo di blocco crittografico. vold
controlla per vedere 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 esegue il trigger on nonencrypted
init
per continuare l’avvio.
- Controlla la password
L’UI chiama
vold
con il comandocryptfs enablecrypto inplace
dovepasswd
è la password del lock screen dell’utente. - Disattiva il framework
vold
controlla gli errori, restituisce -1 se non può criptare e stampa una ragione nel log. Se può criptare, imposta la proprietàvold.decrypt
atrigger_shutdown_framework
. Questo fa sì cheinit.rc
fermi i servizi nelle classilate_start
emain
. - Crea un crypto footer
- Crea un file breadcrumb
- Riavvia
- Rileva il file breadcrumb
- Inizia a criptare
/data
vold
poi imposta il crypto mapping, che crea un dispositivo virtuale di blocco crittografico che mappa sul dispositivo di blocco reale, ma cripta ogni settore quando viene scritto, e decripta ogni settore quando viene letto.vold
quindi crea e scrive i metadati di crittografia. - Mentre sta criptando, mount tmpfs
vold
monta un tmpfs/data
(usando le opzioni tmpfs diro.crypto.tmpfs_options
) e imposta la proprietàvold.encrypt_progress
a 0.vold
prepara il tmpfs/data
per l’avvio di un sistema criptato e imposta la proprietàvold.decrypt
a:trigger_restart_min_framework
- Porta il framework a mostrare il progresso
trigger_restart_min_framework
causainit.rc
l’avvio della classe di servizimain
. Quando il framework vede chevold.encrypt_progress
è impostato a 0, porta in primo piano la barra di progresso, che interroga quella proprietà ogni cinque secondi e aggiorna una barra di progresso.Il ciclo di crittografia aggiornavold.encrypt_progress
ogni volta che cripta un’altra percentuale della partizione. - Quando
/data
è criptato, aggiorna il piè di pagina crittograficoQuando
/data
è criptato con successo,vold
cancella il flagENCRYPTION_IN_PROGRESS
nei metadati.Quando il dispositivo viene sbloccato con successo, la password viene usata per criptare la chiave principale e il piè di pagina crittografico viene aggiornato.
Se il riavvio fallisce per qualche motivo,
vold
imposta la proprietàvold.encrypt_progress
suerror_reboot_failed
e l’interfaccia utente dovrebbe mostrare un messaggio che chiede all’utente di premere un pulsante per riavviare. Questo non dovrebbe mai accadere.
Avvio di un dispositivo criptato con crittografia di default
Questo è ciò che accade quando si avvia un dispositivo criptato senza password.Poiché i dispositivi Android 5.0 sono criptati al primo avvio, non ci dovrebbe essere alcuna setpassword e quindi questo è lo stato di crittografia di default.
- Rileva
/data
criptato senza passwordRileva che il dispositivo Android è criptato perché
/data
non può essere montato e uno dei flagencryptable
oforceencrypt
è impostato.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
sopra il dispositivo a blocchi in modo che il dispositivo sia pronto all’uso. - Mount /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 impostavold.decrypt
sutrigger_post_fs_data
. Questo fa sì cheinit.rc
esegua i suoi comandipost-fs-data
. Essi creeranno qualsiasi directory o link necessario e poi imposterannovold.post_fs_data_done
a 1.Una volta che
vold
vede l’1 in quella proprietà, imposta la proprietàvold.decrypt
a:trigger_restart_framework.
Questo fa sì cheinit.rc
avvii nuovamente i servizi nella classemain
e anche i servizi nella classelate_start
per la prima volta dall’avvio. - Avvia il framework
Ora il framework avvia tutti i suoi servizi usando il
/data
decriptato, e il sistema è pronto all’uso.
Avviare un dispositivo criptato senza crittografia predefinita
Questo è ciò che accade quando si avvia un dispositivo criptato che ha una password impostata. La password del dispositivo può essere un pin, un modello o una password.
- Rileva dispositivo criptato con password
Rileva che il dispositivo Android è criptato perché il flag
ro.crypto.state = "encrypted"
vold
impostavold.decrypt
atrigger_restart_min_framework
perché/data
è criptato con password. - Monta tmpfs
init
imposta cinque proprietà per salvare le opzioni di montaggio iniziali date per/data
con parametri passati dainit.rc
.vold
usa queste proprietà per impostare la mappatura crittografica:-
ro.crypto.fs_type
-
ro.crypto.fs_real_blkdev
-
ro.crypto.fs_mnt_point
-
ro.crypto.fs_options
-
ro.crypto.fs_flags
(numero esadecimale ASCII di 8 cifre preceduto da 0x)
-
- Avvia il framework per richiedere la password
Il framework si avvia e vede che
vold.decrypt
è impostato sutrigger_restart_min_framework
. Questo dice al framework che si sta avviando su un disco tmpfs/data
e ha bisogno di ottenere la password dell’utente.Prima, però, ha bisogno di assicurarsi che il disco sia stato correttamente criptato. Invia il comando
cryptfs cryptocomplete
avold
.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 di crittografia il flagCRYPTO_ENCRYPTION_IN_PROGRESS
. Se è impostato, il processo di crittografia è stato interrotto, e ci sono dati nousable sul dispositivo. Sevold
restituisce un errore, l’UI dovrebbe mostrare un messaggio all’utente per riavviare e resettare il dispositivo, e dare all’utente un pulsante da premere per farlo. - Decifrare i dati con password
Una volta che
cryptfs cryptocomplete
ha successo, il framework mostra un’UI che chiede la password del disco. L’UI controlla la password inviando il comandocryptfs checkpw
avold
. Se la password è corretta (il che è determinato montando con successo il/data
decriptato in una posizione temporanea, poi 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’UI. - Stop framework
L’UI mette un grafico di avvio crittografico e poi chiama
vold
con il comandocryptfs restart
.vold
imposta la proprietàvold.decrypt
sutrigger_reset_main
, che fa sì cheinit.rc
facciaclass_reset main
. Questo ferma tutti i servizi nella classe principale, il che permette di smontare il tmpfs/data
. - Mount
/data
vold
monta quindi la partizione reale/data
decriptata e prepara la nuova partizione (che potrebbe non essere mai stata preparata se è stata criptata con l’opzione wipe, che non è supportata nella prima release). Imposta la proprietàvold.post_fs_data_done
su 0 e impostavold.decrypt
sutrigger_post_fs_data
. Questo fa sì cheinit.rc
esegua i suoi comandipost-fs-data
. Questi creeranno qualsiasi directory o link necessario e poi imposterannovold.post_fs_data_done
a 1. Una volta chevold
vede l’1 in quella proprietà, imposta la proprietàvold.decrypt
atrigger_restart_framework
. Questo fa sì cheinit.rc
avvii nuovamente i servizi nella classemain
e avvii anche i servizi nella classelate_start
per la prima volta dall’avvio. - Avvia il framework completo
Ora il framework avvia tutti i suoi servizi usando il filesystem
/data
decriptato, e il sistema è pronto all’uso.
Failure
Un dispositivo che non riesce a decifrare potrebbe essere sbagliato per alcune ragioni. Il dispositivo inizia con la normale serie di passi per il boot:
- Rileva il dispositivo criptato con una password
- Monta tmpfs
- Avvia il framework per richiedere la password
Ma dopo che il framework si apre, il dispositivo può incontrare alcuni errori:
- La password corrisponde ma non può decifrare i dati
- L’utente inserisce la password sbagliata 30 volte
Se questi errori non sono risolti, invita l’utente a fare un factory wipe:
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
a error_not_encrypted
.L’UI chiede all’utente di riavviare e lo avverte che il processo di crittografia non è mai iniziato. Se l’errore si verifica dopo che il framework è stato abbattuto, ma prima che la barra di avanzamento UI sia su, vold
riavvierà il sistema. Se il riavvio non riesce, imposta vold.encrypt_progress
aerror_shutting_down
e restituisce -1; ma non ci sarà nulla per catturare l’errore. Non ci si aspetta che questo accada.
Se vold
rileva un errore durante il processo di crittografia, impostavold.encrypt_progress
a error_partially_encrypted
e restituisce -1. L’UI dovrebbe quindi visualizzare un messaggio che dice che la crittografia è fallita e fornire un pulsante per l’utente per resettare il dispositivo.
Memorizzazione della chiave crittografata
La chiave crittografata è memorizzata nei metadati di crittografia. Il supporto hardware è implementato utilizzando la capacità di firma del Trusted Execution Environment (TEE).In precedenza, abbiamo criptato la chiave principale con una chiave generata applicando scrypt alla password dell’utente e al sale memorizzato. 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 poi trasformata in una chiave di lunghezza appropriata da un’altra applicazione di scrypt. Questa chiave viene poi usata per criptare e decriptare la chiave principale. Per memorizzare questa chiave:
- Genera una chiave di cifratura del disco (DEK) casuale a 16 byte e un sale a 16 byte.
- Applica scrypt alla password utente e al sale per produrre la chiave intermedia 1 (IK1) a 32 byte.
- Pad IK1 con zero byte per la dimensione della chiave privata legata all’hardware (HBK): 00 || IK1 || 00..00; un byte zero, 32 byte IK1, 223 byte zero.
- Segnamo IK1 imbottito con HBK per produrre 256 byte IK2.
- Applica scrypt a IK2 e sale (stesso sale del passo 2) per produrre 32 byte IK3.
- Utilizzare i primi 16 byte di IK3 come KEK e gli ultimi 16 byte come IV.
- Codifica DEK con AES_CBC, con chiave KEK e vettore di inizializzazione IV.
Modifica della password
Quando un utente sceglie di cambiare o rimuovere la propria password nelle impostazioni, l’UI invia il comando cryptfs changepw
a vold
, evold
ricodifica la chiave master del disco con la nuova password.
Proprietà di crittografia
vold
e init
comunicano tra loro impostando delle proprietà. Ecco una lista delle proprietà disponibili per la crittografia.
Proprietà di crittografia
Proprietà | Descrizione |
---|---|
vold.decrypt trigger_encryption |
Codifica l’unità senza password. |
vold.decrypt trigger_default_encryption |
Controlla l’unità per vedere se è criptata senza password; se lo è, decriptala e montala, altrimenti imposta vold.decrypt su trigger_restart_min_framework. |
vold.decrypt trigger_reset_main |
Imposta da vold per spegnere l’UI che chiede la password del disco. |
vold.decrypt trigger_post_fs_data |
Imposta da vold per preparare /data con le directory necessarie, ecc. |
vold.decrypt trigger_restart_framework |
Imposta da vold per avviare il vero framework e tutti i servizi. |
vold.decrypt trigger_shutdown_framework |
Imposta da vold per spegnere il framework completo per avviare la crittografia. |
vold.decrypt trigger_restart_min_framework |
Imposta da vold per avviare la barra di avanzamento UI per la crittografia o richiedere la password, a seconda del valore di ro.crypto.state . |
vold.encrypt_progress |
Quando il framework si avvia, se questa proprietà è impostata, entra in modalità progress bar UI. |
vold.encrypt_progress 0 to 100 |
La progress bar UI dovrebbe visualizzare il valore percentuale impostato. |
vold.encrypt_progress error_partially_encrypted |
La barra di avanzamento UI dovrebbe visualizzare un messaggio che la crittografia è fallita, e dare all’utente un’opzione per resettare il dispositivo. |
vold.encrypt_progress error_reboot_failed |
La barra di avanzamento UI dovrebbe visualizzare un messaggio che dice crittografia completata, e dare all’utente un pulsante per riavviare il dispositivo. Questo errore non dovrebbe accadere. |
vold.encrypt_progress error_not_encrypted |
La barra di avanzamento UI dovrebbe visualizzare un messaggio che dice che si è verificato un errore, nessun dato è stato criptato o perso, e dare all’utente un pulsante per riavviare il sistema. |
vold.encrypt_progress error_shutting_down |
La barra di avanzamento UI non è in esecuzione, quindi non è chiaro chi risponderà a questo errore. E comunque non dovrebbe mai accadere. |
vold.post_fs_data_done 0 |
Imposta da vold appena prima di impostare vold.decrypt a trigger_post_fs_data . |
vold.post_fs_data_done 1 |
Imposta da init.rc o init.rc appena dopo aver finito il compito post-fs-data . |
init proprietà
Proprietà | Descrizione |
---|---|
ro.crypto.fs_crypto_blkdev |
Imposta dal comando vold checkpw per essere usata successivamente dal comando vold restart . |
ro.crypto.state unencrypted |
Imposta da init per dire che questo sistema sta funzionando con un /data ro.crypto.state encrypted non criptato. Impostato da init per dire che questo sistema è in esecuzione con un /data criptato. |
|
Queste cinque proprietà sono impostate da init quando prova a montare /data con parametri passati da init.rc . vold le usa per impostare la mappatura crittografica. |
ro.crypto.tmpfs_options |
Imposta da init.rc con le opzioni che init dovrebbe usare quando monta il filesystem tmpfs /data . |