Шифрование на уровне файлов

В Android 7.0 и более поздних версиях поддерживается шифрование на уровне файлов. Шифрование на уровне файлов позволяет шифровать разные файлы разными ключами, которые можно разблокировать независимо друг от друга.

В этой статье рассказывается, как включить шифрование на уровне файлов на новых устройствах и как системные приложения могут использовать API прямого запуска, чтобы обеспечить пользователям максимальное удобство и безопасность.

Все устройства с Android 10 и более поздними версиями ОС должны использовать шифрование на уровне файлов.

Direct Boot

Шифрование на уровне файлов позволяет использовать новую функцию, которая появилась в Android 7.0, – режим Direct Boot. Режим Direct Boot позволяет зашифрованным устройствам загружаться сразу до заблокированного экрана. Ранее на зашифрованных устройствах с полным шифрованием диска (FDE) пользователям нужно было вводить учетные данные, прежде чем можно было получить доступ к каким-либо данным, что не позволяло телефону выполнять все операции, кроме самых базовых. Например, не работали будильники и специальные возможности, а также не принимались звонки, за исключением экстренных.

Благодаря шифрованию на уровне файлов и новым API, которые позволяют приложениям распознавать шифрование, приложения могут работать в ограниченном контексте. Это может произойти до того, как пользователи предоставят свои учетные данные, при этом личная информация пользователей будет защищена.

На устройстве с поддержкой FBE у каждого пользователя есть два хранилища, доступных для приложений:

  • Хранилище с шифрованием учетных данных (CE) – хранилище по умолчанию, доступное только после разблокировки устройства пользователем.
  • Хранилище с шифрованием устройства (DE) – хранилище, доступное как в режиме прямой загрузки, так и после разблокировки устройства пользователем.

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

API прямого запуска позволяет приложениям, поддерживающим шифрование, получать доступ к этим областям. В жизненный цикл приложения внесены изменения, чтобы оно могло получать уведомления о том, что хранилище CE пользователя разблокировано после ввода учетных данных на заблокированном экране или рабочего пароля в рабочем профиле. Устройства с Android 7.0 должны поддерживать эти новые API и жизненные циклы независимо от того, реализовано ли на них шифрование на основе файлов. Без FBE хранилища DE и CE всегда разблокированы.

Полная реализация шифрования на уровне файлов в файловых системах Ext4 и F2FS предоставляется в Android Open Source Project (AOSP). Ее нужно только включить на устройствах, соответствующих требованиям. Производители, которые решат использовать FBE, могут изучить способы оптимизации этой функции на основе используемого процессора (SoC).

Все необходимые пакеты в AOSP были обновлены для поддержки режима прямого запуска. Однако если производители устройств используют настроенные версии этих приложений, они должны убедиться, что в них есть пакеты, поддерживающие режим прямого запуска и предоставляющие следующие сервисы:

  • Сервисы телефонии и приложение для звонков
  • Способ ввода паролей на заблокированном экране

Примеры и источник

В Android есть эталонная реализация шифрования на уровне файлов, в которой vold (system/vold) предоставляет функции для управления устройствами хранения данных и томами. Добавление FBE предоставляет vold несколько новых команд для поддержки управления ключами CE и DE нескольких пользователей. Помимо основных изменений, связанных с использованием возможностей шифрования на уровне файлов в ядре, многие системные пакеты, включая экран блокировки и SystemUI, были изменены для поддержки функций шифрования на уровне файлов и прямого запуска. Вот некоторые из них:

  • AOSP Dialer (packages/apps/Dialer)
  • Настольные часы (packages/apps/DeskClock)
  • LatinIME (packages/inputmethods/LatinIME)*
  • Приложение "Настройки" (packages/apps/Settings)*
  • SystemUI (frameworks/base/packages/SystemUI)*

* Системные приложения, использующие атрибут манифеста defaultToDeviceProtectedStorage.

Чтобы найти другие примеры приложений и сервисов, поддерживающих шифрование, выполните команду mangrep directBootAware в каталоге frameworks или packages дерева исходного кода AOSP.

Связанные запросы

