Google cam kết thúc đẩy công bằng chủng tộc cho Cộng đồng người da đen. Xem cách thực hiện.

Các phím được bọc phần cứng

Giống như hầu hết các phần mềm mã hóa ổ đĩa và tệp, mã hóa lưu trữ của Android theo truyền thống dựa vào các khóa mã hóa thô có trong bộ nhớ hệ thống để có thể thực hiện mã hóa. Ngay cả khi mã hóa được thực hiện bởi phần cứng chuyên dụng thay vì phần mềm, phần mềm nói chung vẫn cần quản lý các khóa mã hóa thô.

Theo truyền thống, điều này không được coi là một vấn đề vì các khóa sẽ không xuất hiện trong một cuộc tấn công ngoại tuyến, đây là kiểu tấn công chính mà mã hóa lưu trữ nhằm bảo vệ chống lại. Tuy nhiên, có mong muốn cung cấp khả năng bảo vệ tăng cường chống lại các kiểu tấn công khác, chẳng hạn như tấn công khởi động nguội và tấn công trực tuyến, trong đó kẻ tấn công có thể làm rò rỉ bộ nhớ hệ thống mà không ảnh hưởng hoàn toàn đến thiết bị.

Để giải quyết vấn đề này, Android 11 đã giới thiệu hỗ trợ cho phím bọc phần cứng , nơi có hỗ trợ phần cứng. Khóa bọc phần cứng là khóa lưu trữ chỉ được biết ở dạng thô đối với phần cứng chuyên dụng; phần mềm chỉ nhìn thấy và hoạt động với các khóa này ở dạng được mã hóa (được mã hóa). Phần cứng này phải có khả năng tạo và nhập khóa lưu trữ, gói khóa lưu trữ ở dạng tạm thời và dài hạn, tạo khóa con, lập trình trực tiếp một khóa con vào công cụ mã hóa nội tuyến và trả lại khóa con riêng biệt cho phần mềm.

Lưu ý : Công cụ mã hóa nội tuyến (hoặc phần cứng mã hóa nội tuyến ) đề cập đến phần cứng mã hóa/giải mã dữ liệu trong khi dữ liệu đang trên đường đến/từ thiết bị lưu trữ. Thông thường, đây là bộ điều khiển máy chủ UFS hoặc eMMC thực hiện các tiện ích mở rộng tiền điện tử được xác định bởi thông số kỹ thuật JEDEC tương ứng.

Thiết kế

Phần này trình bày thiết kế của tính năng phím bao bọc phần cứng, bao gồm cả phần hỗ trợ phần cứng cần thiết cho tính năng này. Cuộc thảo luận này tập trung vào mã hóa dựa trên tệp (FBE), nhưng giải pháp này cũng áp dụng cho mã hóa siêu dữ liệu .

Một cách để tránh cần đến các khóa mã hóa thô trong bộ nhớ hệ thống là chỉ giữ chúng trong các khe khóa của một công cụ mã hóa nội tuyến. Tuy nhiên, cách tiếp cận này gặp phải một số vấn đề:

  • Số lượng khóa mã hóa có thể vượt quá số lượng khe khóa.
  • Công cụ mã hóa nội tuyến chỉ có thể được sử dụng để mã hóa/giải mã toàn bộ khối dữ liệu trên đĩa. Tuy nhiên, trong trường hợp của FBE, phần mềm vẫn cần có khả năng thực hiện các công việc mã hóa khác như mã hóa tên tệp và lấy mã định danh khóa. Phần mềm vẫn cần quyền truy cập vào các khóa FBE thô để thực hiện công việc khác này.

Để tránh những sự cố này, thay vào đó, các khóa lưu trữ được tạo thành các khóa bọc phần cứng , chỉ phần cứng chuyên dụng mới có thể mở khóa và sử dụng khóa này. Điều này cho phép số lượng phím không giới hạn được hỗ trợ. Ngoài ra, hệ thống phân cấp khóa được sửa đổi và chuyển một phần sang phần cứng này, cho phép trả lại khóa con cho phần mềm đối với các tác vụ không thể sử dụng công cụ mã hóa nội tuyến.

