Полное шифрование диска

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

Полное шифрование диска было представлено в Android в версии 4.4, но в Android 5.0 появились следующие новые функции:

  • Создано быстрое шифрование, которое шифрует только используемые блоки на разделе данных, чтобы избежать долгой первой загрузки. В настоящее время только файловые системы ext4 и f2fs поддерживают быстрое шифрование.
  • Добавлен флаг forceencrypt fstab для шифрования при первой загрузке.
  • Добавлена ​​поддержка шаблонов и шифрования без пароля.
  • Добавлено аппаратное хранилище ключа шифрования с использованием возможности подписи Trusted Execution Environment (TEE) (например, в TrustZone). Подробнее см. в разделе Хранение зашифрованного ключа .

Внимание: Устройства, обновленные до Android 5.0 и затем зашифрованные, можно вернуть в незашифрованное состояние с помощью сброса заводских данных. Новые устройства Android 5.0, зашифрованные при первой загрузке, нельзя вернуть в незашифрованное состояние.

Как работает полное шифрование диска Android

Полное шифрование диска Android основано на dm-crypt , функции ядра, которая работает на уровне блочных устройств. Благодаря этому шифрование работает с Embedded MultiMediaCard ( eMMC) и аналогичными флэш-устройствами, которые представляют себя ядру как блочные устройства. Шифрование невозможно с YAFFS, который напрямую взаимодействует с необработанным чипом флэш-памяти NAND.

Алгоритм шифрования — 128 Advanced Encryption Standard (AES) с цепочкой шифровальных блоков (CBC) и ESSIV:SHA256. Главный ключ шифруется с помощью 128-битного AES с помощью вызовов библиотеки OpenSSL. Для ключа необходимо использовать 128 бит или больше (256 — необязательно).

Примечание: OEM-производители могут использовать 128-битное или более высокое шифрование для главного ключа.

В версии Android 5.0 существует четыре вида состояний шифрования:

  • по умолчанию
  • ПРИКОЛОТЬ
  • пароль
  • шаблон

При первой загрузке устройство создает случайно сгенерированный 128-битный главный ключ, а затем хэширует его с паролем по умолчанию и сохраненной солью. Пароль по умолчанию: "default_password" Однако полученный хэш также подписывается через TEE (например, TrustZone), который использует хэш подписи для шифрования главного ключа.

Пароль по умолчанию можно найти в файле Android Open Source Project cryptfs.cpp .

Когда пользователь устанавливает PIN-код/пароль или пароль на устройстве, повторно шифруется и сохраняется только 128-битный ключ. (т. е. изменения PIN-кода/пароля/графического ключа пользователя НЕ приводят к повторному шифрованию пользовательских данных.) Обратите внимание, что управляемое устройство может подпадать под ограничения PIN-кода, графического ключа или пароля.

Шифрование управляется init и vold . init вызывает vold , а vold устанавливает свойства для запуска событий в init. Другие части системы также проверяют свойства для выполнения таких задач, как отчет о состоянии, запрос пароля или запрос на сброс настроек к заводским настройкам в случае фатальной ошибки. Для вызова функций шифрования в vold система использует команды cryptfs инструмента командной строки vdc : checkpw , restart , enablecrypto , changepw , cryptocomplete , verifypw , setfield , getfield , mountdefaultencrypted , getpwtype , getpw и clearpw .

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

  • core : Никогда не выключать после запуска.
  • main : Выключение и перезапуск после ввода пароля диска.
  • late_start : не запускается до тех пор, пока /data не будет расшифрован и смонтирован.

Для запуска этих действий свойство vold.decrypt устанавливается в различные строки . Для завершения и перезапуска служб используются следующие команды init :

  • class_reset : останавливает службу, но позволяет перезапустить ее с помощью class_start.
  • class_start : Перезапускает службу.
  • class_stop : Останавливает службу и добавляет флаг SVC_DISABLED . Остановленные службы не отвечают на class_start .

