Encriptación de metadatos

Android 7.0 y versiones posteriores admiten la encriptación basada en archivos (FBE). La FBE permite encriptar diferentes archivos con diferentes claves que se pueden desbloquear de forma independiente. Estas claves se usan para encriptar contenidos y nombres de archivos. Cuando se usa el FBE, no se encripta otra información, como los diseños de directorio, el tamaño de los archivos, los permisos y los tiempos de creación o modificación. En conjunto, esta otra información se conoce como metadatos del sistema de archivos.

En Android 9, se introdujo compatibilidad con la encriptación de metadatos. Con la encriptación de metadatos, una sola clave presente al momento del inicio encripta todo el contenido que no encripta la FBE. Esta clave está protegida por Keymaster, que, a su vez, está protegida por el inicio verificado.

La encriptación de metadatos siempre está habilitada en el almacenamiento adoptable cuando se habilita la FBE. La encriptación de metadatos también se puede habilitar en el almacenamiento interno. Los dispositivos que se lanzan con Android 11 o versiones posteriores deben tener habilitada la encriptación de metadatos en el almacenamiento interno.

Implementación en el almacenamiento interno

Para configurar la encriptación de metadatos en el almacenamiento interno de dispositivos nuevos, configura el sistema de archivos metadata, cambia la secuencia de init y habilita la encriptación de metadatos en el archivo fstab del dispositivo.

Requisitos previos

La encriptación de metadatos solo se puede configurar cuando se formatea la partición de datos por primera vez. Como resultado, esta función es solo para dispositivos nuevos; no es algo que deba cambiar una actualización inalámbrica.

La encriptación de metadatos requiere que el módulo dm-default-key esté habilitado en el kernel. En Android 11 y versiones posteriores, dm-default-key es compatible con los kernels comunes de Android, versión 4.14 y versiones posteriores. Esta versión de dm-default-key usa un framework de encriptación independiente del hardware y el proveedor llamado blk-crypto.

Para habilitar dm-default-key, usa lo siguiente:

CONFIG_BLK_INLINE_ENCRYPTION=y
CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y
CONFIG_DM_DEFAULT_KEY=y

dm-default-key usa hardware de encriptación intercalada (hardware que encripta o desencripta datos mientras se envían al dispositivo de almacenamiento o salen de él) cuando está disponible. Si no usas hardware de encriptación intercalada, también es necesario habilitar un resguardo de la API de criptografía del kernel:

CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y

Cuando no uses hardware de encriptación intercalada, también debes habilitar cualquier aceleración disponible basada en la CPU, como se recomienda en la documentación de FBE.

En Android 10 y versiones anteriores, el kernel común de Android no era compatible con dm-default-key. Por lo tanto, era responsabilidad de los proveedores implementar dm-default-key.

Configura el sistema de archivos de metadatos

Debido a que no se puede leer nada en la partición de datos del usuario hasta que esté presente la clave de encriptación de metadatos, la tabla de particiones debe reservar una partición independiente llamada "partición de metadatos" para almacenar los fragmentos de Keymaster que protegen esta clave. La partición de metadatos debe ser de 16 MB.

fstab.hardware debe incluir una entrada para el sistema de archivos de metadatos que se encuentra en esa partición y que se activa en /metadata, incluida la marca formattable para garantizar que se formatee durante el inicio. El sistema de archivos f2fs no funciona en particiones más pequeñas; recomendamos usar ext4 en su lugar. Por ejemplo:

/dev/block/bootdevice/by-name/metadata              /metadata          ext4        noatime,nosuid,nodev,discard                          wait,check,formattable

Para asegurarte de que exista el punto de activación /metadata, agrega la siguiente línea a BoardConfig-common.mk:

BOARD_USES_METADATA_PARTITION := true

Cambios en la secuencia de inicio

Cuando se usa la encriptación de metadatos, vold debe estar en ejecución antes de que se monte /data. Para asegurarte de que se inicie con suficiente anticipación, agrega la siguiente estrofa a init.hardware.rc:

# We need vold early for metadata encryption
on early-fs
    start vold

Keymaster debe estar en ejecución y listo antes de que init intente activar /data.