Чтобы использовать реализацию FBE в AOSP, устройство должно соответствовать следующим требованиям:

  • Поддержка ядра для шифрования Ext4 или F2FS.
  • Поддержка KeyMint (или Keymaster 1.0 или более поздней версии). Keymaster 0.3 не поддерживается, поскольку не предоставляет необходимых возможностей и не обеспечивает достаточную защиту ключей шифрования.
  • KeyMint/Keymaster и Gatekeeper должны быть реализованы в доверенной среде выполнения (TEE), чтобы защитить ключи DE от несанкционированного доступа со стороны ОС, например кастомной прошивки.
  • Чтобы ключи DE были недоступны для неавторизованной операционной системы, требуется аппаратный корень доверия и проверка при запуске, привязанные к инициализации KeyMint.

Реализация

В первую очередь атрибут android:directBootAware нужно добавить в приложения, которые должны работать сразу после включения устройства, например в будильники, телефон и специальные возможности. Подробнее о режиме Direct Boot в документации для разработчиков.

Поддержка ядра

Поддержка шифрования Ext4 и F2FS на уровне ядра доступна в общих ядрах Android версии 3.18 и выше. Чтобы включить его в ядре версии 5.1 или более поздней, используйте:

CONFIG_FS_ENCRYPTION=y

Для более старых ядер используйте CONFIG_EXT4_ENCRYPTION=y, если файловая система userdata вашего устройства – Ext4, или CONFIG_F2FS_FS_ENCRYPTION=y, если файловая система userdata вашего устройства – F2FS.

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

Помимо поддержки шифрования Ext4 или F2FS, производителям устройств также следует включить криптографическое ускорение, чтобы ускорить шифрование на уровне файлов и повысить удобство работы пользователей. Например, на устройствах ARM64 ускорение ARMv8 CE (Cryptography Extensions) можно включить, задав следующие параметры конфигурации ядра:

CONFIG_CRYPTO_AES_ARM64_CE_BLK=y
CONFIG_CRYPTO_SHA2_ARM64_CE=y

Чтобы повысить производительность и снизить энергопотребление, производители устройств могут также рассмотреть возможность реализации встроенного аппаратного шифрования, которое шифрует и расшифровывает данные при их передаче на накопитель и с него. Общие ядра Android (версии 4.14 и выше) содержат фреймворк, который позволяет использовать встроенное шифрование, если есть поддержка аппаратного обеспечения и драйверов поставщика. Чтобы включить фреймворк встроенного шифрования, задайте следующие параметры конфигурации ядра:

CONFIG_BLK_INLINE_ENCRYPTION=y
CONFIG_FS_ENCRYPTION=y
CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y

Если на вашем устройстве используется хранилище на основе UFS, также включите:

CONFIG_SCSI_UFS_CRYPTO=y

Если на вашем устройстве используется хранилище на основе eMMC, также включите:

CONFIG_MMC_CRYPTO=y

Включить шифрование на уровне файлов

Чтобы включить шифрование на уровне файлов на устройстве, необходимо включить его во внутреннем хранилище (userdata). При этом шифрование на уровне файлов также автоматически включается на внедряемом накопителе. Однако при необходимости формат шифрования на внедряемом накопителе можно переопределить.

Внутренняя память

