Mã hóa siêu dữ liệu

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

Android 9 đã giới thiệu hỗ trợ mã hóa siêu dữ liệu. Với mã hóa siêu dữ liệu, một khóa duy nhất hiện diện khi khởi động sẽ mã hóa mọi nội dung không được FBE mã hóa. Khóa này được bảo vệ bởi Keymaster, từ đó được bảo vệ bằng quá trình khởi động đã được xác minh.

Mã hóa siêu dữ liệu luôn được bật trên bộ lưu trữ có thể sử dụng bất cứ khi nào FBE được bật. Mã hóa siêu dữ liệu cũng có thể được kích hoạt trên bộ nhớ trong. Các thiết bị chạy Android 11 trở lên phải bật mã hóa 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 mã hóa 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ự init 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

Mã hóa siêu dữ liệu chỉ có thể được thiết lập khi phân vùng dữ liệu được định dạng lần đầu. 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à OTA nên thay đổi.

Mã hóa siêu dữ liệu yêu cầu mô dm-default-key phải được bật trong kernel của bạn. Trong Android 11 trở lên, dm-default-key được hỗ trợ bởi các nhân 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 khung mã hóa độc lập với phần cứng và nhà cung cấp được gọi 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ã hóa nội tuyến (phần cứng mã hóa/giải mã dữ liệu khi dữ liệu đang trên đường đến/từ thiết bị lưu trữ) khi khả dụng. Nếu bạn không sử dụng phần cứng mã hóa nội tuyến, bạn cũng cần phải bật tính năng dự phòng cho API mật mã của kernel:

CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y

Khi không sử dụng phần cứng mã hóa nội tuyến, bạn cũng nên kích hoạt mọi khả năng tăng tốc dựa trên CPU có sẵn như được khuyến nghị trong tài liệu FBE .

Trong Android 10 trở xuống, dm-default-key không được nhân chung của Android hỗ trợ. Do đó, việc triển khai dm-default-key là tùy thuộc vào nhà cung cấp.

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

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

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 nó tại /metadata , bao gồm cả cờ formattable để đảm bảo nó được định dạng khi khởi động. Hệ thống tập tin f2fs không hoạt động trên các phân vùng nhỏ hơn; thay vào đó chúng tôi khuyên bạn nên sử dụng ext4. Ví dụ:

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

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

BOARD_USES_METADATA_PARTITION := true

Thay đổi trình tự init

Khi mã hóa siêu dữ liệu được sử dụng, vold phải chạy trước khi /data được gắn kết. Để đảm bảo rằng nó được bắt đầu đủ sớm, hãy thêm đoạn thơ sau vào 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 kết /data .

init.hardware.rc phải chứa lệnh mount_all tự gắn kết /data trong khổ thơ on late-fs . Trước dòng này, hã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 mã hóa siêu dữ liệu

Cuối cùng, thêm keydirectory=/metadata/vold/metadata_encryption vào cột fs_mgr_flags của mục fstab cho userdata . Ví dụ: một dòng fstab đầy đủ có thể trô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ã hóa siêu dữ liệu trên bộ nhớ trong là AES-256-XTS. Điều này có thể được ghi đè bằng cách đặt tùy chọn metadata_encryption , cũng trong cột fs_mgr_flags :

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

Vì giao diện kernel thành dm-default-key đã thay đổi trong Android 11, nên bạn cũng cần đảm bảo rằng mình đã đặ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 cùng Android 11 (API cấp 30), device.mk phải chứa:

PRODUCT_SHIPPING_API_LEVEL := 30

Bạn cũng có thể đặt 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

Thẩm định

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

Kiểm tra

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

adb root
adb shell dmctl table userdata

Đầu ra phải 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 đè cài đặt mã hóa mặc định bằng cách đặt tùy chọn metadata_encryption trong fstab của thiết bị thì kết quả đầu ra sẽ hơi khác so với ở trên. Ví dụ: nếu bạn đã bật mã hóa Adiantum thì trường thứ ba sẽ là xchacha12,aes-adiantum-plain64 thay vì aes-xts-plain64 .

Tiếp theo, chạy vts_kernel_encryption_test để xác minh tính chính xác của mã hóa 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 đề chung

Trong lệnh gọi mount_all , gắn kết phân vùng /data được mã hóa 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 over binder để thiết lập thiết bị được mã hóa siêu dữ liệu và gắn kết phân vùng. Trong suốt thời gian của cuộc gọi này, init bị chặn và các nỗ lực đọc hoặc đặt thuộc tính init sẽ chặn cho đến khi mount_all kết thúc. Nếu ở giai đoạn này, bất kỳ phần nào của công việc vold bị chặn trực tiếp hoặc gián tiếp trong việc đọc hoặc thiết lập thuộc tính thì sẽ dẫn đến bế tắc. Điều quan trọng là phải đảm bảo rằng vold có thể hoàn thành công việc đọc khóa, 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 hoàn toàn khi mount_all chạy, nó sẽ không phản hồi vold cho đến khi nó đọc một số thuộc tính nhất định từ init , dẫn đến bế tắc chính xác được mô tả. Việc đặt exec_start wait_for_keymaster phía trên lệnh gọi mount_all có liên quan như đã đặt ra sẽ đảm bảo rằng Keymaster chạy hoàn toàn trước và do đó tránh được tình trạng bế tắc này.

Cấu hình trên bộ lưu trữ có thể chấp nhận

Kể từ Android 9, một dạng mã hóa siêu dữ liệu luôn được bật trên bộ nhớ có thể sử dụng bất cứ khi nào FBE được bật, ngay cả khi mã hóa siêu dữ liệu không được bật trên bộ nhớ trong.

Trong AOSP, có hai cách triển khai mã hóa siêu dữ liệu trên bộ lưu trữ có thể sử dụng: một cách không dùng nữa dựa trên dm-crypt và một cách triển khai mới hơn dựa trên dm-default-key . Để đảm bảo chọn cách 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 cùng Android 11 (API cấp 30), 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ã hóa siêu dữ liệu ổ đĩa 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 pháp hiện tại

Trên các thiết bị chạy Android 11 trở lên, mã hóa siêu dữ liệu trên bộ nhớ có thể sử dụng sử dụng mô-đun hạt nhân dm-default-key , giống như trên bộ nhớ trong. Xem các điều kiện tiên quyết ở trên để biết nên kích hoạt tùy chọn cấu hình kernel nào. Lưu ý rằng phần cứng mã hóa nội tuyến hoạt động trên bộ nhớ trong của thiết bị có thể không khả dụng trên bộ nhớ có thể sử dụng và do đó CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y có thể được yêu cầu.

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

Phương pháp kế thừa

Trên các thiết bị chạy Android 10 trở xuống, mã hóa siêu dữ liệu trên bộ lưu trữ có thể sử dụng 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ã hóa hai lần: một lần bằng khóa FBE và một lần bằng khóa mã hóa siêu dữ liệu. Mã hóa kép này làm giảm hiệu suất và không bắt buộc phải đạt được mục tiêu bảo mật của mã hóa siêu dữ liệu vì Android đảm bảo rằng khóa FBE ít nhất cũng khó bị xâm phạm như khóa mã hóa siêu dữ liệu. Các nhà cung cấp có thể thực hiện các tùy chỉnh kernel để tránh mã hóa kép, đặc biệt bằng cách triển khai tùy chọn allow_encrypt_override mà Android sẽ chuyển tới dm-crypt khi thuộc tính hệ thống ro.crypto.allow_encrypt_override được đặt thành true . Những tùy chỉnh này không được hạt nhân phổ biến của Android hỗ trợ.

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

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