Mã hoá siêu dữ liệu

Hỗ trợ Android 7.0 trở lên mã hoá dựa trên tệp (FBE). FBE cho phép mã hoá các tệp khác nhau bằng các khoá khác nhau mà có thể mở khoá một cách độc lập. Các khoá này được dùng để mã hoá cả nội dung tệp và tên tệp. Khi sử dụng FBE, các thông tin khác như bố cục thư mục, kích thước tệp, quyền truy cập và thời gian tạo/sửa đổi thì không được mã hoá. Nhìn chung, các thông tin khác này được gọi là siêu dữ liệu hệ thống tệp.

Android 9 đã hỗ trợ tính năng mã hoá siêu dữ liệu. Với tính năng mã hoá siêu dữ liệu, một khoá duy nhất xuất hiện tại thời điểm khởi động sẽ mã hoá mọi nội dung không được FBE mã hoá. Khoá này được bảo vệ bởi Keymaster, được bảo vệ bằng quy trình khởi động xác minh.

Tính năng mã hoá siêu dữ liệu luôn được bật trên bộ nhớ có thể chuyển đổi bất cứ khi nào bạn bật FBE. Bạn cũng có thể bật tính năng mã hoá siêu dữ liệu trên bộ nhớ trong. Các thiết bị chạy Android 11 trở lên phải bật tính năng mã hoá siêu dữ liệu trên bộ nhớ trong.

Triển khai trên bộ nhớ trong

Bạn có thể thiết lập lớp mã hoá siêu dữ liệu trên bộ nhớ trong của thiết bị mới bằng cách thiết lập hệ thống tệp metadata, thay đổi trình tự khởi tạo và bật mã hóa siêu dữ liệu trong tệp fstab của thiết bị.

Điều kiện tiên quyết

Bạn chỉ có thể thiết lập phương thức mã hoá siêu dữ liệu khi phân vùng dữ liệu được thiết lập trước đã định dạng. Do đó, tính năng này chỉ dành cho thiết bị mới; đây không phải là điều mà bản cập nhật qua mạng không dây (OTA) nên thay đổi.

Tính năng mã hoá siêu dữ liệu yêu cầu bạn phải bật mô-đun dm-default-key trong hạt nhân. Trong Android 11 trở lên, dm-default-key được hỗ trợ bởi các nhân hệ điều hành phổ biến của Android, phiên bản 4.14 trở lên. Phiên bản dm-default-key này sử dụng phần cứng và khung mã hoá độc lập với nhà cung cấp có tên là blk-Crypto.

Để bật dm-default-key, hãy sử dụng:

CONFIG_BLK_INLINE_ENCRYPTION=y
CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y
CONFIG_DM_DEFAULT_KEY=y

dm-default-key sử dụng phần cứng mã hoá nội tuyến (phần cứng mã hoá/giải mã dữ liệu trong khi dữ liệu đang trên đường đến/từ thiết bị lưu trữ) khi có. Nếu bạn không sử dụng phần cứng mã hoá cùng dòng, thì cũng cần bật tính năng dự phòng cho API mã hoá của nhân:

CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y

Khi không sử dụng phần cứng mã hoá nội tuyến, bạn cũng nên bật mọi tính năng tăng tốc dựa trên CPU có sẵn như được đề xuất trong tài liệu về FBE.

Trong Android 10 trở xuống, nhân chung của Android không hỗ trợ dm-default-key. Vì vậy, nhà cung cấp có trách nhiệm để triển khai dm-default-key.

Thiết lập hệ thống tệp siêu dữ liệu

Vì không thể đọc nội dung nào trong phân vùng dữ liệu người dùng cho đến khi có khoá mã hoá siêu dữ liệu, nên bảng phân vùng phải dành riêng một phân vùng có tên là "phân vùng siêu dữ liệu" để lưu trữ các blob keymaster bảo vệ khoá này. Phân vùng siêu dữ liệu phải có dung lượng 16 MB.

fstab.hardware phải bao gồm một mục nhập cho hệ thống tệp siêu dữ liệu nằm trên phân vùng đó, gắn kết nó tại /metadata, bao gồm cờ formattable để đảm bảo mã được định dạng vào thời điểm khởi động. Chiến lược phát hành đĩa đơn Hệ thống tệp f2fs không hoạt động trên các phân vùng nhỏ hơn; bạn nên dùng ext4 thay thế. Ví dụ:

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

Để đảm bảo điểm gắn /metadata tồn tại, hãy thêm dòng sau vào BoardConfig-common.mk:

BOARD_USES_METADATA_PARTITION := true

Các thay đổi đối với trình tự khởi tạo