Потоки

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

  • Зашифруйте ранее незашифрованное устройство:
    • Зашифруйте новое устройство с помощью forceencrypt : обязательное шифрование при первой загрузке (начиная с Android L).
    • Шифрование существующего устройства: шифрование, инициированное пользователем (Android K и более ранние версии).
  • Загрузите зашифрованное устройство:
    • Запуск зашифрованного устройства без пароля: загрузка зашифрованного устройства, на котором не установлен пароль (актуально для устройств под управлением Android 5.0 и более поздних версий).
    • Запуск зашифрованного устройства с паролем: загрузка зашифрованного устройства с установленным паролем.

В дополнение к этим потокам, устройство также может не шифровать /data . Каждый из потоков подробно описан ниже.

Зашифруйте новое устройство с помощью forceencrypt

Это обычная первая загрузка устройства Android 5.0.

  1. Обнаружение незашифрованной файловой системы с помощью флага forceencrypt

    /data не зашифрован, но это необходимо, поскольку forceencrypt требует этого. Размонтируйте /data .

  2. Начать шифрование /data

    vold.decrypt = "trigger_encryption" запускает init.rc , что заставляет vold шифровать /data без пароля. (Пароль не установлен, поскольку это должно быть новое устройство.)

  3. Смонтировать tmpfs

    vold монтирует tmpfs /data (используя параметры tmpfs из ro.crypto.tmpfs_options ) и устанавливает свойство vold.encrypt_progress в 0. vold подготавливает tmpfs /data для загрузки зашифрованной системы и устанавливает свойство vold.decrypt в: trigger_restart_min_framework

  4. Поднимите фреймворк, чтобы показать прогресс

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

  5. Когда /data зашифрованы, удалите фреймворк

    vold устанавливает vold.decrypt в trigger_default_encryption , что запускает службу defaultcrypto . (Это запускает поток ниже для монтирования зашифрованных по умолчанию пользовательских данных.) trigger_default_encryption проверяет тип шифрования, чтобы увидеть, зашифрованы ли /data с паролем или без него. Поскольку устройства Android 5.0 шифруются при первой загрузке, пароль не должен быть установлен; поэтому мы расшифровываем и монтируем /data .

  6. Монтировать /data

    Затем init монтирует /data на tmpfs RAMDisk, используя параметры, которые он берет из ro.crypto.tmpfs_options , заданного в init.rc .

  7. Начать фреймворк

    vold устанавливает vold.decrypt в trigger_restart_framework , что продолжает обычный процесс загрузки.

Зашифровать существующее устройство

Вот что происходит, когда вы шифруете незашифрованное устройство Android K или более ранней версии, которое было переведено на L.

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

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

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

Состояние устройства : установите ro.crypto.state = "unencrypted" и выполните триггер init on nonencrypted , чтобы продолжить загрузку.

  1. Проверить пароль

    Пользовательский интерфейс вызывает vold с помощью команды cryptfs enablecrypto inplace , где passwd — пароль блокировки экрана пользователя.

  2. Сними рамки

    vold проверяет наличие ошибок, возвращает -1, если не может зашифровать, и выводит причину в журнал. Если он может зашифровать, он устанавливает свойство vold.decrypt в trigger_shutdown_framework . Это заставляет init.rc останавливать службы в классах late_start и main .

  3. Создать крипто-футер
  4. Создать файл навигации
  5. Перезагрузить
  6. Определить файл навигационной цепочки
  7. Начать шифрование /data

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

  8. Пока идет шифрование, смонтируйте tmpfs

    vold монтирует tmpfs /data (используя параметры tmpfs из ro.crypto.tmpfs_options ) и устанавливает свойство vold.encrypt_progress в 0. vold подготавливает tmpfs /data для загрузки зашифрованной системы и устанавливает свойство vold.decrypt в: trigger_restart_min_framework

  9. Поднимите фреймворк, чтобы показать прогресс

    trigger_restart_min_framework заставляет init.rc запустить main класс служб. Когда фреймворк видит, что vold.encrypt_progress установлен в 0, он выводит пользовательский интерфейс индикатора выполнения, который запрашивает это свойство каждые пять секунд и обновляет индикатор выполнения. Цикл шифрования обновляет vold.encrypt_progress каждый раз, когда шифрует очередной процент раздела.

  10. Если /data зашифрованы, обновите криптографический нижний колонтитул

    После успешного шифрования /data vold очищает флаг ENCRYPTION_IN_PROGRESS в метаданных.

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

    Если перезагрузка по какой-то причине не удалась, vold устанавливает свойство vold.encrypt_progress в error_reboot_failed , а пользовательский интерфейс должен отобразить сообщение с просьбой нажать кнопку для перезагрузки. Этого не должно произойти.