Чтобы включить FBE, добавьте параметр fileencryption=contents_encryption_mode[:filenames_encryption_mode[:flags]] в столбец fs_mgr_flags строки fstab для userdata. Этот параметр определяет формат шифрования на внутреннем накопителе. Он содержит до трех параметров, разделенных двоеточием:

  • Параметр contents_encryption_mode определяет, какой криптографический алгоритм используется для шифрования содержимого файла. Допустимые значения: aes-256-xts или adiantum. Начиная с Android 11, это поле можно оставить пустым, чтобы использовать алгоритм по умолчанию – aes-256-xts.
  • Параметр filenames_encryption_mode определяет, какой криптографический алгоритм используется для шифрования названий файлов. Допустимые значения: aes-256-cts, aes-256-heh, adiantum или aes-256-hctr2. Если значение не указано, по умолчанию используется aes-256-cts, если contents_encryption_mode – это aes-256-xts, или adiantum, если contents_encryption_mode – это adiantum.
  • Параметр flags, появившийся в Android 11, представляет собой список флагов, разделенных символом +. Поддерживаются следующие флаги:
    • Флаг v1 выбирает правила шифрования версии 1, а флаг v2 – версии 2. В правилах шифрования версии 2 используется более безопасная и гибкая функция формирования ключа. По умолчанию используется версия 2, если устройство выпущено с Android 11 или более поздней версией (определяется по ro.product.first_api_level), или версия 1, если устройство выпущено с Android 10 или более ранней версией.
    • Флаг inlinecrypt_optimized выбирает формат шифрования, оптимизированный для аппаратного шифрования, которое неэффективно обрабатывает большое количество ключей. Для этого из каждого ключа CE или DE извлекается только один ключ шифрования содержимого файла, а не по одному на файл. Генерация векторов инициализации (IV) корректируется соответствующим образом.
    • Флаг emmc_optimized похож на inlinecrypt_optimized, но он также выбирает метод генерации вектора инициализации, который ограничивает его размер 32 битами. Этот флаг следует использовать только на оборудовании для встроенного шифрования, которое соответствует спецификации JEDEC eMMC v5.2 и поэтому поддерживает только 32-битные векторы инициализации. На другом оборудовании для встроенного шифрования используйте inlinecrypt_optimized. Этот флаг не должен использоваться в хранилищах на основе UFS, поскольку спецификация UFS позволяет использовать 64-битные векторы инициализации.
    • На устройствах, поддерживающих аппаратные встроенные ключи шифрования, ключи FBE можно сделать аппаратными, добавив флаг wrappedkey или wrappedkey_v0. wrappedkey – это современная версия. wrappedkey_v0 следует использовать только на устройствах, которые не поддерживают wrappedkey или уже запущены с wrappedkey_v0. Подробнее о том, как включить упакованные ключи…
    • Флаг dusize_4k принудительно устанавливает размер блока данных шифрования равным 4096 байтам, даже если размер блока файловой системы не равен 4096 байтам. Размер блока данных шифрования – это степень детализации шифрования содержимого файла. Этот флаг доступен в Android 15 и более поздних версиях. Этот флаг следует использовать только для того, чтобы разрешить использование встроенного оборудования для шифрования, которое не поддерживает блоки данных размером более 4096 байт, на устройстве, использующем размер страницы более 4096 байт и файловую систему f2fs.

Если вы не используете аппаратное обеспечение для встроенного шифрования, для большинства устройств рекомендуется значение fileencryption=aes-256-xts. Если вы используете аппаратное встроенное шифрование, для большинства устройств рекомендуется значение fileencryption=aes-256-xts:aes-256-cts:inlinecrypt_optimized (или эквивалентное ему fileencryption=::inlinecrypt_optimized). На устройствах без ускорения AES вместо AES можно использовать Adiantum, задав значение fileencryption=adiantum.

Начиная с Android 14, AES-HCTR2 – это предпочтительный режим шифрования названий файлов для устройств с инструкциями по ускоренной криптографии. Однако AES-HCTR2 поддерживают только новые ядра Android. В будущих выпусках Android планируется сделать его режимом по умолчанию для шифрования названий файлов. Если ваше ядро поддерживает AES-HCTR2, вы можете включить шифрование названий файлов, задав для параметра filenames_encryption_mode значение aes-256-hctr2. В самом простом случае это можно сделать с помощью fileencryption=aes-256-xts:aes-256-hctr2.

На устройствах, выпущенных с Android 10 или более ранней версией, также можно использовать fileencryption=ice, чтобы указать режим шифрования содержимого файлов FSCRYPT_MODE_PRIVATE. Этот режим не реализован в общих ядрах Android, но может быть реализован поставщиками с помощью специальных исправлений ядра. Формат на диске, созданный в этом режиме, был специфичным для поставщика. На устройствах с Android 11 и более поздними версиями ОС этот режим не поддерживается. Вместо него необходимо использовать стандартный формат шифрования.

По умолчанию шифрование содержимого файлов выполняется с помощью API криптографии ядра Linux. Если вы хотите использовать встроенное аппаратное шифрование, добавьте параметр монтирования inlinecrypt. Например, полная строка fstab может выглядеть так:

