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

Полнодисковое шифрование — это процесс кодирования всех пользовательских данных на устройстве 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), который использует хэш подписи для шифрования главного ключа.

Вы можете найти пароль по умолчанию, определенный в файле cryptfs.cpp проекта Android с открытым исходным кодом.

Когда пользователь устанавливает 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 на RAMDisk tmpfs, используя параметры, полученные из 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 , и система готова к использованию.

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

Вот что происходит, когда вы загружаете зашифрованное устройство с установленным паролем. Паролем устройства может быть 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 и возвращает UI статус 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). Ранее мы зашифровали главный ключ с помощью ключа, сгенерированного путем применения сценария к паролю пользователя и сохраненной соли. Чтобы сделать ключ устойчивым к нестандартным атакам, мы расширяем этот алгоритм, подписывая полученный ключ сохраненным ключом TEE. Результирующая подпись затем преобразуется в ключ соответствующей длины с помощью еще одного применения сценария. Этот ключ затем используется для шифрования и дешифрования главного ключа. Чтобы сохранить этот ключ:

  1. Сгенерируйте случайный 16-байтовый ключ шифрования диска (DEK) и 16-байтовую соль.
  2. Примените сценарий к паролю пользователя и соли, чтобы создать 32-байтовый промежуточный ключ 1 (IK1).
  3. Дополните IK1 нулевыми байтами до размера аппаратно-привязанного закрытого ключа (HBK). В частности, мы заполняем как: 00 || ИК1 || 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.decrypt trigger_encryption Зашифруйте диск без пароля.
vold.decrypt trigger_default_encryption Проверьте диск, чтобы убедиться, что он зашифрован без пароля. Если да, расшифруйте и смонтируйте его, иначе установите для vold.decrypt значение триггер_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