Запустите зашифрованное устройство с шифрованием по умолчанию

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

  1. Обнаружение зашифрованных /data без пароля

    Определите, что устройство Android зашифровано, поскольку /data не может быть смонтирован и установлен один из флагов encryptable или forceencrypt .

    vold устанавливает vold.decrypt в trigger_default_encryption , что запускает службу defaultcrypto . trigger_default_encryption проверяет тип шифрования, чтобы увидеть, зашифрован ли /data с паролем или без него.

  2. Расшифровать /данные

    Создает устройство dm-crypt поверх блочного устройства, чтобы устройство было готово к использованию.

  3. Монтировать /данные

    Затем vold монтирует расшифрованный реальный раздел /data и затем подготавливает новый раздел. Он устанавливает свойство vold.post_fs_data_done в 0, а затем устанавливает vold.decrypt в trigger_post_fs_data . Это заставляет init.rc запустить свои команды post-fs-data . Они создают все необходимые каталоги или ссылки, а затем устанавливают vold.post_fs_data_done в 1.

    Как только vold видит 1 в этом свойстве, он устанавливает свойство vold.decrypt в: trigger_restart_framework. Это заставляет init.rc снова запустить службы в классе main , а также запустить службы в классе late_start в первый раз с момента загрузки.

  4. Начать фреймворк

    Теперь фреймворк загружает все свои службы, используя расшифрованные /data , и система готова к использованию.

Запустить зашифрованное устройство без шифрования по умолчанию

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

  1. Обнаружить зашифрованное устройство с паролем

    Определите, что устройство Android зашифровано, поскольку флаг ro.crypto.state = "encrypted"

    vold устанавливает vold.decrypt в trigger_restart_min_framework , поскольку /data зашифрован паролем.

  2. Смонтировать tmpfs

    init устанавливает пять свойств для сохранения начальных параметров монтирования, указанных для /data с параметрами, переданными из init.rc vold использует эти свойства для настройки криптографического сопоставления:

    1. ro.crypto.fs_type
    2. ro.crypto.fs_real_blkdev
    3. ro.crypto.fs_mnt_point
    4. ro.crypto.fs_options
    5. ro.crypto.fs_flags (8-значное шестнадцатеричное число ASCII, которому предшествует 0x)
  3. Запустить фреймворк для запроса пароля

    Фреймворк запускается и видит, что vold.decrypt установлен на trigger_restart_min_framework . Это сообщает фреймворку, что он загружается с диска tmpfs /data и ему нужно получить пароль пользователя.

    Однако сначала ему нужно убедиться, что диск был правильно зашифрован. Он отправляет команду cryptfs cryptocomplete в vold . vold возвращает 0, если шифрование было завершено успешно, -1 при внутренней ошибке или -2, если шифрование не было завершено успешно. vold определяет это, просматривая метаданные криптографии на предмет флага CRYPTO_ENCRYPTION_IN_PROGRESS . Если он установлен, процесс шифрования был прерван, и на устройстве нет пригодных для использования данных. Если vold возвращает ошибку, пользовательский интерфейс должен отобразить пользователю сообщение о необходимости перезагрузки и сброса устройства к заводским настройкам, а также предоставить пользователю кнопку, которую можно нажать для этого.

  4. Расшифровать данные с помощью пароля

    После успешного выполнения cryptfs cryptocomplete фреймворк отображает пользовательский интерфейс с запросом пароля диска. Пользовательский интерфейс проверяет пароль, отправляя команду cryptfs checkpw в vold . Если пароль правильный (что определяется успешным монтированием расшифрованных /data во временном расположении с последующим их размонтированием), vold сохраняет имя расшифрованного блочного устройства в свойстве ro.crypto.fs_crypto_blkdev и возвращает статус 0 в пользовательский интерфейс. Если пароль неверный, он возвращает -1 в пользовательский интерфейс.

  5. Остановить фреймворк

    Пользовательский интерфейс выводит графику криптозагрузки, а затем вызывает vold с помощью команды cryptfs restart . vold устанавливает свойство vold.decrypt в trigger_reset_main , что заставляет init.rc выполнить class_reset main . Это останавливает все службы в основном классе, что позволяет размонтировать tmpfs /data .

  6. Монтировать /data

    Затем vold монтирует расшифрованный реальный раздел /data и подготавливает новый раздел (который мог бы никогда не быть подготовлен, если бы он был зашифрован с опцией стирания, которая не поддерживается в первом выпуске). Он устанавливает свойство vold.post_fs_data_done в 0, а затем устанавливает vold.decrypt в trigger_post_fs_data . Это заставляет init.rc выполнять свои команды post-fs-data . Они создают все необходимые каталоги или ссылки, а затем устанавливают vold.post_fs_data_done в 1. Когда vold видит 1 в этом свойстве, он устанавливает свойство vold.decrypt в trigger_restart_framework . Это заставляет init.rc снова запустить службы в классе main , а также запустить службы в классе late_start в первый раз с момента загрузки.

  7. Запустить полную структуру

    Теперь фреймворк загружает все свои службы, используя расшифрованную файловую систему /data , и система готова к использованию.