/dev/block/by-name/userdata /data f2fs nodev,noatime,nosuid,errors=panic,inlinecrypt wait,fileencryption=aes-256-xts:aes-256-cts:inlinecrypt_optimized

Внедряемый накопитель

Начиная с Android 9, шифрование на основе файлов и внедряемый накопитель можно использовать вместе.

Если указать параметр fileencryption fstab для userdata, то на внедряемом накопителе автоматически включатся шифрование на основе файлов и шифрование метаданных. Однако вы можете переопределить форматы шифрования метаданных или FBE на внедряемом накопителе, задав свойства в файле PRODUCT_PROPERTY_OVERRIDES.

На устройствах с Android 11 или более поздней версией используйте следующие свойства:

  • ro.crypto.volume.options (новое в Android 11) выбирает формат шифрования на основе файлов для внедряемого накопителя. Синтаксис и значения по умолчанию такие же, как у аргумента параметра fileencryption fstab. Рекомендации по выбору значения для этого параметра приведены выше в разделе, посвященном fileencryption.
  • ro.crypto.volume.metadata.encryption выбирает формат шифрования метаданных на внедряемом накопителе. Подробную информацию можно найти в документации по шифрованию метаданных.

На устройствах, выпущенных с Android 10 и более ранними версиями, используйте следующие свойства:

  • ro.crypto.volume.contents_mode выбирает режим шифрования контента. Это эквивалентно первому полю, отделенному двоеточием, в ro.crypto.volume.options.
  • ro.crypto.volume.filenames_mode выбирает режим шифрования названий файлов. Это эквивалентно второму полю ro.crypto.volume.options, разделенному двоеточием, за исключением того, что на устройствах с Android 10 и более ранними версиями по умолчанию используется aes-256-heh. На большинстве устройств это значение нужно явно переопределить на aes-256-cts.
  • ro.crypto.fde_algorithm и ro.crypto.fde_sector_size выбирают формат шифрования метаданных на внедряемом накопителе. Подробную информацию можно найти в документации по шифрованию метаданных.

Интеграция с KeyMint

HAL KeyMint должен запускаться как часть класса early_hal. Это связано с тем, что для FBE требуется, чтобы KeyMint был готов обрабатывать запросы на этапе загрузки post-fs-data, когда vold настраивает начальные ключи.

Exclude directories (Исключить каталоги)

init применяет системный ключ DE ко всем каталогам верхнего уровня в /data, кроме тех, которые должны быть незашифрованными, например каталога, содержащего сам системный ключ DE, и каталогов, содержащих пользовательские каталоги CE или DE. Ключи шифрования применяются рекурсивно и не могут быть переопределены подкаталогами.

В Android 11 и более поздних версиях ключ, который init применяет к каталогам, можно контролировать с помощью аргумента encryption=<action> команды mkdir в скриптах инициализации. Возможные значения <action> описаны в файле README для языка инициализации Android.

В Android 10 действия по шифрованию init были жестко закодированы в следующем месте:

/system/extras/libfscrypt/fscrypt_init_extensions.cpp

В Android 9 и более ранних версиях ОС:

/system/extras/ext4_utils/ext4_crypt_init_extensions.cpp

Вы можете добавить исключения, чтобы предотвратить шифрование определенных каталогов. Если такие изменения внесены, производитель устройства должен включить правила SELinux, которые предоставляют доступ только тем приложениям, которым необходимо использовать незашифрованный каталог. Это должно исключить все ненадежные приложения.

Единственный известный допустимый вариант использования – поддержка устаревших функций OTA.

Поддержка режима Direct Boot в системных приложениях

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

Чтобы ускорить перенос системных приложений, на уровне приложения можно задать два новых атрибута. Атрибут defaultToDeviceProtectedStorage доступен только для системных приложений. Атрибут directBootAware доступен всем.

<application
    android:directBootAware="true"
    android:defaultToDeviceProtectedStorage="true">

Атрибут directBootAware на уровне приложения – это сокращенное обозначение того, что все компоненты приложения поддерживают шифрование.

