Ключи с аппаратной оболочкой

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

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

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

Примечание . Встроенный механизм шифрования (или встроенное оборудование для шифрования ) относится к оборудованию, которое шифрует/дешифрует данные, пока они находятся на пути к устройству хранения и обратно. Обычно это хост-контроллер UFS или eMMC, который реализует криптографические расширения, определенные соответствующей спецификацией JEDEC.

Дизайн

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

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

  • Количество ключей шифрования может превышать количество ячеек для ключей.
  • Встроенные криптографические механизмы могут использоваться только для шифрования/дешифрования полных блоков данных на диске. Однако в случае FBE программное обеспечение по-прежнему должно выполнять другие криптографические операции, такие как шифрование имен файлов и получение идентификаторов ключей. Программному обеспечению по-прежнему потребуется доступ к необработанным ключам FBE, чтобы выполнять эту другую работу.

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

Ключевая иерархия

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

На следующей диаграмме показана типичная иерархия ключей для FBE, когда ключи с аппаратной оболочкой не используются:

Иерархия ключей FBE (стандартная)
Рис. 1. Иерархия ключей FBE (стандартная)

Ключ класса FBE — это необработанный ключ шифрования, который Android передает ядру Linux, чтобы разблокировать определенный набор зашифрованных каталогов, например хранилище с зашифрованными учетными данными для определенного пользователя Android. (В ядре этот ключ называется главным ключом fscrypt .) Из этого ключа ядро ​​получает следующие подразделы:

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

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

Иерархия ключей FBE (с аппаратным ключом)
Рисунок 2. Иерархия ключей FBE (с аппаратным ключом)

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

  • Один интерфейс для получения inline_encryption_key и непосредственного программирования его в слоте ключей встроенного механизма шифрования. Это позволяет шифровать/дешифровать содержимое файла без программного обеспечения, имеющего доступ к необработанному ключу. В обычных ядрах Android этот интерфейс соответствует операции blk_ksm_ll_ops::keyslot_program , которая должна быть реализована драйвером хранилища.
  • Один интерфейс для получения и возврата sw_secret («программный секрет» — в некоторых местах его также называют «необработанным секретом»), который является ключом, который Linux использует для получения подразделов для всего, кроме шифрования содержимого файла. В обычных ядрах Android этот интерфейс соответствует операции blk_ksm_ll_ops::derive_raw_secret , которая должна быть реализована драйвером хранилища.

Чтобы получить inline_encryption_key и sw_secret из необработанного ключа хранилища, аппаратное обеспечение должно использовать криптографически стойкий KDF. Этот KDF должен следовать передовым методам криптографии; он должен иметь уровень защиты не менее 256 бит, т.е. достаточно для любого алгоритма, используемого позже. Он также должен использовать отдельную метку, контекст и/или информационную строку для конкретного приложения при получении каждого типа подключа, чтобы гарантировать криптографическую изоляцию полученных подключа, т. е. знание одного из них не раскрывает другой. Расширение ключа не требуется, так как необработанный ключ хранения уже представляет собой равномерно случайный ключ.

Технически можно использовать любой KDF, отвечающий требованиям безопасности. Однако в целях тестирования необходимо повторно реализовать тот же KDF в тестовом коде. В настоящее время рассмотрен и реализован один KDF; его можно найти в исходном коде vts_kernel_encryption_test . Рекомендуется, чтобы оборудование использовало этот KDF, который использует NIST SP 800-108 «KDF в режиме счетчика» с AES-256-CMAC в качестве PRF. Обратите внимание, что для обеспечения совместимости все части алгоритма должны быть идентичными, включая выбор контекстов KDF и меток для каждого подключа.

Упаковка ключей

Для обеспечения безопасности ключей с аппаратной оболочкой определены два типа упаковки ключей:

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

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

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

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

  • Интерфейсы для генерации и импорта ключей хранилища, возвращая их в долгосрочной обернутой форме. Доступ к этим интерфейсам осуществляется косвенно через KeyMint, и они соответствуют TAG_STORAGE_KEY KeyMint. Способность «генерировать» используется vold для создания новых ключей хранилища для использования Android, а способность «импорт» используется vts_kernel_encryption_test для импорта тестовых ключей.
  • Интерфейс для преобразования долгосрочного упакованного ключа хранилища в эфемерно упакованный ключ хранилища. Это соответствует convertStorageKeyToEphemeral KeyMint. Этот метод используется vold и vts_kernel_encryption_test для разблокировки хранилища.

Алгоритм переноса ключей — это деталь реализации, но он должен использовать надежный AEAD, такой как AES-256-GCM, со случайными IV.

Требуются изменения программного обеспечения

В AOSP уже есть базовая структура для поддержки аппаратных ключей. Сюда входит поддержка компонентов пользовательского пространства, таких как vold , а также поддержка ядра Linux в blk-crypto , fscrypt и dm-default-key .

Однако требуются некоторые изменения, специфичные для реализации.

Изменения KeyMint

Реализация KeyMint устройства должна быть изменена для поддержки TAG_STORAGE_KEY и реализации метода convertStorageKeyToEphemeral .

В Keymaster вместо exportKey использовался convertStorageKeyToEphemeral .

Изменения ядра Linux

Драйвер ядра Linux для встроенного криптографического механизма устройства необходимо изменить, чтобы установить BLK_CRYPTO_FEATURE_WRAPPED_KEYS , чтобы keyslot_program() и keyslot_evict() поддерживали программирование/удаление ключей с аппаратной оболочкой, а также реализовали derive_raw_secret() .

Тестирование

Хотя шифрование с аппаратными ключами сложнее протестировать, чем шифрование со стандартными ключами, его все же можно протестировать, импортировав тестовый ключ и повторно реализовав создание ключа, которое делает аппаратное обеспечение. Это реализовано в vts_kernel_encryption_test . Чтобы запустить этот тест, выполните:

atest -v vts_kernel_encryption_test

Прочтите журнал тестирования и убедитесь, что тестовые случаи аппаратного ключа (например FBEPolicyTest.TestAesInlineCryptOptimizedHwWrappedKeyPolicy и DmDefaultKeyTest.TestHwWrappedKey ) не были пропущены из-за того, что поддержка аппаратных ключей не была обнаружена, поскольку результаты теста все равно будут «пройдены» в тот случай.

Включение

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

  • FBE: добавьте флаг wrappedkey_v0 в параметр fileencryption . Например, используйте fileencryption=::inlinecrypt_optimized+wrappedkey_v0 . Подробнее см. в документации FBE .
  • Шифрование метаданных: добавьте флаг wrappedkey_v0 в параметр metadata_encryption . Например, используйте metadata_encryption=:wrappedkey_v0 . Дополнительные сведения см. в документации по шифрованию метаданных .