El cifrado de disco completo es el proceso de codificación de todos los datos del usuario en un dispositivo Android mediante una clave cifrada. Una vez que se cifra un dispositivo, todos los datos creados por el usuario se cifran automáticamente antes de enviarlos al disco y todas las lecturas descifran automáticamente los datos antes de devolverlos al proceso de llamada.
El cifrado de disco completo se introdujo en Android en 4.4, pero Android 5.0 introdujo estas nuevas funciones:
- Creó un cifrado rápido, que solo cifra los bloques usados en la partición de datos para evitar que el primer arranque tarde mucho tiempo. Actualmente, solo los sistemas de archivos ext4 y f2fs admiten el cifrado rápido.
- Se agregó el
forceencrypt
fstab para cifrar en el primer arranque. - Se agregó soporte para patrones y encriptación sin contraseña.
- Se agregó almacenamiento respaldado por hardware de la clave de cifrado mediante la capacidad de firma de Trusted Execution Environment (TEE) (como en TrustZone). Consulte Almacenamiento de la clave cifrada para obtener más detalles.
Precaución: Los dispositivos actualizados a Android 5.0 y luego encriptados pueden regresar a un estado no encriptado mediante el restablecimiento de datos de fábrica. Los nuevos dispositivos Android 5.0 cifrados en el primer arranque no se pueden devolver a un estado no cifrado.
Cómo funciona el cifrado de disco completo de Android
El cifrado de disco completo de Android se basa en dm-crypt
, que es una característica del kernel que funciona en la capa de dispositivo de bloque. Debido a esto, el cifrado funciona con Embedded MultiMediaCard ( eMMC) y dispositivos flash similares que se presentan al núcleo como dispositivos de bloque. El cifrado no es posible con YAFFS, que se comunica directamente con un chip flash NAND sin formato.
El algoritmo de cifrado es 128 Advanced Encryption Standard (AES) con encadenamiento de bloques de cifrado (CBC) y ESSIV:SHA256. La clave maestra está cifrada con AES de 128 bits a través de llamadas a la biblioteca OpenSSL. Debe usar 128 bits o más para la clave (256 es opcional).
Nota: los OEM pueden usar 128 bits o más para cifrar la clave maestra.
En la versión de Android 5.0, hay cuatro tipos de estados de cifrado:
- por defecto
- ALFILER
- clave
- patrón
En el primer arranque, el dispositivo crea una clave maestra de 128 bits generada aleatoriamente y luego la codifica con una contraseña predeterminada y sal almacenada. La contraseña predeterminada es: "default_password". Sin embargo, el hash resultante también se firma a través de un TEE (como TrustZone), que utiliza un hash de la firma para cifrar la clave maestra.
Puede encontrar la contraseña predeterminada definida en el archivo cryptfs.cpp del proyecto de código abierto de Android.
Cuando el usuario establece el PIN/contraseña o la contraseña en el dispositivo, solo se vuelve a cifrar y almacenar la clave de 128 bits. (es decir, los cambios de PIN/contraseña/patrón de usuario NO causan el recifrado de los datos de usuario). Tenga en cuenta que el dispositivo administrado puede estar sujeto a restricciones de PIN, patrón o contraseña.
El cifrado es administrado por init
y vold
. init
llama a vold
y vold establece propiedades para desencadenar eventos en init. Otras partes del sistema también analizan las propiedades para realizar tareas como informar el estado, solicitar una contraseña o solicitar un restablecimiento de fábrica en caso de un error fatal. Para invocar funciones de cifrado en vold
, el sistema utiliza los comandos checkpw
de la herramienta de línea de comandos vdc
: cryptfs
, restart
, enablecrypto
, changepw
, cryptocomplete
, verifypw
, setfield
, getfield
, mountdefaultencrypted
, getpwtype
, getpw
y clearpw
.
Para cifrar, descifrar o borrar /data
, /data
no debe estar montado. Sin embargo, para mostrar cualquier interfaz de usuario (IU), el marco debe iniciarse y el marco requiere /data
para ejecutarse. Para resolver este problema, se monta un sistema de archivos temporal en /data
. Esto permite que Android solicite contraseñas, muestre el progreso o sugiera un borrado de datos según sea necesario. Impone la limitación de que para cambiar del sistema de archivos temporal al sistema de archivos /data
verdadero, el sistema debe detener todos los procesos con archivos abiertos en el sistema de archivos temporal y reiniciar esos procesos en el sistema de archivos /data
real. Para hacer esto, todos los servicios deben estar en uno de los tres grupos: core
, main
y late_start
.
-
core
: Nunca apague después de comenzar. -
main
: apague y luego reinicie después de ingresar la contraseña del disco. -
late_start
: no se inicia hasta después/data
haya sido descifrado y montado.
Para desencadenar estas acciones, la propiedad vold.decrypt
se establece en varias cadenas . Para eliminar y reiniciar servicios, los init
de inicio son:
-
class_reset
: detiene un servicio pero permite que se reinicie con class_start. -
class_start
: reinicia un servicio. -
class_stop
: detiene un servicio y agrega un indicadorSVC_DISABLED
. Los servicios detenidos no responden aclass_start
.
Flujos
Hay cuatro flujos para un dispositivo cifrado. Un dispositivo se cifra solo una vez y luego sigue un flujo de arranque normal.
- Cifrar un dispositivo previamente sin cifrar:
- Cifrar un nuevo dispositivo con
forceencrypt
: Cifrado obligatorio en el primer arranque (a partir de Android L). - Cifrar un dispositivo existente: Cifrado iniciado por el usuario (Android K y versiones anteriores).
- Cifrar un nuevo dispositivo con
- Arrancar un dispositivo encriptado:
- Inicio de un dispositivo cifrado sin contraseña: inicio de un dispositivo cifrado que no tiene una contraseña establecida (relevante para dispositivos que ejecutan Android 5.0 y versiones posteriores).
- Iniciar un dispositivo encriptado con una contraseña: Arrancar un dispositivo encriptado que tiene una contraseña establecida.
Además de estos flujos, el dispositivo también puede fallar al cifrar /data
. Cada uno de los flujos se explica en detalle a continuación.
Cifrar un nuevo dispositivo con forceencrypt
Este es el primer arranque normal para un dispositivo Android 5.0.
- Detectar el sistema de archivos sin cifrar con el indicador
forceencrypt
/data
no está encriptado, pero debe estarlo porqueforceencrypt
lo exige. Desmontar/data
. - Empezar a cifrar
/data
vold.decrypt = "trigger_encryption"
activainit.rc
, lo que hará quevold
cifre/data
sin contraseña. (Ninguno está configurado porque debería ser un dispositivo nuevo). - Montar tmpfs
vold
monta un tmpfs/data
(utilizando las opciones tmpfs dero.crypto.tmpfs_options
) y establece la propiedadvold.encrypt_progress
en 0.vold
prepara el tmpfs/data
para iniciar un sistema cifrado y establece la propiedadvold.decrypt
en:trigger_restart_min_framework
- Mostrar el marco para mostrar el progreso
Debido a que el dispositivo prácticamente no tiene datos para cifrar, la barra de progreso a menudo no aparecerá porque el cifrado ocurre muy rápido. Consulte Cifrar un dispositivo existente para obtener más detalles sobre la interfaz de usuario de progreso.
- Cuando
/data
está encriptado, elimine el marcovold
establecevold.decrypt
entrigger_default_encryption
que inicia el servicio dedefaultcrypto
. (Esto inicia el siguiente flujo para montar datos de usuario cifrados predeterminados).trigger_default_encryption
comprueba el tipo de cifrado para ver si/data
está cifrado con o sin contraseña. Debido a que los dispositivos con Android 5.0 se cifran en el primer arranque, no se debe establecer una contraseña; por lo tanto, desciframos y montamos/data
. - Monte
/data
init
luego monta/data
en un tmpfs RAMDisk usando parámetros que recoge dero.crypto.tmpfs_options
, que se establece eninit.rc
. - Marco de inicio
Establezca
vold
entrigger_restart_framework
, que continúa el proceso de arranque habitual.
Cifrar un dispositivo existente
Esto es lo que sucede cuando cifra un dispositivo Android K o anterior sin cifrar que se ha migrado a L.
Este proceso es iniciado por el usuario y se denomina "cifrado en el lugar" en el código. Cuando un usuario selecciona encriptar un dispositivo, la interfaz de usuario se asegura de que la batería esté completamente cargada y el adaptador de CA esté enchufado para que haya suficiente energía para finalizar el proceso de encriptación.
Advertencia: si el dispositivo se queda sin energía y se apaga antes de que haya terminado de cifrar, los datos del archivo quedan en un estado parcialmente cifrado. El dispositivo debe restablecerse de fábrica y se perderán todos los datos.
Para habilitar el cifrado en el lugar, vold
inicia un ciclo para leer cada sector del dispositivo de bloque real y luego lo escribe en el dispositivo de bloque criptográfico. vold
verifica si un sector está en uso antes de leerlo y escribirlo, lo que hace que el cifrado sea mucho más rápido en un dispositivo nuevo que tiene poca o ninguna información.
Estado del dispositivo : establezca init
ro.crypto.state = "unencrypted"
y ejecute el on nonencrypted
de inicio sin cifrar para continuar con el arranque.
- Comprobar contraseña
La interfaz de usuario llama a
vold
con el comandocryptfs enablecrypto inplace
en el lugar dondepasswd
es la contraseña de la pantalla de bloqueo del usuario. - Derribar el marco
vold
comprueba si hay errores, devuelve -1 si no puede cifrar e imprime un motivo en el registro. Si puede cifrar, establece la propiedadvold.decrypt
entrigger_shutdown_framework
. Esto hace queinit.rc
detenga los servicios en las claseslate_start
ymain
. - Crear un pie de página criptográfico
- Crear un archivo de migas de pan
- Reiniciar
- Detectar archivo de migas de pan
- Empezar a cifrar
/data
vold
luego configura el mapeo criptográfico, que crea un dispositivo de bloque criptográfico virtual que se asigna al dispositivo de bloque real pero encripta cada sector a medida que se escribe y descifra cada sector a medida que se lee.vold
luego crea y escribe los metadatos criptográficos. - Mientras está cifrando, monte tmpfs
vold
monta un tmpfs/data
(utilizando las opciones tmpfs dero.crypto.tmpfs_options
) y establece la propiedadvold.encrypt_progress
en 0.vold
prepara tmpfs/data
para iniciar un sistema cifrado y establece la propiedadvold.decrypt
en:trigger_restart_min_framework
- Mostrar el marco para mostrar el progreso
trigger_restart_min_framework
hace queinit.rc
inicie la clasemain
de servicios. Cuando el marco ve quevold.encrypt_progress
está establecido en 0, muestra la interfaz de usuario de la barra de progreso, que consulta esa propiedad cada cinco segundos y actualiza una barra de progreso. El bucle de cifrado actualizavold.encrypt_progress
cada vez que cifra otro porcentaje de la partición. - Cuando
/data
está encriptado, actualice el pie de página criptográficoCuando
/data
se cifra con éxito,vold
borra la marcaENCRYPTION_IN_PROGRESS
en los metadatos.Cuando el dispositivo se desbloquea con éxito, la contraseña se usa para cifrar la clave maestra y se actualiza el pie de página criptográfico.
Si el reinicio falla por algún motivo,
vold
establece la propiedadvold.encrypt_progress
enerror_reboot_failed
y la interfaz de usuario debe mostrar un mensaje que le pide al usuario que presione un botón para reiniciar. No se espera que esto ocurra nunca.
Inicio de un dispositivo cifrado con cifrado predeterminado
Esto es lo que sucede cuando inicia un dispositivo encriptado sin contraseña. Debido a que los dispositivos con Android 5.0 se cifran en el primer arranque, no debe establecerse una contraseña y, por lo tanto, este es el estado de cifrado predeterminado .
- Detectar
/data
cifrados sin contraseñaDetecte que el dispositivo Android está cifrado porque
/data
no se puede montar y uno de los indicadores deencryptable
oforceencrypt
está configurado.vold
establecevold.decrypt
entrigger_default_encryption
, lo que inicia el serviciodefaultcrypto
.trigger_default_encryption
comprueba el tipo de cifrado para ver si/data
está cifrado con o sin contraseña. - Descifrar /datos
Crea el dispositivo
dm-crypt
sobre el dispositivo de bloque para que el dispositivo esté listo para su uso. - Monte /datos
vold
luego monta la partición real/data
descifrada y luego prepara la nueva partición. Establece la propiedadvold.post_fs_data_done
en 0 y luego establecevold.decrypt
entrigger_post_fs_data
. Esto hace queinit.rc
ejecute sus comandospost-fs-data
. Crearán los directorios o enlaces necesarios y luego estableceránvold.post_fs_data_done
en 1.Una vez que
vold
ve el 1 en esa propiedad, establece la propiedadvold.decrypt
en:trigger_restart_framework.
Esto hace queinit.rc
inicie los servicios en la clasemain
nuevamente y también inicie los servicios en la claselate_start
por primera vez desde el inicio. - Marco de inicio
Ahora el marco arranca todos sus servicios usando
/data
descifrado y el sistema está listo para usar.
Inicio de un dispositivo encriptado sin encriptación predeterminada
Esto es lo que sucede cuando inicia un dispositivo encriptado que tiene una contraseña establecida. La contraseña del dispositivo puede ser un PIN, un patrón o una contraseña.
- Detectar dispositivo encriptado con una contraseña
Detectar que el dispositivo Android está encriptado porque la bandera
ro.crypto.state = "encrypted"
vold
establecevold.decrypt
entrigger_restart_min_framework
porque/data
está encriptado con una contraseña. - Montar tmpfs
init
establece cinco propiedades para guardar las opciones de montaje iniciales dadas para/data
con parámetros pasados desdeinit.rc
.vold
usa estas propiedades para configurar el mapeo criptográfico:-
ro.crypto.fs_type
-
ro.crypto.fs_real_blkdev
-
ro.crypto.fs_mnt_point
-
ro.crypto.fs_options
-
ro.crypto.fs_flags
(número hexadecimal de 8 dígitos ASCII precedido por 0x)
-
- Inicie el marco para solicitar la contraseña
El marco se inicia y ve que
vold.decrypt
está configurado entrigger_restart_min_framework
. Esto le dice al marco que está arrancando en un disco tmpfs/data
y necesita obtener la contraseña de usuario.Sin embargo, primero debe asegurarse de que el disco se haya cifrado correctamente. Envía el comando
cryptfs cryptocomplete
avold
.vold
devuelve 0 si el cifrado se completó con éxito, -1 en caso de error interno o -2 si el cifrado no se completó con éxito.vold
determina esto buscando en los metadatos criptográficos el indicadorCRYPTO_ENCRYPTION_IN_PROGRESS
. Si está configurado, el proceso de cifrado se interrumpió y no hay datos utilizables en el dispositivo. Sivold
devuelve un error, la interfaz de usuario debe mostrar un mensaje al usuario para que reinicie y restablezca los valores de fábrica del dispositivo, y le debe dar al usuario un botón para presionar para hacerlo. - Descifrar datos con contraseña
Una vez
cryptfs cryptocomplete
tiene éxito, el marco muestra una interfaz de usuario que solicita la contraseña del disco. La interfaz de usuario comprueba la contraseña enviando el comandocryptfs checkpw
avold
. Si la contraseña es correcta (que se determina montando con éxito los/data
descifrados en una ubicación temporal y luego desmontándolos),vold
guarda el nombre del dispositivo de bloque descifrado en la propiedadro.crypto.fs_crypto_blkdev
y devuelve el estado 0 a la interfaz de usuario. . Si la contraseña es incorrecta, devuelve -1 a la interfaz de usuario. - Marco de parada
La interfaz de usuario muestra un gráfico de arranque criptográfico y luego llama a
vold
con el comandocryptfs restart
.vold
establece la propiedadvold.decrypt
entrigger_reset_main
, lo que hace queinit.rc
hagaclass_reset main
. Esto detiene todos los servicios en la clase principal, lo que permite desmontar tmpfs/data
. - Monte
/data
vold
luego monta la partición real/data
descifrada y prepara la nueva partición (que puede que nunca se haya preparado si se cifró con la opción de borrado, que no es compatible con la primera versión). Establece la propiedadvold.post_fs_data_done
en 0 y luego establecevold.decrypt
entrigger_post_fs_data
. Esto hace queinit.rc
ejecute sus comandospost-fs-data
. Crearán los directorios o enlaces necesarios y luego estableceránvold.post_fs_data_done
en 1. Una vez quevold
vea el 1 en esa propiedad, establece la propiedadvold.decrypt
entrigger_restart_framework
. Esto hace queinit.rc
inicie los servicios en la clasemain
nuevamente y también inicie los servicios en la claselate_start
por primera vez desde el inicio. - Iniciar marco completo
Ahora el marco arranca todos sus servicios utilizando el sistema de archivos
/data
descifrado y el sistema está listo para usarse.
Falla
Un dispositivo que no puede descifrar puede estar mal por varias razones. El dispositivo comienza con la serie normal de pasos para arrancar:
- Detectar dispositivo encriptado con una contraseña
- Montar tmpfs
- Inicie el marco para solicitar la contraseña
Pero después de que se abre el marco, el dispositivo puede encontrar algunos errores:
- La contraseña coincide pero no puede descifrar los datos
- El usuario ingresa una contraseña incorrecta 30 veces
Si estos errores no se resuelven, solicite al usuario que borre de fábrica :
Si vold
detecta un error durante el proceso de encriptación, y si aún no se destruyeron datos y el marco está activo, vold
establece la propiedad vold.encrypt_progress
en error_not_encrypted
. La interfaz de usuario solicita al usuario que reinicie y le advierte que el proceso de cifrado nunca se inició. Si el error se produce después de que se haya eliminado el marco, pero antes de que se active la interfaz de usuario de la barra de progreso, vold
reiniciará el sistema. Si el reinicio falla, establece vold.encrypt_progress
en error_shutting_down
y devuelve -1; pero no habrá nada para detectar el error. No se espera que esto suceda.
Si vold
detecta un error durante el proceso de cifrado, establece vold.encrypt_progress
en error_partially_encrypted
y devuelve -1. La interfaz de usuario debería mostrar un mensaje que indique que el cifrado falló y proporcionar un botón para que el usuario restablezca el dispositivo de fábrica.
Almacenamiento de la clave cifrada
La clave cifrada se almacena en los metadatos criptográficos. El respaldo de hardware se implementa mediante el uso de la capacidad de firma de Trusted Execution Environment (TEE). Anteriormente, encriptamos la clave maestra con una clave generada al aplicar scrypt a la contraseña del usuario y la sal almacenada. Para hacer que la clave sea resistente a los ataques externos, ampliamos este algoritmo firmando la clave resultante con una clave TEE almacenada. La firma resultante se convierte luego en una clave de longitud adecuada mediante una aplicación más de scrypt. Esta clave luego se usa para cifrar y descifrar la clave maestra. Para almacenar esta clave:
- Genere una clave de cifrado de disco (DEK) aleatoria de 16 bytes y sal de 16 bytes.
- Aplique scrypt a la contraseña de usuario y la sal para producir la clave intermedia 1 de 32 bytes (IK1).
- Rellene IK1 con cero bytes al tamaño de la clave privada vinculada al hardware (HBK). Específicamente, rellenamos como: 00 || IK1 || 00..00; un byte cero, 32 bytes IK1, 223 bytes cero.
- Firme IK1 rellenado con HBK para producir IK2 de 256 bytes.
- Aplique scrypt a IK2 y sal (la misma sal que en el paso 2) para producir IK3 de 32 bytes.
- Utilice los primeros 16 bytes de IK3 como KEK y los últimos 16 bytes como IV.
- Cifre DEK con AES_CBC, con clave KEK y vector de inicialización IV.
Cambiar la contraseña
Cuando un usuario elige cambiar o eliminar su contraseña en la configuración, la interfaz de usuario envía el comando cryptfs changepw
a vold
y vold
vuelve a cifrar la clave maestra del disco con la nueva contraseña.
Propiedades de cifrado
vold
e init
se comunican entre sí estableciendo propiedades. Aquí hay una lista de propiedades disponibles para el cifrado.
propiedades vold
Propiedad | Descripción |
---|---|
vold.decrypt trigger_encryption | Cifre la unidad sin contraseña. |
vold.decrypt trigger_default_encryption | Verifique la unidad para ver si está encriptada sin contraseña. Si es así, descifrarlo y montarlo; de lo contrario, establezca vold.decrypt en trigger_restart_min_framework. |
vold.decrypt trigger_reset_main | Establecido por vold para apagar la interfaz de usuario solicitando la contraseña del disco. |
vold.decrypt trigger_post_fs_data | Establecido por vold para preparar /data con los directorios necesarios, et al. |
vold.decrypt trigger_restart_framework | Establecido por vold para iniciar el marco real y todos los servicios. |
vold.decrypt trigger_shutdown_framework | Establecido por vold para cerrar el marco completo para iniciar el cifrado. |
vold.decrypt trigger_restart_min_framework | Establecido por vold para iniciar la interfaz de usuario de la barra de progreso para el cifrado o solicitar la contraseña, según el valor de ro.crypto.state . |
vold.encrypt_progress | Cuando se inicia el marco, si esta propiedad está configurada, ingrese al modo de interfaz de usuario de la barra de progreso. |
vold.encrypt_progress 0 to 100 | La interfaz de usuario de la barra de progreso debe mostrar el valor de porcentaje establecido. |
vold.encrypt_progress error_partially_encrypted | La interfaz de usuario de la barra de progreso debe mostrar un mensaje que indique que el cifrado falló y brindar al usuario la opción de restablecer el dispositivo a los valores de fábrica. |
vold.encrypt_progress error_reboot_failed | La interfaz de usuario de la barra de progreso debe mostrar un mensaje que diga que el cifrado se completó y darle al usuario un botón para reiniciar el dispositivo. No se espera que ocurra este error. |
vold.encrypt_progress error_not_encrypted | La interfaz de usuario de la barra de progreso debe mostrar un mensaje que indique que se produjo un error, que no se cifraron ni se perdieron datos, y que el usuario tenga un botón para reiniciar el sistema. |
vold.encrypt_progress error_shutting_down | La interfaz de usuario de la barra de progreso no se está ejecutando, por lo que no está claro quién responderá a este error. Y nunca debería suceder de todos modos. |
vold.post_fs_data_done 0 | Establecido por vold justo antes de configurar vold.decrypt en trigger_post_fs_data . |
vold.post_fs_data_done 1 | Establecido por init.rc o init.rc justo después de terminar la tarea post-fs-data . |
propiedades de inicio
Propiedad | Descripción |
---|---|
ro.crypto.fs_crypto_blkdev | Establecido por el comando vold checkpw para su uso posterior por el restart del comando vold . |
ro.crypto.state unencrypted | Configurado por init para decir que este sistema se está ejecutando con un /data ro.crypto.state encrypted . Configurado por init para decir que este sistema se está ejecutando con un /data encriptado. |
| Estas cinco propiedades las establece init cuando intenta montar /data con parámetros pasados desde init.rc . vold los usa para configurar el mapeo criptográfico. |
ro.crypto.tmpfs_options | Establecido por init.rc con las opciones que debe usar init al montar el sistema de archivos tmpfs /data . |
Acciones de inicio
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