Атрибут defaultToDeviceProtectedStorage перенаправляет хранилище приложения по умолчанию на хранилище с шифрованием устройства вместо хранилища с шифрованием учетных данных. Системные приложения, использующие этот флаг, должны тщательно проверять все данные, хранящиеся в местоположении по умолчанию, и изменять пути к конфиденциальным данным, чтобы использовать хранилище CE. Производители устройств, использующие этот вариант, должны тщательно проверять сохраняемые данные, чтобы убедиться, что они не содержат личной информации.

В этом режиме доступны следующие системные API, которые позволяют управлять контекстом, поддерживаемым хранилищем CE, когда это необходимо. Они эквивалентны аналогам, защищенным устройством.

  • Context.createCredentialProtectedStorageContext()
  • Context.isCredentialProtectedStorage()

Поддержка нескольких пользователей

В многопользовательской среде каждый пользователь получает отдельный ключ шифрования. Каждый пользователь получает два ключа: DE и CE. Пользователь 0 должен войти в систему первым, так как это особый пользователь. Это важно для администрирования устройств.

Приложения с поддержкой шифрования взаимодействуют с аккаунтами всех пользователей следующим образом: INTERACT_ACROSS_USERS и INTERACT_ACROSS_USERS_FULL позволяют приложению выполнять действия в аккаунтах всех пользователей на устройстве. Однако эти приложения могут получить доступ только к каталогам, зашифрованным с помощью CE, для пользователей, которые уже разблокированы.

Приложение может свободно взаимодействовать с областями DE, но разблокировка одного пользователя не означает, что разблокированы все пользователи на устройстве. Приложение должно проверять этот статус перед попыткой доступа к этим областям.

Каждый идентификатор пользователя рабочего профиля также получает два ключа: DE и CE. Когда пользователь проходит проверку, профиль разблокируется, а KeyMint (в TEE) может предоставить ключ TEE профиля.

Как обрабатывать обновления

Раздел восстановления не может получить доступ к хранилищу, защищенному прямым шифрованием, в разделе userdata. На устройствах с пофайловым шифрованием настоятельно рекомендуется поддерживать беспроводное обновление с помощью A/B-обновлений системы. Поскольку обновление по беспроводной сети можно применить во время обычной работы, для доступа к данным на зашифрованном диске не требуется восстановление.

При использовании устаревшего решения для беспроводного обновления, которое требует восстановления для доступа к файлу обновления в разделе userdata:

  1. Создайте каталог верхнего уровня (например, misc_ne) в разделе userdata.
  2. Настройте этот каталог верхнего уровня как незашифрованный (см. раздел Исключение каталогов).
  3. Создайте каталог в каталоге верхнего уровня, чтобы хранить пакеты OTA.
  4. Добавьте правило SELinux и контексты файлов, чтобы управлять доступом к этому каталогу и его содержимому. Доступ на чтение и запись в этот каталог должен быть только у процессов и приложений, получающих беспроводные обновления. Ни у одного другого приложения или процесса не должно быть доступа к этому каталогу.

Проверка

Чтобы убедиться, что реализованная версия функции работает правильно, сначала запустите многочисленные тесты шифрования CTS, такие как DirectBootHostTest и EncryptionTest.

Если на устройстве установлена ОС Android 11 или более поздней версии, также запустите vts_kernel_encryption_test:

atest vts_kernel_encryption_test

или

vts-tradefed run vts -m vts_kernel_encryption_test

Кроме того, производители устройств могут выполнять следующие тесты вручную. На устройстве с включенным шифрованием на основе файлов:

  • Убедитесь, что ro.crypto.state существует.
    • Убедитесь, что ro.crypto.state зашифрован
  • Убедитесь, что ro.crypto.type существует.
    • Убедитесь, что для параметра ro.crypto.type задано значение file.

Кроме того, тестировщики могут убедиться, что хранилище CE заблокировано до первой разблокировки устройства после загрузки. Для этого используйте сборку userdebug или eng, установите PIN-код, графический ключ или пароль для основного пользователя и перезагрузите устройство. Прежде чем разблокировать устройство, выполните следующую команду, чтобы проверить хранилище CE основного пользователя. Если на устройстве используется режим консольного системного пользователя (как на большинстве устройств Android Automotive), основным пользователем является пользователь 10. Выполните следующую команду:

adb root; adb shell ls /data/user/10

