Шифрование всего диска — это процесс кодирования всех пользовательских данных на устройстве Android с использованием зашифрованного ключа. После шифрования устройства все созданные пользователем данные автоматически шифруются перед записью на диск, а при чтении данные автоматически расшифровываются перед возвратом вызывающему процессу.
Полное шифрование диска было введено в Android в версии 4.4, но Android 5.0 представил следующие новые функции:
- Создана функция быстрого шифрования, которая шифрует только используемые блоки на разделе данных, чтобы избежать длительного времени при первой загрузке. В настоящее время быстрое шифрование поддерживают только файловые системы ext4 и f2fs.
- Добавлен флаг
forceencryptв файле fstab для шифрования при первой загрузке. - Добавлена поддержка графических ключей и шифрования без пароля.
- Добавлено аппаратное хранилище ключа шифрования с использованием возможностей подписи среды доверенного выполнения (TEE) (например, в TrustZone). Дополнительные сведения см. в разделе «Хранение зашифрованного ключа» .
Внимание: устройства, обновленные до Android 5.0 и затем зашифрованные, можно вернуть в незашифрованное состояние путем сброса до заводских настроек. Новые устройства Android 5.0, зашифрованные при первой загрузке, нельзя вернуть в незашифрованное состояние.
Как работает шифрование всего диска в Android
Шифрование всего диска в Android основано на dm-crypt , функции ядра, работающей на уровне блочных устройств. Благодаря этому шифрование работает с картами памяти Embedded MultiMediaCard ( eMMC) и аналогичными флэш-накопителями, которые представляются ядру как блочные устройства. Шифрование невозможно с YAFFS, которая взаимодействует напрямую с необработанным чипом NAND-флэш-памяти.
Алгоритм шифрования — 128-битный AES (Advanced Encryption Standard) с цепочкой блоков шифрования (CBC) и ESSIV:SHA256. Главный ключ шифруется 128-битным AES с помощью вызовов библиотеки OpenSSL. Для ключа необходимо использовать 128 бит или более (256 — необязательно).
Примечание: производители оборудования могут использовать 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. - Начать шифрование
/datavold.decrypt = "trigger_encryption"запускаетinit.rc, в результате чегоvoldшифрует/dataбез пароля. (Пароль не установлен, поскольку это должно быть новое устройство.) - Mount 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 в оперативной памяти, используя параметры, полученные изro.crypto.tmpfs_options, которые заданы вinit.rc - Начало работы над фреймворком
voldустанавливаетvold.decryptв значениеtrigger_restart_framework, что продолжает обычный процесс загрузки.
Зашифровать существующее устройство
Вот что происходит, когда вы шифруете незашифрованное устройство Android K или более ранней версии, которое было переведено на Android 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.rcmainкласс служб. Когда фреймворк обнаруживает, что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зашифрован паролем. - Mount tmpfs
initустанавливает пять свойств для сохранения начальных параметров монтирования, заданных для/dataс помощью параметров, переданных изinit.rcvoldиспользует эти свойства для настройки криптографического сопоставления:-
ro.crypto.fs_type -
ro.crypto.fs_real_blkdev -
ro.crypto.fs_mnt_point -
ro.crypto.fs_options -
ro.crypto.fs_flags(ASCII 8-значное шестнадцатеричное число, которому предшествует 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, что приводит к выполнениюclass_reset maininit.rcЭто останавливает все службы в основном классе, что позволяет отмонтировать каталог tmpfs/data. - Смонтировать
/dataЗатем
voldмонтирует расшифрованный реальный раздел/dataи подготавливает новый раздел (который мог бы никогда не быть подготовлен, если бы он был зашифрован с помощью опции wipe, которая не поддерживается в первой версии). Он устанавливает свойство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, и система готова к использованию.
Отказ
Устройство, которому не удаётся расшифровать данные, может работать некорректно по нескольким причинам. При запуске устройство выполняет обычную последовательность действий:
- Обнаружение зашифрованного устройства с паролем
- Mount tmpfs
- Запустите фреймворк, чтобы запросить пароль.
Однако после запуска фреймворка устройство может столкнуться с некоторыми ошибками:
- Пароль совпадает, но данные расшифровать не удаётся.
- Пользователь вводит неверный пароль 30 раз.
Если эти ошибки не будут устранены, предложите пользователю выполнить сброс до заводских настроек :
Если vold обнаруживает ошибку в процессе шифрования, и если данные еще не были уничтожены и платформа запущена, vold устанавливает свойство vold.encrypt_progress в значение error_not_encrypted . Пользовательский интерфейс предлагает перезагрузить систему и сообщает, что процесс шифрования так и не начался. Если ошибка возникает после завершения работы платформы, но до появления индикатора выполнения, vold перезагружает систему. Если перезагрузка не удалась, vold устанавливает свойство vold.encrypt_progress в error_shutting_down и возвращает -1; однако система не будет обрабатывать эту ошибку. Этого не ожидается.
Если vold обнаруживает ошибку в процессе шифрования, он устанавливает vold.encrypt_progress в значение error_partially_encrypted и возвращает -1. После этого в пользовательском интерфейсе должно отобразиться сообщение о том, что шифрование не удалось, и кнопка для сброса устройства до заводских настроек.
Сохраните зашифрованный ключ.
Зашифрованный ключ хранится в криптографических метаданных. Аппаратная поддержка реализована с использованием возможностей подписи среды доверенного выполнения (TEE). Ранее мы зашифровали главный ключ с помощью ключа, сгенерированного путем применения алгоритма scrypt к паролю пользователя и сохраненной соли. Чтобы сделать ключ устойчивым к атакам вне системы, мы расширили этот алгоритм, подписав полученный ключ сохраненным ключом TEE. Полученная подпись затем преобразуется в ключ соответствующей длины еще одним применением алгоритма scrypt. Этот ключ затем используется для шифрования и расшифровки главного ключа. Для хранения этого ключа:
- Сгенерировать случайный 16-байтовый ключ шифрования диска (DEK) и 16-байтовую соль.
- Примените алгоритм scrypt к паролю пользователя и соли, чтобы получить 32-байтовый промежуточный ключ 1 (IK1).
- Дополняем IK1 нулевыми байтами до размера аппаратно-зависимого закрытого ключа (HBK). В частности, дополняем следующим образом: 00 || IK1 || 00..00; один нулевой байт, 32 байта IK1, 223 нулевых байта.
- Подписанный IK1 с использованием HBK для получения 256-байтового IK2.
- Примените алгоритм scrypt к 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 в значение 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 | Параметр `ro.crypto.state encrypted` задается при init , указывая на то, что система работает с незашифрованным каталогом /data ro.crypto.state encrypted Параметр `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