init.hardware.rc ya debería contener una instrucción mount_all que active /data en la estrofa on late-fs. Antes de esta línea, agrega la directiva para ejecutar el servicio wait_for_keymaster:

on late-fs
    
    # Wait for keymaster
    exec_start wait_for_keymaster

    # Mount RW partitions which need run fsck
    mount_all /vendor/etc/fstab.${ro.boot.hardware.platform} --late

Activa la encriptación de metadatos

Por último, agrega keydirectory=/metadata/vold/metadata_encryption a la columna fs_mgr_flags de la entrada fstab para userdata. Por ejemplo, una línea fstab completa podría verse de la siguiente manera:

/dev/block/bootdevice/by-name/userdata              /data              f2fs        noatime,nosuid,nodev,discard,inlinecrypt latemount,wait,check,fileencryption=aes-256-xts:aes-256-cts:inlinecrypt_optimized,keydirectory=/metadata/vold/metadata_encryption,quota,formattable

De forma predeterminada, el algoritmo de encriptación de metadatos en el almacenamiento interno es AES-256-XTS. Para anular esta configuración, establece la opción metadata_encryption, también en la columna fs_mgr_flags:

  • En los dispositivos que no tienen aceleración AES, se puede habilitar la encriptación Adiantum si se configura metadata_encryption=adiantum.
  • En los dispositivos que admiten claves empaquetadas en hardware, la clave de encriptación de metadatos se puede empaquetar en hardware configurando metadata_encryption=aes-256-xts:wrappedkey_v0 (o, de manera equivalente, metadata_encryption=:wrappedkey_v0, ya que aes-256-xts es el algoritmo predeterminado).

Debido a que la interfaz del kernel a dm-default-key cambió en Android 11, también debes asegurarte de establecer el valor correcto para PRODUCT_SHIPPING_API_LEVEL en device.mk. Por ejemplo, si tu dispositivo se inicia con Android 11 (nivel de API 30), device.mk debe contener lo siguiente:

PRODUCT_SHIPPING_API_LEVEL := 30

También puedes configurar la siguiente propiedad del sistema para forzar el uso de la nueva API de dm-default-key, sin importar el nivel de API de envío:

PRODUCT_PROPERTY_OVERRIDES += \
    ro.crypto.dm_default_key.options_format.version=2

Validación

Para verificar que la encriptación de metadatos esté habilitada y funcione correctamente, ejecuta las pruebas que se describen a continuación. Además, ten en cuenta los problemas comunes que se describen a continuación.

Pruebas

Para comenzar, ejecuta el siguiente comando para verificar que la encriptación de metadatos esté habilitada en el almacenamiento interno:

adb root
adb shell dmctl table userdata

El resultado debería ser similar al siguiente:

Targets in the device-mapper table for userdata:
0-4194304: default-key, aes-xts-plain64 - 0 252:2 0 3 allow_discards sector_size:4096 iv_large_sectors

Si anulaste la configuración de encriptación predeterminada al establecer la opción metadata_encryption en el fstab del dispositivo, el resultado será un poco distinto al anterior. Por ejemplo, si habilitaste la encriptación Adiantum, el tercer campo es xchacha12,aes-adiantum-plain64 en lugar de aes-xts-plain64.

A continuación, ejecuta vts_kernel_encryption_test para verificar la exactitud de la encriptación de metadatos y la FBE:

atest vts_kernel_encryption_test

O bien:

vts-tradefed run vts -m vts_kernel_encryption_test

Problemas comunes

Durante la llamada a mount_all, que activa la partición /data encriptada con metadatos, init ejecuta la herramienta de vdc. La herramienta vdc se conecta a vold a través de binder para configurar el dispositivo encriptado con metadatos y activar la partición. Durante esta llamada, init está bloqueado y se intenta leer o establecer el bloque de propiedades init hasta que finaliza mount_all. Si, en esta etapa, alguna parte del trabajo de vold está bloqueada directa o indirectamente para leer o establecer una propiedad, se produce un interbloqueo. Es importante asegurarse de que vold pueda completar el trabajo de leer las llaves, interactuar con Keymaster y activar el directorio de datos sin interactuar más con init.

