Шифрование метаданных

Android 7.0 и выше поддерживают шифрование на основе файлов (FBE). FBE позволяет шифровать разные файлы с помощью разных ключей, которые можно расшифровать независимо друг от друга. Эти ключи используются для шифрования как содержимого файлов, так и их имен. При использовании FBE другая информация, такая как структура каталогов, размеры файлов, разрешения и время создания/изменения, не шифруется. В совокупности эта информация известна как метаданные файловой системы.

В Android 9 появилась поддержка шифрования метаданных. При шифровании метаданных единственный ключ, присутствующий при загрузке, шифрует любое содержимое, не зашифрованное функцией FBE. Этот ключ защищен KeyMint (ранее Keymaster), который, в свою очередь, защищен функцией Verified Boot.

Шифрование метаданных всегда включено на расширяемой памяти , если включена функция FBE. Шифрование метаданных также можно включить во внутренней памяти. На устройствах, выпущенных под управлением Android 11 или выше, шифрование метаданных во внутренней памяти должно быть включено.

Реализация на внутренней памяти

Настроить шифрование метаданных во внутренней памяти новых устройств можно, настроив файловую систему metadata , изменив последовательность инициализации и включив шифрование метаданных в файле fstab устройства.

Предварительные требования

Шифрование метаданных можно настроить только при первом форматировании раздела данных. Поэтому эта функция доступна только для новых устройств; обновление по воздуху (OTA) не должно это менять.

Для шифрования метаданных необходимо включить модуль dm-default-key в ядре Android. В Android 11 и выше dm-default-key поддерживается стандартными ядрами Android, начиная с версии 4.14. Эта версия dm-default-key использует аппаратно- и сторонних разработчиков независимую от платформы систему шифрования blk-crypto .

Чтобы включить dm-default-key , используйте:

CONFIG_BLK_INLINE_ENCRYPTION=y
CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y
CONFIG_DM_DEFAULT_KEY=y

dm-default-key использует встроенное аппаратное шифрование (оборудование, которое шифрует/дешифрует данные во время их передачи к/от устройства хранения), если оно доступно. Если вы не используете встроенное аппаратное шифрование, также необходимо включить резервный вариант с использованием криптографического API ядра:

CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y

Если вы не используете встроенное аппаратное шифрование, вам также следует включить любое доступное ускорение на основе ЦП, как это рекомендовано в документации FBE .

В Android 10 и более ранних версиях стандартное ядро ​​Android не поддерживало dm-default-key . Поэтому реализация dm-default-key была обязанностью производителей.

Настройка файловой системы метаданных

Поскольку данные в разделе userdata нельзя прочитать, пока не будет присутствовать ключ шифрования метаданных, в таблице разделов необходимо выделить отдельный раздел, называемый разделом метаданных, для хранения больших двоичных объектов KeyMint, защищающих этот ключ. Размер раздела метаданных должен составлять 16 МБ.

В fstab.hardware необходимо указать запись для файловой системы метаданных, расположенной на этом разделе и монтирующей его в /metadata , включая флаг formattable , чтобы гарантировать форматирование при загрузке. Файловая система f2fs не работает на небольших разделах; мы рекомендуем использовать ext4. Например:

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

Чтобы убедиться в существовании точки монтирования /metadata , добавьте следующую строку в BoardConfig-common.mk :

BOARD_USES_METADATA_PARTITION := true

Изменения в последовательности инициализации

При использовании шифрования метаданных vold должен быть запущен до монтирования /data . Чтобы обеспечить его запуск достаточно рано, добавьте следующий фрагмент кода в файл init.hardware.rc :

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

Перед тем как init попытается смонтировать /data необходимо, чтобы KeyMint был запущен и готов к работе.

В init.hardware.rc уже должна содержаться инструкция mount_all , которая монтирует сам каталог /data в разделе on late-fs . Перед этой строкой добавьте директиву для выполнения службы 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

Включите шифрование метаданных

Наконец, добавьте keydirectory=/metadata/vold/metadata_encryption в столбец fs_mgr_flags записи в файле fstab для userdata . Например, полная строка в файле fstab может выглядеть так:

/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

По умолчанию алгоритм шифрования метаданных во внутренней памяти — AES-256-XTS. Это можно изменить, задав параметр metadata_encryption , который также находится в столбце fs_mgr_flags :

  • На устройствах, не поддерживающих AES-ускорение, шифрование Adiantum можно включить, установив параметр metadata_encryption=adiantum .
  • На устройствах, поддерживающих аппаратную обертку ключей шифрования , ключ шифрования метаданных можно сделать аппаратно обернутым, установив параметр metadata_encryption=aes-256-xts:wrappedkey или metadata_encryption=aes-256-xts:wrappedkey_v0 . wrappedkey это современная версия; wrappedkey_v0 следует использовать только на устройствах, которые не поддерживают wrappedkey или уже запущены с wrappedkey_v0 . Для получения дополнительной информации см. раздел «Включение обернутых ключей» .

    В любом случае, aes-256-xts можно опустить, поскольку это алгоритм по умолчанию. Например, metadata_encryption=:wrappedkey эквивалентно metadata_encryption=aes-256-xts:wrappedkey .

Поскольку интерфейс ядра к dm-default-key изменился в Android 11, вам также необходимо убедиться, что вы установили правильное значение для PRODUCT_SHIPPING_API_LEVEL в device.mk . Например, если ваше устройство запускается с Android 11 (уровень API 30), device.mk должен содержать:

PRODUCT_SHIPPING_API_LEVEL := 30