phân cấp khóa

Các khóa có thể được lấy từ các khóa khác bằng cách sử dụng KDF (hàm dẫn xuất khóa) , chẳng hạn như HKDF , dẫn đến hệ thống phân cấp khóa .

Sơ đồ sau đây mô tả hệ thống phân cấp khóa điển hình cho FBE khi không sử dụng các khóa bọc phần cứng:

Phân cấp khóa FBE (tiêu chuẩn)
Hình 1. Hệ thống phân cấp khóa FBE (tiêu chuẩn)

Khóa lớp FBE là khóa mã hóa thô mà Android chuyển đến nhân Linux để mở khóa một tập hợp các thư mục được mã hóa cụ thể, chẳng hạn như bộ nhớ được mã hóa bằng thông tin xác thực cho một người dùng Android cụ thể. (Trong nhân, khóa này được gọi là khóa chính fscrypt .) Từ khóa này, nhân lấy các khóa con sau:

  • Mã định danh chính. Giá trị này không được sử dụng để mã hóa, mà là một giá trị được sử dụng để xác định khóa mà một tệp hoặc thư mục cụ thể được bảo vệ.
  • Khóa mã hóa nội dung tệp
  • Khóa mã hóa tên tệp

Ngược lại, sơ đồ sau đây mô tả hệ thống phân cấp khóa cho FBE khi sử dụng các khóa bọc phần cứng:

Hệ thống phân cấp khóa FBE (với khóa bọc phần cứng)
Hình 2. Hệ thống phân cấp khóa FBE (với khóa bọc phần cứng)

So với trường hợp trước đó, một cấp độ bổ sung đã được thêm vào hệ thống phân cấp khóa và khóa mã hóa nội dung tệp đã được di chuyển. Nút gốc vẫn đại diện cho khóa mà Android chuyển cho Linux để mở khóa một tập hợp các thư mục được mã hóa. Tuy nhiên, giờ đây khóa đó ở dạng được bao bọc tạm thời và để được sử dụng, nó phải được chuyển đến phần cứng chuyên dụng. Phần cứng này phải triển khai hai giao diện có khóa được bao bọc tạm thời:

  • Một giao diện để lấy inline_encryption_key và lập trình trực tiếp nó vào một khe khóa của công cụ mã hóa nội tuyến. Điều này cho phép nội dung tệp được mã hóa/giải mã mà không cần phần mềm có quyền truy cập vào khóa thô. Trong các nhân chung của Android, giao diện này tương ứng với thao tác blk_crypto_ll_ops::keyslot_program , thao tác này phải được trình điều khiển lưu trữ triển khai.
  • Một giao diện để lấy và trả về sw_secret ("bí mật phần mềm" -- còn được gọi là "bí mật thô" ở một số nơi), là khóa mà Linux sử dụng để lấy các khóa con cho mọi thứ khác ngoài mã hóa nội dung tệp. Trong các nhân chung của Android, giao diện này tương ứng với thao tác blk_crypto_ll_ops::derive_sw_secret , thao tác này phải được trình điều khiển lưu trữ triển khai.

Để lấy được inline_encryption_keysw_secret từ khóa lưu trữ thô, phần cứng phải sử dụng một KDF mã hóa mạnh. KDF này phải tuân theo các phương pháp hay nhất về mật mã; nó phải có cường độ bảo mật ít nhất là 256 bit, nghĩa là đủ cho bất kỳ thuật toán nào được sử dụng sau này. Nó cũng phải sử dụng nhãn riêng biệt, ngữ cảnh và/hoặc chuỗi thông tin dành riêng cho ứng dụng khi lấy từng loại khóa con để đảm bảo rằng các khóa con kết quả được cách ly bằng mật mã, nghĩa là kiến ​​thức về một trong số chúng không tiết lộ bất kỳ khóa nào khác. Không cần kéo dài khóa vì khóa lưu trữ thô đã là khóa ngẫu nhiên thống nhất.

