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

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

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

  • Реализовано быстрое шифрование, которое шифрует только используемые блоки на разделе данных, чтобы избежать длительной первой загрузки. В настоящее время быстрое шифрование поддерживают только файловые системы ext4 и f2fs.
  • Добавлен флаг fstab forceencrypt для шифрования при первой загрузке.
  • Добавлена ​​поддержка шаблонов и шифрования без пароля.
  • Добавлено аппаратное хранилище ключа шифрования с использованием функции подписи 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 запускает main класс служб init.rc Когда фреймворк обнаруживает, что 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. Монтировать /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 впервые с момента загрузки.

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

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

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

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

  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 . Это останавливает все службы в классе 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. После этого в пользовательском интерфейсе должно появиться сообщение о сбое шифрования и кнопка для сброса настроек устройства к заводским.

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

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

  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