Szyfrowanie metadanych

Android 7.0 i nowsze wersje obsługują szyfrowanie oparte na plikach (FBE). FBE umożliwia szyfrowanie różnych plików za pomocą różnych kluczy, które można odblokowywać niezależnie. Te klucze służą do szyfrowania zarówno zawartości plików, jak i ich nazw. Gdy używane jest FBE, inne informacje, takie jak układy katalogów, rozmiary plików, uprawnienia oraz czasy utworzenia i modyfikacji, nie są szyfrowane. Te inne informacje są zbiorczo nazywane metadanymi systemu plików.

Android 9 wprowadził obsługę szyfrowania metadanych. W przypadku szyfrowania metadanych pojedynczy klucz obecny w momencie uruchomienia szyfruje wszystkie treści, które nie są szyfrowane przez FBE. Ten klucz jest chroniony przez KeyMint (wcześniej Keymaster), który z kolei jest chroniony przez weryfikację podczas uruchamiania.

Szyfrowanie metadanych jest zawsze włączone w przypadku pamięci dostosowywanej, gdy włączone jest FBE. Szyfrowanie metadanych można też włączyć w pamięci wewnętrznej. Urządzenia, które zostały wprowadzone na rynek z Androidem 11 lub nowszym, muszą mieć włączone szyfrowanie metadanych w pamięci wewnętrznej.

Implementacja w pamięci wewnętrznej

Szyfrowanie metadanych w pamięci wewnętrznej nowych urządzeń możesz skonfigurować, konfigurując system plików metadata, zmieniając sekwencję init i włączając szyfrowanie metadanych w pliku fstab urządzenia.

Wymagania wstępne

Szyfrowanie metadanych można skonfigurować tylko wtedy, gdy partycja danych jest formatowana po raz pierwszy. Dlatego ta funkcja jest przeznaczona tylko dla nowych urządzeń. Nie jest to coś, co powinna zmienić aktualizacja OTA.

Szyfrowanie metadanych wymaga, aby w jądrze był włączony moduł dm-default-key. W Androidzie 11 i nowszych wersjach dm-default-key jest obsługiwany przez wspólne jądra Androida w wersji 4.14 i nowszych. Ta wersja dm-default-key używa niezależnej od sprzętu i dostawcy platformy szyfrowania o nazwie blk-crypto.

Aby włączyć dm-default-key, użyj:

CONFIG_BLK_INLINE_ENCRYPTION=y
CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y
CONFIG_DM_DEFAULT_KEY=y

Gdy jest dostępny, dm-default-key używa sprzętu do szyfrowania wbudowanego (sprzętu, który szyfruje i odszyfrowuje dane podczas ich przesyłania do i z urządzenia pamięci masowej). Jeśli nie używasz sprzętu do szyfrowania wbudowanego, musisz też włączyć rezerwowy interfejs API kryptografii jądra:

CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y

Jeśli nie używasz sprzętu do szyfrowania wbudowanego, włącz też dowolną dostępną akcelerację opartą na procesorze, zgodnie z zaleceniami w dokumentacji FBE.

W Androidzie 10 i starszych wersjach dm-default-key nie był obsługiwany przez wspólne jądro Androida. Dlatego to dostawcy musieli implementować dm-default-key.

Konfigurowanie systemu plików metadanych

Ponieważ niczego nie można odczytać z partycji userdata, dopóki nie będzie dostępny klucz szyfrowania metadanych, w tabeli partycji trzeba wydzielić osobną partycję o nazwie partycja metadanych do przechowywania obiektów blob KeyMint, które chronią ten klucz. Partycja metadanych powinna mieć rozmiar 16 MB.

fstab.hardware musi zawierać wpis dotyczący systemu plików metadanych, który znajduje się na tej partycji, i montować go w /metadata, w tym flagę formattable, aby zapewnić jego formatowanie podczas uruchamiania. System plików f2fs nie działa na mniejszych partycjach. Zalecamy używanie zamiast niego systemu ext4. Przykład:

/dev/block/bootdevice/by-name/metadata              /metadata          ext4        noatime,nosuid,nodev,discard                          wait,check,formattable

Aby upewnić się, że punkt podłączania /metadata istnieje, dodaj ten wiersz do BoardConfig-common.mk:

BOARD_USES_METADATA_PARTITION := true

Zmiany w sekwencji init

Gdy używane jest szyfrowanie metadanych, vold musi być uruchomiony przed zamontowaniem /data. Aby upewnić się, że jest on uruchamiany wystarczająco wcześnie, dodaj ten blok do init.hardware.rc:

# We need vold early for metadata encryption
on early-fs
    start vold

Przed próbą zamontowania /data przez init KeyMint musi być uruchomiony i gotowy.

init.hardware.rc powinien już zawierać instrukcję mount_all , która montuje /data samą w bloku on late-fs. Przed tym wierszem dodaj dyrektywę do wykonania usługi wait_for_keymaster:

