Android 7.0 trở lên hỗ trợ tính năng 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 có thể được mở khoá độ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 FBE được 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ã 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 có mặt 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 KeyMint (trước đây là Keymaster) bảo vệ, và KeyMint được Xác minh quy trình khởi động bảo vệ.
Tính năng mã hoá siêu dữ liệu luôn được bật trên bộ nhớ thích ứng bất cứ khi nào FBE được bật. 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ị ra mắt bằng 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 tính năng mã hoá siêu dữ liệu trên bộ nhớ trong của các 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 động và bật tính năng mã hoá 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 tính năng mã hoá siêu dữ liệu 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 các thiết bị mới; đây không phải là tính năng mà bản cập nhật qua mạng (OTA) nên thay đổi.
Tính năng mã hoá siêu dữ liệu yêu cầu bật mô-đun dm-default-key trong kernel. Trong Android 11 trở lên, dm-default-key được các kernel chung của Android hỗ trợ (phiên bản 4.14 trở lên). Phiên bản dm-default-key này sử dụng một khung mã hoá độc lập với phần cứng và 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ó sẵn. Nếu không sử dụng phần cứng mã hoá nội tuyến, bạn cũng cần 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ã 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 FBE.
Trong Android 10 trở xuống, kernel chung của Android không hỗ trợ dm-default-key. Do đó, các nhà cung cấp phải triển khai dm-default-key.
Thiết lập hệ thống tệp siêu dữ liệu
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ó 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 riêng biệt có tên là phân vùng siêu dữ liệu để lưu trữ các blob KeyMint bảo vệ khoá này. Phân vùng siêu dữ liệu phải có kích thước 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 phân vùng đó tại /metadata, bao gồm cả cờ formattable để đảm bảo phân vùng đó được định dạng tại thời điểm khởi động. 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 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 đối với trình tự khởi động
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 kết. Để đảm bảo rằng tính năng này được khởi động đủ sớm, hãy thêm khổ thơ sau vào init.hardware.rc:
# We need vold early for metadata encryption
on early-fs
start vold
KeyMint phải đang chạy và sẵn sàng trước khi quá trình khởi động cố gắng gắn kết /data.
init.hardware.rc phải đã chứa một mount_all
lệnh gắn kết chính /data trong khổ thơ on
late-fs. Trước dòng này, hãy thêm chỉ thị để 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ụ: 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ã hoá siêu dữ liệu trên bộ nhớ trong là AES-256-XTS. Bạn có thể ghi đè thuật toán này bằng cách đặt tuỳ chọn metadata_encryption, cũng trong cột fs_mgr_flags:
- Trên các thiết bị thiếu tính năng tăng tốc AES, tính năng mã hoá Adiantum có thể được
bật bằng cách đặt
metadata_encryption=adiantum. Trên các thiết bị hỗ trợ khoá mã hoá nội tuyến đượ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 đặt
metadata_encryption=aes-256-xts:wrappedkeyhoặcmetadata_encryption=aes-256-xts:wrappedkey_v0.wrappedkeylà phiên bản hiện đại; bạn chỉ nên sử dụngwrappedkey_v0nên chỉ được sử dụng trên các thiết bị không hỗ trợwrappedkeyhoặc đã ra mắt bằngwrappedkey_v0. Để biết thêm thông tin, xem Bật khoá được gói.Trong cả hai trường hợp,
aes-256-xtscó thể bỏ qua vì đây là thuật toán mặc định. Ví dụ:metadata_encryption=:wrappedkeytương đương vớimetadata_encryption=aes-256-xts:wrappedkey.
Vì giao diện kernel với dm-default-key đã thay đổi trong Android 11, nên bạn cũng cần đảm bảo rằng bạn đã đặt đúng giá trị cho PRODUCT_SHIPPING_API_LEVEL trong device.mk. Ví dụ: nếu thiết bị của bạn ra mắt bằng Android 11 (cấp độ API 30), thì 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
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à đang hoạt động đúng cách, hãy chạy các bài kiểm thử được mô tả bên dưới. Ngoài ra, hãy lưu ý đến các vấn đề thường gặp được mô tả bên dưới.
Xét nghiệm
Bắt đầu bằng cách chạy lệnh sau để xác minh rằng tính năng mã hoá siêu dữ liệu đã được bật trên bộ nhớ trong:
adb rootadb 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ì nội dung xuất sẽ hơi khác so với nội dung trên. Ví dụ: nếu bạn bật tính năng mã hoá Adiantum, thì trường thứ ba
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 tính năng 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 quá trình gọi mount_all (gắn kết 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 kết phân vùng. Trong thời gian gọi này, init bị chặn và các nỗ lực đọc hoặc đặt các thuộc tính init sẽ bị chặn cho đến khi mount_all hoàn tất.
Nếu ở giai đoạn này, bất kỳ phần nào trong 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 một thuộc tính, thì sẽ xảy ra tình trạng bế tắc. Bạn phải đảm bảo rằng vold có thể hoàn tất công việc đọc các khoá, tương tác với KeyMint và gắn kết thư mục dữ liệu mà không cần tương tác thêm với init.
Nếu KeyMint chưa khởi động hoàn toàn khi mount_all chạy, thì KeyMint 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 chính xác tình trạng bế tắc được mô tả. Việc đặt exec_start wait_for_keymaster phía trên lời gọi mount_all có liên quan như đã nêu sẽ đảm bảo rằng KeyMint đang chạy hoàn toàn trước và do đó 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ớ thích ứng bất cứ khi nào FBE được bật, ngay cả khi tính năng mã hoá siêu dữ liệu không được bật trên bộ nhớ trong.
Trong AOSP, có 2 cách triển khai tính năng mã hoá siêu dữ liệu trên bộ nhớ thích ứng: một cách đã ngừng hoạt động dựa trên dm-crypt và một cách mới hơn dựa trên dm-default-key. Để đảm bảo rằng cách triển khai chính xác được chọn cho thiết bị của bạn, hãy đảm bảo rằng bạn đã đặt đúng giá trị cho PRODUCT_SHIPPING_API_LEVEL trong device.mk. Ví dụ: nếu thiết bị của bạn ra mắt bằng Android 11 (cấp độ API 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 ổ đĩ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 thức hiện tại
Trên các thiết bị ra mắt bằng Android 11 trở lên, tính năng mã hoá siêu dữ liệu trên bộ nhớ thích ứng sử dụng mô-đun kernel dm-default-key, 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 kernel
cần bật. Xin lưu ý rằng phần cứng mã hoá nội tuyến hoạt động trên bộ nhớ trong của thiết bị có thể không có trên bộ nhớ thích ứng và 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ã hoá AES-256-XTS với các thành phần mật mã 4096 byte. Bạn có thể ghi đè thuật toán này 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ùng cú pháp với tuỳ chọn fstab metadata_encryption được mô tả ở trên. Ví dụ: trên các thiết bị thiếu 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
ro.crypto.volume.metadata.encryption=adiantum.
Phương thức cũ
Trên các thiết bị ra mắt bằng Android 10 trở xuống, tính năng mã hoá siêu dữ liệu trên bộ nhớ thích ứng sử dụng mô-đun kernel 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á 2 lần: một lần bằng khoá FBE và một lần bằng khoá mã hoá siêu dữ liệu. Việc mã hoá 2 lần này làm giảm hiệu suất và không cần thiết để đạt được các mục tiêu bảo mật của tính năng 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. Các nhà cung cấp có thể tuỳ chỉnh kernel để tránh việc mã hoá 2 lần, đặc biệt 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.
Kernel 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ã hoá AES-128-CBC với ESSIV và các thành phần mật mã 512 byte. Bạn có thể ghi đè thuật toán này bằng cách đặt các thuộc tính hệ thống sau (cũng được dùng cho FDE):
ro.crypto.fde_algorithmchọn thuật toán mã hoá siêu dữ liệu. Các lựa chọn làaes-128-cbcvàadiantum. Bạn chỉ có thể sử dụng Adiantum nếu thiết bị thiếu tính năng tăng tốc AES.ro.crypto.fde_sector_sizechọn kích thước thành phần mật mã. Các lựa chọn là 512, 1024, 2048 và 4096. Đối với tính năng mã hoá Adiantum, hãy sử dụng 4096.