На других устройствах (большинство устройств, не относящихся к Automotive) основным пользователем является пользователь 0, поэтому выполните следующую команду:

adb root; adb shell ls /data/user/0

Убедитесь, что названия файлов закодированы в Base64. Это означает, что они зашифрованы, а ключ для расшифровки пока недоступен. Если названия файлов указаны в виде обычного текста, значит что-то не так.

Производителям устройств также рекомендуется запустить тесты Linux для fscrypt на своих устройствах или ядрах. Эти тесты входят в набор тестов файловой системы xfstests. Однако эти тесты официально не поддерживаются Android.

Сведения о реализации в AOSP

В этом разделе подробно описывается реализация AOSP и принцип работы шифрования на уровне файлов. Производителям устройств не нужно вносить изменения в этот код, чтобы использовать шифрование на основе файлов и режим Direct Boot.

Шифрование fscrypt

В реализации AOSP используется шифрование fscrypt (поддерживается ext4 и f2fs) в ядре. Обычно оно настроено следующим образом:

  • Шифровать содержимое файлов с помощью AES-256 в режиме XTS
  • Шифрование названий файлов с помощью AES-256 в режиме CBC-CTS

Также поддерживается шифрование Adiantum. Если включено шифрование Adiantum, то и содержимое файлов, и их названия шифруются с помощью Adiantum.

fscrypt поддерживает две версии правил шифрования: 1 и 2. Версия 1 устарела, и требования CDD для устройств с Android 11 и более поздними версиями совместимы только с версией 2. В правилах шифрования версии 2 используется HKDF-SHA512, чтобы получить фактические ключи шифрования из ключей, предоставленных пользовательским пространством.

Дополнительную информацию о fscrypt можно найти в документации по ядру.

Классы хранилища

В таблице ниже перечислены ключи FBE и каталоги, которые они защищают.

Класс хранилища Описание Каталоги
Не зашифровано Каталоги в /data, которые не могут или не должны быть защищены шифрованием на уровне файлов. На устройствах, использующих шифрование метаданных, эти каталоги не являются по-настоящему незашифрованными, а защищены ключом шифрования метаданных, который эквивалентен системному ключу шифрования устройства.
  • /data/apex, за исключением /data/apex/decompressed и /data/apex/ota_reserved, которые являются системными расширениями данных.
  • /data/lost+found
  • /data/preloads
  • /data/unencrypted
  • Все каталоги, подкаталоги которых используют разные ключи FBE. Например, поскольку каждый каталог /data/user/${user_id} использует ключ для каждого пользователя, /data/user не использует ключ.
Системный DE Зашифрованные на устройстве данные, не связанные с определенным пользователем
  • /data/apex/decompressed
  • /data/apex/ota_reserved
  • /data/app
  • /data/misc
  • /data/system
  • /data/vendor
  • Все остальные подкаталоги /data, для которых в этой таблице не указан другой класс.
При каждой загрузке Временные системные файлы, которые не нужно сохранять после перезагрузки. /data/per_boot
Пользовательский CE (внутренний) Зашифрованные с помощью учетных данных пользователя данные во внутреннем хранилище
  • /data/data (псевдоним /data/user/0)
  • /data/media/${user_id}
  • /data/misc_ce/${user_id}
  • /data/system_ce/${user_id}
  • /data/user/${user_id}
  • /data/vendor_ce/${user_id}
Пользователь DE (внутренний) Зашифрованные данные пользователей во внутреннем хранилище
  • /data/misc_de/${user_id}
  • /data/system_de/${user_id}
  • /data/user_de/${user_id}
  • /data/vendor_de/${user_id}
Пользовательское расширение (адаптируемое) Данные отдельных пользователей, зашифрованные с помощью учетных данных, на внедряемом накопителе
  • /mnt/expand/${volume_uuid}/media/${user_id}
  • /mnt/expand/${volume_uuid}/misc_ce/${user_id}
  • /mnt/expand/${volume_uuid}/user/${user_id}
Пользователь DE (адаптируемый) Зашифрованные данные пользователей на внедряемом накопителе
  • /mnt/expand/${volume_uuid}/misc_de/${user_id}
  • /mnt/expand/${volume_uuid}/user_de/${user_id}

Хранение и защита ключей

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