on late-fs
    
    # Wait for Keymaster
    exec_start wait_for_keymaster

    # Mount RW partitions which need run fsck
    mount_all /vendor/etc/fstab.${ro.boot.hardware.platform} --late

Włączanie szyfrowania metadanych

Na koniec dodaj keydirectory=/metadata/vold/metadata_encryption do kolumny fs_mgr_flags we wpisie fstab dla userdata. Na przykład pełny wiersz fstab może wyglądać tak:

/dev/block/bootdevice/by-name/userdata              /data              f2fs        noatime,nosuid,nodev,discard,inlinecrypt latemount,wait,check,fileencryption=aes-256-xts:aes-256-cts:inlinecrypt_optimized,keydirectory=/metadata/vold/metadata_encryption,quota,formattable

Domyślnie algorytmem szyfrowania metadanych w pamięci wewnętrznej jest AES-256-XTS. Można to zmienić, ustawiając opcję metadata_encryption, również w kolumnie fs_mgr_flags:

  • Na urządzeniach, które nie mają akceleracji AES, szyfrowanie Adiantum można włączyć, ustawiając metadata_encryption=adiantum.
  • Na urządzeniach, które obsługują klucze szyfrowania wbudowanego zawinięte w sprzęt, klucz szyfrowania metadanych można zawinąć w sprzęt, ustawiając metadata_encryption=aes-256-xts:wrappedkey lub metadata_encryption=aes-256-xts:wrappedkey_v0. wrappedkey to nowoczesna wersja. wrappedkey_v0 należy używać tylko na urządzeniach, które nie obsługują wrappedkey lub zostały już wprowadzone na rynek z wrappedkey_v0. Więcej informacji znajdziesz w artykule Włączanie kluczy zawiniętych.

    W obu przypadkach aes-256-xts można pominąć, ponieważ jest to algorytm domyślny. Na przykład, metadata_encryption=:wrappedkey jest równoważne z metadata_encryption=aes-256-xts:wrappedkey.

Ponieważ interfejs jądra do dm-default-key zmienił się w Androidzie 11, musisz też upewnić się, że w device.mk masz ustawioną prawidłową wartość PRODUCT_SHIPPING_API_LEVEL. Jeśli na przykład Twoje urządzenie zostało wprowadzone na rynek z Androidem 11 (poziom API 30), device.mk powinien zawierać:

PRODUCT_SHIPPING_API_LEVEL := 30

Możesz też ustawić tę właściwość systemu, aby wymusić użycie nowego interfejsu API dm-default-key niezależnie od poziomu API dostawy:

PRODUCT_PROPERTY_OVERRIDES += \
    ro.crypto.dm_default_key.options_format.version=2

Weryfikacja

Aby sprawdzić, czy szyfrowanie metadanych jest włączone i działa prawidłowo, uruchom testy opisane poniżej. Pamiętaj też o typowych problemach opisanych poniżej.

Testy

Zacznij od uruchomienia tego polecenia, aby sprawdzić, czy szyfrowanie metadanych jest włączone w pamięci wewnętrznej:

adb root
adb shell dmctl table userdata

Dane wyjściowe powinny być podobne do tych:

Targets in the device-mapper table for userdata:
0-4194304: default-key, aes-xts-plain64 - 0 252:2 0 3 allow_discards sector_size:4096 iv_large_sectors

Jeśli zastąpisz domyślne ustawienia szyfrowania, ustawiając opcję metadata_encryption w pliku fstab urządzenia, dane wyjściowe będą się nieco różnić od powyższych. Jeśli na przykład włączysz szyfrowanie Adiantum, trzecie pole będzie miało wartość xchacha12,aes-adiantum-plain64 zamiast aes-xts-plain64.

Następnie uruchom vts_kernel_encryption_test aby sprawdzić poprawność szyfrowania metadanych i FBE:

atest vts_kernel_encryption_test

lub:

vts-tradefed run vts -m vts_kernel_encryption_test

Typowe problemy

Podczas wywołania mount_all, które montuje zaszyfrowaną metadanymi partycję /data, init wykonuje narzędzie vdc. Narzędzie vdc łączy się z vold przez binder, aby skonfigurować urządzenie zaszyfrowane metadanymi i zamontować partycję. Podczas tego wywołania init jest zablokowany, a próby odczytania lub ustawienia właściwości init są blokowane do momentu zakończenia mount_all. Jeśli na tym etapie jakakolwiek część pracy vold jest bezpośrednio lub pośrednio blokowana przez odczytywanie lub ustawianie właściwości, dochodzi do zakleszczenia. Ważne jest, aby vold mógł zakończyć odczytywanie kluczy, interakcję z KeyMint i montowanie katalogu danych bez dalszej interakcji z init.