Khi sử dụng tính năng mã hoá siêu dữ liệu, vold phải đang chạy trước khi /data được gắn. Để đảm bảo sự kiện bắt đầu đủ sớm, hãy thêm đoạn thơ sau cho init.hardware.rc:

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

Keymaster phải đang chạy và sẵn sàng trước khi init cố gắng gắn /data.

init.hardware.rc phải chứa một lệnh mount_all để tự gắn /data trong khổ on late-fs. Trước dòng này, thêm lệnh để thực thi Dịch vụ 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

Bật tính năng mã hoá siêu dữ liệu

Cuối cùng, hãy thêm keydirectory=/metadata/vold/metadata_encryption vào Cột fs_mgr_flags của mục nhập fstab cho userdata. Ví dụ: dòng fstab đầy đủ có thể có dạng như sau:

/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

Theo mặc định, thuật toán mã hoá siêu dữ liệu trên bộ nhớ trong là AES-256-XTS. Bạn có thể ghi đè lựa chọn này bằng cách đặt giá trị metadata_encryption, cũng trong Cột fs_mgr_flags:

  • Trên các thiết bị không có tính năng tăng tốc AES, bạn có thể bật tính năng mã hoá Adiantum bằng cách đặt metadata_encryption=adiantum.
  • Trên các thiết bị hỗ trợ khoá được gói bằng phần cứng, bạn có thể tạo khoá mã hoá siêu dữ liệu được gói bằng phần cứng bằng cách thiết lập metadata_encryption=aes-256-xts:wrappedkey_v0 (hoặc tương đương với metadata_encryption=:wrappedkey_v0, vì aes-256-xts là thuật toán mặc định).

Do giao diện kernel thành dm-default-key đã thay đổi trong Android 11, bạn cũng cần đảm bảo rằng bạn đã đặt giá trị chính xác cho PRODUCT_SHIPPING_API_LEVEL trong device.mk. Ví dụ: nếu thiết bị của bạn chạy cùng với Android 11 (API cấp 30), device.mk phải chứa:

PRODUCT_SHIPPING_API_LEVEL := 30

Bạn cũng có thể thiết lập thuộc tính hệ thống sau để buộc sử dụng API dm-default-key mới bất kể cấp độ API vận chuyển:

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

Xác nhận kết quả

Để xác minh rằng tính năng mã hoá siêu dữ liệu đã được bật và hoạt động chính xác, các thử nghiệm được mô tả bên dưới. Ngoài ra, hãy lưu ý đến thông tin chung như mô tả dưới đây.

Kiểm thử

Bắt đầu bằng cách chạy lệnh sau để xác minh rằng mã hoá siêu dữ liệu đã bật trên bộ nhớ trong:

adb root
adb shell dmctl table userdata

Nội dung xuất sẽ tương tự như:

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

Nếu bạn ghi đè chế độ cài đặt mã hoá mặc định bằng cách đặt tuỳ chọn metadata_encryption trong fstab của thiết bị, thì kết quả sẽ hơi khác so với kết quả ở trên. Ví dụ: nếu bạn bật mã hóa Adiantum, thì trường là xchacha12,aes-adiantum-plain64 thay vì aes-xts-plain64.

Tiếp theo, hãy chạy vts_kernel_encryption_test để xác minh tính chính xác của quá trình mã hoá siêu dữ liệu và FBE:

atest vts_kernel_encryption_test

hoặc:

vts-tradefed run vts -m vts_kernel_encryption_test

Các vấn đề thường gặp

Trong lệnh gọi đến mount_all (lệnh gọi này sẽ gắn phân vùng /data được mã hoá siêu dữ liệu), init sẽ thực thi công cụ vdc. Công cụ vdc kết nối với vold qua binder để thiết lập thiết bị được mã hoá siêu dữ liệu và gắn phân vùng. Trong thời gian của lệnh gọi này, init bị chặn và cố gắng đọc hoặc đặt khối thuộc tính init cho đến khi mount_all kết thúc. Nếu tại giai đoạn này, bất kỳ phần nào của công việc của vold bị chặn trực tiếp hoặc gián tiếp khi đọc hoặc đặt thuộc tính, thì kết quả sẽ là tắc nghẽn. Điều quan trọng là phải đảm bảo rằng vold có thể hoàn tất việc đọc các khoá, tương tác với Keymaster và gắn thư mục dữ liệu mà không cần tương tác thêm với init.

Nếu Keymaster không được khởi động đầy đủ khi mount_all chạy, thì Keymaster sẽ không phản hồi vold cho đến khi đọc một số thuộc tính nhất định từ init, dẫn đến tình trạng tắc nghẽn như mô tả. Đặt hàng exec_start wait_for_keymaster trên mức có liên quan Lệnh gọi mount_all như đã đề ra đảm bảo rằng Keymaster hoàn toàn chạy trước nên tránh được tình trạng tắc nghẽn này.