Тип ключа Местоположение ключа Класс хранилища для местоположения ключа
Системный ключ DE /data/unencrypted Не зашифровано
Ключи шифрования учетных данных пользователя (внутренние) /data/misc/vold/user_keys/ce/${user_id} Системный DE
Ключи шифрования на стороне клиента для пользователей (внутренние) /data/misc/vold/user_keys/de/${user_id} Системный DE
Пользовательские ключи CE (адаптируемые) /data/misc_ce/${user_id}/vold/volume_keys/${volume_uuid} Пользовательский CE (внутренний)
Ключи шифрования данных пользователя (с возможностью адаптации) /data/misc_de/${user_id}/vold/volume_keys/${volume_uuid} Пользователь DE (внутренний)

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

vold также применяет уровень шифрования ко всем ключам FBE. Все ключи, кроме ключей CE для внутреннего хранилища, шифруются с помощью AES-256-GCM и собственного ключа Keystore, который не передается за пределы TEE. Это гарантирует, что ключи FBE не могут быть разблокированы, если не загружена доверенная операционная система, как того требует проверка при запуске. Для ключа Keystore также запрашивается защита от отката, что позволяет безопасно удалять ключи FBE на устройствах, где KeyMint поддерживает защиту от отката. Если защита от отката недоступна, в качестве Tag::APPLICATION_ID ключа Keystore используется хеш SHA-512 из 16 384 случайных байтов, хранящихся в файле secdiscardable рядом с ключом. Чтобы восстановить ключ FBE, нужно восстановить все эти байты.

Ключи CE для внутреннего хранилища получают более высокий уровень защиты, который гарантирует, что их нельзя разблокировать, не зная фактора знания заблокированного экрана (LSKF) пользователя (PIN-кода, графического ключа или пароля), токена безопасного сброса пароля или ключей на стороне клиента и сервера для операции возобновления работы после перезагрузки. Токены сброса кода доступа можно создавать только для рабочих профилей и полностью управляемых устройств.

Для этого vold шифрует каждый ключ CE для внутреннего хранилища, используя ключ AES-256-GCM, полученный из синтетического пароля пользователя. Синтетический пароль – это неизменяемый криптографический секрет с высокой энтропией, который генерируется случайным образом для каждого пользователя. LockSettingsService в system_server управляет синтетическим паролем и способами его защиты.

Чтобы защитить синтетический пароль с помощью LSKF, LockSettingsService сначала растягивает LSKF, пропуская его через scrypt, ориентируясь на время около 25 мс и использование памяти около 2 МиБ. Поскольку ключи блокировки экрана обычно короткие, этот шаг не обеспечивает надежную защиту. Основной уровень безопасности – это защитный элемент (SE) или ограничение частоты запросов, применяемое доверенной средой выполнения (TEE), как описано ниже.

Если на устройстве реализован Weaver HAL, то LockSettingsService сопоставляет растянутый LSKF с высокоэнтропийным случайным секретом, хранящимся в SE или TEE, с помощью Weaver. Затем LockSettingsService дважды шифрует синтетический пароль: сначала с помощью программного ключа, полученного из растянутого LSKF и секрета Weaver, а затем с помощью ключа Keystore, не связанного с аутентификацией. Это позволяет ограничить частоту попыток угадать ключ блокировки экрана с помощью защищенного элемента или доверенной среды выполнения.

Если устройство не поддерживает Weaver, LockSettingsService использует растянутый ключ блокировки экрана в качестве пароля Gatekeeper. Затем LockSettingsService дважды шифрует синтетический пароль: сначала с помощью программного ключа, полученного из растянутого LSKF и хеша файла secdiscardable, а затем с помощью ключа Keystore, который привязан к регистрации Gatekeeper. Это позволяет ограничить частоту попыток угадать ключ блокировки экрана, используя доверенную среду выполнения.

При изменении LSKF LockSettingsService удаляет всю информацию, связанную с привязкой синтетического пароля к старому LSKF. На устройствах, поддерживающих Weaver или ключи Keystore, устойчивые к откату, это гарантирует безопасное удаление старой привязки. Поэтому описанные здесь меры защиты применяются, даже если у пользователя нет ключа блокировки экрана.