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 việc mã hóa được thực hiện bằng phần cứng chuyên dụng chứ không phải bằng phần mềm, phần mềm nhìn 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à loại tấn công chính mà mã hóa lưu trữ nhằm mục đích bảo vệ chống lại. Tuy nhiên, người ta mong muốn tăng cường khả năng bảo vệ chống lại các loại 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ể 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 tính năng hỗ trợ cho các khóa được bọc phần cứng , nơi có hỗ trợ phần cứng. Khóa bọc phần cứng là các khóa lưu trữ chỉ được biết đến ở dạng thô đối với phần cứng chuyên dụng; phần mềm chỉ nhìn thấy và làm việc với các khóa này ở dạng được bọ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, lấy 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 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 triển khai các tiện ích mở rộng mật mã được xác định bởi đặc 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 được bao bọc trong phần cứng, bao gồm cả những hỗ trợ phần cứng nào được yêu cầu cho tính năng đó. 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 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 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 vấn đề này, thay vào đó, các khóa lưu trữ được tạo thành các khóa được bọc trong phần cứng , chỉ có thể được mở ra và sử dụng bởi phần cứng chuyên dụng. Điều này cho phép hỗ trợ số lượng khóa không giới hạn. 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 cho các tác vụ không thể sử dụng công cụ mã hóa nội tuyến.

Hệ thống 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 mô tả hệ thống phân cấp khóa điển hình cho FBE khi không sử dụng khóa bọc phần cứng:

Hệ thống phân cấp khóa FBE (tiêu chuẩn)
Hình 1. 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 tới nhân Linux để mở khóa một tập hợp thư mục được mã hóa cụ thể, chẳng hạn như bộ lưu trữ được mã hóa thông tin xác thực cho một người dùng Android cụ thể. (Trong kernel, khóa này được gọi là khóa chính fscrypt .) Từ khóa này, kernel lấy ra 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à 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 tin
  • Khóa mã hóa tên tập tin

Ngược lại, sơ đồ sau mô tả hệ thống phân cấp khóa cho FBE khi sử dụng khóa bọc phần cứ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 được 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 dời. 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, hiện tại khóa đó ở dạng được bao bọc tạm thời và để sử dụng được, 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 phổ biến 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" - ở một số nơi còn được gọi là "bí mật thô"), đây là khóa mà Linux sử dụng để lấy các khóa con cho mọi thứ ngoài mã hóa nội dung tệp. Trong các nhân phổ biến 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 KDF có mật mã 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ó độ mạnh bảo mật ít nhất là 256 bit, tức 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, 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 thu được được cách ly về mặt mật mã, tức 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 yêu cầu bảo mật đều có thể được sử dụng. Tuy nhiên, vì mục đích thử nghiệm, cần phải triển khai lại KDF tương tự trong mã thử nghiệm. Hiện nay đã có 1 KDF được rà soát và triển khai; nó có thể được tìm thấy trong mã nguồn của 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ế độ truy cập" 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 mỗi 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 liên tục, duy nhất được tích hợp trong phần cứng 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 một khóa đang sử dụng từ bộ nhớ hệ thống thì khóa đó sẽ không thể sử dụng được không chỉ trên 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 các 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 gói 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 để 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.
  • Giao diện để chuyển đổi khóa lưu trữ được bọc dài hạn thành khóa lưu trữ được 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 nó phải sử dụng AEAD mạnh 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 được bọc phần cứng. Điều này bao gồm sự 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 cụ thể trong việc triển khai là bắt buộc.

Thay đổi của KeyMint

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 thức convertStorageKeyToEphemeral .

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

Thay đổi nhân Linux

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 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/loại bỏ các khóa 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/loại bỏ các khóa 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/loại bỏ các khóa bọc phần cứng và triển khai keyslot_mgmt_ll_ops::derive_raw_secret .

Kiểm tra

Mặc dù việc mã hóa bằng khóa bọc phần cứng khó kiểm tra hơn 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 quá trình phái sinh 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 bọc phần cứng (ví dụ: FBEPolicyTest.TestAesInlineCryptOptimizedHwWrappedKeyPolicyDmDefaultKeyTest.TestHwWrappedKey ) không bị bỏ qua do không phát hiện được hỗ trợ cho các khóa bọc phần cứng, vì kết quả kiểm tra sẽ vẫn được "thông qua" trong trường hợp.

Cho phép

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

  • FBE: thêm cờ wrappedkey_v0 vào tham fileencryption tệp. Ví dụ: sử dụng fileencryption=::inlinecrypt_optimized+wrappedkey_v0 . Để biết thêm chi tiết, hãy 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 .