Chìa khoá bọc phần cứng

Giống như hầu hết phần mềm mã hoá tệp và đĩa, phương thức mã hoá bộ nhớ của Android thường dựa vào các khoá mã hoá thô có trong bộ nhớ hệ thống để có thể thực hiện quá trình mã hoá. Ngay cả khi thực hiện mã hoá bằng phần cứng chuyên dụng thay vì bằng phần mềm, thì phần mềm thường vẫn cần quản lý khoá mã hoá thô.

Thường thì đây không phải là vấn đề vì các khoá 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à bộ nhớ mã hoá nhằm mục đích bảo vệ. Tuy nhiên, mong muốn cung cấp tăng cường khả năng bảo vệ trước các loại tấn công khác, chẳng hạn như cold boot (khởi động nguội) các cuộc tấn công và cuộc tấn công trực tuyến mà trong đó kẻ tấn công có thể rò rỉ hệ thống mà không gây ảnh hưởng hoàn toàn đến thiết bị.

Để giải quyết vấn đề này, Android 11 đã ra mắt tính năng hỗ trợ dành cho khoá gói phần cứng (có hỗ trợ phần cứng). Khoá bọc phần cứng là khoá lưu trữ chỉ được xác định ở dạng thô để 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 phím này được bọc (được mã hoá). Phần cứng này phải có khả năng tạo và nhập khoá lưu trữ, khoá lưu trữ gói ở dạng tạm thời và dài hạn, lấy từ khoá con, trực tiếp lập trình một khoá con thành một công cụ mã hoá cùng dòng, và trả về một khoá con riêng biệt cho phần mềm.

Lưu ý: Một công cụ mã hoá nội tuyến (hoặc công cụ mã hoá nội tuyến) phần cứng mã hoá) đề cập đến phần cứng mã hoá/giải mã dữ liệu trong khi ảnh đang được truyền đến/từ thiết bị lưu trữ. Thông thường, đây là máy chủ UFS hoặc eMMC bộ điều khiển triển khai các tiện ích Crypto được xác định bằng Quy cách của JEDEC.

Thiết kế

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

Một cách để tránh cần đến khoá mã hoá thô trong bộ nhớ hệ thống là chỉ đặt chúng trong các ô khoá của một công cụ mã hoá cùng dòng. Tuy nhiên, việc này phương pháp tiếp cận này gặp phải một số vấn đề:

  • Số lượng khoá mã hoá có thể vượt quá số lượng khe khoá.
  • Công cụ mã hoá nội tuyến chỉ có thể dùng để mã hoá/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 phải có khả năng thực hiện công việc mật mã khác như mã hoá tên tệp và khoá dẫn xuất giá trị nhận dạng. Phần mềm vẫn cần truy cập vào các khoá FBE thô để làm công việc khác này.

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

Hệ phân cấp khoá

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

Biểu đồ dưới đây mô tả hệ phân cấp khoá điển hình cho FBE khi khoá bọc phần cứng không được sử dụng:

Hệ phân cấp khoá FBE (chuẩn)
Hình 1. Hệ phân cấp khoá FBE (chuẩn)

Khoá lớp FBE là khoá mã hoá thô mà Android truyền sang Linux để mở khoá một tập hợp thư mục đã mã hoá cụ thể, chẳng hạn như bộ nhớ được mã hoá thông tin xác thực cho một người dùng Android cụ thể. (Trong kernel, đây là được gọi là khoá chính fscrypt.) Từ khoá này, hạt nhân suy ra các khoá con sau:

  • Giá trị nhận dạng khoá. Giá trị này không được dùng để mã hoá mà là một giá trị được dùng để xác định khoá cho một tệp hoặc thư mục cụ thể được bảo vệ.
  • Khoá mã hoá nội dung tệp
  • Khoá mã hoá tên tệp

Ngược lại, biểu đồ dưới đây mô tả hệ phân cấp khoá của FBE khi khoá bọc phần cứng được dùng:

Hệ phân cấp khoá FBE (với khoá được bao bọc bằng phần cứng)
Hình 2. Hệ phân cấp khoá FBE (với khoá được bao bọc bằng phần cứng)

So với trường hợp trước, khoá đã được thêm một cấp bổ sung và khoá mã hoá nội dung tệp đã bị chuyển vị trí. Gốc nút vẫn đại diện cho khoá mà Android truyền sang Linux để mở khoá một tập hợp các thư mục đã mã hoá. Tuy nhiên, giờ đây khoá đó nằm ở dạng được gói tạm thời và để sử dụng, URL đó phải được truyền đến phần cứng chuyên dụng. Phần cứng này phải triển khai 2 giao diện lấy một khoá được gói tạm thời:

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

