Полное шифрование диска

Полнодисковое шифрование — это процесс кодирования всех пользовательских данных на 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.

  1. Обнаружение незашифрованной файловой системы с флагом forceencrypt

    /data не зашифровано, но должно быть зашифровано, потому что forceencrypt требует принудительное шифрование. Размонтировать /data .

  2. Начать шифрование /data

    vold.decrypt = "trigger_encryption" запускает init.rc , что приводит к тому, что vold шифрует /data без пароля. (Ни один не установлен, потому что это должно быть новое устройство.)

  3. Смонтировать tmpfs

    vold монтирует tmpfs /data (используя параметры tmpfs из ro.crypto.tmpfs_options ) и устанавливает для свойства vold.encrypt_progress значение 0. vold подготавливает tmpfs /data для загрузки зашифрованной системы и устанавливает для свойства vold.decrypt значение: trigger_restart_min_framework

  4. Поднимите фреймворк, чтобы показать прогресс

    Поскольку на устройстве практически нет данных для шифрования, индикатор выполнения часто не отображается, потому что шифрование происходит очень быстро. Дополнительные сведения об интерфейсе прогресса см. в разделе Шифрование существующего устройства .

  5. Когда /data зашифрован, снимите фреймворк

    vold устанавливает для vold.decrypt значение trigger_default_encryption , которое запускает службу defaultcrypto . (Это запускает приведенный ниже процесс для монтирования зашифрованных пользовательских данных по умолчанию.) trigger_default_encryption проверяет тип шифрования, чтобы увидеть, зашифрован ли /data с паролем или без него. Поскольку устройства Android 5.0 шифруются при первой загрузке, пароль не должен устанавливаться; поэтому мы расшифровываем и монтируем /data .

  6. Смонтировать /data

    Затем init монтирует /data на RAMDisk tmpfs, используя параметры, полученные из ro.crypto.tmpfs_options , которые установлены в init.rc

  7. Запустить фреймворк

    Установите для vold значение trigger_restart_framework , что продолжит обычный процесс загрузки.

Зашифровать существующее устройство

Вот что происходит, когда вы шифруете незашифрованное устройство Android K или более ранней версии, которое было перенесено на L.

Этот процесс инициируется пользователем и в коде называется «шифрованием на месте». Когда пользователь выбирает шифрование устройства, пользовательский интерфейс проверяет, полностью ли заряжен аккумулятор и подключен адаптер переменного тока, чтобы было достаточно энергии для завершения процесса шифрования.

Предупреждение. Если устройство разрядится и выключится до завершения шифрования, данные файла останутся в частично зашифрованном состоянии. Устройство должно быть сброшено к заводским настройкам, и все данные будут потеряны.

Чтобы включить шифрование на месте, vold запускает цикл для чтения каждого сектора реального блочного устройства, а затем записывает его в криптоблочное устройство. vold проверяет, используется ли сектор, прежде чем читать и записывать его, что значительно ускоряет шифрование на новом устройстве, на котором практически нет данных.

Состояние устройства : установите ro.crypto.state = "unencrypted" и выполните on nonencrypted init незашифрованного устройства, чтобы продолжить загрузку.

  1. Проверить пароль

    Пользовательский интерфейс вызывает vold с помощью команды cryptfs enablecrypto inplace где passwd — это пароль пользователя на экране блокировки.

  2. Снять структуру

    vold проверяет наличие ошибок, возвращает -1, если не может зашифровать, и печатает причину в журнале. Если он может шифровать, он устанавливает для свойства vold.decrypt значение trigger_shutdown_framework . Это приводит к тому, что init.rc останавливает службы в классах late_start и main .

  3. Создайте криптографический нижний колонтитул
  4. Создать файл хлебных крошек
  5. Перезагрузить
  6. Обнаружить файл хлебных крошек
  7. Начать шифрование /data

    vold настраивает криптосопоставление, которое создает виртуальное криптоблочное устройство, которое сопоставляется с реальным блочным устройством, но шифрует каждый сектор по мере его записи и расшифровывает каждый сектор по мере его чтения. vold создает и записывает метаданные шифрования.

  8. Пока он шифруется, смонтируйте tmpfs

    vold монтирует tmpfs /data (используя параметры tmpfs из ro.crypto.tmpfs_options ) и устанавливает для свойства vold.encrypt_progress значение 0. vold подготавливает tmpfs /data для загрузки зашифрованной системы и устанавливает для свойства vold.decrypt значение: trigger_restart_min_framework

  9. Поднимите фреймворк, чтобы показать прогресс

    trigger_restart_min_framework заставляет init.rc запускать main класс сервисов. Когда платформа видит, что vold.encrypt_progress имеет значение 0, она вызывает пользовательский интерфейс индикатора выполнения, который запрашивает это свойство каждые пять секунд и обновляет индикатор выполнения. Цикл шифрования обновляет vold.encrypt_progress каждый раз, когда он шифрует очередной процент раздела.

  10. Когда /data зашифрованы, обновите криптографический нижний колонтитул

    Когда /data успешно зашифрованы, vold очищает флаг ENCRYPTION_IN_PROGRESS в метаданных.

    Когда устройство успешно разблокировано, пароль используется для шифрования главного ключа и обновляется криптографический нижний колонтитул.

    Если по какой-то причине перезагрузка не удалась, vold устанавливает для свойства vold.encrypt_progress значение error_reboot_failed , и пользовательский интерфейс должен отображать сообщение, предлагающее пользователю нажать кнопку для перезагрузки. Ожидается, что это никогда не произойдет.

Запуск зашифрованного устройства с шифрованием по умолчанию