Отказ

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

  1. Обнаружить зашифрованное устройство с паролем
  2. Смонтировать tmpfs
  3. Запустить фреймворк для запроса пароля

Но после открытия фреймворка устройство может столкнуться с некоторыми ошибками:

  • Пароль совпадает, но не удается расшифровать данные
  • Пользователь вводит неправильный пароль 30 раз

Если эти ошибки не устранены, предложите пользователю выполнить очистку до заводских настроек :

Если vold обнаруживает ошибку во время процесса шифрования, и если данные еще не были уничтожены, а фреймворк запущен, vold устанавливает свойство vold.encrypt_progress в значение error_not_encrypted . Пользовательский интерфейс предлагает пользователю перезагрузиться и предупреждает его о том, что процесс шифрования не начинался. Если ошибка возникает после того, как фреймворк был снесен, но до того, как пользовательский интерфейс с индикатором выполнения запущен, vold перезагружает систему. Если перезагрузка не удалась, он устанавливает vold.encrypt_progress в error_shutting_down и возвращает -1; но не будет ничего, что могло бы перехватить ошибку. Этого не ожидается.

Если vold обнаруживает ошибку в процессе шифрования, он устанавливает vold.encrypt_progress в error_partially_encrypted и возвращает -1. Затем пользовательский интерфейс должен отобразить сообщение о том, что шифрование не удалось, и предоставить пользователю кнопку для сброса настроек устройства к заводским.

Сохраните зашифрованный ключ

Зашифрованный ключ хранится в криптометаданных. Аппаратная поддержка реализована с использованием возможности подписи Trusted Execution Environment (TEE). Ранее мы шифровали главный ключ с помощью ключа, сгенерированного путем применения scrypt к паролю пользователя и сохраненной соли. Чтобы сделать ключ устойчивым к атакам вне коробки, мы расширяем этот алгоритм, подписывая полученный ключ сохраненным ключом TEE. Затем полученная подпись преобразуется в ключ соответствующей длины с помощью еще одного применения scrypt. Затем этот ключ используется для шифрования и расшифровки главного ключа. Чтобы сохранить этот ключ:

  1. Генерация случайного 16-байтового ключа шифрования диска (DEK) и 16-байтовой соли.
  2. Примените скрипт к паролю пользователя и соли для получения 32-байтового промежуточного ключа 1 (IK1).
  3. Дополняем IK1 нулевыми байтами до размера аппаратно-привязанного закрытого ключа (HBK). В частности, мы дополняем так: 00 || IK1 || 00..00; один нулевой байт, 32 байта IK1, 223 нулевых байта.
  4. Подпишите дополненный IK1 с помощью HBK, чтобы получить 256-байтовый IK2.
  5. Примените скрипт к IK2 и соль (ту же соль, что и на шаге 2) для получения 32-байтового IK3.
  6. Используйте первые 16 байт IK3 как KEK, а последние 16 байт как IV.
  7. Зашифруйте DEK с помощью AES_CBC, с ключом KEK и вектором инициализации IV.

