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