Вот что происходит, когда вы загружаете зашифрованное устройство без пароля. Поскольку устройства Android 5.0 шифруются при первой загрузке, пароль не должен устанавливаться, поэтому это состояние шифрования по умолчанию .

  1. Обнаружение зашифрованных /data без пароля

    Обнаружение того, что устройство Android зашифровано, поскольку /data не может быть смонтировано и установлен один из флагов encryptable или forceencrypt .

    vold устанавливает для vold.decrypt значение trigger_default_encryption , которое запускает службу defaultcrypto . trigger_default_encryption проверяет тип шифрования, чтобы увидеть, зашифрованы ли /data с паролем или без него.

  2. Расшифровать /данные

    Создает устройство dm-crypt поверх блочного устройства, чтобы устройство было готово к использованию.

  3. Смонтировать/данные

    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 в первый раз после загрузки.

  4. Запустить фреймворк

    Теперь фреймворк загружает все свои сервисы, используя расшифрованный /data , и система готова к использованию.

Запуск зашифрованного устройства без шифрования по умолчанию

Вот что происходит, когда вы загружаете зашифрованное устройство с установленным паролем. Паролем устройства может быть PIN-код, шаблон или пароль.

  1. Обнаружить зашифрованное устройство с паролем

    Обнаружение того, что устройство Android зашифровано, поскольку флаг ro.crypto.state = "encrypted"

    vold устанавливает для vold.decrypt значение trigger_restart_min_framework , поскольку /data зашифровано паролем.

  2. Смонтировать tmpfs

    init устанавливает пять свойств для сохранения начальных параметров монтирования, заданных для /data с параметрами, переданными из init.rc vold использует эти свойства для настройки криптосопоставления:

    1. ro.crypto.fs_type
    2. ro.crypto.fs_real_blkdev
    3. ro.crypto.fs_mnt_point
    4. ro.crypto.fs_options
    5. ro.crypto.fs_flags (8-значный шестнадцатеричный номер ASCII, которому предшествует 0x)
  3. Запустите фреймворк, чтобы запросить пароль

    Фреймворк запускается и видит, что vold.decrypt установлено значение trigger_restart_min_framework . Это сообщает фреймворку, что он загружается с диска tmpfs /data и ему необходимо получить пароль пользователя.

    Однако сначала необходимо убедиться, что диск был правильно зашифрован. Он отправляет команду cryptfs cryptocomplete на vold . vold возвращает 0, если шифрование было завершено успешно, -1 в случае внутренней ошибки или -2, если шифрование не было успешно завершено. vold определяет это, просматривая в криптографических метаданных флаг CRYPTO_ENCRYPTION_IN_PROGRESS . Если он установлен, процесс шифрования был прерван, и на устройстве нет пригодных для использования данных. Если vold возвращает ошибку, пользовательский интерфейс должен отобразить сообщение для пользователя о перезагрузке и сбросе устройства до заводских настроек, а также дать пользователю кнопку, которую нужно нажать для этого.

  4. Расшифровать данные с помощью пароля

    После cryptfs cryptocomplete платформа отображает пользовательский интерфейс, запрашивающий пароль диска. Пользовательский интерфейс проверяет пароль, отправляя команду cryptfs checkpw на vold . Если пароль правильный (что определяется успешным монтированием расшифрованных /data во временном расположении, а затем их размонтированием), vold сохраняет имя расшифрованного блочного устройства в свойстве ro.crypto.fs_crypto_blkdev и возвращает в пользовательский интерфейс статус 0. . Если пароль неверен, он возвращает -1 в пользовательский интерфейс.

  5. Остановить фреймворк

    Пользовательский интерфейс отображает графическое изображение загрузки криптографии, а затем вызывает vold с помощью команды cryptfs restart . vold устанавливает для свойства vold.decrypt значение trigger_reset_main , что заставляет init.rc выполнять class_reset main . Это останавливает все службы в основном классе, что позволяет размонтировать tmpfs /data .

  6. Смонтировать /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 в первый раз после загрузки.

  7. Запустить полный фреймворк

    Теперь фреймворк загружает все свои службы, используя расшифрованную файловую систему /data , и система готова к использованию.

Отказ

Устройство, которое не может расшифровать, может быть неисправно по нескольким причинам. Устройство запускается с обычной серией шагов для загрузки:

  1. Обнаружить зашифрованное устройство с паролем
  2. Смонтировать tmpfs
  3. Запустите фреймворк, чтобы запросить пароль

Но после открытия фреймворка устройство может столкнуться с некоторыми ошибками:

  • Пароль совпадает, но не может расшифровать данные
  • Пользователь вводит неправильный пароль 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. Затем этот ключ используется для шифрования и дешифрования главного ключа. Чтобы сохранить этот ключ:

  1. Сгенерируйте случайный 16-байтовый ключ шифрования диска (DEK) и 16-байтовую соль.
  2. Примените scrypt к паролю пользователя и соли, чтобы создать 32-байтовый промежуточный ключ 1 (IK1).
  3. Заполните IK1 нулевыми байтами до размера аппаратно-привязанного закрытого ключа (HBK). В частности, мы заполняем как: 00 || ИК1 || 00..00; один нулевой байт, 32 байта IK1, 223 нулевых байта.
  4. Подпишите дополненный IK1 с помощью HBK, чтобы получить 256-байтовый IK2.
  5. Примените scrypt к IK2 и соль (та же соль, что и в шаге 2), чтобы получить 32-байтовый IK3.
  6. Используйте первые 16 байтов IK3 как KEK и последние 16 байтов как IV.
  7. Зашифруйте 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 .

ro.crypto.fs_type
ro.crypto.fs_real_blkdev
ro.crypto.fs_mnt_point
ro.crypto.fs_options
ro.crypto.fs_flags

Эти пять свойств устанавливаются 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