Полнодисковое шифрование — это процесс кодирования всех пользовательских данных на устройстве 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.
- Обнаружение незашифрованной файловой системы с помощью флага
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
на RAMDisk tmpfs, используя параметры, полученные изro.crypto.tmpfs_options
, которые установлены вinit.rc
- Запустить фреймворк
vold
устанавливает дляvold.decrypt
значениеtrigger_restart_framework
, что продолжает обычный процесс загрузки.
Зашифровать существующее устройство
Вот что происходит, когда вы шифруете незашифрованное устройство Android K или более ранней версии, которое было перенесено на L.
Этот процесс инициируется пользователем и в коде называется «шифрованием на месте». Когда пользователь выбирает шифрование устройства, пользовательский интерфейс проверяет, что аккумулятор полностью заряжен и адаптер переменного тока подключен, чтобы было достаточно энергии для завершения процесса шифрования.
Предупреждение. Если в устройстве заканчивается питание и оно выключается до завершения шифрования, данные файла остаются в частично зашифрованном состоянии. Устройство должно быть сброшено до заводских настроек, и все данные будут потеряны.
Чтобы включить шифрование на месте, vold
запускает цикл для чтения каждого сектора реального блочного устройства, а затем записывает его в криптоблочное устройство. vold
проверяет, используется ли сектор, прежде чем читать и записывать его, что значительно ускоряет шифрование на новом устройстве, на котором практически нет данных.
Состояние устройства : установите ro.crypto.state = "unencrypted"
и выполните триггер инициализации on nonencrypted
init
, чтобы продолжить загрузку.
- Проверить пароль
Пользовательский интерфейс вызывает
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
, и система готова к использованию.
Запуск зашифрованного устройства без шифрования по умолчанию
Вот что происходит, когда вы загружаете зашифрованное устройство с установленным паролем. Паролем устройства может быть 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
. Это останавливает все службы в основном классе, что позволяет размонтировать 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). Ранее мы зашифровали главный ключ с помощью ключа, сгенерированного путем применения сценария к паролю пользователя и сохраненной соли. Чтобы сделать ключ устойчивым к нестандартным атакам, мы расширяем этот алгоритм, подписывая полученный ключ сохраненным ключом TEE. Результирующая подпись затем преобразуется в ключ соответствующей длины с помощью еще одного применения сценария. Этот ключ затем используется для шифрования и дешифрования главного ключа. Чтобы сохранить этот ключ:
- Сгенерируйте случайный 16-байтовый ключ шифрования диска (DEK) и 16-байтовую соль.
- Примените сценарий к паролю пользователя и соли, чтобы создать 32-байтовый промежуточный ключ 1 (IK1).
- Дополните IK1 нулевыми байтами до размера аппаратно-привязанного закрытого ключа (HBK). В частности, мы заполняем как: 00 || ИК1 || 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.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 . |
| Эти пять свойств устанавливаются 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