Полнодисковое шифрование — это процесс кодирования всех пользовательских данных на Android-устройстве с использованием зашифрованного ключа. Как только устройство зашифровано, все данные, созданные пользователем, автоматически шифруются перед их записью на диск, а все операции чтения автоматически расшифровывают данные, прежде чем возвращать их вызывающему процессу.
Полнодисковое шифрование было представлено в Android 4.4, но в Android 5.0 появились следующие новые функции:
- Создано быстрое шифрование, которое шифрует только используемые блоки в разделе данных, чтобы первая загрузка не занимала много времени. Только файловые системы ext4 и f2fs в настоящее время поддерживают быстрое шифрование.
- Добавлен флаг
forceencryptfstab для шифрования при первой загрузке. - Добавлена поддержка шаблонов и шифрования без пароля.
- Добавлено аппаратное хранилище ключа шифрования с использованием возможности подписи 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-битный ключ. (т. е. изменение ПИН-кода/пароля/шаблона пользователя НЕ приводит к повторному шифрованию пользовательских данных.) Обратите внимание, что на управляемое устройство могут быть наложены ограничения по ПИН-коду, шаблону или паролю.
Шифрование управляется init и vold . init вызывает vold , а vold устанавливает свойства для запуска событий в init. Другие части системы также просматривают свойства для выполнения таких задач, как отчет о состоянии, запрос пароля или запрос на сброс настроек в случае фатальной ошибки. Для вызова функций шифрования в vold система использует команды checkpw vdc cryptfs 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на RAMDisk tmpfs, используя параметры, полученные изro.crypto.tmpfs_options, которые установлены вinit.rc - Запустить фреймворк
Установите для
voldзначение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. - Создайте криптографический нижний колонтитул
- Создать файл хлебных крошек
- Перезагрузить
- Обнаружить файл хлебных крошек
- Начать шифрование
/datavoldнастраивает криптосопоставление, которое создает виртуальное криптоблочное устройство, которое сопоставляется с реальным блочным устройством, но шифрует каждый сектор по мере его записи и расшифровывает каждый сектор по мере его чтения.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.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.rcвыполнятьclass_reset main. Это останавливает все службы в основном классе, что позволяет размонтировать tmpfs/data. - Смонтировать
/datavoldмонтирует расшифрованный реальный раздел/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-байтовую соль.
- Примените scrypt к паролю пользователя и соли, чтобы создать 32-байтовый промежуточный ключ 1 (IK1).
- Заполните IK1 нулевыми байтами до размера аппаратно-привязанного закрытого ключа (HBK). В частности, мы заполняем как: 00 || ИК1 || 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 | Ставим по vol для запуска реального фреймворка и всех сервисов. |
vold.decrypt trigger_shutdown_framework | Установите с помощью vol, чтобы отключить полную структуру, чтобы начать шифрование. |
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 для последующего использования командой restart vold . |
ro.crypto.state unencrypted | Установите init , чтобы сказать, что эта система работает с незашифрованным /data ro.crypto.state encrypted . Установите init , чтобы сказать, что эта система работает с зашифрованным файлом /data . |
| Эти пять свойств устанавливаются init , когда он пытается смонтировать /data с параметрами, переданными из init.rc vold использует их для настройки криптосопоставления. |
ro.crypto.tmpfs_options | Задается init.rc с параметрами, которые следует использовать при монтировании файловой системы 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