Si Keymaster no se inicia por completo cuando se ejecuta mount_all, no responde a vold hasta que lee ciertas propiedades de init, lo que genera exactamente el interbloqueo descrito. Colocar exec_start wait_for_keymaster por encima de la invocación mount_all relevante como se indica garantiza que Keymaster se ejecute por completo con anticipación y, por lo tanto, se evita este interbloqueo.

Configuración del almacenamiento adoptable

A partir de Android 9, siempre se habilita una forma de encriptación de metadatos en el almacenamiento adoptable cada vez que se habilita la FBE, incluso cuando la encriptación de metadatos no está habilitada en el almacenamiento interno.

En AOSP, hay dos implementaciones de encriptación de metadatos en el almacenamiento adoptable: una obsoleta basada en dm-crypt y una más nueva basada en dm-default-key. Para asegurarte de que se seleccione la implementación correcta para tu dispositivo, asegúrate de haber establecido el valor correcto para PRODUCT_SHIPPING_API_LEVEL en device.mk. Por ejemplo, si tu dispositivo se inicia con Android 11 (nivel de API 30), device.mk debe contener lo siguiente:

PRODUCT_SHIPPING_API_LEVEL := 30

También puedes establecer las siguientes propiedades del sistema para forzar el uso del nuevo método de encriptación de metadatos de volumen (y la nueva versión predeterminada de la política de FBE) independientemente del nivel de API de envío:

PRODUCT_PROPERTY_OVERRIDES += \
    ro.crypto.volume.metadata.method=dm-default-key \
    ro.crypto.dm_default_key.options_format.version=2 \
    ro.crypto.volume.options=::v2

Método actual

En los dispositivos que se inician con Android 11 o versiones posteriores, la encriptación de metadatos en el almacenamiento adoptable usa el módulo del kernel dm-default-key, al igual que en el almacenamiento interno. Consulta los requisitos previos anteriores para saber qué opciones de configuración del kernel debes habilitar. Ten en cuenta que el hardware de encriptación intercalada que funciona en el almacenamiento interno del dispositivo puede no estar disponible en el almacenamiento adoptable y, por lo tanto, es posible que se requiera CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y.

De forma predeterminada, el método de encriptación de metadatos de volumen dm-default-key usa el algoritmo de encriptación AES-256-XTS con sectores de criptografía de 4,096 bytes. Para anular el algoritmo, configura la propiedad del sistema ro.crypto.volume.metadata.encryption. El valor de esta propiedad tiene la misma sintaxis que la opción fstab metadata_encryption descrita anteriormente. Por ejemplo, en dispositivos sin aceleración AES, la encriptación Adiantum se puede habilitar configurando ro.crypto.volume.metadata.encryption=adiantum.

Método heredado

En los dispositivos que se inician con Android 10 o versiones anteriores, la encriptación de metadatos en el almacenamiento adoptable usa el módulo de kernel dm-crypt en lugar de dm-default-key:

CONFIG_DM_CRYPT=y

A diferencia del método dm-default-key, el método dm-crypt hace que el contenido del archivo se encripte dos veces: una con una clave FBE y otra con la clave de encriptación de metadatos. Esta encriptación doble reduce el rendimiento y no es necesaria para lograr los objetivos de seguridad de la encriptación de metadatos, ya que Android garantiza que las claves FBE sean al menos tan difíciles de comprometer como la clave de encriptación de metadatos. Los proveedores pueden realizar personalizaciones del kernel para evitar la doble encriptación, en particular, implementando la opción allow_encrypt_override que Android pasa a dm-crypt cuando la propiedad del sistema ro.crypto.allow_encrypt_override se establece en true. Estas personalizaciones no son compatibles con el kernel común de Android.

De forma predeterminada, el método de encriptación de metadatos de volumen dm-crypt usa el algoritmo de encriptación AES-128-CBC con ESSIV y sectores de criptografía de 512 bytes. Esto se puede anular configurando las siguientes propiedades del sistema (que también se usan para FDE):

  • ro.crypto.fde_algorithm selecciona el algoritmo de encriptación de metadatos. Las opciones son aes-128-cbc y adiantum. Adiantum solo se puede usar si el dispositivo no tiene aceleración AES.
  • ro.crypto.fde_sector_size selecciona el tamaño del sector de las criptomonedas. Las opciones son 512, 1024, 2048 y 4096. Para la encriptación Adiantum, usa 4096.