Tôi đang trích dẫn từ Hướng dẫn sử dụng Android ở đây , nhưng:
GHI CHÚ:
Nguồn tôi đã sử dụng không liên quan trực tiếp đến Marshmallow nhưng có liên quan đến Lollipop và cao hơn.
TL: DR
Bây giờ tôi sẽ chỉ giải quyết các câu hỏi của OP. Chi tiết kỹ thuật sẽ làm theo.
Khóa mã hóa mặc định đến từ nguồn phần cứng (chip tương tự TPM) và mật khẩu mặc định của AOSP được xác định như default_password
trong cryptfs.c
tệp nguồn, xem bên dưới.
Có, không chỉ mặc định, mà bất kỳ mật khẩu nào cũng được tạo thành khóa và được lưu trữ trên chip giống như TPM, được gọi là TEE (viết tắt của "Môi trường thực thi tin cậy", xem bên dưới để biết thêm chi tiết).
Một hacker có quyền truy cập UART / JTAG vào các chip trên SoC của thiết bị về mặt kỹ thuật có thể truy cập vào khóa TEE hoặc một hạt nhân tùy chỉnh có thể rò rỉ thông tin này cho tin tặc. Một số cơ quan 3 chữ cái trong các lý thuyết âm mưu có thể hợp tác với OEM để có được những hạt nhân không an toàn này được sử dụng trong các thiết bị sản xuất, nhưng tôi sẽ không đặt nhiều cửa hàng bởi nó. Một lần nữa, xem phần cuối của câu trả lời này để biết thêm chi tiết.
Điều duy nhất ngăn chặn tin tặc truy cập vào khóa là số lượng nỗ lực cần thiết để làm điều đó.
- Việc kiểm tra hàm băm (kiểm tra) phần sụn (được gọi là "Khởi động được xác minh" của Google) trên thực tế được thực hiện trên và trên Lollipop theo mặc định (và có sẵn từ JellyBean 4.3 trở đi), bằng mô-đun hạt nhân được gọi
dm-verity
. Tuy nhiên, điều này là độc lập với tình trạng mã hóa.
Nguồn: Hướng dẫn bảo mật AOSP tại đây .
- Về quy trình liên quan đến giải mã hệ thống bằng mật khẩu tùy chỉnh, xem bên dưới. Tôi sẽ chỉ nói với bạn ở đây rằng mật khẩu người dùng có liên quan đến cả việc tạo và sử dụng khóa mã hóa.
Tổng quat
Khi khởi động lần đầu tiên, thiết bị sẽ tạo một khóa chính 128 bit được tạo ngẫu nhiên và sau đó băm nó bằng mật khẩu mặc định và muối được lưu trữ. Mật khẩu mặc định là: "default_password" Tuy nhiên, hàm băm kết quả cũng được ký thông qua TEE (chẳng hạn như TrustZone), sử dụng hàm băm của chữ ký để mã hóa khóa chính.
Bạn có thể tìm thấy mật khẩu mặc định được xác định trong tệp cryptfs.c của Dự án nguồn mở Android .
Khi người dùng đặt mã PIN / mật khẩu hoặc mật khẩu trên thiết bị, chỉ có khóa 128 bit được mã hóa lại và lưu trữ. (ví dụ: thay đổi mã PIN / pass / mẫu của người dùng KHÔNG gây ra mã hóa lại phân vùng userdata.)
Bắt đầu một thiết bị được mã hóa với mã hóa mặc định
Đây là những gì xảy ra khi bạn khởi động một thiết bị được mã hóa không có mật khẩu. Vì các thiết bị Android 5.0 được mã hóa trong lần khởi động đầu tiên, nên không có mật khẩu được đặt và do đó đây là trạng thái mã hóa mặc định.
- Phát hiện mã hóa / dữ liệu không có mật khẩu
Phát hiện thiết bị Android được mã hóa vì / dữ liệu không thể được gắn và một trong các cờ encryptable
hoặc forceencrypt
được đặt.
vold
đặt vold.decrypt
để trigger_default_encryption
, mà bắt đầu các defaultcrypto
dịch vụ. trigger_default_encryption
kiểm tra loại mã hóa để xem / dữ liệu được mã hóa có hoặc không có mật khẩu.
- Giải mã / dữ liệu
Tạo dm-crypt
thiết bị qua thiết bị khối để thiết bị sẵn sàng sử dụng.
- Gắn kết / dữ liệu
vold
sau đó gắn kết phân vùng thực / dữ liệu được giải mã và sau đó chuẩn bị phân vùng mới. Nó đặt tài sản vold.post_fs_data_done
để 0
rồi đặt vold.decrypt
vào trigger_post_fs_data
. Điều này gây ra init.rc
chạy nópost-fs-data
lệnh . Họ sẽ tạo bất kỳ thư mục hoặc liên kết cần thiết và sau đó được đặt vold.post_fs_data_done
thành 1
.
Khi vold
nhìn thấy 1 trong thuộc tính đó, nó đặt thuộc tính vold.decrypt
thành : trigger_restart_framework
. Điều này gây ra init.rc
bắt đầu dịch vụ trong lớp main
một lần nữa và cũng bắt đầu dịch vụ trong lớp late_start lần đầu tiên kể từ khi khởi động.
- Khung bắt đầu
Bây giờ khung khởi động tất cả các dịch vụ của nó bằng cách sử dụng dữ liệu / giải mã và hệ thống đã sẵn sàng để sử dụng.
Bắt đầu một thiết bị được mã hóa mà không cần mã hóa mặc định
Đây là những gì xảy ra khi bạn khởi động một thiết bị được mã hóa có mật khẩu được đặt. Mật khẩu của thiết bị có thể là mã pin, mẫu hoặc mật khẩu.
- Phát hiện thiết bị được mã hóa bằng mật khẩu
Phát hiện thiết bị Android được mã hóa vì cờ ro.crypto.state = "encrypted"
vold
đặt vold.decrypt
thành trigger_restart_min_framework
vì / dữ liệu được mã hóa bằng mật khẩu.
- Núi tmpfs
init
đặt năm thuộc tính để lưu các tùy chọn gắn kết ban đầu được cung cấp cho / dữ liệu với các tham số được truyền từ init.rc
. vold
sử dụng các thuộc tính này để thiết lập ánh xạ tiền điện tử:
ro.crypto.fs_type
ro.crypto.fs_real_blkdev
ro.crypto.fs_mnt_point
ro.crypto.fs_options
ro.crypto.fs_flags
(Số hex 8 chữ số ASCII có trước 0x)
- Bắt đầu khung để nhắc mật khẩu
Khung khởi động và thấy rằng vold.decrypt
được đặt thành trigger_restart_min_framework
. Điều này nói với khung rằng nó đang khởi động trên tmpfs /data
đĩa và nó cần lấy mật khẩu người dùng.
Tuy nhiên, trước tiên, nó cần đảm bảo rằng đĩa đã được mã hóa chính xác. Nó gửi lệnh cryptfs cryptocomplete
đến vold
. vold
trả về 0 nếu mã hóa được hoàn thành thành công, -1 khi lỗi nội bộ hoặc -2 nếu mã hóa không được hoàn thành thành công. vold
xác định điều này bằng cách tìm trong siêu dữ liệu tiền điện tử choCRYPTO_ENCRYPTION_IN_PROGRESS
cờ. Nếu được đặt, quá trình mã hóa bị gián đoạn và không có dữ liệu có thể sử dụng được trên thiết bị.
Nếu vold
trả về lỗi, giao diện người dùng sẽ hiển thị thông báo cho người dùng để khởi động lại và khôi phục cài đặt gốc cho thiết bị và cung cấp cho người dùng một nút để nhấn để làm như vậy.
- Giải mã dữ liệu bằng mật khẩu
Khi cryptfs cryptocomplete
thành công, khung hiển thị giao diện người dùng yêu cầu mật khẩu đĩa. UI kiểm tra mật khẩu bằng cách gửi lệnh cryptfs checkpw
đến vold
. Nếu mật khẩu là chính xác (được xác định bằng cách gắn thành công giải mã /data
tại một vị trí tạm thời, sau đó ngắt kết nối nó), vold lưu tên của thiết bị chặn được giải mã trong thuộc tính ro.crypto.fs_crypto_blkdev
và trả về trạng thái 0 cho UI. Nếu mật khẩu không chính xác, nó sẽ trả về -1 cho UI.
- Dừng khung
Giao diện người dùng đưa ra một đồ họa khởi động tiền điện tử và sau đó gọi vold bằng lệnh cryptfs restart
. vold
bộ tài sản vold.decrypt
để trigger_reset_main
, gây ra init.rc
để làm class_reset main
. Điều này dừng tất cả các dịch vụ trong main
lớp, cho phép tmpfs /data
không bị ngắt kết nối.
- Gắn kết / dữ liệu
vold
sau đó gắn kết /data
phân vùng thực được giải mã và chuẩn bị phân vùng mới (có thể chưa bao giờ được chuẩn bị nếu nó được mã hóa với tùy chọn xóa, không được hỗ trợ trong bản phát hành đầu tiên). Nó đặt tài sản vold.post_fs_data_done
để 0
rồi đặt vold.decrypt
vào trigger_post_fs_data
. Điều này gây ra init.rc
để chạy nó post-fs-data commands
. Họ sẽ tạo bất kỳ thư mục hoặc liên kết cần thiết và sau đó được đặt vold.post_fs_data_done
thành 1
. Khi vold
nhìn thấy 1
trong tài sản đó, nó đặt thuộc tính vold.decrypt
cho trigger_restart_framework
. Điều này gây ra init.rc
bắt đầu dịch vụ trong lớp main
một lần nữa và cũng bắt đầu dịch vụ trong lớp late_start
lần đầu tiên kể từ khi khởi động.
- Bắt đầu khuôn khổ đầy đủ
Bây giờ khung khởi động tất cả các dịch vụ của nó bằng cách sử dụng hệ thống tệp được giải mã / dữ liệu và hệ thống đã sẵn sàng để sử dụng.
Lưu trữ khóa được mã hóa
Khóa được mã hóa được lưu trữ trong siêu dữ liệu tiền điện tử. Việc sao lưu phần cứng được thực hiện bằng cách sử dụng khả năng ký của Môi trường thực thi tin cậy (TEE). Trước đây, chúng tôi đã mã hóa khóa chính bằng một khóa được tạo bằng cách áp dụng scrypt
cho mật khẩu của người dùng và muối được lưu trữ.
Để làm cho khóa trở nên linh hoạt trước các cuộc tấn công ngoài hộp, chúng tôi mở rộng thuật toán này bằng cách ký khóa kết quả bằng khóa TEE được lưu trữ. Chữ ký kết quả sau đó được biến thành một khóa có độ dài phù hợp bằng một ứng dụng nữa scrypt
. Khóa này sau đó được sử dụng để mã hóa và giải mã khóa chính. Để lưu trữ khóa này:
- Tạo khóa mã hóa đĩa 16 byte ngẫu nhiên (DEK) và muối 16 byte.
- Áp dụng
scrypt
cho mật khẩu người dùng và muối để tạo khóa trung gian 32 byte 1 (IK1).
- Pad IK1 có byte bằng 0 với kích thước của khóa riêng bị ràng buộc bởi phần cứng (HBK). Cụ thể, chúng tôi đệm là: 00 || IK1 | | 00..00; một byte 0, 32 IK1 byte, 223 byte 0.
- Ký tên đệm IK1 với HBK để tạo IK2 256 byte.
- Ứng dụng
scrypt
cho IK2 và muối (cùng muối với bước 2) để tạo IK3 32 byte.
- Sử dụng 16 byte đầu tiên của IK3 là KEK và 16 byte cuối cùng là IV.
- Mã hóa DEK bằng AES_CBC, với khóa KEK và vectơ khởi tạo IV.