Để lấy inline_encryption_keysw_secret từ khoá lưu trữ thô, phần cứng phải sử dụng KDF được mã hoá mạnh. KDF này phải tuân theo các phương pháp hay nhất về mật mã học; thiết bị phải có độ mạnh bảo mật là tối thiểu 256 bit, tức là đủ cho mọi thuật toán được sử dụng sau này. Mã này 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 riêng biệt khi lấy từng loại khoá con để đảm bảo rằng các khoá con thu được được tách biệt bằng mật mã, tức là việc biết về một trong số đó sẽ không cho thấy bất kỳ điều gì khác. Không bắt buộc kéo giãn khoá vì khoá lưu trữ thô đã là phím ngẫu nhiên thống nhất.

Về mặt kỹ thuật, bạn có thể sử dụng bất kỳ KDF nào đáp ứng các yêu cầu về bảo mật. Tuy nhiên, đối với mục đích thử nghiệm, cần phải triển khai lại cùng một KDF trong mã kiểm thử. Hiện tại, một KDF đã được xem xét và triển khai; có thể tìm thấy thiết bị đó trong mã nguồn cho vts_kernel_encryption_test. Phần cứng nên sử dụng KDF này. KDF này sử dụng NIST SP 800-108 "KDF ở chế độ bộ đếm" với AES-256-CMAC làm PRF. Xin 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 ngữ cảnh KDF và nhãn cho từng khoá con.

Bao bọc phím

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

  • Gói tạm thời: phần cứng mã hoá khoá thô bằng cách sử dụng một khoá đượ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ã hoá khoá thô bằng cách sử dụng một một khoá duy nhất, cố định được tích hợp sẵn trong phần cứng mà không trực tiếp bên ngoài phần cứng.

Tất cả các khoá được truyền tới nhân hệ điều hành Linux để mở khoá bộ nhớ đều 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 khoá đang sử dụng trong bộ nhớ hệ thống thì không chỉ sử dụng được khoá đó 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ã hoá phím trên ổ đĩa để có thể mở khoá ngay từ đầu. Dữ liệu thô khoá sẽ hoạt động cho mục đích này. Tuy nhiên, chúng ta nên không bao giờ có dữ liệu thô các khoá đều có trong bộ nhớ hệ thống để không ai có thể trích xuất sang được dùng bên ngoài thiết bị, ngay cả khi được trích xuất tại thời điểm khởi động. Vì lý do này, khái niệm là gói dài hạn được xác định.

Để hỗ trợ quản lý các khoá đượ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 khoá lưu trữ, trả lại chú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à các thẻ này tương ứng với thẻ KeyMint TAG_STORAGE_KEY. Lệnh "generate" (tạo) khả năng được vold dùng để tạo bộ nhớ mới các khoá để Android sử dụng, còn tuỳ chọn "nhập" khả năng được sử dụng bởi vts_kernel_encryption_test để nhập khoá kiểm thử.
  • Một giao diện để chuyển đổi khoá lưu trữ được gói trong thời gian dài thành khoá lưu trữ tạm thời. Điều này tương ứng với Phương thức KeyMint convertStorageKeyToEphemeral. Phương thức này được sử dụng bởi cả voldvts_kernel_encryption_test theo thứ tự để mở khoá bộ nhớ.

Thuật toán gói khoá là chi tiết triển khai, nhưng phải sử dụng AEAD mạnh như AES-256-GCM với IV ngẫu nhiên.

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

AOSP đã có khung cơ bản để hỗ trợ các khoá được gói phần cứng. Chiến dịch này bao gồm tính năng hỗ trợ trong các thành phần không gian người dùng như vold, cũng như làm hỗ trợ nhân Linux trong blk-Crypto, fscryptdm-default-key.

Tuy nhiên, bạn bắt buộc phải thực hiện một số thay đổi cụ thể về việc triển khai.

Các thay đổi của KeyMint

Phải sửa đổi quá trình triển khai KeyMint của thiết bị để hỗ trợ TAG_STORAGE_KEY và triển khai convertStorageKeyToEphemeral.

Trong Keymaster, exportKey đã được dùng thay cho convertStorageKeyToEphemeral

Thay đổi nhân hệ điều hành Linux

Bạn phải sửa đổi trình điều khiển nhân hệ điều hành Linux cho công cụ mã hoá cùng dòng của thiết bị để hỗ trợ các khoá được gói phần cứng.

Đối với các hạt nhân android14 trở lên, thiết lập 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ỏ khoá được gói phần cứng, và triển khai blk_crypto_ll_ops::derive_sw_secret.

Đối với các hạt nhân android12android13, đặ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ỏ khoá được gói phần cứng, và triển khai blk_ksm_ll_ops::derive_raw_secret.

Đối với hạt nhân android11, thiết lập 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ỏ khoá được gói phần cứng, và triển khai keyslot_mgmt_ll_ops::derive_raw_secret.

Thử nghiệm

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

atest -v vts_kernel_encryption_test

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

Đang bật

Khi tính năng hỗ trợ khoá bao bọc phần cứng của thiết bị hoạt động đúng cách, 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 công cụ này để mã hoá siêu dữ liệu và FBE:

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