Изменить пароль

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

Свойства шифрования

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

Свойства Vold

Свойство Описание
vold.decrypt trigger_encryption Зашифруйте диск без пароля.
vold.decrypt trigger_default_encryption Проверьте диск, чтобы увидеть, зашифрован ли он без пароля. Если да, расшифруйте и смонтируйте его, в противном случае установите vold.decrypt на trigger_restart_min_framework.
vold.decrypt trigger_reset_main Устанавливается vold для отключения пользовательского интерфейса, запрашивающего пароль диска.
vold.decrypt trigger_post_fs_data Устанавливается vold для подготовки /data с необходимыми каталогами и т. д.
vold.decrypt trigger_restart_framework Устанавливается vold для запуска реального фреймворка и всех служб.
vold.decrypt trigger_shutdown_framework Устанавливается с помощью vold для полного отключения фреймворка и начала шифрования.
vold.decrypt trigger_restart_min_framework Устанавливается параметром vold для запуска пользовательского интерфейса индикатора выполнения для шифрования или запроса пароля, в зависимости от значения ro.crypto.state .
vold.encrypt_progress При запуске фреймворка, если это свойство установлено, войдите в режим пользовательского интерфейса индикатора выполнения.
vold.encrypt_progress 0 to 100 Пользовательский интерфейс индикатора выполнения должен отображать установленное процентное значение.
vold.encrypt_progress error_partially_encrypted Пользовательский интерфейс индикатора выполнения должен отображать сообщение о том, что шифрование не удалось, и предоставлять пользователю возможность выполнить сброс настроек устройства до заводских.
vold.encrypt_progress error_reboot_failed Пользовательский интерфейс полосы прогресса должен отображать сообщение о том, что шифрование завершено, и предоставлять пользователю кнопку для перезагрузки устройства. Эта ошибка не должна возникать.
vold.encrypt_progress error_not_encrypted Пользовательский интерфейс индикатора выполнения должен отображать сообщение о том, что произошла ошибка, данные не были зашифрованы или утеряны, а также предоставлять пользователю кнопку для перезагрузки системы.
vold.encrypt_progress error_shutting_down Пользовательский интерфейс полосы прогресса не работает, поэтому неясно, кто реагирует на эту ошибку. И это в любом случае никогда не должно происходить.
vold.post_fs_data_done 0 Устанавливается vold непосредственно перед установкой vold.decrypt в trigger_post_fs_data .
vold.post_fs_data_done 1 Устанавливается init.rc или init.rc сразу после завершения задачи post-fs-data .

свойства инициализации

Свойство Описание
ro.crypto.fs_crypto_blkdev Устанавливается командой vold checkpw для последующего использования командой vold restart .
ro.crypto.state unencrypted Устанавливается init , чтобы указать, что эта система работает с незашифрованными /data ro.crypto.state encrypted . Устанавливается init , чтобы указать, что эта система работает с зашифрованными /data .

ro.crypto.fs_type
ro.crypto.fs_real_blkdev
ro.crypto.fs_mnt_point
ro.crypto.fs_options
ro.crypto.fs_flags

Эти пять свойств устанавливаются init , когда он пытается смонтировать /data с параметрами, переданными из init.rc vold использует их для настройки криптографического сопоставления.
ro.crypto.tmpfs_options Устанавливается init.rc с параметрами, которые init должен использовать при монтировании файловой системы tmpfs /data .

действия инициализации

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