Полное шифрование диска — это процесс кодирования всех пользовательских данных на устройстве 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.
- Обнаружение незашифрованной файловой системы с помощью флага
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
заставляетinit.rc
запуститьmain
класс служб. Когда фреймворк видит, что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
поверх блочного устройства, чтобы устройство было готово к использованию. - Монтировать /данные
Затем
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
, и система готова к использованию.
Запустить зашифрованное устройство без шифрования по умолчанию
Вот что происходит, когда вы загружаете зашифрованное устройство, на котором установлен пароль. Пароль устройства может быть пин-кодом, шаблоном или паролем.
- Обнаружить зашифрованное устройство с паролем
Определите, что устройство 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
. Это останавливает все службы в основном классе, что позволяет размонтировать 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. Затем пользовательский интерфейс должен отобразить сообщение о том, что шифрование не удалось, и предоставить пользователю кнопку для сброса настроек устройства к заводским.
Сохраните зашифрованный ключ
Зашифрованный ключ хранится в криптометаданных. Аппаратная поддержка реализована с использованием возможности подписи Trusted Execution Environment (TEE). Ранее мы шифровали главный ключ с помощью ключа, сгенерированного путем применения scrypt к паролю пользователя и сохраненной соли. Чтобы сделать ключ устойчивым к атакам вне коробки, мы расширяем этот алгоритм, подписывая полученный ключ сохраненным ключом TEE. Затем полученная подпись преобразуется в ключ соответствующей длины с помощью еще одного применения scrypt. Затем этот ключ используется для шифрования и расшифровки главного ключа. Чтобы сохранить этот ключ:
- Генерация случайного 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