Полное шифрование диска — это процесс кодирования всех пользовательских данных на устройстве 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.
- Обнаружение незашифрованной файловой системы с помощью флага
forceencrypt
/data
не зашифрован, но это необходимо, посколькуforceencrypt
требует этого. Размонтируйте/data
. - Начать шифрование
/data
vold.decrypt = "trigger_encryption"
запускаетinit.rc
, что заставляетvold
шифровать/data
без пароля. (Пароль не установлен, поскольку это должно быть новое устройство.) - Монтировать tmpfs
vold
монтирует tmpfs/data
(используя параметры tmpfs изro.crypto.tmpfs_options
) и устанавливает свойствоvold.encrypt_progress
в 0.vold
подготавливает tmpfs/data
для загрузки зашифрованной системы и устанавливает свойствоvold.decrypt
в:trigger_restart_min_framework
- Откройте фреймворк, чтобы показать прогресс
Поскольку на устройстве практически нет данных для шифрования, индикатор выполнения будет появляться нечасто из-за высокой скорости шифрования. Подробнее об интерфейсе индикатора выполнения см. в статье Шифрование существующего устройства .
- Когда
/data
зашифрованы, удалите фреймворкvold
устанавливаетvold.decrypt
вtrigger_default_encryption
, что запускает службуdefaultcrypto
. (Это запускает описанный ниже процесс монтирования зашифрованных пользовательских данных по умолчанию.)trigger_default_encryption
проверяет тип шифрования, чтобы определить, зашифрован ли/data
с паролем или без него. Поскольку устройства Android 5.0 шифруются при первой загрузке, пароль устанавливать не нужно; поэтому мы расшифровываем и монтируем каталог/data
. - Монтировать
/data
Затем
init
монтирует/data
на tmpfs RAMDisk, используя параметры, которые он берет изro.crypto.tmpfs_options
, заданного вinit.rc
. - Начать фреймворк
vold
устанавливаетvold.decrypt
вtrigger_restart_framework
, что продолжает обычный процесс загрузки.
Зашифровать существующее устройство
Вот что происходит, когда вы шифруете незашифрованное устройство Android K или более ранней версии, которое было переведено на L.
Этот процесс инициируется пользователем и в коде называется «шифрованием на месте». Когда пользователь выбирает шифрование устройства, пользовательский интерфейс проверяет, полностью ли заряжен аккумулятор и подключен ли адаптер переменного тока, чтобы заряда хватало для завершения процесса шифрования.
Внимание: Если устройство разрядится и выключится до завершения шифрования, данные файла останутся в частично зашифрованном состоянии. Необходимо выполнить сброс настроек устройства до заводских, и все данные будут потеряны.
Чтобы включить шифрование на месте, vold
запускает цикл для чтения каждого сектора реального блочного устройства, а затем записывает его на криптографическое блочное устройство. vold
проверяет, используется ли сектор, перед его чтением и записью, что значительно ускоряет шифрование на новом устройстве, на котором мало или совсем нет данных.
Состояние устройства : установите ro.crypto.state = "unencrypted"
и выполните триггер init
on nonencrypted
, чтобы продолжить загрузку.
- Проверить пароль
Пользовательский интерфейс вызывает
vold
с помощью командыcryptfs enablecrypto inplace
, гдеpasswd
— пароль блокировки экрана пользователя. - Снести каркас
vold
проверяет наличие ошибок, возвращает -1, если шифрование невозможно, и выводит причину в журнал. Если шифрование возможно, свойствоvold.decrypt
устанавливается в значениеtrigger_shutdown_framework
. Это приводит к тому, чтоinit.rc
останавливает службы в классахlate_start
иmain
. - Создать крипто-футер
- Создайте файл навигационной цепочки
- Перезагрузить
- Определить файл хлебных крошек
- Начать шифрование
/data
Затем
vold
настраивает криптографическое сопоставление, которое создает виртуальное криптографическое блочное устройство, которое сопоставляется с реальным блочным устройством, но шифрует каждый сектор по мере записи и расшифровывает каждый сектор по мере чтения. Затемvold
создает и записывает криптографические метаданные. - Пока идет шифрование, смонтируйте tmpfs
vold
монтирует tmpfs/data
(используя параметры tmpfs изro.crypto.tmpfs_options
) и устанавливает свойствоvold.encrypt_progress
в 0.vold
подготавливает tmpfs/data
для загрузки зашифрованной системы и устанавливает свойствоvold.decrypt
в:trigger_restart_min_framework
- Откройте фреймворк, чтобы показать прогресс
trigger_restart_min_framework
запускаетmain
класс службinit.rc
Когда фреймворк обнаруживает, чтоvold.encrypt_progress
равен 0, он выводит на экран пользовательский интерфейс индикатора выполнения, который опрашивает это свойство каждые пять секунд и обновляет индикатор выполнения. Цикл шифрования обновляетvold.encrypt_progress
каждый раз при шифровании очередного процента раздела. - Если
/data
зашифрован, обновите нижний колонтитул криптографии.Когда
/data
успешно зашифрован,vold
очищает флагENCRYPTION_IN_PROGRESS
в метаданных.После успешной разблокировки устройства пароль используется для шифрования главного ключа, а криптографический нижний колонтитул обновляется.
Если перезагрузка по какой-либо причине не удалась,
vold
устанавливает свойствоvold.encrypt_progress
в значениеerror_reboot_failed
, а в пользовательском интерфейсе должно появиться сообщение с просьбой нажать кнопку для перезагрузки. Этого, как ожидается, никогда не произойдёт.
Запустить зашифрованное устройство с шифрованием по умолчанию
Вот что происходит при загрузке зашифрованного устройства без пароля. Поскольку устройства Android 5.0 шифруются при первой загрузке, пароль не устанавливается, и поэтому это состояние шифрования по умолчанию .
- Обнаружение зашифрованных
/data
без пароляОпределить, что устройство Android зашифровано, поскольку
/data
не может быть смонтирован и установлен один из флаговencryptable
илиforceencrypt
.vold
устанавливаетvold.decrypt
вtrigger_default_encryption
, что запускает службуdefaultcrypto
.trigger_default_encryption
проверяет тип шифрования, чтобы увидеть, зашифрован ли/data
с паролем или без него. - Расшифровать /данные
Создает устройство
dm-crypt
на блочном устройстве, чтобы устройство было готово к использованию. - Монтировать /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
впервые с момента загрузки. - Начать фреймворк
Теперь фреймворк загружает все свои службы, используя расшифрованные
/data
, и система готова к использованию.
Запустить зашифрованное устройство без шифрования по умолчанию
Вот что происходит при загрузке зашифрованного устройства с установленным паролем. Пароль устройства может представлять собой PIN-код, графический ключ или пароль.
- Обнаружить зашифрованное устройство с паролем
Определите, что устройство Android зашифровано, поскольку флаг
ro.crypto.state = "encrypted"
vold
устанавливаетvold.decrypt
вtrigger_restart_min_framework
, поскольку/data
зашифрованы паролем. - Монтировать tmpfs
init
устанавливает пять свойств для сохранения начальных параметров монтирования, указанных для/data
с параметрами, переданными изinit.rc
vold
использует эти свойства для настройки криптографического сопоставления:-
ro.crypto.fs_type
-
ro.crypto.fs_real_blkdev
-
ro.crypto.fs_mnt_point
-
ro.crypto.fs_options
-
ro.crypto.fs_flags
(8-значное шестнадцатеричное число ASCII, которому предшествует 0x)
-
- Запустить фреймворк для запроса пароля
Фреймворк запускается и обнаруживает, что
vold.decrypt
установлен в значениеtrigger_restart_min_framework
. Это сообщает фреймворку, что он загружается с диска tmpfs/data
и ему необходимо получить пароль пользователя.Однако сначала необходимо убедиться, что диск был правильно зашифрован. Команда
cryptfs cryptocomplete
отправляется вvold
.vold
возвращает 0, если шифрование было успешно завершено, -1 при внутренней ошибке или -2, если шифрование не было завершено успешно.vold
определяет это, просматривая метаданные криптографического кода на предмет флагаCRYPTO_ENCRYPTION_IN_PROGRESS
. Если он установлен, процесс шифрования был прерван, и на устройстве нет пригодных для использования данных. Еслиvold
возвращает ошибку, пользовательский интерфейс должен отобразить пользователю сообщение с просьбой перезагрузить устройство и сбросить настройки до заводских, а также предоставить пользователю кнопку для этого. - Расшифровать данные с помощью пароля
После успешного выполнения
cryptfs cryptocomplete
фреймворк отображает пользовательский интерфейс с запросом пароля диска. Пользовательский интерфейс проверяет пароль, отправляя командуcryptfs checkpw
вvold
. Если пароль верный (что подтверждается успешным монтированием расшифрованного/data
во временном расположении и последующим его размонтированием),vold
сохраняет имя расшифрованного блочного устройства в свойствеro.crypto.fs_crypto_blkdev
и возвращает статус 0 в пользовательский интерфейс. Если пароль неверный, он возвращает -1 в пользовательский интерфейс. - Остановить фреймворк
Пользовательский интерфейс отображает загрузочный графический интерфейс криптографической системы, а затем вызывает
vold
с помощью командыcryptfs restart
.vold
устанавливает свойствоvold.decrypt
в значениеtrigger_reset_main
, что приводит к выполнениюinit.rc
class_reset main
. Это останавливает все службы в классе main , что позволяет отмонтировать папку tmpfs/data
. - Монтировать
/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
впервые с момента загрузки. - Запустить полный фреймворк
Теперь фреймворк загружает все свои службы, используя расшифрованную файловую систему
/data
, и система готова к использованию.
Отказ
Устройство, которому не удаётся расшифровать данные, может работать некорректно по нескольким причинам. Загрузка устройства начинается с обычной последовательности действий:
- Обнаружить зашифрованное устройство с паролем
- Монтировать tmpfs
- Запустить фреймворк для запроса пароля
Однако после открытия фреймворка устройство может столкнуться с некоторыми ошибками:
- Пароль совпадает, но не может расшифровать данные
- Пользователь ввел неправильный пароль 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. Затем полученная подпись преобразуется в ключ соответствующей длины с помощью ещё одного применения скрипта. Этот ключ затем используется для шифрования и дешифрования главного ключа. Для хранения этого ключа:
- Генерация случайного 16-байтового ключа шифрования диска (DEK) и 16-байтовой соли.
- Примените скрипт к паролю пользователя и соли, чтобы получить 32-байтовый промежуточный ключ 1 (IK1).
- Дополняем IK1 нулевыми байтами до размера аппаратно-привязанного закрытого ключа (HBK). В частности, мы дополняем следующим образом: 00 || IK1 || 00..00; один нулевой байт, 32 байта IK1, 223 нулевых байта.
- Подпишите дополненный IK1 с помощью HBK, чтобы получить 256-байтовый IK2.
- Применяем скрипт к IK2 и соль (ту же соль, что и в шаге 2) для получения 32-байтового IK3.
- Используйте первые 16 байт IK3 как KEK и последние 16 байт как IV.
- Зашифруйте 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 . |
| Эти пять свойств устанавливаются 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