Cấu hình trên bộ nhớ thích ứng

Kể từ Android 9, một hình thức mã hoá siêu dữ liệu luôn được bật trên bộ nhớ có thể chuyển đổi bất cứ khi nào FBE được bật, ngay cả khi bạn không bật tính năng mã hoá siêu dữ liệu trên bộ nhớ trong.

Trong AOSP, có hai cách triển khai mã hoá siêu dữ liệu trên bộ nhớ: một bộ nhớ không dùng nữa dựa trên dm-crypt và một bộ nhớ mới hơn dựa trên vào ngày dm-default-key. Để đảm bảo rằng triển khai chính xác cho thiết bị của bạn, hãy đảm bảo rằng bạn đã đặt giá trị chính xác cho PRODUCT_SHIPPING_API_LEVEL trong device.mk. Ví dụ: nếu thiết bị của bạn khởi chạy bằng Android 11 (API cấp 30), thì device.mk phải chứa:

PRODUCT_SHIPPING_API_LEVEL := 30

Bạn cũng có thể đặt các thuộc tính hệ thống sau để buộc sử dụng phương thức mã hoá siêu dữ liệu phương tiện mới (và phiên bản chính sách FBE mặc định mới) bất kể cấp độ API vận chuyển:

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

Phương thức hiện tại

Trên các thiết bị chạy Android 11 trở lên, việc mã hoá siêu dữ liệu trên bộ nhớ có thể sử dụng sử dụng dm-default-key nhân, giống như trên bộ nhớ trong. Hãy xem các điều kiện tiên quyết ở trên để biết các tuỳ chọn cấu hình hạt nhân cần bật. Xin lưu ý rằng phần cứng mã hoá cùng dòng hoạt động trên bộ nhớ trong của thiết bị có thể không có trên bộ nhớ có thể chuyển đổi, do đó, bạn có thể cần CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y.

Theo mặc định, phương thức mã hoá siêu dữ liệu ổ đĩa dm-default-key sử dụng thuật toán mã hóa AES-256-XTS với các lĩnh vực mật mã 4096 byte. Bạn có thể ghi đè thuật toán bằng cách đặt thuộc tính hệ thống ro.crypto.volume.metadata.encryption. Chiến dịch này giá trị của thuộc tính có cú pháp giống như metadata_encryption fstab được mô tả ở trên. Ví dụ: trên các thiết bị không có AES tăng tốc, mã hoá Adiantum có thể được bật bằng cách cài đặt ro.crypto.volume.metadata.encryption=adiantum.

Phương thức cũ

Trên các thiết bị chạy Android 10 trở xuống, tính năng mã hoá siêu dữ liệu trên bộ nhớ có thể chuyển đổi sẽ sử dụng mô-đun hạt nhân dm-crypt thay vì dm-default-key:

CONFIG_DM_CRYPT=y

Không giống như phương thức dm-default-key, phương thức dm-crypt khiến nội dung tệp được mã hoá hai lần: một lần bằng khoá FBE và một lần bằng khoá khoá mã hoá siêu dữ liệu. Phương thức mã hoá kép này làm giảm hiệu suất và không bắt buộc phải đạt được các mục tiêu bảo mật của việc mã hoá siêu dữ liệu, vì Android đảm bảo rằng các khoá FBE ít nhất cũng khó bị xâm phạm như khoá mã hoá siêu dữ liệu. Nhà cung cấp có thể tuỳ chỉnh hạt nhân để tránh việc mã hoá gấp đôi, cụ thể là bằng cách triển khai tuỳ chọn allow_encrypt_override mà Android chuyển đến dm-crypt khi thuộc tính hệ thống ro.crypto.allow_encrypt_override được đặt thành true. Hạt nhân chung của Android không hỗ trợ các tuỳ chỉnh này.

Theo mặc định, phương thức mã hoá siêu dữ liệu ổ đĩa dm-crypt sử dụng Thuật toán mã hóa AES-128-CBC với các lĩnh vực tiền mã hóa 512 byte và ESSIV. Chiến dịch này có thể bị ghi đè bằng cách đặt các thuộc tính hệ thống sau (cũng nằm được sử dụng cho FDE):

  • ro.crypto.fde_algorithm chọn phương thức mã hoá siêu dữ liệu thuật toán. Các lựa chọn là aes-128-cbcadiantum. Bạn chỉ có thể sử dụng Adiantum nếu thiết bị không có tính năng tăng tốc AES.
  • ro.crypto.fde_sector_size chọn kích thước của ngành tiền mã hoá. Các lựa chọn là 512, 1024, 2048 và 4096. Đối với phương thức mã hoá Adiantum, hãy sử dụng 4096.