Về mặt kỹ thuật, bất kỳ KDF nào đáp ứng các yêu cầu bảo mật đều có thể được sử dụng. Tuy nhiên, với mục đích thử nghiệm, cần triển khai lại cùng một KDF trong mã thử nghiệm. Hiện tại, một KDF đã được xem xét và triển khai; nó có thể được tìm thấy trong mã nguồn cho vts_kernel_encryption_test . Phần cứng nên sử dụng KDF này, sử dụng NIST SP 800-108 "KDF ở Chế độ bộ đếm" với AES-256-CMAC làm PRF. Lưu ý rằng để tương thích, tất cả các phần của thuật toán phải giống hệt nhau, bao gồm cả việc lựa chọn bối cảnh và nhãn KDF cho từng khóa con.

gói chìa khóa

Để đáp ứng các mục tiêu bảo mật của khóa bọc phần cứng, hai loại gói khóa được xác định:

  • Gói tạm thời : phần cứng mã hóa khóa thô bằng cách sử dụng khóa được tạo ngẫu nhiên ở mỗi lần khởi động và không được hiển thị trực tiếp bên ngoài phần cứng.
  • Gói dài hạn : phần cứng mã hóa khóa thô bằng cách sử dụng khóa duy nhất, liên tục được tích hợp trong phần cứng, khóa này không được hiển thị trực tiếp bên ngoài phần cứng.

Tất cả các khóa được chuyển đến nhân Linux để mở khóa bộ lưu trữ đều được gói tạm thời. Điều này đảm bảo rằng nếu kẻ tấn công có thể trích xuất khóa đang sử dụng từ bộ nhớ hệ thống, thì khóa đó sẽ không sử dụng được không chỉ ngoài thiết bị mà còn trên thiết bị sau khi khởi động lại.

Đồng thời, Android vẫn cần có khả năng lưu trữ phiên bản mã hóa của khóa trên đĩa để có thể mở khóa chúng ngay từ đầu. Các khóa thô sẽ hoạt động cho mục đích này. Tuy nhiên, điều mong muốn là không bao giờ có các khóa thô trong bộ nhớ hệ thống để chúng không bao giờ có thể được trích xuất để sử dụng bên ngoài thiết bị, ngay cả khi được trích xuất khi khởi động. Vì lý do này, khái niệm gói dài hạn được xác định.

Để hỗ trợ quản lý các khóa được bọc theo hai cách khác nhau này, phần cứng phải triển khai các giao diện sau:

  • Các giao diện để tạo và nhập khóa lưu trữ, trả lại chúng ở dạng gói dài hạn. Các giao diện này được truy cập gián tiếp thông qua KeyMint và chúng tương ứng với thẻ TAG_STORAGE_KEY KeyMint. Khả năng "tạo" được vold sử dụng để tạo khóa lưu trữ mới cho Android sử dụng, trong khi khả năng "nhập" được vts_kernel_encryption_test sử dụng để nhập khóa kiểm tra.
  • Một giao diện để chuyển đổi khóa lưu trữ được bao bọc dài hạn thành khóa lưu trữ được bao bọc tạm thời. Điều này tương ứng với phương thức convertStorageKeyToEphemeral KeyMint. Phương pháp này được cả voldvts_kernel_encryption_test sử dụng để mở khóa bộ nhớ.

Thuật toán gói khóa là một chi tiết triển khai, nhưng thuật toán này nên sử dụng AEAD mạnh chẳng hạn như AES-256-GCM với các IV ngẫu nhiên.

Yêu cầu thay đổi phần mềm

