La encriptación de disco completo es el proceso de codificar todos los datos del usuario en un dispositivo Android con una clave encriptada. Una vez que se encripta un dispositivo, todos los datos creados por el usuario se encriptan automáticamente antes de escribirse en el disco, y todas las lecturas desencriptan automáticamente los datos antes de devolverlos al proceso de llamada.
El cifrado de disco completo se introdujo en Android 4.4, pero Android 5.0 incorporó estas nuevas funciones:
- Se creó una encriptación rápida que solo encripta los bloques usados en la partición de datos para evitar que el primer inicio tarde mucho. Actualmente, solo los sistemas de archivos ext4 y f2fs admiten la encriptación rápida.
- Se agregó la marca fstab de
forceencryptpara encriptar en el primer inicio. - Se agregó compatibilidad con patrones y encriptación sin contraseña.
- Se agregó el almacenamiento de la clave de encriptación respaldado por hardware con la capacidad de firma del entorno de ejecución confiable (TEE) (como en una TrustZone). Consulta Cómo almacenar la clave encriptada para obtener más detalles.
Precaución: Los dispositivos que se actualizaron a Android 5.0 y luego se encriptaron pueden volver a un estado sin encriptar si se restablece la configuración de fábrica. Los dispositivos nuevos con Android 5.0 que se encriptan en el primer inicio no se pueden devolver a un estado sin encriptar.
Cómo funciona la encriptación de disco completo de Android
La encriptación de disco completo de Android se basa en dm-crypt, que es una función del kernel que funciona en la capa del dispositivo de bloque. Por este motivo, la encriptación funciona con Embedded MultiMediaCard (eMMC) y dispositivos flash similares que se presentan al kernel como dispositivos de bloque. La encriptación no es posible con YAFFS, que se comunica directamente con un chip flash NAND sin procesar.
El algoritmo de encriptación es el estándar de encriptación avanzada (AES) de 128 bits con encadenamiento de bloques de cifrado (CBC) y ESSIV:SHA256. La clave maestra se encripta con AES de 128 bits a través de llamadas a la biblioteca de OpenSSL. Debes usar 128 bits o más para la clave (256 es opcional).
Nota: Los OEM pueden usar 128 bits o más para encriptar la clave maestra.
En la versión de Android 5.0, hay cuatro tipos de estados de encriptación:
- default
- PIN
- contraseña
- patrón
En el primer arranque, el dispositivo crea una clave maestra de 128 bits generada de forma aleatoria y, luego, la codifica con una contraseña predeterminada y una 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 usa un hash de la firma para encriptar la clave maestra.
Puedes 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, el código o la contraseña en el dispositivo, solo se vuelve a encriptar y almacenar la clave de 128 bits. (es decir, los cambios de PIN, contraseña o patrón del usuario NO provocan el reencriptado de los datos del usuario). Ten en cuenta que el dispositivo administrado puede estar sujeto a restricciones de PIN, patrón o contraseña.
init y vold administran la encriptación.
init llama a vold, y vold establece propiedades para activar 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 las funciones de encriptación en vold, el sistema usa los comandos cryptfs de la herramienta de línea de comandos vdc: checkpw, restart, enablecrypto, changepw, cryptocomplete, verifypw, setfield, getfield, mountdefaultencrypted, getpwtype, getpw y clearpw.
Para encriptar, desencriptar o borrar /data, /data no debe estar montado. Sin embargo, para mostrar cualquier interfaz de usuario (IU), el framework debe iniciarse y requiere /data para ejecutarse. Para resolver este acertijo, se activa un sistema de archivos temporal en /data.
Esto permite que Android solicite contraseñas, muestre el progreso o sugiera un restablecimiento de datos según sea necesario. Sin embargo, 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 ello, todos los servicios deben pertenecer a uno de los tres grupos: core, main y late_start.
core: Nunca se apaga después de iniciarse.main: Apaga y reinicia el equipo después de ingresar la contraseña del disco.late_start: No se inicia hasta que se descifró y se activó/data.
Para activar estas acciones, la propiedad vold.decrypt se establece en varias cadenas.
Para detener y reiniciar servicios, los comandos init son los siguientes:
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 una marcaSVC_DISABLED. Los servicios detenidos no responden aclass_start.
Flows
Existen cuatro flujos para un dispositivo encriptado. Un dispositivo se encripta solo una vez y, luego, sigue un flujo de inicio normal.
- Encripta un dispositivo que no estaba encriptado anteriormente:
- Encripta un dispositivo nuevo con
forceencrypt: Encriptación obligatoria en el primer arranque (a partir de Android L). - Encriptar un dispositivo existente: Encriptación iniciada por el usuario (Android K y versiones anteriores)
- Encripta un dispositivo nuevo con
- Cómo arrancar un dispositivo encriptado:
- Cómo iniciar un dispositivo encriptado sin contraseña: Se inicia un dispositivo encriptado que no tiene una contraseña establecida (relevante para dispositivos con 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 encriptar /data.
A continuación, se explica cada uno de los flujos en detalle.
Cómo encriptar un dispositivo nuevo con forceencrypt
Este es el primer inicio normal de un dispositivo con Android 5.0.
- Detecta un sistema de archivos sin encriptar con la marca
forceencrypt/datano está encriptado, pero debe estarlo porqueforceencryptlo exige. Desmonta/data. - Comenzar a encriptar
/datavold.decrypt = "trigger_encryption"activainit.rc, lo que hace quevoldencripte/datasin contraseña. (No se configuró ninguno porque debería ser un dispositivo nuevo). - Cómo activar tmpfs
voldactiva un tmpfs/data(con las opciones de tmpfs dero.crypto.tmpfs_options) y establece la propiedadvold.encrypt_progressen 0.voldprepara el tmpfs/datapara iniciar un sistema encriptado y establece la propiedadvold.decryptentrigger_restart_min_framework. - Cómo mostrar el framework para indicar el progreso
Como el dispositivo prácticamente no tiene datos para encriptar, la barra de progreso no aparecerá con frecuencia porque la encriptación se realiza muy rápido. Consulta Cómo encriptar un dispositivo existente para obtener más detalles sobre la IU de progreso.
- Cuando
/dataesté encriptado, quita el frameworkvoldestablecevold.decryptentrigger_default_encryption, lo que inicia el serviciodefaultcrypto. (Esto inicia el flujo que se muestra a continuación para montar datos de usuario encriptados predeterminados).trigger_default_encryptionverifica el tipo de encriptación para ver si/dataestá encriptado con o sin contraseña. Dado que los dispositivos con Android 5.0 están encriptados desde el primer inicio, no debería haber una contraseña establecida. Por lo tanto, desencriptamos y montamos/data. - Soporte
/dataLuego,
initactiva/dataen un disco RAM tmpfs con parámetros que toma dero.crypto.tmpfs_options, que se configura eninit.rc. - Start framework
voldestablecevold.decryptentrigger_restart_framework, lo que continúa el proceso de arranque habitual.
Cómo encriptar un dispositivo existente
Esto es lo que sucede cuando encriptas un dispositivo Android K o anterior sin encriptar que se migró a L.
Este proceso lo inicia el usuario y se conoce como “encriptación in situ” en el código. Cuando un usuario selecciona cifrar un dispositivo, la IU 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 cifrado.
Advertencia: Si el dispositivo se queda sin batería y se apaga antes de que termine de encriptar, los datos de los archivos quedarán en un estado parcialmente encriptado. Se debe restablecer la configuración de fábrica del dispositivo y se perderán todos los datos.
Para habilitar la encriptación in situ, vold inicia un bucle para leer cada sector del dispositivo de bloqueo real y, luego, escribirlo en el dispositivo de bloqueo criptográfico. vold verifica si un sector está en uso antes de leerlo y escribirlo, lo que hace que el proceso de encriptación sea mucho más rápido en un dispositivo nuevo que tiene pocos datos o ninguno.
Estado del dispositivo: Establece ro.crypto.state = "unencrypted" y ejecuta el activador on nonencrypted init para continuar con el inicio.
- Verificar contraseña
La IU llama a
voldcon el comandocryptfs enablecrypto inplace, dondepasswdes la contraseña de la pantalla de bloqueo del usuario. - Cómo quitar el framework
voldverifica si hay errores, devuelve -1 si no puede encriptar y registra un motivo en el registro. Si puede encriptar, establece la propiedadvold.decryptentrigger_shutdown_framework. Esto hace queinit.rcdetenga los servicios en las claseslate_startymain. - Cómo crear un pie de página criptográfico
- Crea un archivo de rutas de navegación
- Reiniciar
- Detectar archivo de ruta de navegación
- Comenzar a encriptar
/dataLuego,
voldconfigura la asignación de criptografía, lo que crea un dispositivo de bloqueo criptográfico virtual que se asigna al dispositivo de bloqueo real, pero encripta cada sector a medida que se escribe y desencripta cada sector a medida que se lee. Luego,voldcrea y escribe los metadatos criptográficos. - Mientras se encripta, activa tmpfs
voldactiva un tmpfs/data(con las opciones de tmpfs dero.crypto.tmpfs_options) y establece la propiedadvold.encrypt_progressen 0.voldprepara el tmpfs/datapara iniciar un sistema encriptado y establece la propiedadvold.decryptentrigger_restart_min_framework. - Cómo mostrar el framework para indicar el progreso
trigger_restart_min_frameworkhace queinit.rcinicie la clase de serviciosmain. Cuando el framework ve quevold.encrypt_progressestá establecido en 0, muestra la IU de la barra de progreso, que consulta esa propiedad cada cinco segundos y actualiza una barra de progreso. El bucle de encriptación actualizavold.encrypt_progresscada vez que encripta otro porcentaje de la partición. - Cuando
/dataestá encriptado, actualiza el pie de página criptográficoCuando
/datase encripta correctamente,voldborra la marcaENCRYPTION_IN_PROGRESSen los metadatos.Cuando el dispositivo se desbloquea correctamente, la contraseña se usa para encriptar la clave maestra y se actualiza el pie de página criptográfico.
Si el reinicio falla por algún motivo,
voldestablece la propiedadvold.encrypt_progressenerror_reboot_failed, y la IU debe mostrar un mensaje en el que se le solicite al usuario que presione un botón para reiniciar el dispositivo. No se espera que esto ocurra nunca.
Cómo iniciar un dispositivo encriptado con la encriptación predeterminada
Esto es lo que sucede cuando inicias un dispositivo encriptado sin contraseña. Dado que los dispositivos con Android 5.0 se encriptan en el primer inicio, no debería haber una contraseña establecida y, por lo tanto, este es el estado de encriptación predeterminada.
- Detecta
/dataencriptado sin contraseñaDetectar que el dispositivo Android está encriptado porque no se puede activar
/datay se establece una de las marcasencryptableoforceencryptvoldestablecevold.decryptentrigger_default_encryption, lo que inicia el serviciodefaultcrypto.trigger_default_encryptionverifica el tipo de encriptación para ver si/dataestá encriptado con o sin contraseña. - Desencripta /data
Crea el dispositivo
dm-cryptsobre el dispositivo de bloque para que esté listo para usarse. - Cómo activar /data
vold, luego, se activa la partición/datareal desencriptada y, luego, se prepara la partición nueva. Establece la propiedadvold.post_fs_data_doneen 0 y, luego, establecevold.decryptentrigger_post_fs_data. Esto hace queinit.rcejecute sus comandospost-fs-data. Crean los directorios o vínculos necesarios y, luego, establecenvold.post_fs_data_doneen 1.Una vez que
voldve el 1 en esa propiedad, establece la propiedadvold.decrypten:trigger_restart_framework.Esto hace queinit.rcvuelva a iniciar los servicios en la clasemainy también inicie los servicios en la claselate_startpor primera vez desde el inicio. - Start framework
Ahora, el framework inicia todos sus servicios con el
/datadescifrado, y el sistema está listo para usarse.
Cómo iniciar un dispositivo encriptado sin encriptación predeterminada
Esto es lo que sucede cuando inicias 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.
- Cómo detectar un dispositivo encriptado con una contraseña
Detecta que el dispositivo Android está encriptado porque la marca
ro.crypto.state = "encrypted"voldestablecevold.decryptentrigger_restart_min_frameworkporque/dataestá encriptado con una contraseña. - Cómo activar tmpfs
initestablece cinco propiedades para guardar las opciones de activación iniciales proporcionadas para/datacon los parámetros que se pasan desdeinit.rc.voldusa estas propiedades para configurar la asignación de criptomonedas:ro.crypto.fs_typero.crypto.fs_real_blkdevro.crypto.fs_mnt_pointro.crypto.fs_optionsro.crypto.fs_flags(número hexadecimal de 8 dígitos en ASCII precedido por 0x)
- Iniciar framework para solicitar contraseña
El framework se inicia y ve que
vold.decryptestá establecido entrigger_restart_min_framework. Esto le indica al framework que se está iniciando en un disco/datatmpfs y que debe obtener la contraseña del usuario.Sin embargo, primero debe asegurarse de que el disco se haya encriptado correctamente. Envía el comando
cryptfs cryptocompleteavold.volddevuelve 0 si la encriptación se completó correctamente, -1 si hubo un error interno o -2 si la encriptación no se completó correctamente.volddetermina esto buscando la marcaCRYPTO_ENCRYPTION_IN_PROGRESSen los metadatos criptográficos. Si se establece, significa que se interrumpió el proceso de encriptación y que no hay datos utilizables en el dispositivo. Sivolddevuelve un error, la IU debe mostrar un mensaje al usuario para que reinicie el dispositivo y restablezca la configuración de fábrica, y debe darle al usuario un botón para que lo haga. - Desencriptar datos con contraseña
Una vez que
cryptfs cryptocompletese ejecuta correctamente, el framework muestra una IU que solicita la contraseña del disco. La IU verifica la contraseña enviando el comandocryptfs checkpwavold. Si la contraseña es correcta (lo que se determina al montar correctamente el/datadesencriptado en una ubicación temporal y, luego, desmontarlo),voldguarda el nombre del dispositivo de bloqueo desencriptado en la propiedadro.crypto.fs_crypto_blkdevy devuelve el estado 0 a la IU. Si la contraseña es incorrecta, se devuelve -1 a la IU. - Detener el framework
La IU muestra un gráfico de inicio de criptografía y, luego, llama a
voldcon el comandocryptfs restart.voldestablece la propiedadvold.decryptentrigger_reset_main, lo que hace queinit.rcrealiceclass_reset main. Esto detiene todos los servicios de la clase principal, lo que permite desmontar el/datade tmpfs. - Soporte
/dataLuego,
voldactiva la partición/datareal descifrada y prepara la partición nueva (que tal vez nunca se haya preparado si se encriptó con la opción de borrado, que no se admite en la primera versión). Establece la propiedadvold.post_fs_data_doneen 0 y, luego, establecevold.decryptentrigger_post_fs_data. Esto hace queinit.rcejecute sus comandospost-fs-data. Crea los directorios o vínculos necesarios y, luego, establecevold.post_fs_data_doneen 1. Cuandovoldve el 1 en esa propiedad, establece la propiedadvold.decryptentrigger_restart_framework. Esto hace queinit.rcvuelva a iniciar los servicios en la clasemainy también inicie los servicios en la claselate_startpor primera vez desde el inicio. - Iniciar el framework completo
Ahora, el framework inicia todos sus servicios con el sistema de archivos
/datadescifrado, y el sistema está listo para usarse.
Error
Un dispositivo que no puede descifrar puede tener problemas por varios motivos. El dispositivo comienza con la secuencia normal de pasos para el inicio:
- Detectar un dispositivo encriptado con una contraseña
- Cómo activar tmpfs
- Framework de inicio para solicitar la contraseña
Sin embargo, después de que se abre el marco, el dispositivo puede encontrar algunos errores:
- La contraseña coincide, pero no se pueden desencriptar los datos
- El usuario ingresa una contraseña incorrecta 30 veces.
Si estos errores no se resuelven, pídele al usuario que restablezca la configuración de fábrica:
Si vold detecta un error durante el proceso de encriptación y si aún no se destruyeron datos y el framework está en funcionamiento, vold establece la propiedad vold.encrypt_progress en error_not_encrypted.
La IU le solicita al usuario que reinicie el dispositivo y le advierte que el proceso de encriptación nunca se inició. Si el error se produce después de que se desmantela el framework, pero antes de que aparezca la IU de la barra de progreso, vold reinicia el sistema. Si falla el reinicio, se establece vold.encrypt_progress en error_shutting_down y se devuelve -1, pero no habrá nada para detectar el error. Esto no debería suceder.
Si vold detecta un error durante el proceso de encriptación, establece vold.encrypt_progress en error_partially_encrypted y devuelve -1. Luego, la IU debería mostrar un mensaje que indique que falló el encriptado y proporcionar un botón para que el usuario restablezca la configuración de fábrica del dispositivo.
Almacena la clave encriptada
La clave encriptada se almacena en los metadatos de criptografía. El respaldo de hardware se implementa con la capacidad de firma del entorno de ejecución confiable (TEE). Anteriormente, encriptábamos la clave maestra con una clave generada aplicando scrypt a la contraseña del usuario y a la sal almacenada. Para que la clave sea resistente a los ataques externos, extendemos este algoritmo firmando la clave resultante con una clave del TEE almacenada. Luego, la firma resultante se convierte en una clave de longitud adecuada con una aplicación más de scrypt. Luego, esta clave se usa para encriptar y desencriptar la clave maestra. Para almacenar esta clave, haz lo siguiente:
- Genera una clave de encriptación de disco (DEK) de 16 bytes y una sal de 16 bytes aleatorias.
- Aplica scrypt a la contraseña del usuario y a la sal para generar la clave intermedia 1 (IK1) de 32 bytes.
- Agrega bytes de relleno a IK1 hasta alcanzar el tamaño de la clave privada vinculada al hardware (HBK). Específicamente, agregamos relleno de la siguiente manera: 00 || IK1 || 00…00; un byte cero, 32 bytes de IK1 y 223 bytes cero.
- Firma IK1 con HBK para producir IK2 de 256 bytes.
- Aplica scrypt a IK2 y a la sal (la misma sal que en el paso 2) para producir IK3 de 32 bytes.
- Usa los primeros 16 bytes de IK3 como KEK y los últimos 16 bytes como IV.
- Encripta la DEK con AES_CBC, con la clave KEK y el vector de inicialización IV.
Cambia la contraseña
Cuando un usuario elige cambiar o quitar su contraseña en la configuración, la IU envía el comando cryptfs changepw a vold, y vold vuelve a encriptar la clave maestra del disco con la nueva contraseña.
Propiedades de encriptación
vold y init se comunican entre sí estableciendo propiedades. A continuación, se muestra una lista de las propiedades disponibles para la encriptación.
Propiedades de Vold
| Propiedad | Descripción |
|---|---|
vold.decrypt trigger_encryption |
Encripta la unidad sin contraseña. |
vold.decrypt trigger_default_encryption |
Verifica si la unidad está encriptada sin contraseña.
Si es así, descifrarlo y montarlo; de lo contrario, establecer vold.decrypt en trigger_restart_min_framework. |
vold.decrypt trigger_reset_main |
Vold establece este valor para apagar la IU que solicita la contraseña del disco. |
vold.decrypt trigger_post_fs_data |
vold lo establece para preparar /data con los directorios necesarios, etc. |
vold.decrypt trigger_restart_framework |
Vold lo establece para iniciar el framework real y todos los servicios. |
vold.decrypt trigger_shutdown_framework |
vold lo configura para apagar el framework completo y comenzar la encriptación. |
vold.decrypt trigger_restart_min_framework |
Vold lo establece para iniciar la IU de la barra de progreso para la encriptación o solicitar la contraseña, según el valor de ro.crypto.state. |
vold.encrypt_progress |
Cuando se inicia el framework, si se configura esta propiedad, se ingresa al modo de IU de la barra de progreso. |
vold.encrypt_progress 0 to 100 |
La IU de la barra de progreso debe mostrar el valor porcentual establecido. |
vold.encrypt_progress error_partially_encrypted |
La IU de la barra de progreso debe mostrar un mensaje que indique que falló el encriptado y darle al usuario la opción de restablecer la configuración de fábrica del dispositivo. |
vold.encrypt_progress error_reboot_failed |
La IU de la barra de progreso debe mostrar un mensaje que indique que se completó el proceso de encriptación y proporcionar al usuario un botón para reiniciar el dispositivo. No se espera que se produzca este error. |
vold.encrypt_progress error_not_encrypted |
La IU de la barra de progreso debe mostrar un mensaje que indique que se produjo un error, que no se encriptaron ni perdieron datos, y debe brindarle al usuario un botón para reiniciar el sistema. |
vold.encrypt_progress error_shutting_down |
La IU de la barra de progreso no se está ejecutando, por lo que no está claro quién responde a este error. Y, de todos modos, nunca debería ocurrir. |
vold.post_fs_data_done 0 |
vold lo establece justo antes de establecer vold.decrypt en trigger_post_fs_data. |
vold.post_fs_data_done 1 |
Se establece con init.rc o init.rc justo después de finalizar la tarea post-fs-data. |
Propiedades de inicialización
| Propiedad | Descripción |
|---|---|
ro.crypto.fs_crypto_blkdev |
Se establece con el comando vold checkpw para que el comando vold restart lo use más adelante. |
ro.crypto.state unencrypted |
init lo establece para indicar que este sistema se ejecuta con un /data ro.crypto.state encrypted sin encriptar. init lo establece para indicar que este sistema se ejecuta con un /data encriptado. |
|
init establece estas cinco propiedades cuando intenta activar /data con los parámetros que se pasan desde init.rc. vold usa estos datos para configurar la asignación de criptomonedas. |
ro.crypto.tmpfs_options |
init.rc establece con las opciones que init debe usar cuando se activa el sistema de archivos 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