Вы также можете установить следующее системное свойство, чтобы принудительно использовать новый API dm-default-key независимо от уровня API доставки:

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

Валидация

Чтобы убедиться, что шифрование метаданных включено и работает корректно, выполните описанные ниже тесты. Также обратите внимание на распространенные проблемы, описанные ниже.

Тесты

Для начала выполните следующую команду, чтобы убедиться, что шифрование метаданных включено во внутренней памяти:

adb root
adb shell dmctl table userdata

Результат должен выглядеть примерно так:

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

Если вы переопределили настройки шифрования по умолчанию, установив параметр metadata_encryption в fstab устройства, то вывод будет немного отличаться от приведенного выше. Например, если вы включили шифрование Adiantum , то третье поле будет xchacha12,aes-adiantum-plain64 вместо aes-xts-plain64 .

Далее запустите vts_kernel_encryption_test , чтобы проверить корректность шифрования метаданных и FBE:

atest vts_kernel_encryption_test

или:

vts-tradefed run vts -m vts_kernel_encryption_test

Общие проблемы

Во время вызова функции mount_all , которая монтирует зашифрованный метаданными раздел /data , init запускает инструмент vdc. Инструмент vdc подключается к vold через binder для настройки зашифрованного метаданными устройства и монтирования раздела. На время этого вызова init блокируется и пытается либо читать, либо устанавливать свойства init , пока не завершится mount_all . Если на этом этапе какая-либо часть работы vold прямо или косвенно блокируется на чтении или установке свойства, возникает взаимоблокировка. Важно убедиться, что vold может завершить работу по чтению ключей, взаимодействию с KeyMint и монтированию каталога данных без дальнейшего взаимодействия с init .

Если KeyMint не запущен полностью к моменту выполнения mount_all , он не отвечает vold до тех пор, пока не прочтет определенные свойства из init , что приводит к описанной выше взаимоблокировке. Размещение exec_start wait_for_keymaster перед соответствующим вызовом mount_all как указано выше, гарантирует, что KeyMint будет полностью запущен заранее, и, таким образом, предотвращает эту взаимоблокировку.

Конфигурация на подключаемом хранилище

Начиная с Android 9, шифрование метаданных всегда включено на подключаемой памяти , если включена функция FBE, даже если шифрование метаданных не включено на внутренней памяти.

В AOSP существует две реализации шифрования метаданных для адаптируемого хранилища: устаревшая, основанная на dm-crypt , и более новая, основанная на dm-default-key . Чтобы убедиться, что для вашего устройства выбрана правильная реализация, проверьте правильность значения параметра PRODUCT_SHIPPING_API_LEVEL в device.mk . Например, если ваше устройство запускается с Android 11 (уровень API 30), device.mk должен содержать:

PRODUCT_SHIPPING_API_LEVEL := 30

Также можно установить следующие системные параметры, чтобы принудительно использовать новый метод шифрования метаданных тома (и новую версию политики FBE по умолчанию) независимо от уровня API поставки:

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

Текущий метод

На устройствах с Android 11 и выше шифрование метаданных на подключаемом хранилище использует модуль ядра dm-default-key , как и на внутреннем хранилище. См. приведенные выше предварительные требования , чтобы узнать, какие параметры конфигурации ядра следует включить. Обратите внимание, что встроенное шифрование, работающее на внутреннем хранилище устройства, может быть недоступно на подключаемом хранилище, поэтому может потребоваться CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y .

По умолчанию метод шифрования метаданных тома dm-default-key использует алгоритм шифрования AES-256-XTS с криптографическими секторами размером 4096 байт. Алгоритм можно переопределить, установив системное свойство ro.crypto.volume.metadata.encryption . Значение этого свойства имеет тот же синтаксис, что и параметр metadata_encryption в файле fstab, описанный выше. Например, на устройствах, не имеющих ускорения AES, шифрование Adiantum можно включить, установив ro.crypto.volume.metadata.encryption=adiantum .

Метод наследия

На устройствах с Android 10 и ниже шифрование метаданных в расширяемой памяти использует модуль ядра dm-crypt а не dm-default-key :

CONFIG_DM_CRYPT=y

В отличие от метода dm-default-key , метод dm-crypt приводит к двойному шифрованию содержимого файла: один раз с помощью ключа FBE и один раз с помощью ключа шифрования метаданных. Это двойное шифрование снижает производительность и не требуется для достижения целей безопасности шифрования метаданных, поскольку Android гарантирует, что ключи FBE как минимум так же сложно скомпрометировать, как и ключ шифрования метаданных. Производители могут вносить изменения в ядро, чтобы избежать двойного шифрования, в частности, путем реализации параметра allow_encrypt_override , который Android передает в dm-crypt когда системное свойство ro.crypto.allow_encrypt_override установлено в true . Эти изменения не поддерживаются стандартным ядром Android.

По умолчанию метод шифрования метаданных тома dm-crypt использует алгоритм шифрования AES-128-CBC с ESSIV и 512-байтовыми криптографическими секторами. Это можно изменить, задав следующие системные свойства (которые также используются для FDE):

  • ro.crypto.fde_algorithm выбирает алгоритм шифрования метаданных. Доступны варианты aes-128-cbc и adiantum . Adiantum можно использовать только в том случае, если устройство не поддерживает ускорение AES.
  • ro.crypto.fde_sector_size выбирает размер криптографического сектора. Доступные значения: 512, 1024, 2048 и 4096. Для шифрования Adiantum используйте значение 4096.