AOSP đã có một khung cơ bản để hỗ trợ các khóa bọc phần cứng. Điều này bao gồm hỗ trợ trong các thành phần không gian người dùng như vold , cũng như hỗ trợ nhân Linux trong blk-crypto , fscryptdm-default-key .

Tuy nhiên, một số thay đổi triển khai cụ thể là bắt buộc.

KeyMint thay đổi

Việc triển khai KeyMint của thiết bị phải được sửa đổi để hỗ trợ TAG_STORAGE_KEY và triển khai phương pháp convertStorageKeyToEphemeral .

Trong Keymaster, exportKey đã được sử dụng thay vì convertStorageKeyToEphemeral .

nhân Linux thay đổi

Trình điều khiển nhân Linux cho công cụ mã hóa nội tuyến của thiết bị phải được sửa đổi để hỗ trợ các khóa được bọc phần cứng.

Đối với các nhân android14 trở lên, hãy đặt BLK_CRYPTO_KEY_TYPE_HW_WRAPPED trong blk_crypto_profile::key_types_supported , tạo blk_crypto_ll_ops::keyslot_programblk_crypto_ll_ops::keyslot_evict hỗ trợ lập trình/gỡ bỏ các khóa được bọc phần cứng và triển khai blk_crypto_ll_ops::derive_sw_secret .

Đối với nhân android12android13 , hãy đặt BLK_CRYPTO_FEATURE_WRAPPED_KEYS trong blk_keyslot_manager::features , tạo blk_ksm_ll_ops::keyslot_programblk_ksm_ll_ops::keyslot_evict hỗ trợ lập trình/gỡ bỏ các khóa được bọc phần cứng và triển khai blk_ksm_ll_ops::derive_raw_secret .

Đối với nhân android11 , hãy đặt BLK_CRYPTO_FEATURE_WRAPPED_KEYS trong keyslot_manager::features , tạo keyslot_mgmt_ll_ops::keyslot_programkeyslot_mgmt_ll_ops::keyslot_evict hỗ trợ lập trình/gỡ bỏ các khóa được bọc phần cứng và triển khai keyslot_mgmt_ll_ops::derive_raw_secret .

thử nghiệm

Mặc dù mã hóa bằng khóa được bao bọc bởi phần cứng khó kiểm tra hơn so với mã hóa bằng khóa tiêu chuẩn, nhưng vẫn có thể kiểm tra bằng cách nhập khóa kiểm tra và triển khai lại dẫn xuất khóa mà phần cứng thực hiện. Điều này được thực hiện trong vts_kernel_encryption_test . Để chạy thử nghiệm này, hãy chạy:

atest -v vts_kernel_encryption_test

Đọc nhật ký kiểm tra và xác minh rằng các trường hợp kiểm tra khóa bao bọc phần cứng (ví dụ: FBEPolicyTest.TestAesInlineCryptOptimizedHwWrappedKeyPolicyDmDefaultKeyTest.TestHwWrappedKey ) không bị bỏ qua do không phát hiện hỗ trợ cho các khóa bao bọc phần cứng, vì kết quả kiểm tra sẽ vẫn "đạt" trong trường hợp.

Cho phép

Sau khi hỗ trợ khóa được bao bọc bởi phần cứng của thiết bị hoạt động bình thường, bạn có thể thực hiện các thay đổi sau đối với tệp fstab của thiết bị để Android sử dụng tệp đó cho FBE và mã hóa siêu dữ liệu:

  • FBE: thêm cờ wrappedkey_v0 vào tham số fileencryption . Ví dụ: sử dụng fileencryption=::inlinecrypt_optimized+wrappedkey_v0 . Để biết thêm chi tiết, xem tài liệu FBE .
  • Mã hóa siêu dữ liệu: thêm cờ wrappedkey_v0 vào tham số metadata_encryption . Ví dụ: sử dụng metadata_encryption=:wrappedkey_v0 . Để biết thêm chi tiết, hãy xem tài liệu mã hóa siêu dữ liệu .