Полнодисковое шифрование — это процесс кодирования всех пользовательских данных на Android-устройстве с использованием зашифрованного ключа. Как только устройство зашифровано, все данные, созданные пользователем, автоматически шифруются перед их записью на диск, а все операции чтения автоматически расшифровывают данные, прежде чем возвращать их вызывающему процессу.
Полнодисковое шифрование было представлено в Android 4.4, но в Android 5.0 появились следующие новые функции:
- Создано быстрое шифрование, которое шифрует только используемые блоки в разделе данных, чтобы первая загрузка не занимала много времени. Только файловые системы ext4 и f2fs в настоящее время поддерживают быстрое шифрование.
- Добавлен флаг
forceencrypt
fstab для шифрования при первой загрузке. - Добавлена поддержка шаблонов и шифрования без пароля.
- Добавлено аппаратное хранилище ключа шифрования с использованием возможности подписи Trusted Execution Environment (TEE) (например, в TrustZone). Дополнительные сведения см. в разделе Хранение зашифрованного ключа .
Внимание! Устройства, обновленные до Android 5.0 и затем зашифрованные, могут быть возвращены в незашифрованное состояние путем сброса заводских данных. Новые устройства Android 5.0, зашифрованные при первой загрузке, не могут быть возвращены в незашифрованное состояние.
Как работает полное шифрование диска Android
Полнодисковое шифрование Android основано на dm-crypt
— функции ядра, работающей на уровне блочного устройства. По этой причине шифрование работает с Embedded MultiMediaCard ( eMMC) и аналогичными флэш-устройствами, которые представляются ядру как блочные устройства. Шифрование невозможно с YAFFS, который напрямую взаимодействует с необработанным чипом флэш-памяти NAND.
Алгоритм шифрования — 128 Advanced Encryption Standard (AES) с цепочкой блоков шифрования (CBC) и ESSIV:SHA256. Главный ключ шифруется с помощью 128-битного AES через вызовы библиотеки OpenSSL. Вы должны использовать 128 бит или более для ключа (256 бит не является обязательным).
Примечание. OEM-производители могут использовать 128-битный или более высокий уровень шифрования для главного ключа.
В версии Android 5.0 существует четыре типа состояний шифрования:
- По умолчанию
- ПРИКОЛОТЬ
- пароль
- шаблон
При первой загрузке устройство создает случайно сгенерированный 128-битный мастер-ключ, а затем хэширует его с паролем по умолчанию и сохраненной солью. Пароль по умолчанию: «default_password». Однако результирующий хэш также подписывается через TEE (например, TrustZone), который использует хэш подписи для шифрования главного ключа.
Вы можете найти пароль по умолчанию, определенный в файле Android Open Source Project cryptfs.cpp .
Когда пользователь устанавливает PIN-код/пароль или пароль на устройстве, повторно шифруется и сохраняется только 128-битный ключ. (т. е. изменение ПИН-кода/пароля/шаблона пользователя НЕ приводит к повторному шифрованию пользовательских данных.) Обратите внимание, что на управляемое устройство могут быть наложены ограничения по ПИН-коду, шаблону или паролю.
Шифрование управляется 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
. - Начать шифрование
/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
значение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). Ранее мы зашифровали мастер-ключ с помощью ключа, сгенерированного путем применения 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