Jeśli KeyMint nie jest w pełni uruchomiony, gdy działa mount_all, nie odpowiada na vold, dopóki nie odczyta określonych właściwości z init, co powoduje opisane zakleszczenie. Umieszczenie exec_start wait_for_keymaster nad odpowiednim wywołaniem mount_all zgodnie z instrukcjami zapewnia, że KeyMint jest w pełni uruchomiony z wyprzedzeniem, co pozwala uniknąć tego zakleszczenia.

Konfiguracja w pamięci dostosowywanej

Od Androida 9 forma szyfrowania metadanych jest zawsze włączona w przypadku pamięci adaptacyjnej, gdy włączone jest FBE, nawet jeśli szyfrowanie metadanych nie jest włączone w pamięci wewnętrznej.

W AOSP są 2 implementacje szyfrowania metadanych w pamięci adaptacyjnej: przestarzała oparta na dm-crypt i nowsza oparta na dm-default-key. Aby upewnić się, że dla Twojego urządzenia jest wybrana prawidłowa implementacja, sprawdź, czy w device.mk masz ustawioną prawidłową wartość PRODUCT_SHIPPING_API_LEVEL. Jeśli na przykład Twoje urządzenie zostało wprowadzone na rynek z Androidem 11 (poziom API 30), device.mk powinien zawierać:

PRODUCT_SHIPPING_API_LEVEL := 30

Możesz też ustawić te właściwości systemu, aby wymusić użycie nowej metody szyfrowania metadanych woluminu (i nowej domyślnej wersji zasad FBE) niezależnie od poziomu API dostawy:

PRODUCT_PROPERTY_OVERRIDES += \
    ro.crypto.volume.metadata.method=dm-default-key \
    ro.crypto.dm_default_key.options_format.version=2 \
    ro.crypto.volume.options=::v2

Obecna metoda

Na urządzeniach wprowadzonych na rynek z Androidem 11 lub nowszym szyfrowanie metadanych w pamięci dostosowywanej używa modułu jądra dm-default-key, tak jak w pamięci wewnętrznej. Wymagania wstępne dotyczące tego, które opcje konfiguracji jądra należy włączyć, znajdziesz powyżej. Pamiętaj, że sprzęt do szyfrowania wbudowanego, który działa w pamięci wewnętrznej urządzenia, może być niedostępny w pamięci adaptacyjnej, dlatego może być wymagane ustawienie CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y.

Domyślnie metoda szyfrowania metadanych woluminu dm-default-key używa algorytmu szyfrowania AES-256-XTS z 4096-bajtowymi sektorami kryptograficznymi. Algorytm można zastąpić, ustawiając właściwość systemu ro.crypto.volume.metadata.encryption. Wartość tej właściwości ma taką samą składnię jak opisana powyżej opcja metadata_encryption fstab. Na przykład na urządzeniach, które nie mają akceleracji AES , szyfrowanie Adiantum można włączyć, ustawiając ro.crypto.volume.metadata.encryption=adiantum.

Starsza metoda

Na urządzeniach wprowadzonych na rynek z Androidem 10 i starszymi wersjami szyfrowanie metadanych w pamięci dostosowywanej używa modułu jądra dm-crypt zamiast dm-default-key:

CONFIG_DM_CRYPT=y

W przeciwieństwie do metody dm-default-key metoda dm-crypt powoduje dwukrotne szyfrowanie zawartości plików: raz za pomocą klucza FBE i raz za pomocą klucza szyfrowania metadanych. To podwójne szyfrowanie zmniejsza wydajność i nie jest wymagane do osiągnięcia celów bezpieczeństwa szyfrowania metadanych, ponieważ Android zapewnia, że klucze FBE są co najmniej tak samo trudne do złamania jak klucz szyfrowania metadanych. Dostawcy mogą dostosować jądro, aby uniknąć podwójnego szyfrowania, w szczególności przez zaimplementowanie opcji allow_encrypt_override którą Android przekazuje do dm-crypt gdy właściwość systemu ro.crypto.allow_encrypt_override jest ustawiona na true. Te dostosowania nie są obsługiwane przez wspólne jądro Androida.

Domyślnie metoda szyfrowania metadanych woluminu dm-crypt używa algorytmu szyfrowania AES-128-CBC z ESSIV i 512-bajtowymi sektorami kryptograficznymi. Można to zmienić, ustawiając te właściwości systemu (które są też używane w przypadku FDE):

  • ro.crypto.fde_algorithm wybiera algorytm szyfrowania metadanych. Dostępne opcje to aes-128-cbc i adiantum. Adiantum można używać tylko wtedy, gdy urządzenie nie ma akceleracji AES.
  • ro.crypto.fde_sector_size wybiera rozmiar sektora kryptograficznego. Dostępne opcje to 512, 1024, 2048 i 4096. W przypadku szyfrowania Adiantum użyj 4096.